--- inn-1.7.2q.orig/debian/README.Debian +++ inn-1.7.2q/debian/README.Debian @@ -0,0 +1,145 @@ +Patches applied: + +0_insync_actived +0_insync_dbz_3.3 +0_insync_fastrm_symlink +0_insync_misc (history+timer+perl_mode+perl_messageid) +0_insync_largerhash +0_insync_overscream +0_insync_pathfeed +Ported from the insync patch kit, with some local changes: actived, +DBZ 3.2, fastrm symlink bug fix, precommit cache, Joe Greco's timers, +bigger hash table in expire, mmapped overview, Path feed from a +newsfeeds entry. +To enable actived put "useactived: yes" in inn.conf and "DOACTIVED=true" +in /etc/news/boot. It will *NOT* be used by nnrpd by default. + +1_perl_filter_patch +1_perl_misc +All patches from cleanfeed (mode.patch, messageid.patch, dynamic-load.patch, +filter.patch), some parts in 0_insync_misc too. +Updates for perl 5.8 by Marco d'Itri. + +2_perl_timer +Perl filter timer support. (Marco d'Itri) + +addhist +Disallow addhist when the server is paused or throttled. +(Miquel van Smoorenburg) + +bindaddress +Added port and bindaddress entries to inn.conf (Miquel van Smoorenburg +and Marco d'Itri). + +clientactive.c +Small inews-related fix. (Miquel van Smoorenburg) + +distribution_crash +Distribution header parsing patch. (Sylvain Robitaille) + +fastrm_allow_symlinks +Remove -u from the default fastrm command line. + +fixinterps +Support recent perl releases. + +getmodaddr.c +Use a local moderators file if inews cannot get one from the server. + +inet_addr_is_int +inet_addr does return int, not long. + +inews-misc +inews buffer overflow fix and something else I do not remember. +inews opens the active with CAopen instead of CAlistopen (Colin Watson). +inews authenticates with the remote server (Chip Salzenberg). + +inewsport +Add the inewsport inn.conf option. + +inncheck +Make it check for the right permissions for debian systems. + +innd.c_init_TimeOut +Bugfix: tv_usec must be initialized. + +innwatch_ctlinnd_timeout +Use a timeout when invoking ctlinnd from innwatch. + +misc_config_files +Change some defaults for debian packaging. + +misc_inn.conf +Document all new parameters. + +misc_makefiles +Fix support for $DESTDIR and other minor bugfixes. + +misc_paths.h +Add all new inn.conf parameters. + +misc_rc.news +Disable innwatch by default, add actived support. + +newsgroups_whitespace +Ignore whitespace in Newsgroups headers instead of rejecting the article. + +nnrpd_needs_libcrypt +Link nnrpd with -lcrypt. + +nnrpd_perl_edit_headers+bofh +From the BOFH patch by Andrew Gierth: in filter_post() the authenticated +user is available in the $user variable and the article body is put in +$body. If the string returned by filter_post() starts with DROP, the +article is silently dropped. +Backported from INN 2.x the code to modify headers in filter_nnrpd.pl. + +nntpsend.ctl_in_etc +Move nntpsend.ctl to /etc/. + +no_throttled_rmgroups +Bugfix: disallow rmgroups when the server is throttled or the history +will be damaged. + +parsedate_y2k +Y2K bugfix by Bettina Fink. + +path_audit +path_audit_fix +Path audit trail patch (Ian Jackson). Please read hosts.nntp(5). + +poison+remember_trash +Poison and REMEMBER_TRASH patch by Russ Allbery. + +recommend_ID +Tell clients the recommended Message-ID (Olaf Titz). + +rnews_reject_reason +Have rnews add an header to saved rejected articles. + +rnews_unknown +Minor rnews fixes (Marco d'Itri). + +scanlogs_use_innreport +innreport backported from INN 2.x. + +sendbatch +send-uucp +Commented some hardcoded configuration values, but everybody should use +send-uucp.pl anyway. + +use_controlchan +Controlchan support (backported from INN 2.x by Marco d'Itri). + +use_strerror +sys_errlist[] is deprecated. + +xmode +Add the XMODE command. + +x-trace +X-Trace header generation. + +More precise timer when innd is idle most of the time (Olaf Titz). +[Buried somewhere in the 0_insync_* patches.] + --- inn-1.7.2q.orig/debian/changelog +++ inn-1.7.2q/debian/changelog @@ -0,0 +1,670 @@ +inn (1:1.7.2q-46build2) hirsute; urgency=medium + + * No-change rebuild for the perl update. + + -- Matthias Klose Mon, 09 Nov 2020 10:51:13 +0100 + +inn (1:1.7.2q-46build1) focal; urgency=medium + + * No-change rebuild for the perl update. + + -- Matthias Klose Fri, 18 Oct 2019 19:28:01 +0000 + +inn (1:1.7.2q-46) unstable; urgency=medium + + * Suggest gnupg1 instead of gnupg. + * Install pgpverify.8 reproducibly. + + -- Marco d'Itri Sun, 17 Feb 2019 20:18:43 +0100 + +inn (1:1.7.2q-45) unstable; urgency=medium + + * Fixed a lot of compiler warnings, which should solve the NNTP + streaming feed corruption experienced on 64 bit platforms since + 1.7.2q-41+b1. (Closes: #784115) + * Switched to libsystemd-dev. (Closes: #779745) + * Rebuilt with current Perl. (Closes: #836788) + * Enabled --diff-ignore for recent versions of dpkg-source. + + -- Marco d'Itri Thu, 29 Dec 2016 04:24:28 +0100 + +inn (1:1.7.2q-44.1) unstable; urgency=medium + + * Non-maintainer upload. + * Apply fix from gregor herrmann fixing FTBFS with newer pod2man + (Closes: #787450) + + -- Dominic Hargreaves Thu, 20 Aug 2015 15:56:52 +0200 + +inn (1:1.7.2q-44) unstable; urgency=medium + + * inn.service: remove NoNewPrivileges=yes because it prevents innd + from sending emails since postdrop is sgid. + * inn.service: require network-online.target because innd will try to + resolve the hostnames in hosts.nntp only once at startup. + * prerm: stop the socket on removal. + + -- Marco d'Itri Wed, 23 Jul 2014 23:44:38 +0200 + +inn (1:1.7.2q-43) unstable; urgency=medium + + * Build-Depend on pkg-config. + * Do not log with LOG_CRIT normal shutdowns. (Closes: #10240) + * Mention pan instead of trn in the description. (Closes: #691248) + * Prevent fclose(NULL) on dbminit() failure. (Closes: #715994) + + -- Marco d'Itri Sun, 11 May 2014 02:46:08 +0200 + +inn (1:1.7.2q-42) unstable; urgency=medium + + * Added systemd unit files and implemented socket activation. + * Switched from /var/run/ to /run/. + * Stopped using $[ in innreport. + * Updated control.ctl and moderators. + + -- Marco d'Itri Sat, 10 May 2014 22:25:01 +0200 + +inn (1:1.7.2q-41) unstable; urgency=low + + * Replaced innmail, which uses obsolete Perl features, with mailx. + * config.data.debian: added support for dpkg-buildflags. + * New patch fix_perl514: stops using perl4's getopts.pl. (Closes: #670751) + * New patch siteinfo_format: fixes a format error. + * Added a xunbatch program. + + -- Marco d'Itri Fri, 29 Jun 2012 01:51:17 +0200 + +inn (1:1.7.2q-40) unstable; urgency=low + + * Stop using "sort +1n" in makehistory, because it is not supported + anymore by the squeeze version of coreutils. (Closes: #612265) + * Disable CHECK_INCLUDED_TEXT, we have perl filters to do this. + (Closes: #573993) + + -- Marco d'Itri Sat, 16 Apr 2011 02:41:34 +0200 + +inn (1:1.7.2q-39) unstable; urgency=low + + * Updated patch fix_perl510: backported from 2.x the changesets 7937, 7939 + and 8421. Thanks to Julien ÉLIE. (Closes: #541130) + * Link again with libpthread the binaries embedding perl because + binutils-gold correctly requires it. (Closes: #554920) + * Made the old shell control message handlers use bash. (Closes: #530104) + * Updated control.ctl. + + -- Marco d'Itri Sat, 26 Dec 2009 02:48:13 +0100 + +inn (1:1.7.2q-38) unstable; urgency=medium + + * Backported fixes from 2.4: + + New patch fix_ad_flag: honour the Ad newsfeeds flag. + + Updated patch fix_perl510: use newSVpvn_share to create the article + body SV much more efficiently. + + -- Marco d'Itri Wed, 10 Sep 2008 02:07:47 +0200 + +inn (1:1.7.2q-37) unstable; urgency=medium + + * Clean up /var/lib/news/ in the purge target instead of the remove target. + (Closes: #493824) + + -- Marco d'Itri Thu, 28 Aug 2008 04:08:44 +0200 + +inn (1:1.7.2q-36) unstable; urgency=low + + * Fixed the malformed poison+remember_trash patch which confused the + new dpkg. (Closes: #485368) + * Updated patch 1_perl_filter_patch: added more headers. + * Updated patch fix_perl510 with fixes/cleanups from 2.4.5 (and the + INN::syslog callback). + + -- Marco d'Itri Tue, 01 Jul 2008 02:29:46 +0200 + +inn (1:1.7.2q-35) unstable; urgency=high + + * Fixed a FTBFS Heisenbug. (Closes: #481867) + + -- Marco d'Itri Tue, 20 May 2008 02:51:38 +0200 + +inn (1:1.7.2q-34) unstable; urgency=high + + * Packaging converted to quilt. + * New patch fix_perl510: fixes segfaults with perl 5.10, hopefully + without introducing new bugs. If you know about XS, please help! + + -- Marco d'Itri Tue, 06 May 2008 12:56:04 +0200 + +inn (1:1.7.2debian-33) unstable; urgency=medium + + * Updated control.ctl. + * Fixed the init script to create /var/run/innd/ instead of /var/run/news/. + * New patch newsgroups_whitespace: ignore whitespace in Newsgroups headers + instead of rejecting the article. + * Sanitize the perl ccopts and ldopts to prevent linking nnrpd with -lm. + * Updated patch man_sections: fix some ten years old syntax errors in + the man pages. + * Do not use --stop and --exec in the init script because the on-disk + binary changes after upgrades. + + -- Marco d'Itri Sun, 20 Apr 2008 03:43:16 +0200 + +inn (1:1.7.2debian-32) unstable; urgency=low + + * New patch gnukfreebsd_port: fixes FTBFS on GNU/kFreeBSD. (Closes: #414980) + + -- Marco d'Itri Tue, 07 Aug 2007 18:59:52 +0200 + +inn (1:1.7.2debian-31) unstable; urgency=medium + + * Create /var/run/news in the init script if it does not exist. + * New patch posix_arguments: makes innstat use tail -n. + * Updated control.ctl. + + -- Marco d'Itri Fri, 18 Aug 2006 18:46:30 +0200 + +inn (1:1.7.2debian-30) unstable; urgency=medium + + * Fixed a gcc 4 FTBFS bug. (Closes: #297185) + * Do not fail in postrm if /var/log/news/ does not exist. (Closes: #313354) + * Do not reference rc.news in innwatch(8). (Closes: #286062) + * Updated the control.ctl and moderators files. + + -- Marco d'Itri Sun, 31 Jul 2005 12:54:04 +0200 + +inn (1:1.7.2debian-29) unstable; urgency=medium + + * Conflict with inn2-dev. (Closes: #274787) + * New patch rc_initialise_everything: fixes some uninitialised variables + in rc.c. Patch courtesy of Devin Carraway. (Closes: #277459) + * Fixed a command option in inn-README.gz. (Closes: #267125) + * Fixed the keyring path in pgpverify. + * New patch man_sections: fixes the section of some man pages. + + -- Marco d'Itri Tue, 26 Oct 2004 21:14:51 +0200 + +inn (1:1.7.2debian-28) unstable; urgency=medium + + * Depend on exim4 instead of exim. (Closes: #228585) + * Make postrm not fail if /var/spool/news does not exist. (Closes: #244404) + * New patch use_system_prototypes: fixes FTBFS with gcc-3.4. + (Closes: #258959) + * Updated patch rnews_reject_reason to fix mixed use of buffered and + non-buffered I/O. + + -- Marco d'Itri Mon, 12 Jul 2004 18:33:06 +0200 + +inn (1:1.7.2debian-27) unstable; urgency=high + + * Compiled with new perl. + + -- Marco d'Itri Wed, 29 Oct 2003 11:03:57 +0100 + +inn (1:1.7.2debian-26) unstable; urgency=medium + + * Fix postinst failure on new installs. (Closes: #215586) + * Stop providing inewsinn, other packages should depend on + "inn2-inews | inews" instead. + + -- Marco d'Itri Tue, 14 Oct 2003 20:29:16 +0200 + +inn (1:1.7.2debian-25) unstable; urgency=medium + + * Merge the inewsinn package in the inn package and kill the inn-dev + package. (Closes: #210772) + + -- Marco d'Itri Sat, 27 Sep 2003 00:32:34 +0200 + +inn (1:1.7.2debian-24) unstable; urgency=medium + + * Fixed a bug introduced in 1:1.7.2debian-22 which caused the creation + of broken X-Trace headers. + * Fixed a bug in the recommend_ID patch which caused articles without + a Message-ID to be refused by innd. + * New patch: overlapping_strcpy. + * Stop creating /etc/news/organization if it does not exist, as it's + not even used by this inews. (Closes: #210470) + + -- Marco d'Itri Fri, 12 Sep 2003 13:48:50 +0200 + +inn (1:1.7.2debian-23) unstable; urgency=medium + + * Fixed the bug introduced in 1:1.7.2-14 by the path_audit patch which + caused random segfaults when hosts.nntp was reloaded. + * Fixed the innreport path in scanlogs. + * Added support for a inewsport config file option. (Closes: #54975) + * Remove /etc/news/crontab and add /etc/cron.d/inn. + * Updated the default control.ctl from ftp.isc.org. + + -- Marco d'Itri Wed, 20 Aug 2003 04:46:14 +0200 + +inn (1:1.7.2debian-22) unstable; urgency=medium + + * Package converted to DBS. + * Depends on perlapi-5.8.0. (Closes: #187716) + * inn does not need libgdbm-dev. (Closes: #199591) + * Sub-processes are now niced to 10. + * Moved send-* symlinks from /usr/lib/news/ to /usr/lib/news/bin/. + * Applied the poison patch (from rra's poison+remember_trash patch). + * Updated send-uucp.pl from INN 2.4. + * Updated innreport from INN 2.4. + * Updated default control.ctl. + * Added timer support to the perl filter. + + -- Marco d'Itri Sun, 6 Jul 2003 14:36:14 +0200 + +inn (1:1.7.2-21) unstable; urgency=medium + + * Switch back to custom memrchr() to unbreak XOVER (Closes: #169777). + * Backported controlchan support from INN 2 (Closes: #14677, #149042). + * Backported the INN 2 code to allow modifying headers in the nnrpd + perl filter. Now the body is available in $body. + * Applied two small patches by Olaf Titz to tell clients the recommended + Message-ID and have a more precise timers on usually idle systems. + * Added NNTP-Posting-Date to the list of headers which cannot be set + with POST. + * Make innreport generate valid HTML (see #166372). + * Added support for $INND_BIND_ADDRESS. + * Updated control.ctl. + * Renamed the nntpport inn.conf entry to port. + * Added support for the INN 2 bindaddress entry. + + -- Marco d'Itri Wed, 20 Nov 2002 21:47:35 +0100 + +inn (1:1.7.2-20) unstable; urgency=medium + + * Added a fix for the latest perl (Closes: #158462, #163333). + * Added a #include in lib/perl.c for the the xmalloc() prototype + (Closes: #126101). + * Clear all stamps in debian/rules (Closes: #126102). + * Brand new init script which uses ctlinnd. + + -- Marco d'Itri Thu, 26 Sep 2002 21:13:59 +0200 + +inn (1:1.7.2-19) unstable; urgency=medium + + * Fixed outdated perl dependancy (Closes: #113209). + * Does not Suggests anymore innfeed and news-reader. + * Installs gpgverify instead of pgpverify, Suggests gpg instead of pgp. + + -- Marco d'Itri Sun, 23 Sep 2001 14:02:35 +0200 + +inn (1:1.7.2-18) unstable; urgency=low + + * Fixed build dep. (Closes: #92112). + * Removed suidregister support (Closes: #84383). + + -- Marco d'Itri Fri, 6 Apr 2001 20:10:45 +0200 + +inn (1:1.7.2-17) unstable; urgency=low + + * Compiled against perl 5.6 (Closes: #80699). + * Removed misleading message from postinst (Closes: #63449). + * Start innd only if the user asked for it (Closes: #70738). + * Disabled quoting check (Closes: #58184, #58236). + * pgpverify now correctly sources /etc/news/innshellvars.pl and should + work out of the box. + * Downgraded to priority extra: most people don't need a news server + on their system! + + -- Marco d'Itri Fri, 19 Jan 2001 21:24:26 +0100 + +inn (1:1.7.2-16) frozen unstable; urgency=medium + + * Fixed RC bug in postinst (Closes: #57427, #57534). + + -- Marco d'Itri Wed, 9 Feb 2000 18:53:19 +0100 + +inn (1:1.7.2-15) frozen unstable; urgency=medium + + * README.Debian was not installed. + * A bogus /var/spool/news/\ directory was created. + * Commented description of ident protocol use in hosts.nntp(5). + * Added /t to localhost entry in hosts.nntp. + + -- Marco d'Itri Sun, 6 Feb 2000 20:53:36 +0100 + +inn (1:1.7.2-14) frozen unstable; urgency=medium + + * Comments *.foo.com in nnrp.access (Closes: #56369). + * pgpverify automatically uses GnuPG if pgpgpg is found. + * actived stdin/out/err are not opened to the console anymore. + * RNEWS_LOG_DUPS set to SYSLOG. + * LOCAL_MAX_ARTSIZE set to 2 MB. + * fixed "cant read after 0" bug in rnews. + * articles filed in in.coming/bad/ by rnews gets a X-rnews-Reject-Reason + header. + * Applied Path audit trail patch from Ian Jackson (Closes: 54201). + + -- Marco d'Itri Sat, 29 Jan 2000 17:49:01 +0100 + +inn (1:1.7.2-13) frozen unstable; urgency=medium + + * Converted to debhelper. + * Now everything installed in /etc is a conffile. + * Fixed the bug in the Distribution parsing code. + * Fixed Y2K bug. + * Patches from insync release: DBZ 3.2, bigger hash table in expire, + fastrm symlink bug, perl filter updates, timers, precommit cache, + Path feed, mmapped overview, actived. + * Patches from cleanfeed: mode.patch, messageid.patch, filter.patch. + * Applied X-Trace patch. + * Removed generation of the X-Server-Date header. + * From the BOFH patch: in filter_post() the authenticated user is + available as $user, the article body as $hdr{'__BODY__'}. If the + string returned by filter_post() starts with DROP, the article + is silently dropped. + * Updated pgpverify, control.ctl and moderators. Now pgpgpg can be + used instead of pgp. + * Innreport is used instead of innlog. + * Closes: #54609, #24504, #37737, #43896, #44918, #49673, #51944, #54526. + * Closes: #55062, #11614, #26659, #43895, #31145, #52762, #55467, #37888. + * Closes: #54411, #54759, #25181, #21586, #32416, #48739. + * Now inn is maintained by Marco d'Itri. The following changes have + been made by Bdale: + * reinstate 1.7.2 as package 'inn' and friends, the 2.2.2 bits are being + renamed to inn2, et al, as part of Debian INN peace project. + * reopen *lots* of bugs against the inn package that were closed by the + upgrade to 2.2.2, so that they can be dealt with again for 1.7.2 as + needed. + * update control file texts to point new installations to inn2 + * add a check for inn version 2.2.2 to the preinst, and suggest aborting + to select inn2 instead of inn if the user has already upgraded to 2.2.2. + + -- Marco d'Itri Sat, 22 Jan 2000 20:56:19 +0100 + +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 Wed, 06 Oct 1996 15:38:30 +0200 + +INN (1.4unoff4-1) - Miquel van Smoorenburg + + * 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 + + * 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-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. --- inn-1.7.2q.orig/debian/control +++ inn-1.7.2q/debian/control @@ -0,0 +1,44 @@ +Source: inn +Section: news +Priority: optional +Maintainer: Marco d'Itri +Build-Depends: debhelper-compat (= 12), quilt, + pkg-config, libsystemd-dev, + bison, groff, + libperl-dev (>= 5.8) +Standards-Version: 4.3.0.2 +Rules-Requires-Root: binary-targets +Vcs-Git: https://salsa.debian.org/md/inn.git +Vcs-Browser: https://salsa.debian.org/md/inn + +Package: inn +Architecture: any +Pre-Depends: ${misc:Pre-Depends} +Depends: ${shlibs:Depends}, ${misc:Depends}, cron, + default-mta | mail-transport-agent, bsd-mailx | mailx, + lsb-base, + time, perl, ${PERLAPI} +Suggests: gnupg1 +Provides: news-transport-system, inews +Conflicts: inn2, inn2-inews, inn2-dev, inewsinn, news-transport-system +Replaces: inewsinn +Description: News transport system `InterNetNews' by the ISC and Rich Salz + This is INN version 1.x, provided for smaller sites which do not need + the complexity of INN 2.x. + Large sites should use Debian's inn2 package instead. + . + The news transport is the part of the system that stores the articles + and the lists of which groups are available and so on, and provides + those articles on request to users. It receives news (either posted + locally or from a newsfeed site), files it, and passes it on to any + downstream sites. Each article is kept for a period of time and then + deleted (this is known as `expiry'). + . + By default Debian's INN will install in a fairly simple `local-only' + configuration. + . + In order to make use of the services provided by INN you'll have to + use a user-level newsreader program such as pan. The newsreader is + the program that fetches articles from the server and shows them to + the user, remembering which the user has seen so that they don't get + shown again. It also provides the posting interface for the user. --- inn-1.7.2q.orig/debian/copyright +++ inn-1.7.2q/debian/copyright @@ -0,0 +1,32 @@ +This is Debian GNU/Linux's prepackaged version of Rich Salz's +INN news transport system. + +It is currently maintained by Marco d'Itri . +Bdale Garbee, Miquel van Smoorenburg and Ian Jackson maintained +this package in the past. + +The authors of applied patches are listed in README.Debian. + +Copyright 1991 Rich Salz. All rights reserved. +Modifications for Debian GNU/Linux Copyright 1994 Ian Jackson. +Modifications for Debian GNU/Linux Copyright 1995-1997 Miquel van Smoorenburg. +Modifications for Debian GNU/Linux Copyright 2000 Marco d'Itri + +Redistribution and use in any form are permitted provided that the +following restrictions are are met: + 1. Source distributions must retain this entire copyright notice + and comment. + 2. Binary distributions must include the acknowledgement ``This + product includes software developed by Rich Salz'' in the + documentation or other materials provided with the + distribution. This must not be represented as an endorsement + or promotion without specific prior written permission. + 3. The origin of this software must not be misrepresented, either + by explicit claim or by omission. Credits must appear in the + source and documentation. + 4. Altered versions must be plainly marked as such in the source + and documentation and must not be misrepresented as being the + original software. +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. --- inn-1.7.2q.orig/debian/gbp.conf +++ inn-1.7.2q/debian/gbp.conf @@ -0,0 +1,6 @@ +[DEFAULT] +upstream-tag = v%(version)s +pristine-tar = False + +[pq] +patch-numbers = False --- inn-1.7.2q.orig/debian/inn.cron.d +++ inn-1.7.2q/debian/inn.cron.d @@ -0,0 +1,21 @@ +PATH=/usr/lib/news/bin:/bin:/sbin:/usr/bin:/usr/sbin +MAILTO=usenet + +# Expire old news and old overview entries nightly, generate reports. +08 4 * * * news [ -x /usr/lib/news/bin/news.daily ] && /usr/lib/news/bin/news.daily expireover delayrm + +# Refresh the hosts cache every night. +02 4 * * * news [ -x /usr/lib/news/bin/ctlinnd ] && /usr/lib/news/bin/ctlinnd -t 300 -s reload hosts.nntp "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. +14 * * * * news [ -x /usr/bin/rnews ] && /usr/bin/rnews -U + +# Enable this entry to send posted news back to your upstream provider. +# Not if you use innfeed, ofcourse. +#*/15 * * * * news send-nntp news.myprovider.com + +# 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 --- inn-1.7.2q.orig/debian/inn.dirs +++ inn-1.7.2q/debian/inn.dirs @@ -0,0 +1,11 @@ +etc/init.d +etc/news/scripts +usr/bin +usr/sbin +usr/share +usr/lib/news +usr/lib/news/bin +usr/lib/news/control +usr/lib/news/rnews +var/lib/news +var/spool/news --- inn-1.7.2q.orig/debian/inn.init +++ inn-1.7.2q/debian/inn.init @@ -0,0 +1,71 @@ +#!/bin/sh -e +### BEGIN INIT INFO +# Provides: inn +# 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. +# + +. /lib/lsb/init-functions + +test -f /usr/sbin/innd || exit 0 + +case "$1" in + start) + if [ ! -d /var/run/innd ]; then + mkdir -p /var/run/innd + chown news:news /var/run/innd + chmod 775 /var/run/innd + fi + start-stop-daemon --quiet --start --exec /etc/news/boot + ;; + stop) + echo -n "Stopping news server:" + if [ -f /var/run/innd/innwatch.pid ]; then + echo -n " innwatch" + start-stop-daemon --quiet --stop --oknodo \ + --pidfile /var/run/innd/innwatch.pid + fi + if [ -f /var/run/innd/actived.pid ]; then + echo -n " actived" + start-stop-daemon --quiet --stop --oknodo + --pidfile /var/run/innd/actived.pid --exec /usr/lib/news/bin/actived + fi + rm -f /var/run/innd/actived.pid /var/run/innd/innwatch.pid + if [ -f /var/run/innd/innd.pid ]; then + echo -n " innd" + ctlinnd -s -t 20 throttle 'system is going down' || true + ctlinnd -s -t 20 shutdown 'system is going down' || true + start-stop-daemon --quiet --stop --oknodo \ + --pidfile /var/run/innd/innd.pid + fi + echo "." + ;; + reload|force-reload) + echo -n "Reloading INN configuration files: " + ctlinnd -t 20 reload '' /etc/init.d/inn + ;; + restart) + echo -n "Restarting innd: " + if [ -f /var/run/innd/innd.pid ]; then + ctlinnd -s -t 20 throttle "restarting" || true + ctlinnd -s -t 20 xexec inndstart || + start-stop-daemon --quiet --start --exec /etc/news/boot + else + start-stop-daemon --quiet --start --exec /etc/news/boot + fi + echo "done." + ;; + *) + echo "Usage: /etc/init.d/inn start|stop|restart|reload" >&2 + exit 1 + ;; +esac + +exit 0 --- inn-1.7.2q.orig/debian/inn.links +++ inn-1.7.2q/debian/inn.links @@ -0,0 +1,9 @@ +/etc/news/scripts/send-ihave /usr/lib/news/bin/send-ihave +/etc/news/scripts/send-nntp /usr/lib/news/bin/send-nntp +/etc/news/scripts/send-uucp /usr/lib/news/bin/send-uucp +/usr/lib/news/innshellvars /etc/news/innshellvars +/usr/lib/news/innshellvars.csh /etc/news/innshellvars.csh +/usr/lib/news/innshellvars.pl /etc/news/innshellvars.pl +/usr/lib/news/innshellvars.tcl /etc/news/innshellvars.tcl +/usr/lib/news/bin/ctlinnd /usr/sbin/ctlinnd +/usr/share/man/man8/innd.8 /usr/share/man/man8/inndstart.8 --- inn-1.7.2q.orig/debian/inn.postinst +++ inn-1.7.2q/debian/inn.postinst @@ -0,0 +1,82 @@ +#!/bin/sh -e + +make_directories() { + NEED_DIR='in.coming in.coming/bad in.coming/tmp + out.going over.view news.archive' + for D in $NEED_DIR; do + if [ ! -d /var/spool/news/$D ]; then + install -d -m 775 -o news -g news /var/spool/news/$D + fi + done +} + +init_var_lib_news() { + if [ ! -f /var/lib/news/active ]; then + cat > /var/lib/news/active << END +control 0000000000 0000000001 n +control.cancel 0000000000 0000000001 n +junk 0000000000 0000000001 y +misc.test 0000000000 0000000001 y +misc.test.moderated 0000000000 0000000001 m +END + chown news:news /var/lib/news/active + fi + + if [ ! -f /var/lib/news/history ]; then + touch /var/lib/news/history + /usr/lib/news/bin/makehistory -or + chown news:news /var/lib/news/history* + fi + + if [ ! -f /var/lib/news/newsgroups ]; then + cat > /var/lib/news/newsgroups << END +control News server internal group. +control.cancel News server internal group. +junk News server internal group. +misc.test For testing of network software. Very boring. +misc.test.moderated Testing of posting to moderated groups. (Moderated) +END + chown news:news /var/lib/news/newsgroups + fi +} + +add_mail_alias() { + if ! grep -qs '^usenet:' /etc/aliases; then + echo 'usenet: root' >> /etc/aliases + newaliases || echo "newaliases command not available." + fi +} + +init_etc_files() { + if [ ! -f /etc/news/server ]; then + echo 'localhost' > /etc/news/server + fi + + if [ ! -f /etc/news/whoami ]; then + if [ -f /etc/mailname ]; then + cp /etc/mailname /etc/news/whoami + else + hostname --fqdn > /etc/news/whoami + fi + fi +} + +case "$1" in + configure) + make_directories + init_var_lib_news + add_mail_alias + init_etc_files + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument '$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + --- inn-1.7.2q.orig/debian/inn.postrm +++ inn-1.7.2q/debian/inn.postrm @@ -0,0 +1,52 @@ +#!/bin/bash -e + +clean_var_lib() { + echo "Purging active file and history data..." + rm -f /var/lib/news/active* /var/lib/news/history* \ + /var/lib/news/newsgroups + if [ -d /var/lib/news/ ]; then + rmdir --ignore-fail-on-non-empty /var/lib/news/ + fi +} + +clean_var_run() { + rm -rf /run/innd/ +} + +remove_logs() { + echo "Removing files in /var/log/news and /run/innd..." + rm -f /var/lib/news/{.news.daily,active.old} + [ -e /var/log/news/ ] || return 0 + rm -rf /var/log/news/OLD/ + rm -f /var/log/news/{expire.log,log,errlog,unwanted.log} + : > /var/log/news/news.crit + : > /var/log/news/news.err + : > /var/log/news/news.notice +} + +case "$1" in + remove) + ;; + + purge) + clean_var_lib + clean_var_run + remove_logs + + # We do not remove /var/spool/news because that might + # take a lot of time. Most of the time it is on a seperate + # disk anyway and it is faster to do a mkfs on it.. + echo "Remove the news spool in /var/spool/news yourself!" + ;; + + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument '$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + --- inn-1.7.2q.orig/debian/inn.prerm +++ inn-1.7.2q/debian/inn.prerm @@ -0,0 +1,16 @@ +#!/bin/sh -e + +# delete the pid file if INN is dead, or the init script may fail later +PIDFILE="/run/innd/innd.pid" +if [ -f $PIDFILE ]; then + INNPID=$(cat $PIDFILE) + kill -s 0 $INNPID 2> /dev/null || rm -f $PIDFILE +fi + +# Stop the socket on removal so innd is not restarted via socket activation +if [ "$1" = remove -a -d /run/systemd/system/ ]; then + deb-systemd-invoke stop inn.socket > /dev/null || true +fi + +#DEBHELPER# + --- inn-1.7.2q.orig/debian/inn.service +++ inn-1.7.2q/debian/inn.service @@ -0,0 +1,21 @@ +[Unit] +Description=InterNetNews +Documentation=man:innd(8) +Requires=inn.socket +After=network-online.target +Wants=network-online.target + +[Service] +Type=notify +Restart=on-abort +ExecStart=/etc/news/boot +ExecReload=/usr/sbin/ctlinnd -t 20 reload all 'by systemd' +ExecStop=-/usr/sbin/ctlinnd -s -t 20 throttle 'system is going down' +ExecStop=-/usr/sbin/ctlinnd -s -t 20 shutdown 'system is going down' +User=news +Group=news +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target + --- inn-1.7.2q.orig/debian/inn.socket +++ inn-1.7.2q/debian/inn.socket @@ -0,0 +1,12 @@ +[Unit] +Description=NNTP Socket activation for INN + +[Socket] +# When using socket activation, the port and bindaddress parameters in +# inn.conf are ignored. Only a single IPv4 socket is supported. +ListenStream=0.0.0.0:119 +Service=inn.service + +[Install] +WantedBy=sockets.target + --- inn-1.7.2q.orig/debian/inn.tmpfile +++ inn-1.7.2q/debian/inn.tmpfile @@ -0,0 +1,2 @@ +d /run/innd 0775 news news + --- inn-1.7.2q.orig/debian/patches/0_insync_actived +++ inn-1.7.2q/debian/patches/0_insync_actived @@ -0,0 +1,1550 @@ +--- inn-1.7.2.orig/config/files.list ++++ inn-1.7.2/config/files.list +@@ -107,4 +107,5 @@ + ../syslog/syslog.c + ../syslog/syslog.conf + ../syslog/syslogd.c ++../actived/Makefile + ;; Do not run subst on its own manpage! ../doc/subst.1 +--- inn-1.7.2.orig/include/paths.h ++++ inn-1.7.2/include/paths.h +@@ -210,3 +217,13 @@ + + /* =()<#define _PATH_PERL_FILTER_NNRPD "@<_PATH_PERL_FILTER_NNRPD>@">()= */ + #define _PATH_PERL_FILTER_NNRPD "/usr/news/bin/control/filter_nnrpd.pl" ++ ++/* ++** 18. actived configuration ++*/ ++ ++/* =()<#define _PATH_ACTIVED "@<_PATH_ACTIVED>@">()= */ ++#define _PATH_ACTIVED "/usr/lib/news/bin/actived" ++/* =()<#define _PATH_ACTIVEDPID "@<_PATH_ACTIVEDPID>@">()= */ ++#define _PATH_ACTIVEDPID "/var/run/innd/actived.pid" ++ +--- inn-1.7.2.orig/nnrpd/Makefile ++++ inn-1.7.2/nnrpd/Makefile +@@ -37,13 +37,15 @@ + LIBNEWS = ../libinn.a + LINTLIB = ../llib-linn.ln + ++CFLAGS+= -DOVERSCREAM ++ + SOURCES = \ + article.c group.c commands.c misc.c newnews.c nnrpd.c \ +- perl.c post.c loadave.c ++ perl.c post.c loadave.c udp.c + + OBJECTS = \ + article.o group.o commands.o misc.o newnews.o nnrpd.o \ +- perl.o post.o loadave.o ++ perl.o post.o loadave.o udp.o + + ALL = nnrpd + +--- inn-1.7.2.orig/nnrpd/group.c ++++ inn-1.7.2/nnrpd/group.c +@@ -8,6 +8,15 @@ + #include "clibrary.h" + #include "nnrpd.h" + #include "mydir.h" ++#include "../actived/protocol.h" ++#include ++#include ++ ++BOOL XGetGroupList(); ++int write_udp(int s, char *buf, int len); ++int read_udp(int s, char *buf, int len); ++int create_udp_socket(int port); ++int connect_udp_socket(int s, char *address, int port); + + + /* +@@ -30,13 +33,34 @@ + STATIC GROUPENTRY *GRPentries; + STATIC int GRPbuckets; + STATIC int GRPsize; ++STATIC int GRPactived = -1; ++int GRPuselocalhash = 1; /*actived is disabled by default*/ ++STATIC int NRequestID; ++ ++ ++void ++NNewRequestID() ++{ ++ static int pid = -1; ++ static int count = 123456789; ++ struct timeval tv; ++ ++ if (pid < 0) { ++ pid = getpid(); ++ } ++ gettimeofday(&tv, NULL); ++ count += pid; ++ NRequestID = tv.tv_sec ^ tv.tv_usec ^ pid ^ count; ++} ++ ++ + + + /* + ** See if a given newsgroup exists. + */ + GROUPENTRY * +-GRPfind(group) ++XGRPfind(group) + register char *group; + { + register char *p; +@@ -56,8 +80,129 @@ + } + + ++ ++GROUPENTRY * ++NGRPfind(group) ++ register char *group; ++{ ++ int now = time(NULL); ++ int expireat = now + ACTIVED_TIMEOUT; ++ int last = now - 2; ++ static struct wireprotocol buffer; ++ fd_set fdset; ++ struct timeval timeout; ++ static GROUPENTRY data; ++ ++ /* Okay. Let's ask the server for the data. */ ++ NNewRequestID(); ++ while (now < expireat) { ++ now = time(NULL); ++ if (last < now - 1) { ++ last = now; ++ buffer.RequestID = NRequestID; ++ buffer.RequestType = REQ_FIND; ++ strncpy(buffer.Name, group, sizeof(buffer.Name) - 1); ++ buffer.Name[sizeof(buffer.Name) - 1] = '\0'; ++ ++ if (write_udp(GRPactived, (char *)&buffer, sizeof(buffer)) != sizeof(buffer)) { ++ syslog(L_ERROR, "%s actived socket couldnt be written FIND %m", ++ ClientHost); ++ sleep(1); ++ continue; ++ } ++ } ++ FD_ZERO(&fdset); ++ FD_SET(GRPactived, &fdset); ++ timeout.tv_sec = 1; ++ timeout.tv_usec = 0; ++ if (select(GRPactived + 1, &fdset, NULL, NULL, &timeout) < 0) { ++ syslog(L_ERROR, "%s actived socket failed select %m", ++ ClientHost); ++ sleep(1); ++ continue; ++ } ++ if (FD_ISSET(GRPactived, &fdset)) { ++ if (read_udp(GRPactived, (char *)&buffer, sizeof(buffer)) != sizeof(buffer)) { ++ syslog(L_ERROR, "%s actived socket couldnt be read FINDRESP %m", ++ ClientHost); ++ sleep(1); ++ continue; ++ } ++ if (buffer.RequestID != NRequestID) { ++ syslog(L_ERROR, "%s actived socket returned a different request-ID %d/%d", ++ ClientHost, buffer.RequestID, NRequestID); ++ sleep(1); ++ continue; ++ } ++ if (buffer.RequestType != REQ_FINDRESP) { ++ syslog(L_ERROR, "%s actived socket returned a non-FINDRESP %d", ++ ClientHost, buffer.RequestType); ++ sleep(1); ++ continue; ++ } ++ ++ /* Was the request successful? Did we find the group? */ ++ if (! buffer.Success) { ++ return(NULL); ++ } ++ ++ /* Looks good! Copy all the data to the static "data" struct */ ++ if (! buffer.NameNull) { ++ data.Name = buffer.Name; ++ } else { ++ data.Name = NULL; ++ } ++ data.High = buffer.High; ++ data.Low = buffer.Low; ++ data.Flag = buffer.Flag; ++ if (! buffer.AliasNull) { ++ data.Alias = buffer.Alias; ++ } else { ++ data.Alias = NULL; ++ } ++ return(&data); ++ } ++ } ++ ++ /* Something is very wrong. Fall back to local access and whine like ++ hell. GRPuselocalhash is explicitly checked by GRPfind, and will ++ handle initializing the database for us. */ ++ ++ syslog(L_ERROR, "%s NOT using actived", ClientHost); ++ GRPuselocalhash++; ++ return(NULL); ++} ++ ++ ++GROUPENTRY * ++GRPfind(group) ++ register char *group; ++{ ++ GROUPENTRY *rval; ++ ++ /* ++ * If we are not flagged to use local hash, call NGRPfind. ++ * That could potentially fail (server no answer, etc) in which ++ * case we fall back to standard INN and scream bloody murder. ++ * NGRPfind will toggle GRPuselocalhash to TRUE if it has problems. ++ */ ++ ++ if (! GRPuselocalhash) { ++ rval = NGRPfind(group); ++ if (! GRPuselocalhash) { ++ return(rval); ++ } ++ ++ /* Ow! We are falling back to local access since NGRPfind failed! */ ++ XGetGroupList(); ++ } ++ ++ return(XGRPfind(group)); ++} ++ ++ + STATIC void +-GRPhash() ++XGRPhash() + { + register char *p; + register int i; +@@ -100,7 +245,7 @@ + ** newsgroups read in. Return TRUE if okay, FALSE on error. + */ + BOOL +-GetGroupList() ++XGetGroupList() + { + static char *active; + register char *p; +@@ -166,10 +311,112 @@ + } + + GRPsize = i; +- GRPhash(); ++ XGRPhash(); + return TRUE; + } + ++BOOL ++NGetGroupList() ++{ ++ int now = time(NULL); ++ int expireat = now + ACTIVED_TIMEOUT; ++ int last = now - 2; ++ int s; ++ struct wireprotocol buffer; ++ fd_set fdset; ++ struct timeval timeout; ++ ++ if (GRPactived < 0) { ++ if ((s = create_udp_socket(0)) < 0) { ++ syslog(L_ERROR, "%s actived socket couldnt be created %m", ++ ClientHost); ++ return(FALSE); ++ } ++ if (connect_udp_socket(s, "localhost", 1119) < 0) { ++ syslog(L_ERROR, "%s actived socket couldnt be connected %m", ++ ClientHost); ++ return(FALSE); ++ } ++ if (fcntl(s, F_SETFL, O_NDELAY) < 0) { ++ syslog(L_ERROR, "%s actived socket couldnt be fcntl O_NDELAY %m", ++ ClientHost); ++ return(FALSE); ++ } ++ GRPactived = s; ++ } ++ ++ /* Okay. Let's ask the server if it's there. */ ++ NNewRequestID(); ++ while (now < expireat) { ++ now = time(NULL); ++ if (last < now - 1) { ++ last = now; ++ buffer.RequestID = NRequestID; ++ buffer.RequestType = REQ_AYT; ++ ++ if (write_udp(GRPactived, (char *)&buffer, sizeof(buffer)) != sizeof(buffer)) { ++ syslog(L_ERROR, "%s actived socket couldnt be written AYT %m", ++ ClientHost); ++ sleep(1); ++ continue; ++ } ++ } ++ FD_ZERO(&fdset); ++ FD_SET(GRPactived, &fdset); ++ timeout.tv_sec = 1; ++ timeout.tv_usec = 0; ++ if (select(GRPactived + 1, &fdset, NULL, NULL, &timeout) < 0) { ++ syslog(L_ERROR, "%s actived socket failed select %m", ++ ClientHost); ++ sleep(1); ++ return(FALSE); ++ } ++ if (FD_ISSET(GRPactived, &fdset)) { ++ if (read_udp(GRPactived, (char *)&buffer, sizeof(buffer)) != sizeof(buffer)) { ++ syslog(L_ERROR, "%s actived socket couldnt be read AYTACK %m", ++ ClientHost); ++ sleep(1); ++ continue; ++ } ++ if (buffer.RequestID != NRequestID) { ++ syslog(L_ERROR, "%s actived socket returned a different request-ID %d/%d", ++ ClientHost, buffer.RequestID, NRequestID); ++ sleep(1); ++ continue; ++ } ++ if (buffer.RequestType != REQ_AYTACK) { ++ syslog(L_ERROR, "%s actived socket returned a non-AYTACK %d", ++ ClientHost, buffer.RequestType); ++ sleep(1); ++ continue; ++ } ++ /* Looks good! */ ++ return(TRUE); ++ } ++ } ++ return(FALSE); ++} ++ ++BOOL ++GetGroupList() ++{ ++ /* ++ * If we are not flagged to use local hash, call NGetGroupList. ++ * That could potentially fail (server no answer, etc) in which ++ * case we fall back to standard INN and scream bloody murder. ++ */ ++ if (! GRPuselocalhash) { ++ if (NGetGroupList() == FALSE) { ++ syslog(L_ERROR, "%s NOT using actived", ClientHost); ++ GRPuselocalhash++; ++ return(XGetGroupList()); ++ } ++ return(TRUE); ++ } else { ++ return(XGetGroupList()); ++ } ++} ++ + + /* + ** Sorting predicate to put newsgroup names into numeric order. +--- inn-1.7.2.orig/nnrpd/nnrpd.c ++++ inn-1.7.2/nnrpd/nnrpd.c +@@ -636,6 +637,14 @@ + ExitWithStats(0); + } + ++ { ++ char *UseActived; ++ extern int GRPuselocalhash; ++ if ((UseActived = GetConfigValue(_CONF_USEACTIVED)) != NULL) ++ if (EQ(UseActived, "true") || EQ(UseActived, "yes")) ++ GRPuselocalhash = 0; ++ } ++ + ARTreadschema(); + if (!GetGroupList()) { + /* This shouldn't really happen. */ +--- inn-1.7.2.orig/nnrpd/udp.c ++++ inn-1.7.2/nnrpd/udp.c +@@ -0,0 +1,162 @@ ++#include ++#include ++#include "clibrary.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "logging.h" ++ ++#ifdef NEED_BZERO_ETC ++#include ++void ++bzero(b, length) ++ char *b; ++ int length; ++{ ++ while (--length >= 0) ++ *b++ = '\0'; ++} ++void ++bcopy(b1, b2, length) ++ char *b1; ++ char *b2; ++ int length; ++{ ++ while (--length >= 0) ++ *b2++ = *b1++; ++} ++#endif ++ ++int create_udp_socket(int port) ++{ ++ int s; ++ struct sockaddr_in sin; ++ ++ sin.sin_port = htons(port); ++ sin.sin_family = AF_INET; ++ sin.sin_addr.s_addr = INADDR_ANY; ++ ++ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ++ syslog(L_ERROR, "create_udp_socket: socket: %m"); ++ return(-1); ++ } ++ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ++ syslog(L_ERROR, "create_udp_socket: bind: %m"); ++ return(-1); ++ } ++ return(s); ++} ++ ++ ++ ++ ++ ++int make_udp_sockaddr(struct sockaddr_in *addr, char *ascii) ++{ ++ struct hostent *host; ++ int dots = 0; ++ int numeric = 0; ++ char *str, *colon, *lastdot, *ptr; ++ ++ if (! (str = malloc(strlen(ascii) + 1))) { ++ syslog(L_ERROR, "make_udp_sockaddr: malloc: %m"); ++ return(-1); ++ } ++ strcpy(str, ascii); ++ colon = strrchr(str, ':'); ++ lastdot = strrchr(str, '.'); ++ ++ addr->sin_family = AF_INET; ++ ++ /* Count the number of dots in the address. */ ++ for (ptr = str; *ptr; ptr++) { ++ if (*ptr == '.') { ++ dots++; ++ } ++ } ++ ++ /* Check if it seems to be numeric. */ ++ numeric = isdigit(*str); ++ ++ /* If numeric and four dots, we have a.b.c.d.6000 */ ++ if (numeric && dots == 4) { ++ *lastdot = '\0'; ++ addr->sin_port = htons(atoi(lastdot + 1)); ++ } ++ /* If nonnumeric, check if the last part is a port */ ++ if (! numeric && lastdot && isdigit(*(lastdot + 1))) { ++ *lastdot = '\0'; ++ addr->sin_port = htons(atoi(lastdot + 1)); ++ } ++ /* Now do we have a numeric address */ ++ if (numeric) { ++ addr->sin_addr.s_addr = inet_addr(str); ++ free(str); ++ return(0); ++ } ++ /* Or a name */ ++ if (! (host = gethostbyname(str))) { ++ free(str); ++ syslog(L_ERROR, "make_udp_sockaddr: gethostbyname: %m"); ++ return(-1); ++ } ++ bcopy(host->h_addr_list[0], (char *)&addr->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr)); ++ free(str); ++ return(0); ++} ++ ++ ++ ++ ++ ++int connect_udp_socket(int s, char *address, int port) ++{ ++ struct sockaddr_in sin; ++ ++ bzero(&sin, sizeof(sin)); ++ sin.sin_port = htons(port); ++ sin.sin_family = AF_INET; ++ sin.sin_addr.s_addr = INADDR_ANY; ++ ++ if (make_udp_sockaddr(&sin, address) < 0) { ++ return(-1); ++ } ++ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ++ syslog(L_ERROR, "connect_udp_socket: connect: %m"); ++ return(-1); ++ } ++ return(0); ++} ++ ++ ++ ++ ++ ++int write_udp(int s, char *buf, int len) ++{ ++ int rval; ++ ++ if ((rval = send(s, buf, len, 0x0)) < 0) { ++ syslog(L_ERROR, "write_udp: send: %m"); ++ return(-1); ++ } ++ return(rval); ++} ++ ++ ++ ++ ++ ++int read_udp(int s, char *buf, int len) ++{ ++ int rval; ++ ++ if ((rval = recv(s, buf, len, 0x0)) < 0) { ++ syslog(L_ERROR, "read_udp: recv: %m"); ++ return(-1); ++ } ++ return(rval); ++} +--- inn-1.7.2.orig/Makefile ++++ inn-1.7.2/Makefile +@@ -17,7 +17,7 @@ + RCSCOFLAGS = -u + + ## The first two directories must be config and lib. +-PROGS = config lib frontends innd nnrpd backends expire doc ++PROGS = config lib frontends innd nnrpd actived backends expire doc + DIRS = $(PROGS) site + + ## We invoke an extra process and set this to be what to make. +--- inn-1.7.2.orig/actived/Makefile ++++ inn-1.7.2/actived/Makefile +@@ -0,0 +1,97 @@ ++## $Revision: 1.16 $ ++SHELL = /bin/sh ++MAKE = make ++DESTDIR = ++D = $(DESTDIR) ++## =()

@>()= ++P = ++ ++## =()@>()= ++CC = gcc ++## =()@>()= ++DEFS = -I../include ++## =()@>()= ++CFLAGS = $(DEFS) -g ++## =()@>()= ++LDFLAGS = ++## =()@>()= ++LINTFLAGS = -b -h -z $(DEFS) ++## =()@>()= ++LINTFILTER = | sed -n -f ../sedf.sun ++## =()@>()= ++CTAGS = ctags -t -w ++## =()@>()= ++PROF = -pg ++ ++## =()@>()= ++ACTIVED = /usr/lib/news/bin/actived ++## =()@ -G @@>()= ++OWNER = -O news -G news ++ ++## =()@>()= ++LIBS = -lutil ++LIBNEWS = ../libinn.a ++LINTLIB = ../llib-linn.ln ++ ++SOURCES = \ ++ actived.c group.c udp.c activedstats.c ++ ++OBJECTS = \ ++ actived.o group.o udp.o activedstats.o ++ ++ALL = actived ++ ++all: $(ALL) ++ ++install: $D$(ACTIVED) ++ ++## Low-level install actions. ++$D$(ACTIVED): actived ++ $(SHELL) ../installit.sh $(OWNER) -m 0555 -b .OLD $? $@ ++ ++clobber clean: ++ rm -f *.o $(ALL) ++ rm -f actived activedp profiled ++ rm -f all install lint ++ ++tags ctags: $(SOURCES) ++ $(CTAGS) $(SOURCES) ../lib/*.c actived.h ../include/*.h ++ ++actived: $(P) $(OBJECTS) $(LIBNEWS) ++ @rm -f $@ ++ $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBNEWS) $(LIBS) ++ ++lint: $(ALL) ++ @rm -f lint ++ lint $(LINTFLAGS) $(SOURCES) $(LINTLIB) $(LINTFILTER) >lint ++ ++../include/dbz.h: ++ (cd ../lib ; $(MAKE) ../include/dbz.h) ++$(LIBNEWS) $(LINTLIB): ++ (cd ../lib ; $(MAKE) install ) ++ ++## Profiling. The rules are a bit brute-force, but good enough. ++profiled: activedp ++ date >$@ ++ ++activedp: $(SOURCES) ++ rm -f $(OBJECTS) ++ $(MAKE) actived CFLAGS="$(CFLAGS) $(PROF)" LIBNEWS=../libinn_p.a ++ mv actived activedp ++ rm -f $(OBJECTS) ++ ++ccenter: $(SOURCES) ++ #load $(CFLAGS) $(SOURCES) $(LIBNEWS) ++ ++## Dependencies. Default list, below, is probably good enough. ++depend: Makefile $(SOURCES) ++ makedepend $(DEFS) $(SOURCES) ++ ++# DO NOT DELETE THIS LINE -- make depend depends on it. ++$(OBJECTS): actived.h \ ++ ../include/clibrary.h ../include/configdata.h \ ++ ../include/libinn.h ../include/logging.h \ ++ ../include/macros.h ../include/nntp.h \ ++ ../include/paths.h ../include/qio.h ++group.o: ../include/mydir.h ++misc.o: ../include/dbz.h +--- inn-1.7.2.orig/actived/actived.c ++++ inn-1.7.2/actived/actived.c +@@ -0,0 +1,193 @@ ++/* $Revision: 1.18 $ ++** ++** Active file server for readers (NNRP) for InterNetNews. ++*/ ++ ++#define UPDATE_INTERVAL 30 ++#define MAINLINE ++#include ++#include ++#include "actived.h" ++#include "protocol.h" ++#include "configdata.h" ++#include "paths.h" ++ ++BOOL GetGroupList(); ++int create_udp_socket(int port); ++int loads(int reader_count, int startup_count); ++ ++ ++char ACTIVE[] = _PATH_ACTIVE; ++char PID[] = _PATH_ACTIVEDPID; ++char INNDDIR[] = _PATH_INNDDIR; ++STATIC UID_T NewsUID; ++STATIC GID_T NewsGID; ++struct stat Sb; ++ ++int ++handle(s) ++ int s; ++{ ++ GROUPENTRY *ptr; ++ struct sockaddr saddr; ++ struct sockaddr_in *sin = (struct sockaddr_in *)&saddr; ++ int saddrsiz = sizeof(saddr); ++ struct wireprotocol buffer; ++ int len = sizeof(buffer); ++ int rval; ++ ++ if ((rval = recvfrom(s, (char *)&buffer, len, 0, &saddr, &saddrsiz)) < 0) { ++ syslog(L_ERROR, "cant recvfrom %m"); ++ return(-1); ++ } ++ ++ if (rval != sizeof(buffer)) { ++ syslog(L_ERROR, "message size wrong"); ++ return(-1); ++ } ++ ++ /* XXX If not 127.0.0.1, then reject and return */ ++ ++ ++ switch (buffer.RequestType) { ++ case REQ_AYT: ++ buffer.RequestType = REQ_AYTACK; ++ if (sendto(s, (char *)&buffer, len, 0, &saddr, saddrsiz) < 0) { ++ syslog(L_ERROR, "cant sendto %m"); ++ return(-1); ++ } ++ return(0); ++ case REQ_FIND: ++ buffer.RequestType = REQ_FINDRESP; ++ ++ buffer.Name[sizeof(buffer.Name) - 1] = '\0'; ++ if (! (ptr = GRPfind(buffer.Name))) { ++ buffer.Success = 0; ++ } else { ++ buffer.Success = 1; ++ if (ptr->Name) { ++ buffer.NameNull = 0; ++ strncpy(buffer.Name, ptr->Name, sizeof(buffer.Name) - 1); ++ buffer.Name[sizeof(buffer.Name) - 1] = '\0'; ++ } else { ++ buffer.NameNull = 1; ++ } ++ buffer.High = ptr->High; ++ buffer.Low = ptr->Low; ++ buffer.Flag = ptr->Flag; ++ if (ptr->Alias) { ++ buffer.AliasNull = 0; ++ strncpy(buffer.Alias, ptr->Alias, sizeof(buffer.Alias) - 1); ++ buffer.Alias[sizeof(buffer.Alias) - 1] = '\0'; ++ } else { ++ buffer.AliasNull = 1; ++ } ++ } ++ if (sendto(s, (char *)&buffer, len, 0, &saddr, saddrsiz) < 0) { ++ syslog(L_ERROR, "cant sendto %m"); ++ return(-1); ++ } ++ return(0); ++ } ++ syslog(L_ERROR, "unknown requesttype %d", buffer.RequestType); ++ return(-1); ++} ++ ++ ++ ++ ++ ++/* ARGSUSED0 */ ++int ++main(argc, argv) ++ int argc; ++ char *argv[]; ++{ ++ int s, i; ++ time_t last_active_update = time(NULL), now; ++ fd_set fdset; ++ struct timeval tv; ++ FILE *F; ++ PID_T pid; ++ static char WHEN[] = "Pid file"; ++ char LogName[] = "ACTIVED"; ++ if (stat(INNDDIR, &Sb) < 0 || !S_ISDIR(Sb.st_mode)) { ++ syslog(L_FATAL, "inndstart cant stat %s %m", INNDDIR); ++ exit(1); ++ } ++ NewsUID = Sb.st_uid; ++ NewsGID = Sb.st_gid; ++ ++ openlog("actived", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG); ++ ++ if ((s = create_udp_socket(1119)) < 0) { ++ syslog(L_ERROR, "cant createudpsocket %m"); ++ exit(1); ++ } ++ if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { ++ syslog(L_ERROR, "cant fcntl O_NDELAY socket %m"); ++ exit(1); ++ } ++ if (!GetGroupList()) { ++ /* This shouldn't really happen. */ ++ syslog(L_ERROR, "cant getgrouplist %m"); ++ exit(1); ++ } ++ i = fork(); ++ if (i < 0) ++ syslog(L_ERROR, "daemon: cannot fork"); ++ if (i != 0) ++ exit(0); ++ ++ /* Change our UID and GID */ ++ if (setgid(NewsGID) == -1) ++ syslog(L_ERROR, "actived cant setgid: %m"); ++ if (setuid(NewsUID) == -1) ++ syslog(L_ERROR, "actived cant setuid: %m"); ++ ++ /* Record our PID. */ ++ pid = getpid(); ++ if ((F = fopen(PID, "w")) == NULL) { ++ i = errno; ++ syslog(L_ERROR, "%s cant fopen %s %m", LogName, PID); ++ } ++ else { ++ if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F)) { ++ i = errno; ++ syslog(L_ERROR, "%s cant fprintf %s %m", LogName, PID); ++ } ++ if (fclose(F) == EOF) { ++ i = errno; ++ syslog(L_ERROR, "%s cant fclose %s %m", LogName, PID); ++ } ++ if (chmod(PID, 0664) < 0) { ++ i = errno; ++ syslog(L_ERROR, "%s cant chmod %s %m", LogName, PID); ++ } ++ } ++ ++ for (;;) { ++ FD_ZERO(&fdset); ++ FD_SET(s, &fdset); ++ tv.tv_sec = 0; ++ tv.tv_usec = 300000; ++ if (select(s + 1, &fdset, NULL, NULL, &tv) < 0) { ++ syslog(L_ERROR, "cant select %m"); ++ exit(1); ++ } ++ now = time(NULL); ++ if (now > last_active_update + UPDATE_INTERVAL) { ++ last_active_update = now; ++ if (!GetGroupList()) { ++ /* This shouldn't really happen. */ ++ syslog(L_ERROR, "cant getgrouplist %m"); ++ exit(1); ++ } ++ } ++ if (FD_ISSET(s, &fdset)) { ++ handle(s); ++ loads(0, 1); ++ } ++ } ++ /* NOTREACHED */ ++} +--- inn-1.7.2.orig/actived/actived.h ++++ inn-1.7.2/actived/actived.h +@@ -0,0 +1,51 @@ ++/* $Revision: 1.15 $ ++** ++*/ ++#include "configdata.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(VAR_VARARGS) ++#include ++#endif /* defined(VAR_VARARGS) */ ++#if defined(VAR_STDARGS) ++#include ++#endif /* defined(VAR_STDARGS) */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "paths.h" ++#include "nntp.h" ++#include "logging.h" ++#include "clibrary.h" ++#include "libinn.h" ++#include "qio.h" ++#include "macros.h" ++ ++ ++/* ++** A group entry. ++*/ ++typedef struct _GROUPENTRY { ++ char *Name; ++ ARTNUM High; ++ ARTNUM Low; ++ char Flag; ++ char *Alias; ++} GROUPENTRY; ++ ++ ++#if defined(MAINLINE) ++#define EXTERN /* NULL */ ++#else ++#define EXTERN extern ++#endif /* defined(MAINLINE) */ ++ ++extern char ACTIVE[]; ++extern GROUPENTRY *GRPfind(); +--- inn-1.7.2.orig/actived/activedstats.c ++++ inn-1.7.2/actived/activedstats.c +@@ -0,0 +1,150 @@ ++/* ++ * Copyright (c) 1996 ++ * Joe Greco. 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 Joe Greco. ++ * 4. Neither the name of the author nor the names of any co-contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY JOE GRECO 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 JOE GRECO 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 ++#include ++#include ++ ++int dumploads(); ++int fprintloads(FILE *fp); ++ ++ ++/* This breaks past 1024; see comments in sys/param.h - soln: make 64 bits */ ++ ++#define FSHIFT 11 /* bits to right of fixed binary point */ ++#define FSCALE (1<ldavg[i] = (cexp[i] * avg->ldavg[i] + ++ nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT; ++} ++ ++/* ++ * Call this every half a second or so - every five seconds, it will ++ * calculate loads. ++ * ++ * Originally designed for readers. We don't care for actived and ++ * instead we call with loads(0, 1) for requests, and loads (0, 0) ++ * for periodic calls. ++ * ++ * Formerly: ++ * When a reader connects: loads(+1, 1) ++ * disconn's: loads(-1, 0) ++ */ ++ ++int ++loads(int reader_count, int startup_count) ++{ ++ static int readers = 0; ++ static int startups = 0; ++ struct timeval tv; ++ static int tv_next = 0; ++ ++ readers += reader_count; ++ startups += startup_count; ++ ++ gettimeofday(&tv, NULL); ++ ++ if (! tv_next) { ++ tv_next = tv.tv_sec + 5; ++ } ++ if (tv.tv_sec >= tv_next) { ++ tv_next += 5; ++ loadav(&avgreaders, readers); ++ loadav(&avgstartups, startups); ++ startups = 0; ++ dumploads(); ++ } ++ return(0); ++} ++ ++int dumploads() ++{ ++ FILE *fp; ++ ++ if (! (fp = fopen("/var/log/news/activedloads", "w"))) { ++ return(-1); ++ } ++ fprintloads(fp); ++ fclose(fp); ++ return(0); ++} ++ ++int ++fprintloads(FILE *fp) ++{ ++ double avenrun[3]; ++ int i; ++ ++ for (i = 0; i < 3; i++) { ++ avenrun[i] = (double) avgstartups.ldavg[i] / avgstartups.fscale; ++ } ++ fprintf(fp, "Average ACTIVED Loads: "); ++ for (i = 0; i < (sizeof(avenrun) / sizeof(avenrun[0])); i++) { ++ if (i > 0) ++ fprintf(fp, ","); ++ fprintf(fp, " %6.2f", avenrun[i]); ++ } ++ fprintf(fp, "\n"); ++} +--- inn-1.7.2.orig/actived/group.c ++++ inn-1.7.2/actived/group.c +@@ -0,0 +1,166 @@ ++/* $Revision: 1.13 $ ++** ++** Newsgroups and the active file. ++*/ ++#include "actived.h" ++ ++ ++/* ++** Newsgroup hashing stuff. See comments in innd/ng.c. ++*/ ++ ++#define GRP_HASH(Name, p, j) \ ++ for (p = Name, j = 0; *p; ) j = (j << 5) + j + *p++ ++#define GRP_SIZE 65536 ++#define GRP_BUCKET(j) &GRPtable[j & (GRP_SIZE - 1)] ++ ++typedef struct _GRPHASH { ++ int Size; ++ int Used; ++ GROUPENTRY **Groups; ++} GRPHASH; ++ ++ ++STATIC GRPHASH GRPtable[GRP_SIZE]; ++STATIC GROUPENTRY *GRPentries; ++STATIC int GRPbuckets; ++STATIC int GRPsize; ++ ++ ++/* ++** See if a given newsgroup exists. ++*/ ++GROUPENTRY * ++GRPfind(group) ++ register char *group; ++{ ++ register char *p; ++ register unsigned int j; ++ register int i; ++ register GROUPENTRY **gpp; ++ GRPHASH *htp; ++ char c; ++ ++ /* SUPPRESS 6 *//* Over/underflow from plus expression */ ++ GRP_HASH(group, p, j); ++ htp = GRP_BUCKET(j); ++ for (c = *group, gpp = htp->Groups, i = htp->Used; --i >= 0; gpp++) ++ if (c == gpp[0]->Name[0] && EQ(group, gpp[0]->Name)) ++ return gpp[0]; ++ return NULL; ++} ++ ++ ++STATIC void ++GRPhash() ++{ ++ register char *p; ++ register int i; ++ register GROUPENTRY *gp; ++ register unsigned int j; ++ register GRPHASH *htp; ++ ++ /* Set up the default hash buckets. */ ++ GRPbuckets = GRPsize / GRP_SIZE; ++ if (GRPbuckets == 0) ++ GRPbuckets = 1; ++ if (GRPtable[0].Groups) ++ for (i = GRP_SIZE, htp = GRPtable; --i >= 0; htp++) ++ htp->Used = 0; ++ else ++ for (i = GRP_SIZE, htp = GRPtable; --i >= 0; htp++) { ++ htp->Size = GRPbuckets; ++ htp->Groups = NEW(GROUPENTRY*, htp->Size); ++ htp->Used = 0; ++ } ++ ++ /* Now put all groups into the hash table. */ ++ for (i = GRPsize, gp = GRPentries; --i >= 0; gp++) { ++ /* SUPPRESS 6 *//* Over/underflow from plus expression */ ++ GRP_HASH(gp->Name, p, j); ++ htp = GRP_BUCKET(j); ++ if (htp->Used >= htp->Size) { ++ htp->Size += GRPbuckets; ++ RENEW(htp->Groups, GROUPENTRY*, htp->Size); ++ } ++ htp->Groups[htp->Used++] = gp; ++ } ++ ++ /* Note that we don't sort the buckets. */ ++} ++ ++ ++/* ++** Read the active file into memory, sort it, and set the number of ++** newsgroups read in. Return TRUE if okay, FALSE on error. ++*/ ++BOOL ++GetGroupList() ++{ ++ static char *active; ++ register char *p; ++ register char *q; ++ register GROUPENTRY *gp; ++ register int i; ++ ++ /* If re-scanning, free previous groups. */ ++ if (active != NULL) { ++ DISPOSE(active); ++ DISPOSE(GRPentries); ++ } ++ ++ /* Get the new file. */ ++ active = ReadInFile(ACTIVE, (struct stat *)NULL); ++ if (active == NULL) { ++ syslog(L_ERROR, "cant read %s %m", ACTIVE); ++ return FALSE; ++ } ++ ++ /* Count lines. */ ++ for (p = active, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++) ++ continue; ++ ++ /* Fill in the group array. */ ++ GRPentries = NEW(GROUPENTRY, i); ++ for (i = 0, gp = GRPentries, p = active; *p; i++, gp++, p = q + 1) { ++ gp->Name = p; ++ if ((p = strchr(p, ' ')) == NULL) { ++ syslog(L_ERROR, "internal no_space1 \"%.20s...\"", ++ gp->Name); ++ return FALSE; ++ } ++ *p++ = '\0'; ++ ++ /* Get the high mark. */ ++ if ((q = strchr(p, ' ')) == NULL) { ++ syslog(L_ERROR, "internal no_space2 \"%.20s...\"", ++ gp->Name); ++ return FALSE; ++ } ++ *q++ = '\0'; ++ gp->High = atol(p); ++ ++ /* Get the low mark. */ ++ if ((p = strchr(q, ' ')) == NULL) { ++ syslog(L_ERROR, "internal no_space3 \"%.20s...\"", ++ gp->Name); ++ return FALSE; ++ } ++ *p++ = '\0'; ++ gp->Low = atol(q); ++ ++ /* Kill the newline. */ ++ if ((q = strchr(p, '\n')) == NULL) { ++ syslog(L_ERROR, "internal newline \"%.20s...\"", ++ gp->Name); ++ return FALSE; ++ } ++ *q = '\0'; ++ gp->Flag = *p; ++ gp->Alias = gp->Flag == NF_FLAG_ALIAS ? p + 1 : NULL; ++ } ++ ++ GRPsize = i; ++ GRPhash(); ++ return TRUE; ++} +--- inn-1.7.2.orig/actived/protocol.h ++++ inn-1.7.2/actived/protocol.h +@@ -0,0 +1,19 @@ ++#define ACTIVED_TIMEOUT 10 ++ ++#define REQ_AYT 1 ++#define REQ_AYTACK 2 ++#define REQ_FIND 3 ++#define REQ_FINDRESP 4 ++ ++struct wireprotocol { ++ int RequestType; ++ int RequestID; ++ int Success; ++ int NameNull; ++ char Name[1024]; ++ ARTNUM High; ++ ARTNUM Low; ++ char Flag; ++ int AliasNull; ++ char Alias[1024]; ++}; +--- inn-1.7.2.orig/actived/query.c ++++ inn-1.7.2/actived/query.c +@@ -0,0 +1,48 @@ ++#include ++#include "actived.h" ++#include "protocol.h" ++ ++ ++int main(argc, argv) ++int argc; ++char *argv[]; ++{ ++ int s, i; ++ int start = time(NULL) - 1; ++ struct wireprotocol buffer; ++ ++ if ((s = create_udp_socket(0)) < 0) { ++ fprintf(stderr, "couldnt create socket\n"); ++ exit(1); ++ } ++ if (connect_udp_socket(s, "localhost", 1119) < 0) { ++ fprintf(stderr, "couldnt connect socket\n"); ++ exit(1); ++ } ++ i = 0; ++ buffer.RequestType = REQ_FIND; ++ buffer.RequestID = getpid(); ++ sprintf(buffer.Name, argv[1]); ++ ++ fprintf(stderr, "asking question: request-id %d, group \"%s\"\n\n", buffer.RequestID, buffer.Name); ++ ++ if (write_udp(s, (char *)&buffer, sizeof(buffer)) < 0) { ++ fprintf(stderr, "couldnt write packet\n"); ++ exit(1); ++ } ++ if (read_udp(s, (char *)&buffer, sizeof(buffer)) != sizeof(buffer)) { ++ fprintf(stderr, "couldnt read packet\n"); ++ exit(1); ++ } ++ fprintf(stderr, "request-id ok? %s (%d)\n", buffer.RequestID == getpid() ? "yes" : "no", buffer.RequestID); ++ fprintf(stderr, "response type correct? %s (%d)\n", buffer.RequestType == REQ_FINDRESP ? "yes" : "no", buffer.RequestType); ++ fprintf(stderr, "success? %s\n", buffer.Success ? "yes" : "no"); ++ fprintf(stderr, "name? %s\n", buffer.NameNull ? "" : buffer.Name); ++ fprintf(stderr, "alias? %s\n", buffer.AliasNull ? "" : buffer.Alias); ++ fprintf(stderr, "range? %d-%d\n", buffer.Low, buffer.High); ++ fprintf(stderr, "flag? %c\n", buffer.Flag); ++} ++ ++ ++ ++ +--- inn-1.7.2.orig/actived/test.c ++++ inn-1.7.2/actived/test.c +@@ -0,0 +1,43 @@ ++#include ++#include "actived.h" ++#include "protocol.h" ++ ++ ++int main(argc, argv) ++int argc; ++char *argv[]; ++{ ++ int s, i; ++ int start = time(NULL) - 1; ++ struct wireprotocol buffer; ++ ++ if ((s = create_udp_socket(0)) < 0) { ++ fprintf(stderr, "couldnt create socket\n"); ++ exit(1); ++ } ++ if (connect_udp_socket(s, "localhost", 1119) < 0) { ++ fprintf(stderr, "couldnt connect socket\n"); ++ exit(1); ++ } ++ i = 0; ++ fprintf(stderr, "%08d", 0); ++ for (;;) { ++ buffer.RequestType = REQ_FIND; ++ sprintf(buffer.Name, "alt.sex"); ++ if (write_udp(s, (char *)&buffer, sizeof(buffer)) < 0) { ++ fprintf(stderr, "couldnt write packet\n"); ++ exit(1); ++ } ++ if (read_udp(s, (char *)&buffer, sizeof(buffer)) != sizeof(buffer)) { ++ fprintf(stderr, "couldnt read packet\n"); ++ exit(1); ++ } ++ if (! (++i % 100)) { ++ fprintf(stderr, "\r%08d %5.2f", i, (float)i / (time(NULL) - start)); ++ } ++ } ++} ++ ++ ++ ++ +--- inn-1.7.2.orig/actived/udp.c ++++ inn-1.7.2/actived/udp.c +@@ -0,0 +1,162 @@ ++#include ++#include ++#include "clibrary.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include "logging.h" ++ ++#ifdef NEED_BZERO_ETC ++#include ++void ++bzero(b, length) ++ char *b; ++ int length; ++{ ++ while (--length >= 0) ++ *b++ = '\0'; ++} ++void ++bcopy(b1, b2, length) ++ char *b1; ++ char *b2; ++ int length; ++{ ++ while (--length >= 0) ++ *b2++ = *b1++; ++} ++#endif ++ ++int create_udp_socket(int port) ++{ ++ int s; ++ struct sockaddr_in sin; ++ ++ sin.sin_port = htons(port); ++ sin.sin_family = AF_INET; ++ sin.sin_addr.s_addr = INADDR_ANY; ++ ++ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ++ syslog(L_ERROR, "create_udp_socket: socket: %m"); ++ return(-1); ++ } ++ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ++ syslog(L_ERROR, "create_udp_socket: bind: %m"); ++ return(-1); ++ } ++ return(s); ++} ++ ++ ++ ++ ++ ++int make_udp_sockaddr(struct sockaddr_in *addr, char *ascii) ++{ ++ struct hostent *host; ++ int dots = 0; ++ int numeric = 0; ++ char *str, *colon, *lastdot, *ptr; ++ ++ if (! (str = malloc(strlen(ascii) + 1))) { ++ syslog(L_ERROR, "make_udp_sockaddr: malloc: %m"); ++ return(-1); ++ } ++ strcpy(str, ascii); ++ colon = strrchr(str, ':'); ++ lastdot = strrchr(str, '.'); ++ ++ addr->sin_family = AF_INET; ++ ++ /* Count the number of dots in the address. */ ++ for (ptr = str; *ptr; ptr++) { ++ if (*ptr == '.') { ++ dots++; ++ } ++ } ++ ++ /* Check if it seems to be numeric. */ ++ numeric = isdigit(*str); ++ ++ /* If numeric and four dots, we have a.b.c.d.6000 */ ++ if (numeric && dots == 4) { ++ *lastdot = '\0'; ++ addr->sin_port = htons(atoi(lastdot + 1)); ++ } ++ /* If nonnumeric, check if the last part is a port */ ++ if (! numeric && lastdot && isdigit(*(lastdot + 1))) { ++ *lastdot = '\0'; ++ addr->sin_port = htons(atoi(lastdot + 1)); ++ } ++ /* Now do we have a numeric address */ ++ if (numeric) { ++ addr->sin_addr.s_addr = inet_addr(str); ++ free(str); ++ return(0); ++ } ++ /* Or a name */ ++ if (! (host = gethostbyname(str))) { ++ free(str); ++ syslog(L_ERROR, "make_udp_sockaddr: gethostbyname: %m"); ++ return(-1); ++ } ++ bcopy(host->h_addr_list[0], (char *)&addr->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr)); ++ free(str); ++ return(0); ++} ++ ++ ++ ++ ++ ++int connect_udp_socket(int s, char *address, int port) ++{ ++ struct sockaddr_in sin; ++ ++ bzero(&sin, sizeof(sin)); ++ sin.sin_port = htons(port); ++ sin.sin_family = AF_INET; ++ sin.sin_addr.s_addr = INADDR_ANY; ++ ++ if (make_udp_sockaddr(&sin, address) < 0) { ++ return(-1); ++ } ++ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ++ syslog(L_ERROR, "connect_udp_socket: connect: %m"); ++ return(-1); ++ } ++ return(0); ++} ++ ++ ++ ++ ++ ++int write_udp(int s, char *buf, int len) ++{ ++ int rval; ++ ++ if ((rval = send(s, buf, len, 0x0)) < 0) { ++ syslog(L_ERROR, "write_udp: send: %m"); ++ return(-1); ++ } ++ return(rval); ++} ++ ++ ++ ++ ++ ++int read_udp(int s, char *buf, int len) ++{ ++ int rval; ++ ++ if ((rval = recv(s, buf, len, 0x0)) < 0) { ++ syslog(L_ERROR, "read_udp: recv: %m"); ++ return(-1); ++ } ++ return(rval); ++} +--- inn-1.7.2.orig/actived/README.actived ++++ inn-1.7.2/actived/README.actived +@@ -0,0 +1,46 @@ ++This is nnrpd-actived. ++ ++I found that one of the huge bottlenecks in an nnrp-oriented INN system ++is creating new sessions. I spent some time and tracked down one of the ++big time-consumers... hashing the active file. Even with sharedactive, ++each client would hash the contents into a local hash table, and with a ++very large active file, this took an appreciable amount of time. ++ ++My CPU's could do it a few times a second, but during peak periods, I ++see 5+ new connections per second, which essentially floods the CPU. ++ ++One fix would have been to have the nnrpd that updated the shared memory ++space also update a shared hash table. I didn't like that since I still ++think the sharedactive thing is uccchy. It used to occasionally snag ++a semaphore and hang a few hundred nnrpd's in limbo. Sharing the active ++file via mmap had drawbacks as well. ++ ++I finally decided to go a different route. I created an "active file ++server". This server reads and rehashes the active file once every 30 ++seconds, and will answer UDP requests about the contents of the file. ++ ++This is able to handle thousands of transactions per second, even though ++I rarely even see hundreds in production use. I can start up a hundred ++nnrp sessions a second without response time suffering noticeably. ++ ++The system is designed to fall back to standard active file accesses in ++the case actived falls over, which it hasn't in several months of ++production use. Hopefully my code is correct. I would strongly advise ++anyone who runs it to periodically check to see if actived has died, and ++restart it. Just because I've had luck with it,... ;-) ++ ++To install: patch your nnrpd with the enclosed "group.c.patch". ++Build the contents of this directory, install and run "actived", you ++can compile "query" and ask it a few questions (i.e. "query alt.sex"), ++and then install your new nnrpd if all looks good. ++ ++JG970605 ++ ++-- ++ ++I've made several changes to Joe's code (with Joe's assistance--thanks) to ++make actived a bit more portable. I've successfully compiled this version on ++Solaris 2.4, Solaris 2.5.1, SunOS 4.1.4, Linux 2.0.30, and OpenBSD 2.1, so ++I suspect it'll compile on just about anything now. ++ ++-Andrew Smith 970625 --- inn-1.7.2q.orig/debian/patches/0_insync_dbz_3.3 +++ inn-1.7.2q/debian/patches/0_insync_dbz_3.3 @@ -0,0 +1,745 @@ +--- inn-1.7.2.orig/dbz/dbz.c ++++ inn-1.7.2/dbz/dbz.c +@@ -1,6 +1,6 @@ + /* + +-dbz.c V3.2 ++dbz.c V3.3 + + 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 +@@ -19,6 +19,22 @@ + Merged in MMAP code by David Robinson, formerly + now (January, 1993). + ++Introduced "offset fuzzy", i.e., dropping several least significant bits ++of the offset value, to allocate more bits on hash and named as ++dbz v3.3 by Sang-yong Suh (October, 1997) ++ ++Increased the table size factor from 1.5 to 2.0, to make more holes ++in the table. The extra holes will speed up history lookup. ++The base file usage is added at the third .dir line. ++Sang-yong Suh (October, 1997) ++ ++Keeps from too many identical "can't tag" error messages which occurred ++some news servers started with fresh history. Also added more ++sofisticated prediction of the future history size hoping that no_tagging ++situation occur. If this succeeds, we have another bit for hash tagging! ++Currently, the bit is used to record the flag whether the offset is tagged ++or not. Sang-yong Suh (December, 1997) ++ + 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. +@@ -39,7 +55,7 @@ + #ifndef __STDC__ + extern int errno; + #endif +-#include ++#include "dbz.h" + + /* + * #ifdef index. "LIA" = "leave it alone unless you know what you're doing". +@@ -74,6 +90,26 @@ + + static int dbzversion = 3; /* for validating .dir file format */ + ++/******************************************************************* ++ Start of dbz version 3.3 specific definitions ++ ******************************************************************/ ++ ++/* MAXDROPBITS is the maximum number of bits in the offset value. ++ The least significant bits are dropped. The space is used to ++ store hash bits, thereby increasing the possibility of the ++ hash conflict */ ++#define MAXDROPBITS 4 /* max # of bits to drop from the offset */ ++ ++/* MAXDROPBYTES must be derived from MAXDROPBITS as ((1 << MAXDROPBITS) - 1) */ ++#define MAXDROPBYTES ((1 << MAXDROPBITS) - 1) ++ ++/* START_OF_KEY is the last character of an entry, and it must be unique. */ ++#define START_OF_KEY '<' ++ ++/******************************************************************* ++ End of dbz version 3.3 sepecific definitions ++ ******************************************************************/ ++ + /* + * The dbz database exploits the fact that when news stores a + * tuple, the `value' part is a seek offset into a text file, pointing to +@@ -147,6 +183,7 @@ + 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 notag_warned=0; /* a switch to keep from repeated err msges */ + #define HASTAG(o) ((o)&taghere) + #define TAG(o) ((o)&tagbits) + #define NOTAG(o) ((o)&~tagboth) +@@ -159,7 +196,10 @@ + * the user supplies this info, but there have to be defaults. + */ + #ifndef DEFSIZE +-#define DEFSIZE 120011 /* 300007 might be better */ ++#define DEFSIZE 1000003 /* receiving 500K messsages in the 1st day. */ ++#endif ++#ifndef DEFSIZE_BASE ++#define DEFSIZE_BASE 100000000 /* history will not grow this much 1st day */ + #endif + #ifdef OLDBNEWS + #define DEFCASE '0' /* B2.10 -- no mapping */ +@@ -199,6 +239,7 @@ + # endif + # define NUSEDS (1+NMEMORY) + of_t used[NUSEDS]; /* entries used today, yesterday, ... */ ++ of_t vused[NUSEDS]; /* max values used today, yesterday, ... */ + int valuesize; /* size of table values, == SOF */ + int bytemap[SOF]; /* byte-order map */ + char casemap; /* case-mapping algorithm (see cipoint()) */ +@@ -206,6 +247,8 @@ + 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 offsetfuzzy; /* number of fuzzy bytes in offset */ + }; + static struct dbzconfig conf; + static int getconf(); +@@ -355,7 +398,6 @@ + extern void CloseOnExec(); + + /* misc. forwards */ +-static long hash(); + static void crcinit(); + static char *cipoint(); + static char *mapcase(); +@@ -384,11 +426,78 @@ + static int written; /* has a store() been done? */ + + /* ++ - dbzconfbase - reconfigure dbzconf from base file size. ++ */ ++static void dbzconfbase(c, bsize) ++struct dbzconfig *c; ++of_t bsize; /* base file size */ ++{ ++ int i; ++ register of_t m; ++ ++ /* if no tag requested, just return. */ ++ if ((c->tagmask | c->tagenb) == 0) ++ return; ++ ++ /* ++ * The base file will grow until the next dbz rebuild. ++ * Therefore the prediction of correct size is important. ++ * If the predicted size is too small, the "can't tag" occurs. ++ * If the prediction is too big, we'll waste tag bits. ++ */ ++ ++ /* History of a fresh news server will not grow this much in a day */ ++ if (bsize < 1000) ++ bsize = DEFSIZE_BASE; ++ ++ /* This must be a small server. It may grow 50% in a day. */ ++ else if (bsize < DEFSIZE_BASE) ++ bsize += bsize / 2; ++ ++ /* This is a midsize server. It can grow 20% in a day. */ ++ else if (bsize < 2 * DEFSIZE_BASE) ++ bsize += bsize / 5; ++ ++ /* This must be a big server. It can grow 10% in a day. */ ++ else ++ bsize += bsize / 10; ++ ++ /* calculate tagging from old file */ ++ for (m = 1, i = 0; m < bsize; 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->offsetfuzzy = (int)(1 << c->dropbits) - 1; ++ ++ m = (c->tagmask | c->tagenb) << c->tagshift; ++ if (m & (bsize >> c->dropbits)) { ++ fprintf(stderr, "m 0x%lx size 0x%lx\n", m, bsize); ++ exit(1); ++ } ++} ++ ++/* + - dbzfresh - set up a new database, no historical info + */ + int /* 0 success, -1 failure */ + dbzfresh(name, size, fs, cmap, tagmask) +-char *name; /* base name; .dir and .pag must exist */ ++char *name; /* base name; base file must exist */ + long size; /* table size (0 means default) */ + int fs; /* field-separator character in base file */ + int cmap; /* case-map algorithm (0 means default) */ +@@ -398,6 +507,7 @@ + struct dbzconfig c; + register of_t m; + register FILE *f; ++ struct stat sb; + + if (pagf != NULL) { + DEBUG(("dbzfresh: database already open\n")); +@@ -443,6 +553,8 @@ + c.tagshift = 0; + c.tagmask = 0; + c.tagenb = 0; ++ c.dropbits = 0; ++ c.offsetfuzzy = 0; + break; + default: + m = tagmask; +@@ -453,9 +565,16 @@ + } + c.tagmask = m; + c.tagenb = (m << 1) & ~m; ++ c.dropbits = 0; ++ c.offsetfuzzy = 0; + break; + } + ++ /* if big enough base file exists, update config */ ++ if (stat(name, &sb) == -1) ++ sb.st_size = 0; ++ dbzconfbase(&c, sb.st_size); ++ + /* write it out */ + fn = enstring(name, dir); + if (fn == NULL) +@@ -504,7 +623,7 @@ + DEBUG(("dbzsize: preposterous input (%ld)\n", contents)); + return(DEFSIZE); + } +- n = (contents/2)*3; /* try to keep table at most 2/3 full */ ++ n = contents*2; /* try to keep table at most 1/2 full */ + if (!(n&01)) /* make it odd */ + n++; + DEBUG(("dbzsize: tentative size %ld\n", n)); +@@ -561,12 +680,11 @@ + register char *fn; + struct dbzconfig c; + register int i; +- register long top; ++ register long top, vtop; + register FILE *f; + register int newtable; + register of_t newsize; + struct stat sb; +- register of_t m; + + if (pagf != NULL) { + DEBUG(("dbzagain: database already open\n")); +@@ -590,35 +708,34 @@ + return(-1); + } + +- /* calculate tagging from old file */ +- if (stat(oldname, &sb) != -1) { +- for (m = 1, i = 0; m < sb.st_size; i++, m <<= 1) +- continue; +- +- /* if we had more tags than the default, use the new data */ +- 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; +- } +- } +- + /* tinker with it */ + top = 0; ++ vtop = 0; + newtable = 0; + for (i = 0; i < NUSEDS; i++) { + if (top < c.used[i]) + top = c.used[i]; +- if (c.used[i] == 0) ++ if (vtop < c.vused[i]) ++ vtop = c.vused[i]; ++ if (c.used[i] == 0 || c.vused[i] == 0) + newtable = 1; /* hasn't got full usage history yet */ + } +- if (top == 0) { ++ if (top == 0 || vtop == 0) { + DEBUG(("dbzagain: old table has no contents!\n")); + newtable = 1; + } +- for (i = NUSEDS-1; i > 0; i--) ++ for (i = NUSEDS-1; i > 0; i--) { + c.used[i] = c.used[i-1]; ++ c.vused[i] = c.vused[i-1]; ++ } + c.used[0] = 0; ++ c.vused[0] = 0; ++ ++ /* calculate tagging from old file */ ++ if (stat(oldname, &sb) != -1 && vtop < sb.st_size) ++ vtop = sb.st_size; ++ dbzconfbase(&c, vtop); ++ + newsize = dbzsize(top); + if (!newtable || newsize > c.tsize) /* don't shrink new table */ + c.tsize = newsize; +@@ -790,6 +907,7 @@ + /* misc. setup */ + crcinit(); + written = 0; ++ notag_warned = 0; + prevp = FRESH; + DEBUG(("dbminit: succeeded\n")); + return(0); +@@ -861,7 +979,6 @@ + DEBUG(("dbmclose: fclose(dirf) failed\n")); + ret = -1; + } +- + DEBUG(("dbmclose: %s\n", (ret == 0) ? "succeeded" : "failed")); + return(ret); + } +@@ -953,12 +1070,13 @@ + fetch(key) + datum key; + { +- char buffer[DBZMAXKEY + 1]; ++ char buffer[DBZMAXKEY + MAXDROPBYTES + 1]; + static of_t key_ptr; /* return value points here */ + datum output; + register size_t keysize; + register size_t cmplen; +- register char *sepp; ++ int j, nb2r; ++ char *bp; + + DEBUG(("fetch: (%s)\n", key.dptr)); + output.dptr = NULL; +@@ -982,33 +1100,41 @@ + } + + cmplen = keysize; +- sepp = &conf.fieldsep; + if (key.dptr[keysize-1] == '\0') { + cmplen--; +- sepp = &buffer[keysize-1]; + } ++ nb2r = keysize + conf.offsetfuzzy; + start(&srch, &key, FRESH); + while ((key_ptr = search(&srch)) != NOTFOUND) { + DEBUG(("got 0x%lx\n", key_ptr)); + + /* fetch the key */ ++ key_ptr <<= conf.dropbits; + if (fseek(basef, key_ptr, SEEK_SET) != 0) { + DEBUG(("fetch: seek failed\n")); + return(output); + } +- if (fread((POINTER)buffer, 1, keysize, basef) != keysize) { ++ if (fread((POINTER)buffer, 1, nb2r, basef) < keysize) { + DEBUG(("fetch: read failed\n")); + return(output); + } ++ for (j=0,bp=buffer; j conf.vused[0]) ++ conf.vused[0] = value; ++ value >>= conf.dropbits; + DEBUG(("store: (%s, %ld)\n", key.dptr, (long)value)); + if (!okayvalue(value)) { + DEBUG(("store: reserved bit or overflow in 0x%lx\n", value)); +@@ -1166,7 +1295,7 @@ + { + register long m; + register long tagmask; +- register int i; ++ register int i, j; + + if (size <= 0) + return(0L); /* silly size */ +@@ -1174,6 +1303,10 @@ + for (m = 1, i = 0; m < size; i++, m <<= 1) + continue; + ++ for (j=0; m < (1 << TAGSHIFT) && j<=MAXDROPBITS; j++) { ++ m <<= 1; ++ i--; ++ } + if (m < (1 << TAGSHIFT)) + return(0L); /* not worth tagging */ + +@@ -1204,15 +1337,19 @@ + cp->fieldsep = '\t'; + for (i = 0; i < NUSEDS; i++) + cp->used[i] = 0; ++ for (i = 0; i < NUSEDS; i++) ++ cp->vused[i] = 0; + cp->valuesize = SOF; + mybytemap(cp->bytemap); + cp->casemap = DEFCASE; + cp->tagenb = TAGENB; + cp->tagmask = TAGMASK; + cp->tagshift = TAGSHIFT; +- DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n", ++ cp->dropbits = 0; ++ cp->offsetfuzzy = 0; ++ DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d %d))\n", + cp->tsize, cp->casemap, cp->tagenb, +- cp->tagmask, cp->tagshift)); ++ cp->tagmask, cp->tagshift, cp->dropbits)); + return(0); + } + (void) ungetc(c, df); +@@ -1238,8 +1375,22 @@ + } + for (i = 0; i < cp->valuesize; i++) + cp->bytemap[i] = getno(df, &err); +- if (getc(df) != '\n') +- err = -1; ++ ++ /* dbz v3.3 has one more parameter, dropbits, at the end. */ ++ cp->dropbits = 0; ++ if ((c = getc(df)) != '\n') { ++ (void) ungetc(c, df); ++ cp->dropbits = getno(df, &err); ++ if (cp->dropbits < 0 || cp->dropbits > MAXDROPBITS) { ++ DEBUG(("getconf: invalid dropbits (%d)\n", cp->dropbits)); ++ err = -1; ++ cp->dropbits = 0; ++ } ++ if (getc(df) != '\n') ++ err = -1; ++ } ++ cp->offsetfuzzy = (1 << cp->dropbits) - 1; ++ + #ifdef DBZDEBUG + DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize, + cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask, +@@ -1248,16 +1399,32 @@ + for (i = 0; i < cp->valuesize; i++) { + DEBUG((" %d", cp->bytemap[i])); + } ++ DEBUG((" dbit %d", cp->dropbits)); + DEBUG(("\n")); + #endif + + /* second line, the usages */ + for (i = 0; i < NUSEDS; i++) + cp->used[i] = getno(df, &err); +- if (getc(df) != '\n') ++ if ((c = getc(df)) != '\n') { ++ DEBUG(("getconf: unexpected char %c detected on 2nd line\n", c)); + err = -1; ++ } + DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2])); + ++ /* third line, the base file sizes. handle earlier format as well */ ++ if ((c = getc(df)) != EOF) { ++ (void) ungetc(c, df); ++ for (i = 0; i < NUSEDS; i++) ++ cp->vused[i] = getno(df, &err); ++ if (getc(df) != '\n') ++ err = -1; ++ DEBUG(("used %ld %ld %ld...\n", cp->vused[0], cp->vused[1], cp->vused[2])); ++ } else { ++ for (i = 0; i < NUSEDS; i++) ++ cp->vused[i] = 0; ++ } ++ + if (err < 0) { + DEBUG(("getconf error\n")); + return(-1); +@@ -1324,9 +1491,12 @@ + cp->tagmask, cp->tagshift, cp->valuesize); + for (i = 0; i < cp->valuesize; i++) + (void) fprintf(f, " %d", cp->bytemap[i]); ++ (void) fprintf(f, " %d", cp->dropbits); + (void) fprintf(f, "\n"); + for (i = 0; i < NUSEDS; i++) + (void) fprintf(f, "%ld%c", cp->used[i], (i < NUSEDS-1) ? ' ' : '\n'); ++ for (i = 0; i < NUSEDS; i++) ++ (void) fprintf(f, "%ld%c", cp->vused[i], (i < NUSEDS-1) ? ' ' : '\n'); + + (void) fflush(f); + if (ferror(f)) +@@ -1343,13 +1513,16 @@ + getcore(f) + FILE *f; + { ++ register char *it; ++#ifndef MMAP + register of_t *p; + register size_t i; + register size_t nread; +- register char *it; +-#ifdef MMAP ++#else + struct stat st; ++#endif + ++#ifdef MMAP + if (fstat(fileno(f), &st) == -1) { + DEBUG(("getcore: fstat failed\n")); + return(NULL); +@@ -1368,7 +1541,7 @@ + DEBUG(("getcore: mmap failed\n")); + return(NULL); + } +-#if defined (MADV_RANDOM) ++#if defined (MADV_RANDOM) + /* not present in all versions of mmap() */ + madvise(it, (size_t)conf.tsize * SOF, MADV_RANDOM); + #endif +@@ -1426,7 +1599,7 @@ + { + register long h; + +- h = hash(kp->dptr, kp->dsize); ++ h = dbzhash(kp->dptr, kp->dsize); + if (osp != FRESH && osp->hash == h) { + if (sp != osp) + *sp = *osp; +@@ -1434,8 +1607,9 @@ + } else { + sp->hash = h; + sp->tag = MKTAG(h / conf.tsize); +- DEBUG(("tag 0x%lx\n", sp->tag)); + sp->place = h % conf.tsize; ++ DEBUG(("hash %8.8lx tag %8.8lx place %ld\n", ++ sp->hash, sp->tag, sp->place)); + sp->tabno = 0; + sp->run = (conf.olddbz) ? conf.tsize : MAXRUN; + sp->aborted = 0; +@@ -1564,6 +1738,10 @@ + if (v != LONG_MAX) /* and it won't overflow */ + #endif + value = v; ++ } else if (notag_warned == 0) { ++ notag_warned = 1; ++ fprintf(stderr, "can't tag value 0x%lx", v); ++ fprintf(stderr, " tagboth = 0x%lx\n", tagboth); + } + DEBUG(("tagged value is 0x%lx\n", value)); + value = BIAS(value); +@@ -1716,10 +1894,10 @@ + } + + /* +- - hash - Honeyman's nice hashing function ++ - dbzhash - Honeyman's nice hashing function + */ +-static long +-hash(name, size) ++long ++dbzhash(name, size) + register char *name; + register int size; + { +@@ -1728,11 +1906,44 @@ + while (size--) { + sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f]; + } +- DEBUG(("hash: returns (%ld)\n", sum)); ++ DEBUG(("hash: returns (%8.8lx)\n", sum)); + return(sum); + } + + /* ++ - dbzhash64 - 64-bit extended hashing function ++ */ ++ ++void ++dbzhash64(name_in, size_in, hash) ++register char *name_in; ++register int size_in; ++long hash[2]; ++{ ++ char *name; ++ int size; ++ long sum = 0L; ++ char buffer[DBZMAXKEY + 1]; ++ ++ if (size_in > DBZMAXKEY) ++ size_in = DBZMAXKEY; ++ name = mapcase(buffer, name_in, size_in); ++ ++ size = size_in; ++ while (size--) { ++ sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f]; ++ } ++ hash[0] = sum; ++ ++ size = size_in; ++ while (size--) { ++ sum = (sum >> 7) ^ CrcTable[(sum ^ (*--name)) & 0x7f]; ++ } ++ /* set bit 31 from the number of characters in name */ ++ hash[1] = sum; ++} ++ ++/* + * case-mapping stuff + * + * Borrowed from C News, by permission of the authors. Somewhat modified. +@@ -1891,7 +2102,7 @@ + /* crazy -- "postmaster" is case-insensitive */ + return(s); + } +- return(p); ++ return(p); + case '=': /* 2.11, neither sensible nor conformant */ + return(s); /* all case-insensitive */ + } +@@ -1914,3 +2125,95 @@ + return(old); + } + #endif ++ ++#ifdef DBZTEST ++void CloseOnExec(int i, int j) {} ++ ++usage() ++{ ++ fprintf(stderr, "usage: dbztest [-r] [-s size] \n"); ++ fprintf(stderr, " -r rebuild history. deletes .dir .pag files\n"); ++ fprintf(stderr, " -s size number of history lines[500000]\n"); ++ fprintf(stderr, " history history text file\n"); ++ exit(1); ++} ++ ++int main(argc, argv) ++int argc; ++char *argv[]; ++{ ++ int i, line; ++ FILE *fpi; ++ char ibuf[2048], *p; ++ datum key, val, data; ++ long where; ++ int initialize = 0, size = 500000; ++ char *history = NULL; ++ ++ for (i=1; i 0) ++ syslog(L_NOTICE, "SERVER history cache final: %lu lookups, %lu hits", ++ HIScachelookups, HIScachehits); + } + + +@@ -138,8 +167,14 @@ + register int i; + + /* Get the seek value into the history file. */ ++#if defined(TIMER) ++ TMRstart(TMR_HISGREP); ++#endif /* defined(TIMER) */ + HISsetkey(MessageID, &key); + val = dbzfetch(key); ++#if defined(TIMER) ++ TMRstop(TMR_HISGREP); ++#endif /* defined(TIMER) */ + if (val.dptr == NULL || val.dsize != sizeof offset) + return NULL; + +@@ -198,9 +233,36 @@ + { + datum key; + datum val; ++ long hash_pos, hash_val; + ++ ++ /* hash msg id */ ++ hash_val = dbzhash(MessageID, strlen(MessageID)); ++ hash_pos = hash_val % HISCACHESIZE; ++ ++ /* check history lookup cache for hashed msg id */ ++ HIScachelookups++; ++ if (HIScache[hash_pos].MessageIDHash == hash_val) { ++ HIScachehits++; ++ return HIScache[hash_pos].Found; ++ } ++ ++ /* check dbz history for msg id */ ++#if defined(TIMER) ++ TMRstart(TMR_HISHAVE); ++#endif /* defined(TIMER) */ + HISsetkey(MessageID, &key); + val = dbzfetch(key); ++ ++ /* store hashed msg id, lookup result in history lookup cache */ ++ HIScache[hash_pos].MessageIDHash = hash_val; ++ HIScache[hash_pos].Found = (char)(val.dptr != NULL); ++ ++#if defined(TIMER) ++ TMRstop(TMR_HISHAVE); ++#endif /* defined(TIMER) */ ++ ++ /* return result of lookup */ + return val.dptr != NULL; + } + +@@ -237,11 +299,14 @@ + char *paths; + { + static char NOPATHS[] = ""; +- long offset; ++ long offset, hash_val, hash_pos; + datum key; + datum val; + int i; + ++#if defined(TIMER) ++ TMRstart(TMR_HISWRITE); ++#endif /* defined(TIMER) */ + HISsetkey(Data->MessageID, &key); + if (paths != NULL && paths[0] != '\0') + HISslashify(paths); +@@ -268,6 +333,9 @@ + i = errno; + syslog(L_ERROR, "%s cant write history %m", LogName); + IOError("history", i); ++#if defined(TIMER) ++ TMRstop(TMR_HISWRITE); ++#endif /* defined(TIMER) */ + return FALSE; + } + +@@ -278,8 +346,19 @@ + i = errno; + syslog(L_ERROR, "%s cant dbzstore %m", LogName); + IOError("history database", i); ++#if defined(TIMER) ++ TMRstop(TMR_HISWRITE); ++#endif /* defined(TIMER) */ + return FALSE; + } ++#if defined(TIMER) ++ TMRstop(TMR_HISWRITE); ++#endif /* defined(TIMER) */ ++ /* store hashed message id value in history lookup cache */ ++ hash_val = dbzhash(Data->MessageID, strlen(Data->MessageID)); ++ hash_pos = hash_val % HISCACHESIZE; ++ HIScache[hash_pos].MessageIDHash = hash_val; ++ HIScache[hash_pos].Found = TRUE; + + if (++HISdirty >= ICD_SYNC_COUNT) + HISsync(); +--- inn-1.7.2.orig/innd/nc.c ++++ inn-1.7.2/innd/nc.c +@@ -1,4 +1,4 @@ +-/* $Revision: 1.51 $ ++/* $Revision: 1.51+precommit-cache$ + ** + ** Routines for the NNTP channel. Other channels get the descriptors which + ** we turn into NNTP channels, and over which we speak NNTP. +@@ -107,6 +108,45 @@ + + + /* ++ * precommit cache ++ */ ++#define NCPRECOMCACHESIZE 4096L ++#define NCPRECOMCACHETIMEOUT 30 ++ ++/* uncomment line below to: ++ * - zap cache entry after art acceptance or rejection ++ */ ++/* #define NCPRECOM_PEDANTIC */ ++ ++/* uncomment line below to: ++ * - have CHECK return DEFER instead of REFUSE ++ * for cache hits ++ */ ++/* #define NCPRECOM_DEFER */ ++ ++typedef struct { ++ long MessageIDHash; ++ time_t Timestamp; ++} _NCprecomcache; ++ ++STATIC _NCprecomcache NCprecomcache[NCPRECOMCACHESIZE]; ++unsigned long NCprecomhits; ++unsigned long NCprecomlookups; ++STATIC long NCprecompos, NCprecomval; ++STATIC NCprecominit = 0; ++ ++ ++STATIC void ++NCprecomclear () ++{ ++ memset((void *)&NCprecomcache, 0, sizeof(NCprecomcache)); ++ NCprecomhits = NCprecomlookups = 0; ++} ++ ++ ++ ++ ++/* + ** Clear the work-in-progress entry and wake up anyone who might + ** have been waiting for us. + */ +@@ -264,6 +304,11 @@ + } + cp->State = CSgetcmd; + NCwritereply(cp, response); ++#ifdef NCPRECOM_PEDANTIC ++ NCprecomval = dbzhash(wp->MessageID, strlen(wp->MessageID)); ++ NCprecompos = NCprecomval % NCPRECOMCACHESIZE; ++ NCprecomcache[NCprecompos].MessageIDHash = 0L; ++#endif + break; + + case OMthrottled: +@@ -343,7 +388,7 @@ + } + + /* Write the terminator. */ +- WCHANappend(cp, NCdotterm, STRLEN(NCdotterm)); ++ NCwritereply(cp, NCdot); /* Was WCHANappend. fixed 1997/10/31 yone@pi.ntts.co.jp */ + } + #endif /* 0 */ + +@@ -382,7 +427,7 @@ + } + + /* Write the terminator. */ +- NCwritereply(cp, NCdot); ++ NCwritereply(cp, NCdot); /* Was WCHANappend. fixed 1997/10/31 yone@pi.ntts.co.jp */ + } + + +@@ -595,7 +640,20 @@ + if (NCbadid(cp, p)) + return; + +- if (HIShavearticle(p)) { ++ /* compute msg id hash for pre-commit cache check */ ++ NCprecomval = dbzhash(p, strlen(p)); ++ NCprecompos = NCprecomval % NCPRECOMCACHESIZE; ++ NCprecomlookups++; ++ ++ /* check pre-commit cache for msg id, with timeout */ ++ if ((NCprecomcache[NCprecompos].MessageIDHash == NCprecomval) && ++ ((NCprecomcache[NCprecompos].Timestamp + NCPRECOMCACHETIMEOUT) > Now.time)) { ++ NCprecomhits++; ++ cp->Refused++; ++ NCwritereply(cp, NNTP_HAVEIT); ++ } ++ ++ else if (HIShavearticle(p)) { + cp->Refused++; + NCwritereply(cp, NNTP_HAVEIT); + } +@@ -612,6 +670,9 @@ + #endif /* defined(NNTP_RESENDIT_LATER) */ + } + else { ++ /* pre-commit msg id so that noone else offers us this for 30 seconds */ ++ NCprecomcache[NCprecompos].MessageIDHash = NCprecomval; ++ NCprecomcache[NCprecompos].Timestamp = Now.time; + cp->State = CSgetarticle; + NCwritereply(cp, NNTP_SENDIT); + } +@@ -1409,6 +1474,14 @@ + register CHANNEL *cp; + int i; + ++ /* one-time initialization of pre-commit cache */ ++ if (!NCprecominit) { ++ NCprecomclear(); ++ NCprecominit = 1; ++ syslog(L_NOTICE, "Pre-commit cache initialized: %ld entries, %ld bytes", ++ NCPRECOMCACHESIZE, (long) sizeof(NCprecomcache)); ++ } ++ + /* Create the channel. */ + cp = CHANcreate(fd, CTnntp, MustAuthorize ? CSgetauth : CSgetcmd, + NCreader, NCwritedone); +@@ -1484,6 +1557,12 @@ + int msglen; + WIP *who; + ++#if defined(DO_PERL) ++ char *perlrc; ++#endif /* DO_PERL */ ++ ++ ++ + if (AmSlave) { + NCwritereply(cp, NCbadcommand); + return; +@@ -1508,14 +1587,51 @@ + return; + } + +- if (HIShavearticle(p)) { ++#if defined(DO_PERL) ++ /* invoke a perl message filter on the message id */ ++ else if ((perlrc = (char *)HandleMessageID(p)) != NULL) { ++ cp->Refused++; ++ (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_ERR_GOTID_VAL, p); ++ NCwritereply(cp, cp->Sendid.Data); ++ } ++#endif ++ ++ /* compute msg id hash for pre-commit cache check */ ++ NCprecomval = dbzhash(p, msglen - 5); ++ NCprecompos = NCprecomval % NCPRECOMCACHESIZE; ++ NCprecomlookups++; ++ ++ /* check pre-commit cache for msg id, with timeout */ ++ if ((NCprecomcache[NCprecompos].MessageIDHash == NCprecomval) && ++ ((NCprecomcache[NCprecompos].Timestamp + NCPRECOMCACHETIMEOUT) > Now.time)) { ++ NCprecomhits++; ++ ++#ifdef NCPRECOM_DEFER ++ (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_RESENDID_VAL, p); ++#else ++ cp->Refused++; ++ (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_ERR_GOTID_VAL, p); ++#endif ++ NCwritereply(cp, cp->Sendid.Data); ++ } ++ ++ /* check history for msg id existence */ ++ else if (HIShavearticle(p)) { + cp->Refused++; + (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_ERR_GOTID_VAL, p); + NCwritereply(cp, cp->Sendid.Data); ++ ++ /* check to see if article's already in progress on some other channel */ + } else if (NCinprogress(cp, p, &who)) { + (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_RESENDID_VAL, p); + NCwritereply(cp, cp->Sendid.Data); ++ ++ /* otherwise, we don't have the message, tell remote to send it to us */ + } else { ++ /* pre-commit msg id so that noone else offers us this for 30 seconds */ ++ NCprecomcache[NCprecompos].MessageIDHash = NCprecomval; ++ NCprecomcache[NCprecompos].Timestamp = Now.time; ++ + (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_OK_SENDID_VAL, p); + NCwritereply(cp, cp->Sendid.Data); + } +@@ -1540,10 +1656,21 @@ + continue; + for ( ; ISWHITE(*p); p++) + continue; ++ ++ msglen = strlen(p) + 5; /* 3 digits + space + id + null */ ++ + if (!ARTidok(p)) { + syslog(L_NOTICE, "%s bad_messageid %s", CHANname(cp), MaxLength(p, p)); + } +- msglen = strlen(p) + 5; /* 3 digits + space + id + null */ ++ ++ /* pre-commit msg id so that noone else offers us this for 30 seconds */ ++ else { ++ NCprecomval = dbzhash(p, msglen - 5); ++ NCprecompos = NCprecomval % NCPRECOMCACHESIZE; ++ NCprecomcache[NCprecompos].MessageIDHash = NCprecomval; ++ NCprecomcache[NCprecompos].Timestamp = Now.time; ++ } ++ + if (cp->Sendid.Size < msglen) { + if (cp->Sendid.Size > 0) DISPOSE(cp->Sendid.Data); + if (msglen > MAXHEADERSIZE) cp->Sendid.Size = msglen; +--- inn-1.7.2.orig/innd/cc.c ++++ inn-1.7.2/innd/cc.c +@@ -737,6 +744,10 @@ + return "1 Not active"; + } + ++extern unsigned long HIScachehits; ++extern unsigned long HIScachelookups; ++extern unsigned long NCprecomhits; ++extern unsigned long NCprecomlookups; + + /* + ** Return our operating mode. +@@ -746,6 +757,9 @@ + CCmode(av) + char *av[]; + { ++#if defined(DO_PERL) ++ dSP; ++#endif + register char *p; + register int i; + int h; +@@ -842,9 +856,37 @@ + p += strlen(strcpy(p, "enabled")); + else + p += strlen(strcpy(p, "disabled")); ++ ++ /* perl filter status */ ++ ++ if (perl_get_cv("filter_stats", FALSE) != NULL) { ++ *p++ = '\n'; ++ p += strlen(strcpy(p, "Perl filter stats: ")); ++ ++ ENTER ; ++ SAVETMPS; ++ ++ perl_call_argv("filter_stats", G_EVAL|G_NOARGS, NULL); ++ ++ SPAGAIN; ++ ++ p += strlen(strcpy(p, POPp)); ++ ++ PUTBACK; ++ FREETMPS; ++ LEAVE; ++ } ++ + #endif /* defined(DO_PERL) */ + +- i = strlen(buff); ++ *p++ = '\n'; ++ sprintf(p, "History cache: %lu lookups, %lu hits", HIScachelookups, HIScachehits); ++ p += strlen(p); ++ *p++ = '\n'; ++ sprintf(p, "Precommit cache: %lu lookups, %lu hits", NCprecomlookups, NCprecomhits); ++ p += strlen(p); ++ ++ i = strlen(buff); + if (CCreply.Size <= i) { + CCreply.Size = i; + RENEW(CCreply.Data, char, CCreply.Size + 1); +--- inn-1.7.2.orig/innd/chan.c ++++ inn-1.7.2/innd/chan.c +@@ -31,6 +31,8 @@ + STATIC CHANNEL *CHANrc; + #endif /* PRIORITISE_REMCONN */ + ++#include "timer.h" ++ + + /* + ** Set a buffer's contents, ignoring anything that might have +@@ -781,6 +793,10 @@ + char *p; + time_t LastUpdate; + ++#if defined(TIMER) ++ TMRinit(); ++#endif /* defined(TIMER) */ ++ + LastUpdate = GetTimeInfo(&Now) < 0 ? 0 : Now.time; + for ( ; ; ) { + /* See if any processes died. */ +@@ -790,8 +806,17 @@ + MyRead = RCHANmask; + MyWrite = WCHANmask; + MyTime = TimeOut; ++#if defined(TIMER) ++ i = TMRmainloophook(); ++ if (i) ++ MyTime.tv_sec = i; ++ TMRstart(TMR_IDLE); ++#endif /* defined(TIMER) */ + count = select(CHANlastfd + 1, &MyRead, &MyWrite, (FDSET *)NULL, + &MyTime); ++#if defined(TIMER) ++ TMRstop(TMR_IDLE); ++#endif /* defined(TIMER) */ + if (GotTerminate) { + (void)write(2, EXITING, STRLEN(EXITING)); + CleanupAndExit(0, (char *)NULL); +--- inn-1.7.2.orig/innd/art.c ++++ inn-1.7.2/innd/art.c +@@ -10,6 +10,9 @@ + #include "dbz.h" + #include "art.h" + #include ++#if defined(TIMER) ++#include "timer.h" ++#endif /* defined(TIMER) */ + + typedef struct iovec IOVEC; + +@@ -1725,6 +1768,7 @@ + static BUFFER Files; + static BUFFER Header; + static char buff[SPOOLNAMEBUFF]; ++ static char path[MAXHEADERSIZE]; + register char *p; + register int i; + register int j; +@@ -1757,6 +1803,18 @@ + Data.MessageID = ihave; + error = ARTclean(article, &Data); + ++ /* This makes me want to scream in agony and rip my eyeballs ++ out. We clobber our Path: header all to hell later on, so ++ we will preserve the data in a static buffer. I suppose ++ we could have gone groveling around in the article buffer, ++ but that seemed even worse, and more complex code. JG970605 */ ++ strcpy(path, "?"); ++ if (p = HDR(_path)) { ++ sprintf(path, "%s", p); ++ Data.Path = path; ++ Data.PathLength = strlen(path); ++ } ++ + /* Not much we can do here except toss it and report the error. */ + if (error != NULL) { + (void)sprintf(buff, "%d %s", NNTP_REJECTIT_VAL, +@@ -2174,6 +2283,9 @@ + ngp->PostCount = 0; + + if (Data.Name[0] == '\0') { ++#if defined(TIMER) ++ TMRstart(TMR_ARTWRITE); ++#endif /* defined(TIMER) */ + /* Write the article the first time. */ + (void)sprintf(Data.Name, "%s/%lu", ngp->Dir, ngp->Filenum); + if (ARTwrite(Data.Name, article, &Data) < 0 +@@ -2192,12 +2304,21 @@ + if (distributions) + DISPOSE(distributions); + ARTreject(buff, article); ++#if defined(TIMER) ++ TMRstop(TMR_ARTWRITE); ++#endif /* defined (TIMER) */ + return buff; + } ++#if defined(TIMER) ++ TMRstop(TMR_ARTWRITE); ++#endif /* defined(TIMER) */ + p += strlen(strcpy(p, Data.Name)); + Data.NameLength = strlen(Data.Name); + } + else { ++#if defined(TIMER) ++ TMRstart(TMR_ARTLINK); ++#endif /* defined(TIMER) */ + /* Link to the main article. */ + (void)sprintf(linkname, "%s/%lu", ngp->Dir, ngp->Filenum); + if (DoLinks && link(Data.Name, linkname) < 0 +@@ -2223,6 +2344,9 @@ + } + #endif /* defined(DONT_HAVE_SYMLINK) */ + } ++#if defined(TIMER) ++ TMRstop(TMR_ARTLINK); ++#endif /* defined(TIMER) */ + *p++ = ' '; + p += strlen(strcpy(p, linkname)); + } +@@ -2279,11 +2403,25 @@ + * has been processed. We could pause ourselves here, but it doesn't + * seem to be worth it. */ + if (Accepted) { +- if (ControlHeader >= 0) ++ if (ControlHeader >= 0) { ++#if defined(TIMER) ++ TMRstart(TMR_ARTCTRL); ++#endif /* defined(TIMER) */ + ARTcontrol(&Data, HDR(ControlHeader)); ++#if defined(TIMER) ++ TMRstop(TMR_ARTCTRL); ++#endif /* defined(TIMER) */ ++ } + p = HDR(_supersedes); +- if (*p && ARTidok(p)) ++ if (*p && ARTidok(p)) { ++#if defined(TIMER) ++ TMRstart(TMR_ARTCNCL); ++#endif /* defined(TIMER) */ + ARTcancel(&Data, p, FALSE); ++#if defined(TIMER) ++ TMRstop(TMR_ARTCNCL); ++#endif /* defined(TIMER) */ ++ } + } + + /* If we need the overview data, write it. */ +@@ -2292,8 +2430,15 @@ + + /* And finally, send to everyone who should get it */ + for (sp = Sites, i = nSites; --i >= 0; sp++) +- if (sp->Sendit) ++ if (sp->Sendit) { ++#if defined(TIMER) ++ TMRstart(TMR_SITESEND); ++#endif /* defined(TIMER) */ + SITEsend(sp, &Data); ++#if defined(TIMER) ++ TMRstop(TMR_SITESEND); ++#endif /* defined(TIMER) */ ++ } + + return NNTP_TOOKIT; + } +--- inn-1.7.2.orig/innd/Makefile ++++ inn-1.7.2/innd/Makefile +@@ -44,14 +44,18 @@ + LINTLIB = ../llib-linn.ln + ## =()@>()= + TCL_LIB = ++## =()@>()= ++IDENT_LIB = -lident ++ ++CFLAGS+= -DTIMER + + SOURCES = \ + art.c cc.c chan.c his.c icd.c innd.c lc.c nc.c newsfeeds.c ng.c \ +- proc.c rc.c site.c tcl.c perl.c ++ proc.c rc.c site.c tcl.c perl.c timer.c + + OBJECTS = \ + art.o cc.o chan.o his.o icd.o innd.o lc.o nc.o newsfeeds.o ng.o \ +- proc.o rc.o site.o tcl.o perl.o ++ proc.o rc.o site.o tcl.o perl.o timer.o + + ALL = innd inndstart + +@@ -68,7 +72,7 @@ + $(CTAGS) $(SOURCES) ../lib/*.c innd.h ../include/*.h + + innd: $(P) $(OBJECTS) $(LIBNEWS) +- $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBNEWS) $(TCL_LIB) $(PERLLIB) $(LIBS) ++ $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBNEWS) $(TCL_LIB) $(PERLLIB) $(IDENT_LIB) $(LIBS) + + inndstart: $(P) inndstart.o $(LIBNEWS) + $(CC) $(LDFLAGS) -o $@ inndstart.o $(LIBNEWS) $(LIBS) +--- inn-1.7.2.orig/innd/timer.c ++++ inn-1.7.2/innd/timer.c +@@ -0,0 +1,149 @@ ++#include ++#include ++#include ++ ++#include "logging.h" ++#include "timer.h" ++ ++unsigned start[MAXTIMERS]; ++unsigned cumulative[MAXTIMERS]; ++unsigned count[MAXTIMERS]; ++ ++unsigned last_summary; ++ ++int maxtimer = 0; ++ ++/* ++ * This package is a quick hack to allow me to draw some conclusions ++ * about INN and "where the time goes" without having to run profiling ++ * and continually stop/restart the server. ++ * ++ * 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'. 'n' is probably one of the constants in ++ * timer.h. You probably want to add a description to TMRsummary ++ * explaining what your 'n' represents. ++ * ++ * There are no sanity checks to see if you have failed to start a timer, ++ * etc., etc. It is assumed that the user is moderately intelligent and ++ * can properly deploy this code. ++ * ++ * Recursion is not allowed on a given timer. Setting multiple timers ++ * 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, blah blah.. which are components of the total art write time) ++ * ++ * This package is written with the assumption that TMRmainloophook() ++ * will be called with none of the timers started. The statistics are ++ * generated here. It may not be fatal to have a timer running, but ++ * it will not be properly accounted for (at least within that time slice). ++ */ ++ ++/* ++ * 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. ++ */ ++ ++unsigned gettime() ++{ ++ static 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 TMRinit() ++{ ++ int i; ++ ++ last_summary = gettime(); /* First invocation */ ++ ++ for (i = 0; i < MAXTIMERS; i++) { ++ count[i] = start[i] = cumulative[i] = 0; ++ } ++} ++ ++ ++ ++ ++ ++void dosummary(secs) ++unsigned secs; ++{ ++ char buffer[8192]; ++ char buf[256]; ++ char *str; ++ int i; ++ ++ sprintf(buffer, "ME time %d ", secs); ++ for (i = 0; i < maxtimer; i++) { ++ str = "???"; ++ switch (i) { ++ case TMR_IDLE: str = "idle"; break; ++ case TMR_ARTWRITE: str = "artwrite"; break; ++ case TMR_ARTLINK: str = "artlink"; break; ++ case TMR_HISWRITE: str = "hiswrite"; break; ++ case TMR_HISSYNC: str = "hissync"; break; ++ case TMR_SITESEND: str = "sitesend"; break; ++ case TMR_ARTCTRL: str = "artctrl"; break; ++ case TMR_ARTCNCL: str = "artcncl"; break; ++ case TMR_HISHAVE: str = "hishave"; break; ++ case TMR_HISGREP: str = "hisgrep"; break; ++ } ++ sprintf(buf, "%s %d(%d) ", str, cumulative[i], count[i]); ++ cumulative[i] = count[i] = 0; ++ strcat(buffer, buf); ++ } ++ syslog(L_NOTICE, "%s", buffer); ++} ++ ++ ++ ++ ++ ++int TMRmainloophook() ++{ ++ unsigned now = gettime(); ++ ++ if (now - last_summary >= SUMMARY_INTERVAL) { ++ dosummary(now - last_summary); ++ last_summary = now; ++ return 0; ++ } ++ return SUMMARY_INTERVAL - (now - last_summary)/1000; ++} ++ ++ ++ ++ ++ ++void TMRstart(n) ++int n; ++{ ++ if (n >= maxtimer) { ++ maxtimer = n + 1; ++ } ++ start[n] = gettime(); ++} ++ ++ ++ ++ ++void TMRstop(n) ++int n; ++{ ++ cumulative[n] += gettime() - start[n]; ++ count[n]++; ++} +--- inn-1.7.2.orig/innd/timer.h ++++ inn-1.7.2/innd/timer.h +@@ -0,0 +1,19 @@ ++#define SUMMARY_INTERVAL 300000 ++ ++#define MAXTIMERS 32 ++ ++#define TMR_IDLE 0 ++#define TMR_ARTWRITE 1 ++#define TMR_ARTLINK 2 ++#define TMR_HISWRITE 3 ++#define TMR_HISSYNC 4 ++#define TMR_SITESEND 5 ++#define TMR_ARTCTRL 6 ++#define TMR_ARTCNCL 7 ++#define TMR_HISHAVE 8 ++#define TMR_HISGREP 9 ++ ++extern void TMRinit(); ++extern int TMRmainloophook(); ++extern void TMRstart(int); ++extern void TMRstop(int); --- inn-1.7.2q.orig/debian/patches/0_insync_overscream +++ inn-1.7.2q/debian/patches/0_insync_overscream @@ -0,0 +1,584 @@ +--- inn-1.7.2.orig/nnrpd/article.c ++++ inn-1.7.2/nnrpd/article.c +@@ -8,6 +8,17 @@ + #include "clibrary.h" + #include "nnrpd.h" + ++/* ++ * OVERSCREAM - to make the overview database screaming fast, and because ++ * I scream in terror about the previous implementation. ++ * See http://www.xs4all.nl/~johnpc/inn/ for more information on this patch. ++ */ ++ ++#ifdef OVERSCREAM ++# include ++# include ++#endif /* OVERSCREAM */ ++ + + /* + ** Data structures for use in ARTICLE/HEAD/BODY/STAT common code. +@@ -61,11 +72,33 @@ + /* + ** Overview state information. + */ ++#ifdef OVERSCREAM ++ ++STATIC caddr_t OVERshm = (caddr_t) NULL; /* location of mmap */ ++STATIC size_t OVERsize; /* size of mmap */ ++STATIC size_t OVERmsize; /* real size of mmap */ ++STATIC int OVERfd; /* fd of file */ ++STATIC ARTNUM OVERfirst, OVERlast; /* first/last entries */ ++STATIC int OVERopens; /* Number of opens done */ ++STATIC char* OVERcache; /* cached position */ ++STATIC ARTNUM OVERprev; /* previous found art */ ++#define LINSEARCH 5 /* linear search range */ ++#define MIDSKEW 0.1 /* 10% bias toward middle */ ++ ++STATIC int mmapsuck; /* did we syslog already */ ++#define YOUR_MMAP_SUCKS if ( ! mmapsuck++ ) \ ++ syslog(L_NOTICE, "Your mmap() implementation sucks.") ++ ++#else /* !OVERSCREAM */ ++ + STATIC QIOSTATE *OVERqp; /* Open overview file */ + STATIC char *OVERline; /* Current line */ + STATIC ARTNUM OVERarticle; /* Current article */ + STATIC int OVERopens; /* Number of opens done */ + ++#endif ++ ++ + + /* + ** Read the overview schema. +@@ -691,6 +724,10 @@ + register int i; + ARTOVERFIELD *fp; + char *next; ++#ifdef OVERSCREAM ++ char* eol = strchr(p, '\n'); ++#endif ++ + + fp = &ARTfields[field - 1]; + +@@ -698,8 +735,13 @@ + field = ARTfirstfullfield; + + /* Skip leading headers. */ +- for (; --field >= 0 && *p; p++) ++ for (; --field >= 0 && *p && *p != '\n'; p++) ++#ifdef OVERSCREAM ++ if ((p = memchr(p, '\t', OVERsize - (p - OVERshm))) == NULL || ++ p > eol ) ++#else + if ((p = strchr(p, '\t')) == NULL) ++#endif + return NULL; + if (*p == '\0') + return NULL; +@@ -717,10 +759,22 @@ + } + + /* Figure out length; get space. */ ++ ++#ifdef OVERSCREAM ++ if ((next = memchr(p, '\t', OVERsize - (p - OVERshm))) != NULL && ++ p < eol ) ++ i = next - p; ++ else ++ i = eol - p; ++ ++#else /* !OVERSCREAM */ ++ + if ((next = strchr(p, '\t')) != NULL) + i = next - p; + else + i = strlen(p); ++#endif ++ + if (buffsize == 0) { + buffsize = i; + buff = NEW(char, buffsize + 1); +@@ -735,6 +789,430 @@ + return buff; + } + ++#ifdef OVERSCREAM ++ ++/* ++ * helper function, search backwards in memory ++ */ ++ ++STATIC char* ++inn_memrchr(p, c, l) ++ register char* p; ++ register char c; ++ register int l; ++{ ++ for (; l--; --p) ++ if ( *p == c ) ++ return(p); ++ return(NULL); ++} ++ ++/* ++ * mmap an OVERVIEW file. ++ */ ++ ++STATIC BOOL ++OVERopen() ++{ ++ char name[SPOOLNAMEBUFF]; ++ struct stat sb; ++ char* p; ++ static int pagesize = 0; ++ ++ /* return true if already mapped */ ++ if ( OVERshm ) { ++ return TRUE; ++ } ++ /* return false if already failed */ ++ if ( OVERopens++ ) { ++ return FALSE; ++ } ++ /* get memory pagesize if we don't have it already */ ++ if ( ! pagesize && ! ++#ifdef _SC_PAGE_SIZE ++ (pagesize = sysconf(_SC_PAGE_SIZE)) ++#else ++# ifdef _SC_PAGESIZE ++ (pagesize = sysconf(_SC_PAGESIZE)) ++# else ++ (pagesize = getpagesize()) ++# endif ++#endif ++ ) { ++ syslog(L_NOTICE, "%s: Can't getpagesize", ClientHost); ++ return FALSE; ++ } ++ /* mmap the file */ ++ (void)sprintf(name, "%s/%s/%s", _PATH_OVERVIEWDIR, GRPlast, _PATH_OVERVIEW); ++ if ( (OVERfd = open(name, O_RDONLY)) < 0 ) { ++ /* no overview file */ ++ syslog(L_NOTICE, "%s can't open %s: %m", ClientHost, name); ++ return FALSE; ++ } ++ if ( fstat(OVERfd, &sb) == -1 ) { ++ syslog(L_NOTICE, "%s can't stat %s: %m", ClientHost, name); ++ (void)close(OVERfd); ++ return FALSE; ++ } ++ if ( (OVERsize = sb.st_size) <= 1 ) { ++ syslog(L_NOTICE, "%s: %s is too small", ClientHost, name); ++ (void)close(OVERfd); ++ return FALSE; ++ } ++ OVERmsize = (OVERsize + pagesize - 1) & ~(pagesize - 1); ++ if ( (OVERshm = mmap(NULL, OVERmsize, PROT_READ, MAP_SHARED, OVERfd, 0)) ++ == (caddr_t) -1 ) ++ { ++ syslog(L_NOTICE, "%s can't mmap %s: %m", ClientHost, name); ++ (void)close(OVERfd); ++ OVERshm = NULL; ++ return FALSE; ++ } ++ /* get first entry */ ++ if ( (OVERfirst = atol((char*) OVERshm)) == 0 ) { ++ syslog(L_NOTICE, "%s: %s: bad format", ClientHost, name); ++ (void)munmap(OVERshm, OVERmsize); ++ (void)close(OVERfd); ++ OVERshm = NULL; ++ return FALSE; ++ } ++ ++ /* get last entry */ ++ if ( *(OVERshm + OVERsize - 1) != '\n' ) { ++ /* ++ * If you get here, then your mmap() implementation sucks. ++ * Go complain with your OS vendor, that their mmap() can't ++ * do mmap()ing of growing files properly. ++ * We try to find a decent record near the end, for the poor ++ * sobs without proper mmap. There are a lot of other places ++ * in the code with hacks for bad mmap(). Mainly because I'm ++ * one of the poor sobs :( ++ */ ++ YOUR_MMAP_SUCKS; ++ } ++ do { ++ /* ++ * Try to find any newline. If there isn't any, the entire file ++ * is crap. Normally this finds the newline right at the end. ++ */ ++ p = inn_memrchr(OVERshm + OVERsize - 1, '\n', OVERsize - 1); ++ if ( p == NULL ) { ++ /* overview file only contains garbage. */ ++ (void)munmap(OVERshm, OVERmsize); ++ (void)close(OVERfd); ++ OVERshm = NULL; ++ return FALSE; ++ } ++ OVERsize = p - OVERshm + 1; ++ if ( (p = inn_memrchr((char*) OVERshm + OVERsize - 2, '\n', ++ OVERsize - 2)) == NULL ) ++ { ++ /* Apparently only 1 (usable) line */ ++ OVERlast = OVERfirst; ++ OVERcache = NULL; ++ return TRUE; ++ } ++ OVERlast = atol(p+1); ++ } ++ while ( OVERlast == 0 && --OVERsize ); ++ ++ if ( !OVERsize ) { ++ (void)munmap(OVERshm, OVERmsize); ++ (void)close(OVERfd); ++ OVERshm = NULL; ++ return FALSE; ++ } ++ ++ OVERcache = NULL; ++ return TRUE; ++} ++ ++/* ++ * Close an overview file, if any. ++ */ ++ ++void ++OVERclose() ++{ ++ if ( OVERshm ) { ++ if ( munmap(OVERshm, OVERmsize) == -1 ) { ++ syslog(L_NOTICE, "%s can't munmap: %m", ClientHost); ++ } ++ (void)close(OVERfd); ++ OVERshm = NULL; ++ } ++ OVERopens = 0; ++} ++ ++/* ++ * find an overview article using binary search in the overview file. ++ * Returns a pointer to the actual line in the overview file (so it's ++ * !!NOT!! null terminated, and can't be written to!!), or NULL on failure. ++ */ ++ ++STATIC char* ++OVERfind(artnum) ++ ARTNUM artnum; ++{ ++ char* bottom; ++ char* top; ++ ARTNUM bottomnr; ++ ARTNUM topnr; ++ char* pos; ++ ARTNUM nr; ++ int i; ++ ++ /* default startpos */ ++ bottom = OVERshm; ++ bottomnr = OVERfirst; ++ top = OVERshm + OVERsize - 1; ++ topnr = OVERlast; ++ ++ if ( OVERcache ) { ++ /* ++ * for speedy sequential access. OVERcache, if non-NULL, points to ++ * the "next" entry. OVERprev is the previous article number found. ++ * Also check for sucking mmap() implementations. ++ */ ++ if ( *OVERcache == '\0' ) { ++ YOUR_MMAP_SUCKS; ++ OVERcache = memchr(OVERcache, '\n', ++ OVERsize - (OVERshm - OVERcache)); ++ if ( OVERcache == NULL || OVERcache == OVERshm + OVERsize - 1 ) { ++ OVERcache = NULL; ++ return NULL; ++ } ++ OVERcache++; ++ } ++ nr = atol(OVERcache); ++ if ( nr < OVERfirst || nr > OVERlast ) { ++ /* boo */ ++ OVERcache = NULL; ++ return NULL; ++ } ++ if ( nr == artnum ) { ++ pos = OVERcache; ++ goto bingo; /* calculate next OVERcache + return. (EW! a goto! :) */ ++ } ++ else if ( artnum > nr ) { ++ /* treat cache as first binary search */ ++ bottom = OVERcache; ++ bottomnr = nr; ++ } ++ else { ++ /* cache is first top */ ++ top = OVERcache - 1; ++ topnr = nr - 1; ++ if ( artnum > OVERprev ) { ++ /* ++ * optimization: we're searching for something that isn't ++ * in the database, but we want to keep the cache clean. ++ * this occurs when we think an article is there, but it ++ * really isn't, eg. because NOSCANDIR is on, or simply ++ * because the overview database leaks. ++ */ ++ return(NULL); ++ } ++ } ++ } ++ ++ /* sanity check */ ++ if ( artnum < bottomnr || artnum > topnr ) { ++ OVERcache = NULL; ++ return NULL; ++ } ++ ++ for (;;) { ++ /* ++ * This is the binary search loop, there are about a zillion ++ * exits so I found it neater to code it in an endless loop :) ++ * It simply continues until it is either found or it isn't... ++ * ++ * Note that we don't do a real binary search, but we guess ++ * a position using the fact that the overview database usually ++ * contains a reasonably linear range of articles, without any ++ * big leaps, but we skew it a bit towards the middle to prevent ++ * slow convergence in boundary cases (see also below). ++ * ++ * We switch to linear searching when we're "close", ++ * because on short ranges, linear searches are about as fast ++ * (or faster) anyway. LINSEARCH is currently guessed at 5, ++ * because on average it takes 2.5 searches using a linear search, ++ * where it usually takes 3 "straight" binary searches. ++ * ++ * Unfortunately, we can't be sure we get into linear search when ++ * we're close, because the database may have large holes. ++ */ ++ /* test if it's near the bottom */ ++ if ( artnum < bottomnr + LINSEARCH ) { ++ i = 0; ++ while ( artnum > bottomnr && i++ < LINSEARCH ) { ++ /* search next line */ ++ bottom = memchr(bottom, '\n', OVERsize - (bottom - OVERshm)); ++ if ( bottom == NULL || bottom == top + 1 ) { ++ /* reached end of file */ ++ OVERcache = NULL; ++ return NULL; ++ } ++ if ( *++bottom == 0 ) { ++ YOUR_MMAP_SUCKS; ++ continue; ++ } ++ bottomnr = atol(bottom); ++ if ( bottomnr < OVERfirst || bottomnr > OVERlast ) { ++ OVERcache = NULL; ++ return NULL; ++ } ++ } ++ if ( artnum == bottomnr ) { ++ pos = bottom; ++ goto bingo; /* calculate next OVERcache + return. */ ++ } ++ else { ++ /* didn't find it, but we came close. still cache position */ ++ OVERcache = bottom; ++ OVERprev = artnum; ++ return NULL; ++ } ++ /*NOTREACHED*/ ++ } ++ /* test if it's near the top */ ++ if ( artnum > topnr - LINSEARCH ) { ++ /* ++ * topnr is frequently guessed, so we must first determine it ++ * correctly. The fun part about searching backwards is that ++ * the next position (OVERcache) follows easily... ++ */ ++ i = 0; ++ do { ++ OVERcache = (top == OVERshm + OVERsize - 1) ? NULL : top + 1; ++ if ( (top = inn_memrchr(--top, '\n', top - OVERshm)) ++ == NULL || top + 1 == bottom ) ++ { ++ /* search hit bottom */ ++ OVERcache = NULL; ++ return NULL; ++ } ++ if ( *(top + 1) == 0 ) { ++ YOUR_MMAP_SUCKS; ++ /* make sure we continue */ ++ topnr = artnum + 1; ++ continue; ++ } ++ topnr = atol(top + 1); ++ if ( topnr < OVERfirst || topnr > OVERlast ) { ++ OVERcache = NULL; ++ return NULL; ++ } ++ } ++ while ( artnum < topnr && i++ < LINSEARCH ); ++ if ( artnum == topnr ) { ++ /* bingo. This time we know OVERcache already */ ++ OVERprev = artnum; ++ return(top + 1); ++ } ++ else { ++ /* not found, but close. cache position */ ++ OVERprev = artnum; ++ return NULL; ++ } ++ /*NOTREACHED*/ ++ } ++ ++ /* ++ * now for the real binary search: ++ * Estimate the position of artnum, but with a small offset towards ++ * the middle, for better convergence in case the set of articles ++ * is non-linear (you get a straight binary search if MIDSKEW is 1.0). ++ * MIDSKEW is currently determined using a big thumb, occultism, ++ * astrology, cat /dev/uri-geller and some common sense (but not much) ++ * MIDSKEW == 0.0 makes the search take only 1 iteration in case ++ * the overview database is a monotonous array of lines with equal ++ * length, but can make for really lousy searches in anything not like ++ * the above, which, in the real world, is practically always. ++ * MIDSKEW == 1.0 gives you a true binary search without any guessing ++ * whatsoever. ++ * I thought 10% would be good enough. Only riggid testing can ++ * determine the optimal value, and then it still depends on a lot ++ * of settings, like expire times, user newsgroups preference, ++ * presence of cancelbots or cancelwars, frequency of expireover ++ * runs... need I say more? :) ++ */ ++ if ( topnr <= bottomnr ) { ++ /* Safety net. This REALLY should never happen. */ ++ syslog(L_NOTICE, ++ "%s: ASSERTION FAILED: %lu < %lu looking for %lu in %s", ++ ClientHost, topnr, bottomnr, artnum, GRPlast); ++ } ++ pos = bottom + (int) ((double) (top - bottom) * (MIDSKEW * 0.5) + ++ (top - bottom) * (1.0 - MIDSKEW) * ++ (artnum - bottomnr) / (topnr - bottomnr)); ++ /* search forward for newline */ ++ if ( (pos = memchr(pos, '\n', OVERsize - (pos - OVERshm))) == NULL ) { ++ /* this shouldn't happen */ ++ OVERcache = NULL; ++ return NULL; ++ } ++ if ( pos == top ) { ++ /* hmm... */ ++ if ( (pos = inn_memrchr(--pos, '\n', pos - OVERshm)) ++ == NULL || pos == bottom - 1 ) ++ { ++ /* ++ * This is what happens when there's a large hole and we're ++ * looking for something inside the hole (which isn't there). ++ * still record the position in this case... ++ */ ++ OVERcache = (top == OVERshm + OVERsize - 1) ? NULL : top + 1; ++ OVERprev = artnum; ++ return NULL; ++ } ++ } ++ /* see where we are */ ++ if ( *++pos == 0 ) { ++ YOUR_MMAP_SUCKS; ++ pos = memchr(pos, '\n', OVERsize - (pos - OVERshm)); ++ if ( pos == NULL || pos == OVERshm + OVERsize - 1 || pos == top ) { ++ OVERcache = NULL; ++ return NULL; ++ } ++ pos++; ++ } ++ nr = atol(pos); ++ if ( nr < OVERfirst || nr > OVERlast ) { ++ OVERcache = NULL; ++ return NULL; ++ } ++ if ( nr == artnum ) { ++ /* bingo. Set cache to next entry */ ++bingo: ++ OVERcache = memchr(pos, '\n', OVERsize - (pos - OVERshm)); ++ if ( OVERcache == OVERshm + OVERsize - 1 ) ++ OVERcache = NULL; ++ else if ( OVERcache ) ++ OVERcache++; ++ OVERprev = artnum; ++ return (pos); ++ } ++ if ( nr < artnum ) { ++ /* found a new bottom */ ++ bottom = pos; ++ bottomnr = nr; ++ } ++ else /* nr > artnum */ { ++ /* ++ * found a new top. Setting topnr to nr-1 is not entirely ++ * correct, but who cares. (In fact we do care, but adjust ++ * later :) ++ */ ++ top = pos - 1; ++ topnr = nr - 1; ++ } ++ } ++ /*NOTREACHED*/ ++} ++ ++#else /* !OVERSCREAM */ + + /* + ** Open an OVERVIEW file. +@@ -771,7 +1249,7 @@ + if (OVERqp != NULL) { + QIOclose(OVERqp); + OVERqp = NULL; +- OVERopens = 0; ++ OVERopens = 0; /* this is a bug */ + } + } + +@@ -794,7 +1272,7 @@ + } + + for ( ; OVERarticle < artnum; OVERarticle = atol(OVERline)) +- if ((OVERline = QIOread(OVERqp)) == NULL) { ++ while ((OVERline = QIOread(OVERqp)) == NULL) { + if (QIOtoolong(OVERqp)) + continue; + /* Don't close file; we may rewind. */ +@@ -804,6 +1282,8 @@ + return OVERarticle == artnum ? OVERline : NULL; + } + ++#endif ++ + + /* + ** Read an article and create an overview line without the trailing +@@ -1093,12 +1573,22 @@ + if (ARTfind(i) < 0) + continue; + ++ /*OVERVIEWcount++;*/ + if (Opened && (p = OVERfind(i)) != NULL) { ++#ifdef OVERSCREAM ++ char* eol = memchr(p, '\n', OVERsize - (p - OVERshm)); ++ if ( eol == NULL ) ++ continue; /* this should NEVER NEVER EVER NEVER EVER happen */ ++ fwrite(p, 1, eol - p, stdout); ++ fwrite("\r\n", 1, 2, stdout); ++#else + Printf("%s\r\n", p); ++#endif + continue; + } + + (void)sprintf(buff, "%ld", i); ++ /*OVERGENcount++;*/ + if ((p = OVERgen(buff)) != NULL) + Printf("%s\r\n", p); + } --- inn-1.7.2q.orig/debian/patches/0_insync_pathfeed +++ inn-1.7.2q/debian/patches/0_insync_pathfeed @@ -0,0 +1,44 @@ +--- inn-1.7.2.orig/doc/newsfeeds.5 ++++ inn-1.7.2/doc/newsfeeds.5 +@@ -304,6 +304,7 @@ + N Value of the Newsgroups header + O Overview data + R Information needed for replication ++ P Path header information needed for inpaths + .fi + More than one letter can be used; the entries will be separated by a + space, and written in the order in which they are specified. +--- inn-1.7.2.orig/include/configdata.h ++++ inn-1.7.2/include/configdata.h +@@ -383,6 +389,7 @@ + #define FEED_MAXFLAGS 20 + #define FEED_BYTESIZE 'b' + #define FEED_FULLNAME 'f' ++#define FEED_PATH 'P' + #define FEED_HDR_DISTRIB 'D' + #define FEED_HDR_NEWSGROUP 'N' + #define FEED_MESSAGEID 'm' +--- inn-1.7.2.orig/innd/newsfeeds.c ++++ inn-1.7.2/innd/newsfeeds.c +@@ -339,6 +339,7 @@ + NeedOverview = TRUE; /* Overview data */ + break; + case FEED_BYTESIZE: /* Size in bytes */ ++ case FEED_PATH: /* Pathline header */ + case FEED_FULLNAME: /* Full filename */ + case FEED_HDR_DISTRIB: /* Distribution header */ + case FEED_HDR_NEWSGROUP: /* Newsgroup header */ +--- inn-1.7.2.orig/innd/site.c ++++ inn-1.7.2/innd/site.c +@@ -445,6 +445,11 @@ + BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); + BUFFappend(bp, Data->Feedsite, Data->FeedsiteLength); + break; ++ case FEED_PATH: ++ if (Dirty) ++ BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP)); ++ BUFFappend(bp, Data->Path, Data->PathLength); ++ break; + } + Dirty = TRUE; + } --- inn-1.7.2q.orig/debian/patches/1_perl_filter_patch +++ inn-1.7.2q/debian/patches/1_perl_filter_patch @@ -0,0 +1,64 @@ +--- inn-1.7.2.orig/innd/art.c ++++ inn-1.7.2/innd/art.c +@@ -139,6 +139,29 @@ + { "Posting-Version", HTobs }, + { "Received", HTobs }, + { "Relay-Version", HTobs }, ++ { "NNTP-Posting-Host", HTstd }, ++ { "Followup-To", HTstd }, ++ { "Organization", HTstd }, ++ { "Content-Type", HTstd }, ++ { "Content-Base", HTstd }, ++ { "Content-Disposition", HTstd }, ++ { "Content-Transfer-Encoding", HTstd }, ++ { "X-Trace", HTstd }, ++ { "X-Newsreader", HTstd }, ++ { "X-Mailer", HTstd }, ++ { "X-Newsposter", HTstd }, ++ { "X-Cancelled-By", HTstd }, ++ { "X-Canceled-By", HTstd }, ++ { "Cancel-Key", HTstd }, ++ { "Cancel-Lock", HTstd }, ++ { "List-ID", HTstd }, ++ { "X-HTTP-UserAgent", HTstd }, ++ { "X-HTTP-Via", HTstd }, ++ { "X-No-Archive", HTstd }, ++ { "Injection-Info", HTstd }, ++ { "Injection-Date", HTstd }, ++ { "NNTP-Posting-Date", HTstd }, ++ { "In-Reply-To", HTstd }, + }; + + ARTHEADER *ARTheadersENDOF = ENDOF(ARTheaders); +@@ -1833,7 +1856,7 @@ + + #if defined(DO_PERL) + pathForPerl = HeaderFind(article->Data, "Path", 4) ; +- if ((perlrc = (char *)HandleArticle()) != NULL) { ++ if ((perlrc = (char *)HandleArticle(Data.Body)) != NULL) { + (void)sprintf(buff, "%d %s", NNTP_REJECTIT_VAL, perlrc); + syslog(L_NOTICE, "rejecting[perl] %s %s", HDR(_message_id), buff); + ARTlog(&Data, ART_REJECT, buff); +--- inn-1.7.2.orig/innd/perl.c ++++ inn-1.7.2/innd/perl.c +@@ -34,7 +34,8 @@ + extern char *pathForPerl ; + + char * +-HandleArticle() ++HandleArticle(artBody) ++char *artBody; + { + dSP; + ARTHEADER *hp; +@@ -54,6 +55,10 @@ + hv_store(hdr, (char *) hp->Name, strlen(hp->Name), newSVpv(hp->Value, 0), 0); + } + ++ /* store article body */ ++ if (artBody != NULL) ++ hv_store(hdr, (char *) "__BODY__", 8, newSVpv(artBody, 0), 0) ; ++ + if (pathForPerl != NULL) + { + char *p = strchr (pathForPerl,'\n') ; --- inn-1.7.2q.orig/debian/patches/1_perl_misc +++ inn-1.7.2q/debian/patches/1_perl_misc @@ -0,0 +1,203 @@ +--- inn-1.7.2.orig/lib/perl.c ++++ inn-1.7.2/lib/perl.c +@@ -29,11 +29,15 @@ + #include + #include + ++#include "libinn.h" /* xmalloc() prototype */ + #include "macros.h" + ++extern void xs_init _((pTHX)); ++extern void boot_DynaLoader _((CV* cv)); ++ + int PerlFilterActive = FALSE; + +-static PerlInterpreter *PerlCode; ++PerlInterpreter *PerlCode; + CV *perl_filter_cv ; /* filter_art or filter_post holder */ + extern char LogName[]; + +@@ -56,9 +60,9 @@ + if (PerlFilterActive && !value) { + if (perl_get_cv("filter_end", FALSE) != NULL) { + perl_call_argv("filter_end", G_EVAL|G_DISCARD|G_NOARGS, NULL); +- if (SvTRUE(GvSV(errgv))) /* check $@ */ { ++ if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl function filter_end died: %s", +- LogName, SvPV(GvSV(errgv), na)) ; ++ LogName, SvPV(ERRSV, PL_na)) ; + POPs ; + } + } else { +@@ -89,7 +93,7 @@ + /* We can't call 'eval' and 'do' directly for some reason, so we define + some wrapper functions to give us access. */ + +- perl_parse (PerlCode,NULL,5,argv,NULL) ; ++ perl_parse (PerlCode,xs_init,5,argv,NULL) ; + } + + +@@ -126,9 +130,9 @@ + + SPAGAIN ; + +- if (SvTRUE(GvSV(errgv))) /* check $@ */ { ++ if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl loading %s failed: %s", +- LogName, startupfile, SvPV(GvSV(errgv), na)) ; ++ LogName, startupfile, SvPV(ERRSV, PL_na)) ; + PerlFilter (FALSE) ; + + } else { +@@ -163,9 +167,9 @@ + + if (perl_get_cv("filter_before_reload", FALSE) != NULL) { + perl_call_argv("filter_before_reload",G_EVAL|G_DISCARD|G_NOARGS,NULL); +- if (SvTRUE(GvSV(errgv))) /* check $@ */ { ++ if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl function filter_before_reload died: %s", +- LogName, SvPV(GvSV(errgv), na)) ; ++ LogName, SvPV(ERRSV, PL_na)) ; + POPs ; + PerlFilter (FALSE) ; + } +@@ -173,9 +177,9 @@ + + perl_call_argv ("_load_", 0, argv) ; + +- if (SvTRUE(GvSV(errgv))) /* check $@ */ { ++ if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl loading %s failed: %s", +- LogName, filterfile, SvPV(GvSV(errgv), na)) ; ++ LogName, filterfile, SvPV(ERRSV, PL_na)) ; + PerlFilter (FALSE) ; + + /* If the reload failed we don't want the old definition hanging +@@ -184,9 +188,9 @@ + sprintf (argv[0],"undef &%s",function) ; + perl_call_argv ("_eval_",0,argv) ; + +- if (SvTRUE(GvSV(errgv))) /* check $@ */ { ++ if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl undef &%s failed: %s", +- LogName, function, SvPV(GvSV(errgv), na)) ; ++ LogName, function, SvPV(ERRSV, PL_na)) ; + } + DISPOSE (argv[0]) ; + } else if ((perl_filter_cv = perl_get_cv(function, FALSE)) == NULL) { +@@ -195,9 +199,9 @@ + + if (perl_get_cv("filter_after_reload", FALSE) != NULL) { + perl_call_argv("filter_after_reload", G_EVAL|G_DISCARD|G_NOARGS, NULL); +- if (SvTRUE(GvSV(errgv))) /* check $@ */ { ++ if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl function filter_after_reload died: %s", +- LogName, SvPV(GvSV(errgv), na)) ; ++ LogName, SvPV(ERRSV, PL_na)) ; + POPs ; + PerlFilter (FALSE) ; + } +@@ -221,5 +225,13 @@ + PerlFilterActive = FALSE; + } + ++extern void xs_init(pTHX) ++{ ++ char * file = __FILE__; ++ dXSUB_SYS; ++ ++ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); ++} ++ + #endif /* defined(DO_PERL) */ + +--- inn-1.7.2.orig/innd/perl.c ++++ inn-1.7.2/innd/perl.c +@@ -27,6 +27,8 @@ + + #include + #include ++#define my_perl PerlCode ++extern PerlInterpreter *PerlCode; + + extern BOOL PerlFilterActive; + extern ARTHEADER ARTheaders[], *ARTheadersENDOF; +@@ -79,10 +81,63 @@ + + buf [0] = '\0' ; + +- if (SvTRUE(GvSV(errgv))) /* check $@ */ ++ if (SvTRUE(ERRSV)) /* check $@ */ + { + syslog (L_ERROR,"Perl function filter_art died: %s", +- SvPV(GvSV(errgv), na)) ; ++ SvPV(ERRSV, PL_na)) ; ++ POPs ; ++ PerlFilter (FALSE) ; ++ } ++ else if (rc == 1) ++ { ++ p = POPp; ++ ++ if (p != NULL && *p != '\0') ++ { ++ strncpy(buf, p, sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = '\0'; ++ } ++ } ++ ++ PUTBACK; ++ FREETMPS; ++ LEAVE; ++ ++ if (buf[0] != '\0') ++ return buf ; ++ return NULL; ++} ++ ++ ++char * ++HandleMessageID(messageID) ++char *messageID; ++{ ++ dSP; ++ int rc; ++ char *p; ++ static char * args[2]; ++ static char buf[256]; ++ ++ if (!PerlFilterActive || perl_filter_cv == NULL || perl_get_cv("filter_messageid", FALSE) == NULL) ++ return NULL; ++ ++ ++ ENTER ; ++ SAVETMPS ; ++ ++ args[0] = messageID; ++ args[1] = 0; ++ rc = perl_call_argv ("filter_messageid", G_EVAL|G_SCALAR, args); ++ ++ SPAGAIN; ++ ++ buf [0] = '\0' ; ++ ++ if (SvTRUE(ERRSV)) /* check $@ */ ++ { ++ syslog (L_ERROR,"Perl function filter_messageid died: %s", ++ SvPV(ERRSV, PL_na)) ; + POPs ; + PerlFilter (FALSE) ; + } +@@ -137,9 +192,9 @@ + + if (perl_get_cv("filter_mode", FALSE) != NULL) { + perl_call_argv("filter_mode", G_EVAL|G_DISCARD|G_NOARGS, NULL); +- if (SvTRUE(GvSV(errgv))) { /* check $@ */ ++ if (SvTRUE(ERRSV)) { /* check $@ */ + syslog (L_ERROR,"Perl function filter_mode died: %s", +- SvPV(GvSV(errgv), na)) ; ++ SvPV(ERRSV, PL_na)) ; + POPs ; + PerlFilter (FALSE) ; + } --- inn-1.7.2q.orig/debian/patches/2_perl_timer +++ inn-1.7.2q/debian/patches/2_perl_timer @@ -0,0 +1,43 @@ +diff -ruN inn-1.7.2.orig/innd/art.c inn-1.7.2/innd/art.c +--- inn-1.7.2.orig/innd/art.c 2003-07-06 14:34:10.000000000 +0200 ++++ inn-1.7.2/innd/art.c 2003-07-06 14:32:05.000000000 +0200 +@@ -1856,7 +1856,9 @@ + + #if defined(DO_PERL) + pathForPerl = HeaderFind(article->Data, "Path", 4) ; ++ TMRstart(TMR_PERL); + if ((perlrc = (char *)HandleArticle(Data.Body)) != NULL) { ++ TMRstop(TMR_PERL); + (void)sprintf(buff, "%d %s", NNTP_REJECTIT_VAL, perlrc); + syslog(L_NOTICE, "rejecting[perl] %s %s", HDR(_message_id), buff); + ARTlog(&Data, ART_REJECT, buff); +@@ -1868,6 +1870,7 @@ + ARTreject(buff, article); + return buff; + } ++ TMRstop(TMR_PERL); + #endif /* DO_PERL */ + + /* I suppose some masochist will run with both TCP and PERL in together */ +diff -ruN inn-1.7.2.orig/innd/timer.c inn-1.7.2/innd/timer.c +--- inn-1.7.2.orig/innd/timer.c 2003-07-06 14:34:08.000000000 +0200 ++++ inn-1.7.2/innd/timer.c 2003-07-06 14:28:03.000000000 +0200 +@@ -101,6 +101,7 @@ + case TMR_ARTCNCL: str = "artcncl"; break; + case TMR_HISHAVE: str = "hishave"; break; + case TMR_HISGREP: str = "hisgrep"; break; ++ case TMR_PERL: str = "perl"; break; + } + sprintf(buf, "%s %d(%d) ", str, cumulative[i], count[i]); + cumulative[i] = count[i] = 0; +diff -ruN inn-1.7.2.orig/innd/timer.h inn-1.7.2/innd/timer.h +--- inn-1.7.2.orig/innd/timer.h 2003-07-06 14:34:08.000000000 +0200 ++++ inn-1.7.2/innd/timer.h 2003-07-06 14:28:27.000000000 +0200 +@@ -12,6 +12,7 @@ + #define TMR_ARTCNCL 7 + #define TMR_HISHAVE 8 + #define TMR_HISGREP 9 ++#define TMR_PERL 10 + + extern void TMRinit(); + extern int TMRmainloophook(); --- inn-1.7.2q.orig/debian/patches/addhist +++ inn-1.7.2q/debian/patches/addhist @@ -0,0 +1,50 @@ +INN can destroy the history database when paused or throttled, because the +history database is closed when INN is in such a mode. It does try to open +the history database briefly, but that's too late. + +This patch fixes that: it refuses to do an addhist when the server is throttled, +and it does it in the right way when the server is paused. + +Miquel van Smoorenburg , 21-Aug-1997 + +--- /project/tmp/inn-1.5.1/innd/cc.c Sat Nov 30 00:32:18 1996 ++++ inn-1.5.1/innd/cc.c Thu Aug 21 12:36:58 1997 +@@ -232,8 +232,19 @@ + /* Check the fields. */ + if ((p = CCgetid(av[0], &Data.MessageID)) != NULL) + return p; +- if (HIShavearticle(Data.MessageID)) ++ ++ /* If throttled, don't try to use the history database. */ ++ if (Mode == OMthrottled) ++ return "1 Server throttled"; ++ ++ /* If paused, briefly open the history database. */ ++ if (Mode != OMrunning) ++ HISsetup(); ++ ++ if (HIShavearticle(Data.MessageID)) { ++ if (Mode != OMrunning) HISclose(); + return "1 Duplicate"; ++ } + if (strspn(av[1], DIGITS) != strlen(av[1])) + return "1 Bad arrival date"; + Data.Arrived = atol(av[1]); +@@ -244,14 +255,10 @@ + return "1 Bad posted date"; + Data.Posted = atol(av[3]); + +- if (Mode == OMrunning) +- ok = HISwrite(&Data, av[4]); +- else { +- /* Possible race condition, but documented in ctlinnd manpage. */ +- HISsetup(); +- ok = HISwrite(&Data, av[4]); ++ ok = HISwrite(&Data, av[4]); ++ if (Mode != OMrunning) + HISclose(); +- } ++ + return ok ? NULL : "1 Write failed"; + } + --- inn-1.7.2q.orig/debian/patches/bindaddress +++ inn-1.7.2q/debian/patches/bindaddress @@ -0,0 +1,49 @@ +--- inn-1.7.2.orig/lib/getconfig.c ++++ inn-1.7.2/lib/getconfig.c +@@ -77,5 +77,18 @@ + return "text/plain; charset=US-ASCII"; + if (EQ(value, _CONF_ENCODING)) + return "7bit"; ++ if (EQ(value, _CONF_PORT)) { ++ sprintf(ConfigBuff, "%d", NNTP_PORT); ++ return ConfigBuff; ++ } ++ if (EQ(value, _CONF_BINDADDRESS)) { ++ sprintf(ConfigBuff, "0.0.0.0"); ++ return ConfigBuff; ++ } ++ if (EQ(value, _CONF_USEACTIVED)) ++ return "no"; ++ if (EQ(value, _CONF_USECONTROLCHAN)) ++ return "no"; ++ + return NULL; + } +--- inn-1.7.2.orig/innd/inndstart.c ++++ inn-1.7.2/innd/inndstart.c +@@ -100,9 +100,9 @@ + syslog(L_ERROR, "inndstart cant setsockopt %m"); + #endif /* defined(SO_REUSEADDR) */ + (void)memset((POINTER)&server, 0, sizeof server); +- server.sin_port = htons(NNTP_PORT); ++ server.sin_port = htons(atoi(GetConfigValue(_CONF_PORT))); + server.sin_family = AF_INET; +- server.sin_addr.s_addr = htonl(INADDR_ANY); ++ server.sin_addr.s_addr = inet_addr(GetConfigValue(_CONF_BINDADDRESS)); + if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) { + syslog(L_FATAL, "inndstart cant bind %m"); + exit(1); +--- inn-1.7.2.orig/innd/rc.c ++++ inn-1.7.2/innd/rc.c +@@ -646,9 +846,9 @@ + syslog(L_ERROR, "%s cant setsockopt RCreader %m", LogName); + #endif /* defined(SO_REUSEADDR) */ + (void)memset((POINTER)&server, 0, sizeof server); +- server.sin_port = htons(NNTP_PORT); ++ server.sin_port = htons(atoi(GetConfigValue(_CONF_PORT))); + server.sin_family = AF_INET; +- server.sin_addr.s_addr = htonl(INADDR_ANY); ++ server.sin_addr.s_addr = inet_addr(GetConfigValue(_CONF_BINDADDRESS)); + if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) { + syslog(L_FATAL, "%s cant bind RCreader %m", LogName); + exit(1); --- inn-1.7.2q.orig/debian/patches/clientactive.c +++ inn-1.7.2q/debian/patches/clientactive.c @@ -0,0 +1,23 @@ +When posting an article with inews, first the active file is gotten from +the server. Then inews tries to read the distrib.pats file from the server +using CA_listopen. If that _fails_ (no remote copy and no local copy) CAclose +is called by CA_listopen, and CApathname is removed and CAfp closed. Ofcourse +those static variables are references to the active file opened with CAopen().. + +The following patch fixes this, but IMO CApathname and CAfp should not +be used at all. + +Miquel van Smoorenburg , 23-Mar-1998 + +--- inn-1.7.2/lib/clientactive.c.orig Mon Mar 23 17:15:54 1998 ++++ inn-1.7.2/lib/clientactive.c Mon Mar 23 17:15:56 1998 +@@ -67,7 +67,8 @@ + if (fgets(buff, sizeof buff, FromServer) == NULL + || !EQn(buff, NNTP_LIST_FOLLOWS, STRLEN(NNTP_LIST_FOLLOWS))) { + oerrno = errno; +- CAclose(); ++ /* Only call CAclose if opened through CAopen() */ ++ if (strcmp(CApathname, pathname) == 0) CAclose(); + errno = oerrno; + return NULL; + } --- inn-1.7.2q.orig/debian/patches/dbminit_fclose_null +++ inn-1.7.2q/debian/patches/dbminit_fclose_null @@ -0,0 +1,17 @@ +prevent fclose(NULL) on dbminit() failure + +When fed a bad database, dbminit() could call fclose() on a NULL pointer. +Bug reported by the Mayhem team at CMU. + +--- a/dbz/dbz.c ++++ b/dbz/dbz.c +@@ -873,7 +873,8 @@ char *name; + /* pick up configuration */ + if (getconf(dirf, pagf, &conf) < 0) { + DEBUG(("dbminit: getconf failure\n")); +- (void) fclose(basef); ++ if (basef != NULL) ++ (void) fclose(basef); + (void) fclose(pagf); + (void) fclose(dirf); + free((POINTER)pagfname); --- inn-1.7.2q.orig/debian/patches/distribution_crash +++ inn-1.7.2q/debian/patches/distribution_crash @@ -0,0 +1,81 @@ +From syl@alcor.concordia.ca Thu Jan 20 10:23:57 2000 +Return-Path: +Delivered-To: md@wonderland.linux.it +Received: by wonderland.linux.it (Postfix, from userid 10) + id E0F4198A8; Thu, 20 Jan 2000 10:23:57 +0100 (CET) +Received: (from uucp@localhost) + by giano.linux.it (8.9.3/8.9.3/Md) with UUCP id CAA10359 + for md@wonderland.linux.it; Thu, 20 Jan 2000 02:05:08 +0100 +Received: from alcor.concordia.ca (syl@alcor.Concordia.CA [132.205.7.51]) + by kirk.linux.it (8.9.3/8.9.3/Debian/GNU) with ESMTP id BAA26574 + for ; Thu, 20 Jan 2000 01:20:42 +0100 +Received: (from syl@localhost) + by alcor.concordia.ca (8.8.7/8.8.7) id UAA04363; + Wed, 19 Jan 2000 20:01:58 -0500 (EST) +Date: Wed, 19 Jan 2000 20:01:58 -0500 (EST) +From: Sylvain Robitaille +Message-Id: <200001200101.UAA04363@alcor.concordia.ca> +To: md@linux.it, inn-workers@isc.org +Subject: Re: Distribution bug +In-Reply-To: <20000119223928.A2979@wonderland.linux.it> +References: <20000119223928.A2979@wonderland.linux.it> +Status: RO +Content-Length: 2192 + +You wrote to the Inn-workers mailing list: + +>Can somebody send me the patch for fixing the "Distribution: ," bug? +>I need it for the debian INN 1.7.2 package. + +Appended is the patch I applied to my Inn-1.7 server. + +I hope that helps... + +-- +---------------------------------------------------------------------- +Sylvain Robitaille syl@alcor.concordia.ca + +Systems analyst Concordia University +Instructional & Information Technology Montreal, Quebec, Canada +---------------------------------------------------------------------- + + + +--- inn-1.7.2.orig/innd/art.c ++++ inn-1.7.2/innd/art.c +@@ -1943,6 +1943,27 @@ + p = HDR(_distribution); + distributions = *p ? CommaSplit(p) : NULL; + if (distributions) { ++ /* ++ * 1999/11/18 Sylvain Robitaille: Adapted from a patch posted to ++ * the inn-workers mailing list by Don Lewis. Reject ++ * articles with a malformed Distribution: header. ++ * Ensure not only that we are pointing to a non-null ++ * string, but also that our *pointer* is not null to ++ * begin with. ++ */ ++ if (distributions[0] == '\0' || *distributions[0] == '\0') { ++ (void)sprintf(buff, "%d bogus distribution \"%s\"", ++ NNTP_REJECTIT_VAL, MaxLength(p, p)); ++ ARTlog(&Data, ART_REJECT, buff); ++#if defined(DO_REMEMBER_TRASH) ++ if (Mode == OMrunning && !HISwrite(&Data, "")) ++ syslog(L_ERROR, "%s cant write history %s %m", ++ LogName, Data.MessageID); ++#endif /* defined(DO_REMEMBER_TRASH) */ ++ DISPOSE(distributions); ++ ARTreject(buff, article); ++ return buff; ++ } else { + DISTparse(distributions, &Data); + if (ME.Distributions + && !DISTwantany(ME.Distributions, distributions)) { +@@ -1959,6 +1980,7 @@ + ARTreject(buff, article); + return buff; + } ++ } + } + else { + Data.Distribution = "?"; --- inn-1.7.2q.orig/debian/patches/fastrm_allow_symlinks +++ inn-1.7.2q/debian/patches/fastrm_allow_symlinks @@ -0,0 +1,11 @@ +--- inn-1.7.2.orig/samples/expirerm ++++ inn-1.7.2/samples/expirerm +@@ -8,7 +8,7 @@ + MAIL="${MAILCMD} -s 'Problem removing expired files' ${NEWSMASTER}" + + #RMPROC="xargs rm" +-RMPROC="fastrm -e -u -s ${SPOOL}" ++RMPROC="fastrm -e -s ${SPOOL}" + + if [ -z "$1" ] ; then + echo "Expire called with zero list of files on `hostname`" \ --- inn-1.7.2q.orig/debian/patches/fix_ad_flag +++ inn-1.7.2q/debian/patches/fix_ad_flag @@ -0,0 +1,15 @@ +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 + +--- a/innd/art.c ++++ b/innd/art.c +@@ -1682,7 +1682,7 @@ ARTpropagate(Data, hops, hopcount, list) + && !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; + --- inn-1.7.2q.orig/debian/patches/fix_perl510 +++ inn-1.7.2q/debian/patches/fix_perl510 @@ -0,0 +1,372 @@ +--- a/innd/perl.c ++++ b/innd/perl.c +@@ -45,6 +45,7 @@ char *artBody; + int rc; + char *p; + static char buf[256]; ++ char *argv[] = { NULL }; + + if (!PerlFilterActive || perl_filter_cv == NULL) + return NULL; +@@ -59,7 +60,11 @@ char *artBody; + + /* store article body */ + if (artBody != NULL) ++#if (PERL_VERSION < 7) || ((PERL_VERSION == 7) && (PERL_SUBVERSION < 1)) + hv_store(hdr, (char *) "__BODY__", 8, newSVpv(artBody, 0), 0) ; ++#else ++ hv_store(hdr, "__BODY__", 8, newSVpvn_share(artBody, 0, 42), 0); ++#endif /* Perl < 5.7.1 */ + + if (pathForPerl != NULL) + { +@@ -73,7 +78,7 @@ char *artBody; + ENTER ; + SAVETMPS ; + +- rc = perl_call_argv ("filter_art", G_EVAL|G_SCALAR,NULL); ++ rc = perl_call_argv ("filter_art", G_EVAL|G_SCALAR, argv); + + SPAGAIN; + +@@ -168,6 +173,7 @@ char *reason; + { + dSP ; + HV *hdr; ++ char *argv[] = { NULL }; + + ENTER ; + SAVETMPS ; +@@ -191,7 +197,7 @@ char *reason; + hv_store(hdr, "reason", 6, newSVpv(reason, 0), 0); + + if (perl_get_cv("filter_mode", FALSE) != NULL) { +- perl_call_argv("filter_mode", G_EVAL|G_DISCARD|G_NOARGS, NULL); ++ perl_call_argv("filter_mode", G_EVAL|G_DISCARD|G_NOARGS, argv); + if (SvTRUE(ERRSV)) { /* check $@ */ + syslog (L_ERROR,"Perl function filter_mode died: %s", + SvPV(ERRSV, PL_na)) ; +--- a/lib/perl.c ++++ b/lib/perl.c +@@ -33,11 +33,15 @@ static void use_rcsid (const char *rid) + #include "macros.h" + + extern void xs_init _((pTHX)); +-extern void boot_DynaLoader _((CV* cv)); ++XS(boot_DynaLoader); ++ ++void PerlSilence(void); ++void PerlUnSilence(void); ++ + + int PerlFilterActive = FALSE; + +-PerlInterpreter *PerlCode; ++PerlInterpreter *PerlCode = NULL; + CV *perl_filter_cv ; /* filter_art or filter_post holder */ + extern char LogName[]; + +@@ -52,6 +55,7 @@ PerlFilter(value) + BOOL value ; + { + dSP; ++ char *argv[] = { NULL }; + + ENTER ; + SAVETMPS ; +@@ -59,7 +63,7 @@ PerlFilter(value) + /* Execute an end function */ + if (PerlFilterActive && !value) { + if (perl_get_cv("filter_end", FALSE) != NULL) { +- perl_call_argv("filter_end", G_EVAL|G_DISCARD|G_NOARGS, NULL); ++ perl_call_argv("filter_end", G_EVAL|G_DISCARD|G_NOARGS, argv); + if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl function filter_end died: %s", + LogName, SvPV(ERRSV, PL_na)) ; +@@ -110,23 +114,36 @@ PERLsetup (startupfile, filterfile, func + char *startupfile, *filterfile, *function; + { + if (PerlCode == NULL) { ++ /* Perl waits on standard input if not called with '-e'. */ ++ int argc = 3; ++ const char *argv_innd[] = { "innd", "-e", "0", NULL }; ++ char **argv = (char **)argv_innd; /* Cast required by Perl 5.10. */ ++ char **env = { NULL }; ++#ifdef PERL_SYS_INIT3 ++ PERL_SYS_INIT3(&argc, &argv, &env); ++#endif + PerlCode = perl_alloc(); + perl_construct(PerlCode); +- PerlParse () ; ++ PL_exit_flags |= PERL_EXIT_DESTRUCT_END; ++ perl_parse(PerlCode, xs_init, argc, argv, env) ; + } + + if (startupfile != NULL && filterfile != NULL) { +- char *argv[2] ; +- int rc ; ++ char *evalfile = NULL; ++ size_t length; + dSP; + + ENTER ; + SAVETMPS ; + +- argv[0] = startupfile ; +- argv[1] = NULL ; +- +- rc = perl_call_argv ("_load_",G_DISCARD, argv) ; ++ /* 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 ; + +@@ -157,16 +174,15 @@ PERLreadfilter(filterfile, function) + char *filterfile, *function ; + { + dSP ; +- char *argv [3] ; ++ char *argv[] = { NULL }; ++ char *evalfile = NULL; ++ size_t length; + + ENTER ; + SAVETMPS ; + +- argv[0] = filterfile ; +- argv[1] = NULL ; +- + if (perl_get_cv("filter_before_reload", FALSE) != NULL) { +- perl_call_argv("filter_before_reload",G_EVAL|G_DISCARD|G_NOARGS,NULL); ++ perl_call_argv("filter_before_reload",G_EVAL|G_DISCARD|G_NOARGS,argv); + if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl function filter_before_reload died: %s", + LogName, SvPV(ERRSV, PL_na)) ; +@@ -175,7 +191,17 @@ PERLreadfilter(filterfile, function) + } + } + +- perl_call_argv ("_load_", 0, argv) ; ++ /* 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,"%s perl loading %s failed: %s", +@@ -184,21 +210,21 @@ PERLreadfilter(filterfile, function) + + /* If the reload failed we don't want the old definition hanging + around. */ +- argv[0] = NEW (char,strlen (function) + strlen ("undef &%s")) ; +- sprintf (argv[0],"undef &%s",function) ; +- perl_call_argv ("_eval_",0,argv) ; ++ 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,"%s perl undef &%s failed: %s", + LogName, function, SvPV(ERRSV, PL_na)) ; + } +- DISPOSE (argv[0]) ; + } 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, NULL); ++ perl_call_argv("filter_after_reload", G_EVAL|G_DISCARD|G_NOARGS, argv); + if (SvTRUE(ERRSV)) /* check $@ */ { + syslog (L_ERROR,"%s perl function filter_after_reload died: %s", + LogName, SvPV(ERRSV, PL_na)) ; +@@ -220,17 +246,126 @@ PERLreadfilter(filterfile, function) + void + PerlClose() + { +- perl_destruct(PerlCode); +- perl_free(PerlCode); ++ if (PerlCode != NULL) { ++ 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(pTHX) + { + char * file = __FILE__; + dXSUB_SYS; + + newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); ++ newXS("INN::syslog", XS_INN_syslog, file); + } + + #endif /* defined(DO_PERL) */ +--- a/nnrpd/perl.c ++++ b/nnrpd/perl.c +@@ -52,6 +52,7 @@ char *artBody; + int rc; + char *p; + static char buf[256]; ++ char *args[] = { NULL }; + register int i; + register char *s,*t; + HE *scan; +@@ -96,7 +97,7 @@ char *artBody; + sv_setpv(body, artBody); + + /* Call the filtering function */ +- rc = perl_call_argv("filter_post", G_EVAL|G_SCALAR, NULL); ++ rc = perl_call_argv("filter_post", G_EVAL|G_SCALAR, args); + + SPAGAIN; + +@@ -139,7 +140,7 @@ char *artBody; + } + + hv_undef (hdr); +- sv_setsv (body, &PL_sv_undef); ++ body = &PL_sv_undef; + + buf [0] = '\0' ; + +--- a/innd/cc.c ++++ b/innd/cc.c +@@ -860,13 +860,15 @@ CCmode(av) + /* perl filter status */ + + if (perl_get_cv("filter_stats", FALSE) != NULL) { ++ char *argv[] = { NULL }; ++ + *p++ = '\n'; + p += strlen(strcpy(p, "Perl filter stats: ")); + + ENTER ; + SAVETMPS; + +- perl_call_argv("filter_stats", G_EVAL|G_NOARGS, NULL); ++ perl_call_argv("filter_stats", G_EVAL|G_NOARGS, argv); + + SPAGAIN; + --- inn-1.7.2q.orig/debian/patches/fix_perl514 +++ inn-1.7.2q/debian/patches/fix_perl514 @@ -0,0 +1,76 @@ +--- a/config/fixinterps.pl ++++ b/config/fixinterps.pl +@@ -15,13 +15,13 @@ + # use the one in the samples directory) + # + +-require 'getopts.pl' ; ++use Getopt::Std; + + $0 =~ s!.*/!! ; + + $usage = "$0 [ -v -n -q ][ -d dir ][ -f innshellvars.pl ][ -t topdir ] file...\n" ; + +-&Getopts ("vnqd:f:h") || die $usage ; ++getopts("vnqd:f:h") || die $usage ; + + die $usage if $opt_h ; + +@@ -151,20 +151,10 @@ sub perlVersion { + + return 0 if (! -x $perl) ; + +- open (PERL,"$perl -v|") || die "Can't check version of perl ($perl)\n"; +- while () { +- if (/^this\s+is\s+perl,\s+v(\d+\.\d+\.\d+)/i) { +- $rval = $1; last; +- } +- if (/^this\s+is\s+perl,\s+version\s+(\S+)/i) { +- $rval = $1; +- } +- } +- close (PERL); +- return $rval; ++ $rval = `$perl -MConfig -e 'print \$Config{version}'`; + +- if ($rval !~ /^\d+\.\d+(_\d+|)$/) { +- warn "perl version from $perl looks suspicious: $rval\n"; ++ if ($rval !~ /^\d+\.\d+(\.\d+|)$/) { ++ die "perl version from $perl looks suspicious: $rval\n"; + } + + return $rval; +--- a/samples/innlog.pl ++++ b/samples/innlog.pl +@@ -25,9 +25,9 @@ $[ = 1; # set array base to 1 (hangove + + ($PROGNAME = $0) =~ s#.*/##; # basename of what we're invoked as + +-require "getopts.pl"; ++use Getopt::Std; + +-&Getopts("acdghn") || die("Usage $PROGNAME [-a] [-c] [-d] [-g] [-h] [-n]\ ++getopts("acdghn") || die("Usage $PROGNAME [-a] [-c] [-d] [-g] [-h] [-n]\ + -a Print nnrp gethostbyaddr failures\ + -c Print nnrp newsgroup requests by category\ + -d Print nnrp summary by domain\ +--- a/samples/scanspool ++++ b/samples/scanspool +@@ -94,7 +94,7 @@ + + # perl requirements + # +-require "getopts.pl"; ++use Getopt::Std; + + # setup non-buffered stdout and stderr + # +@@ -116,7 +116,7 @@ $reason = "running scanspool"; # thrott + + # parse args + # +-&Getopts("a:s:vcn"); ++getopts("a:s:vcn"); + $active = $opt_a if (defined($opt_a)); + $spool = $opt_s if (defined($opt_s)); + --- inn-1.7.2q.orig/debian/patches/fixinterps +++ inn-1.7.2q/debian/patches/fixinterps @@ -0,0 +1,18 @@ +--- inn-1.7.2.orig/config/fixinterps.pl ++++ inn-1.7.2/config/fixinterps.pl +@@ -153,11 +153,15 @@ + + open (PERL,"$perl -v|") || die "Can't check version of perl ($perl)\n"; + while () { ++ if (/^this\s+is\s+perl,\s+v(\d+\.\d+\.\d+)/i) { ++ $rval = $1; last; ++ } + if (/^this\s+is\s+perl,\s+version\s+(\S+)/i) { + $rval = $1; + } + } + close (PERL); ++ return $rval; + + if ($rval !~ /^\d+\.\d+(_\d+|)$/) { + warn "perl version from $perl looks suspicious: $rval\n"; --- inn-1.7.2q.orig/debian/patches/format_errors +++ inn-1.7.2q/debian/patches/format_errors @@ -0,0 +1,166 @@ +--- a/innd/cc.c ++++ b/innd/cc.c +@@ -1142,7 +1142,7 @@ CCparam(av) + break; + case 'c': + Cutoff = atoi(p) * 24 * 60 * 60; +- syslog(L_NOTICE, "%s changed -c %d", LogName, Cutoff); ++ syslog(L_NOTICE, "%s changed -c %ld", LogName, Cutoff); + break; + case 'i': + MaxIncoming = atoi(p); +@@ -1710,7 +1710,7 @@ CCreader(cp) + char *tbuff ; + + if (cp != CCchan) { +- syslog(L_ERROR, "%s internal CCreader wrong channel 0x%x not 0x%x", ++ syslog(L_ERROR, "%s internal CCreader wrong channel %p not %p", + LogName, cp, CCchan); + return; + } +--- a/innd/chan.c ++++ b/innd/chan.c +@@ -206,13 +206,13 @@ CHANtracing(cp, Flag) + syslog(L_NOTICE, "%s trace address %s lastactive %ld nextlog %ld", + p, inet_ntoa(cp->Address), cp->LastActive, cp->NextLog); + if (FD_ISSET(cp->fd, &SCHANmask)) +- syslog(L_NOTICE, "%s trace sleeping %ld 0x%x", ++ syslog(L_NOTICE, "%s trace sleeping %ld %p", + p, (long)cp->Waketime, cp->Waker); + if (FD_ISSET(cp->fd, &RCHANmask)) +- syslog(L_NOTICE, "%s trace reading %d %s", ++ syslog(L_NOTICE, "%s trace reading %ld %s", + p, cp->In.Used, MaxLength(cp->In.Data, cp->In.Data)); + if (FD_ISSET(cp->fd, &WCHANmask)) +- syslog(L_NOTICE, "%s trace writing %d %s", ++ syslog(L_NOTICE, "%s trace writing %ld %s", + p, cp->Out.Left, MaxLength(cp->Out.Data, cp->Out.Data)); + } + } +@@ -237,7 +237,7 @@ CHANclose(cp, name) + else if (cp->Type == CTreject) + syslog(L_NOTICE, "%s %ld", name, cp->Rejected); + else if (cp->Out.Left) +- syslog(L_NOTICE, "%s closed lost %d", name, cp->Out.Left); ++ syslog(L_NOTICE, "%s closed lost %ld", name, cp->Out.Left); + else + syslog(L_NOTICE, "%s closed", name); + WCHANremove(cp); +@@ -662,12 +662,12 @@ WCHANflush(cp) + for (bp = &cp->Out; bp->Left > 0; bp->Left -= i, bp->Used += i) { + i = largewrite(cp->fd, &bp->Data[bp->Used], bp->Left); + if (i < 0) { +- syslog(L_ERROR, "%s cant flush count %d %m", ++ syslog(L_ERROR, "%s cant flush count %ld %m", + CHANname(cp), bp->Left); + return FALSE; + } + if (i == 0) { +- syslog(L_ERROR, "%s cant flush count %d", ++ syslog(L_ERROR, "%s cant flush count %ld", + CHANname(cp), bp->Left); + return FALSE; + } +--- a/innd/lc.c ++++ b/innd/lc.c +@@ -28,7 +28,7 @@ LCreader(cp) + CHANNEL *new; + + if (cp != LCchan) { +- syslog(L_ERROR, "%s internal LCreader wrong channel 0x%x not 0x%x", ++ syslog(L_ERROR, "%s internal LCreader wrong channel %p not %p", + LogName, cp, LCchan); + return; + } +--- a/innd/nc.c ++++ b/innd/nc.c +@@ -199,7 +199,7 @@ NCwritereply(cp, 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\", %d)", ++ syslog(L_TRACE, "%s NCwritereply %d=write(%d, \"%.15s\", %ld)", + CHANname(cp), i, cp->fd, &bp->Data[bp->Used], bp->Left); + if (i > 0) bp->Used += i; + if (bp->Used == bp->Left) { +@@ -989,7 +989,7 @@ NCproc(cp) + int i; + + if (Tracing || cp->Tracing) +- syslog(L_TRACE, "%s NCproc Used=%d", ++ syslog(L_TRACE, "%s NCproc Used=%ld", + CHANname(cp), cp->In.Used); + + bp = &cp->In; +@@ -1200,7 +1200,7 @@ NCproc(cp) + } + p = wp->MessageID; + i = wp->Size + bp->Used; +- syslog(L_ERROR, "%s internal rejecting huge article %s (%d > %d)", ++ syslog(L_ERROR, "%s internal rejecting huge article %s (%d > %ld)", + CHANname(cp), p ? p : "(null)", i, LargestArticle); + (void)sprintf(buff, "%d Article exceeds local limit of %ld bytes", + NNTP_REJECTIT_VAL, LargestArticle); +@@ -1338,7 +1338,7 @@ NCproc(cp) + break; + } + if (Tracing || cp->Tracing) +- syslog(L_TRACE, "%s NCproc Rest=%d Used=%d SaveUsed=%d", ++ syslog(L_TRACE, "%s NCproc Rest=%d Used=%ld SaveUsed=%d", + CHANname(cp), cp->Rest, bp->Used, cp->SaveUsed); + + if (cp->Rest > 0) { +@@ -1371,7 +1371,7 @@ NCreader(cp) + int i; + + if (Tracing || cp->Tracing) +- syslog(L_TRACE, "%s NCreader Used=%d", ++ syslog(L_TRACE, "%s NCreader Used=%ld", + CHANname(cp), cp->In.Used); + + /* Read any data that's there; ignore errors (retry next time it's our +--- a/innd/rc.c ++++ b/innd/rc.c +@@ -320,7 +320,7 @@ RCreader(cp) + CHANNEL tempchan; + + if (cp != RCchan) { +- syslog(L_ERROR, "%s internal RCreader wrong channel 0x%x not 0x%x", ++ syslog(L_ERROR, "%s internal RCreader wrong channel %p not %p", + LogName, cp, RCchan); + return; + } +--- a/innd/site.c ++++ b/innd/site.c +@@ -206,7 +206,7 @@ SITECHANbilge(sp) + i = write(fd, (POINTER) &sp->Channel->Out.Data[sp->Channel->Out.Used], + (SIZE_T) sp->Channel->Out.Left); + if(i <= 0) { +- syslog(L_ERROR,"%s cant spool count %d",CHANname(sp->Channel), ++ syslog(L_ERROR,"%s cant spool count %ld",CHANname(sp->Channel), + sp->Channel->Out.Left); + close(fd); + return FALSE; +@@ -778,7 +778,7 @@ SITEchanclose(cp) + * site spooling, copy any data that might be pending, + * and arrange to retry later. */ + if (!SITEspool(sp, (CHANNEL *)NULL)) { +- syslog(L_ERROR, "%s loss %d bytes", sp->Name, cp->Out.Left); ++ syslog(L_ERROR, "%s loss %ld bytes", sp->Name, cp->Out.Left); + return; + } + WCHANsetfrombuffer(sp->Channel, &cp->Out); +@@ -869,11 +869,11 @@ SITEflush(sp, Restart) + else if (cp != NULL && cp->Out.Left) { + if (sp->Type == FTfile || sp->Spooling) { + /* Can't flush a file? Hopeless. */ +- syslog(L_ERROR, "%s dataloss %d", sp->Name, cp->Out.Left); ++ syslog(L_ERROR, "%s dataloss %ld", sp->Name, cp->Out.Left); + return; + } + /* Must be a working channel; spool and retry. */ +- syslog(L_ERROR, "%s spooling %d bytes", sp->Name, cp->Out.Left); ++ syslog(L_ERROR, "%s spooling %ld bytes", sp->Name, cp->Out.Left); + if (SITEspool(sp, cp)) + SITEflush(sp, FALSE); + return; --- inn-1.7.2q.orig/debian/patches/getmodaddr.c +++ inn-1.7.2q/debian/patches/getmodaddr.c @@ -0,0 +1,22 @@ +--- inn-1.7.2.orig/lib/getmodaddr.c ++++ inn-1.7.2/lib/getmodaddr.c +@@ -120,6 +120,7 @@ + (void)strcpy(GMApathname, _PATH_TEMPMODERATORS); + (void)mktemp(GMApathname); + GMAfp = GMA_listopen(GMApathname, FromServer, ToServer, "moderators"); ++ if (GMAfp == NULL) GMAfp = fopen(_PATH_MODERATORS, "r"); + } + + if (GMAfp != NULL) { +--- inn-1.7.2.orig/doc/inews.1 ++++ inn-1.7.2/doc/inews.1 +@@ -129,7 +129,8 @@ + If an unapproved posting is made to a moderated newsgroup, + .I inews + will try to mail the article to the moderator for posting. +-It uses the ++It will query the remote news server for a moderators listing. If ++that doesn't succeed, it will fallback to using the local + .IR moderators (5) + file to determine the mailing address. + If no address is found, it will use the --- inn-1.7.2q.orig/debian/patches/gnukfreebsd_port +++ inn-1.7.2q/debian/patches/gnukfreebsd_port @@ -0,0 +1,14 @@ +Surprisingly, GNU/kFreeBSD has /proc/loadavg and no nlist(3). + +diff -ruNp inn-1.7.2.orig/nnrpd/loadave.c inn-1.7.2/nnrpd/loadave.c +--- inn-1.7.2.orig/nnrpd/loadave.c 1997-12-09 00:48:50.000000000 +0100 ++++ inn-1.7.2/nnrpd/loadave.c 2007-08-07 21:27:09.000000000 +0200 +@@ -7,7 +7,7 @@ + #include "clibrary.h" + #include "nnrpd.h" + #if NNRP_LOADLIMIT > 0 +-#ifdef linux ++#ifdef __GLIBC__ + + /* + ** Get the current load average as an integer. --- inn-1.7.2q.orig/debian/patches/implicit_decls +++ inn-1.7.2q/debian/patches/implicit_decls @@ -0,0 +1,96 @@ +--- a/lib/remopen.c ++++ b/lib/remopen.c +@@ -11,6 +11,7 @@ + #include + #endif /* defined(DO_HAVE_UNIX_DOMAIN) */ + #include ++#include + #include + #include "nntp.h" + #include "paths.h" +--- a/lib/tempname.c ++++ b/lib/tempname.c +@@ -37,6 +37,7 @@ static void use_rcsid (const char *rid) + + + #include ++#include + #include + #include "configdata.h" + #include "clibrary.h" +--- a/innd/inndstart.c ++++ b/innd/inndstart.c +@@ -10,7 +10,9 @@ + #include + #include + #include ++#include + #include ++#include + #include "paths.h" + #include "logging.h" + #include "libinn.h" +--- a/nnrpd/nnrpd.h ++++ b/nnrpd/nnrpd.h +@@ -150,4 +150,6 @@ extern void Reply(); + */ + #if defined(DO_PERL) + char *HandleHeaders(char *artBody); ++int PERLsetup (char *, char *, char *); ++void PerlFilter(BOOL); + #endif /* defined(DO_PERL) */ +--- a/innd/innd.h ++++ b/innd/innd.h +@@ -606,4 +606,9 @@ extern void TCLclose(); + #if defined(DO_PERL) + char *HandleArticle(char *artBody); + char *HandleMessageID(char *messageID); ++void PerlFilter(BOOL value); ++void PerlMode(OPERATINGMODE Mode, OPERATINGMODE NewMode, char *reason); ++int PERLreadfilter(char *filterfile, char *function); ++void PerlClose(void); ++int PERLsetup (char *, char *, char *); + #endif /* defined(DO_PERL) */ +--- a/lib/perl.c ++++ b/lib/perl.c +@@ -37,6 +37,7 @@ XS(boot_DynaLoader); + + void PerlSilence(void); + void PerlUnSilence(void); ++int PERLreadfilter(char *filterfile, char *function); + + + int PerlFilterActive = FALSE; +--- a/innd/timer.c ++++ b/innd/timer.c +@@ -48,7 +48,7 @@ int maxtimer = 0; + + unsigned gettime() + { +- static init = 0; ++ static int init = 0; + static struct timeval start_tv; + struct timeval tv; + +--- a/innd/nc.c ++++ b/innd/nc.c +@@ -133,7 +133,7 @@ STATIC _NCprecomcache NCprecomcache[NCPR + unsigned long NCprecomhits; + unsigned long NCprecomlookups; + STATIC long NCprecompos, NCprecomval; +-STATIC NCprecominit = 0; ++STATIC int NCprecominit = 0; + + + STATIC void +--- a/innd/rc.c ++++ b/innd/rc.c +@@ -30,6 +30,8 @@ extern unsigned long htonl(); /* nobody + #include + #endif /* defined(DO_TCPIDENT_PATH) */ + ++int RCfix_options(int fd, struct sockaddr_in *remote); ++ + /* + ** A remote host has an address and a password. + */ --- inn-1.7.2q.orig/debian/patches/implicit_pointers +++ inn-1.7.2q/debian/patches/implicit_pointers @@ -0,0 +1,104 @@ +Description: implicit pointer conversion for HandleArticle + Add a function prototype for HandleArticle() and remove the + existing explicit cast to quiet function pointer conversion + warning which is fatal to the build. + . + implicit pointer conversion xalloc/xrealloc + Perl is using libinn ensure we are including the appropriate headers to + quiet function pointer conversion warning which is fatal to the build. +Author: Andy Whitcroft +Bug-Ubuntu: http://bugs.launchpad.net/bugs/1528545 +Index: inn-1.7.2q/innd/innd.h +=================================================================== +--- inn-1.7.2q.orig/innd/innd.h ++++ inn-1.7.2q/innd/innd.h +@@ -598,3 +598,11 @@ extern void TCLreadfilter(); + extern void TCLsetup(); + extern void TCLclose(); + #endif /* defined(DO_TCL) */ ++ ++ ++/* ++** PERL Functions ++*/ ++#if defined(DO_PERL) ++char *HandleArticle(char *artBody); ++#endif /* defined(DO_PERL) */ +Index: inn-1.7.2q/innd/art.c +=================================================================== +--- inn-1.7.2q.orig/innd/art.c ++++ inn-1.7.2q/innd/art.c +@@ -1920,7 +1920,7 @@ ARTpost(cp, Replic, ihave) + #if defined(DO_PERL) + pathForPerl = HeaderFind(article->Data, "Path", 4) ; + TMRstart(TMR_PERL); +- if ((perlrc = (char *)HandleArticle(Data.Body)) != NULL) { ++ if ((perlrc = HandleArticle(Data.Body)) != NULL) { + TMRstop(TMR_PERL); + (void)sprintf(buff, "%d %s", NNTP_REJECTIT_VAL, perlrc); + syslog(L_NOTICE, "rejecting[perl] %s %s", HDR(_message_id), buff); +Index: inn-1.7.2q/nnrpd/nnrpd.h +=================================================================== +--- inn-1.7.2q.orig/nnrpd/nnrpd.h ++++ inn-1.7.2q/nnrpd/nnrpd.h +@@ -144,3 +144,10 @@ extern void Reply(char *, ...); + #if defined(VAR_VARARGS) + extern void Reply(); + #endif /* defined(VAR_VARARGS) */ ++ ++/* ++** PERL Functions ++*/ ++#if defined(DO_PERL) ++char *HandleHeaders(char *artBody); ++#endif /* defined(DO_PERL) */ +Index: inn-1.7.2q/nnrpd/post.c +=================================================================== +--- inn-1.7.2q.orig/nnrpd/post.c ++++ inn-1.7.2q/nnrpd/post.c +@@ -896,7 +896,7 @@ ARTpost(article, idbuff) + + #if defined(DO_PERL) + /* Calls the Perl subroutine for headers management */ +- if ((p = (char *)HandleHeaders(article)) != NULL) { ++ if ((p = HandleHeaders(article)) != NULL) { + if (strncmp(p, "DROP", 4) == 0) { + syslog(L_NOTICE, "%s post %s", ClientHost, p); + return NULL; +Index: inn-1.7.2q/innd/innd.h +=================================================================== +--- inn-1.7.2q.orig/innd/innd.h ++++ inn-1.7.2q/innd/innd.h +@@ -605,4 +605,5 @@ extern void TCLclose(); + */ + #if defined(DO_PERL) + char *HandleArticle(char *artBody); ++char *HandleMessageID(char *messageID); + #endif /* defined(DO_PERL) */ +Index: inn-1.7.2q/innd/nc.c +=================================================================== +--- inn-1.7.2q.orig/innd/nc.c ++++ inn-1.7.2q/innd/nc.c +@@ -1589,7 +1589,7 @@ NCcheck(cp) + + #if defined(DO_PERL) + /* invoke a perl message filter on the message id */ +- else if ((perlrc = (char *)HandleMessageID(p)) != NULL) { ++ else if ((perlrc = HandleMessageID(p)) != NULL) { + cp->Refused++; + (void)sprintf(cp->Sendid.Data, "%d %s", NNTP_ERR_GOTID_VAL, p); + NCwritereply(cp, cp->Sendid.Data); + + +Index: inn-1.7.2q/nnrpd/perl.c +=================================================================== +--- inn-1.7.2q.orig/nnrpd/perl.c ++++ inn-1.7.2q/nnrpd/perl.c +@@ -24,6 +24,7 @@ static void use_rcsid (const char *rid) + #include "post.h" + #include "logging.h" + #include "macros.h" ++#include "nnrpd.h" + + #if defined(DO_PERL) + --- inn-1.7.2q.orig/debian/patches/inet_addr_is_int +++ inn-1.7.2q/debian/patches/inet_addr_is_int @@ -0,0 +1,11 @@ +--- inn-1.7.2.orig/include/clibrary.h ++++ inn-1.7.2/include/clibrary.h +@@ -111,7 +111,7 @@ + #endif /* !defined(strerror) */ + extern long atol(); + extern time_t time(); +-extern unsigned long inet_addr(); ++extern unsigned int inet_addr(); + extern FREEVAL free(); + extern POINTER malloc(); + extern POINTER realloc(); --- inn-1.7.2q.orig/debian/patches/inews-misc +++ inn-1.7.2q/debian/patches/inews-misc @@ -0,0 +1,271 @@ +--- inn-1.7.2.orig/frontends/inews.c ++++ inn-1.7.2/frontends/inews.c +@@ -28,7 +28,7 @@ + #define HEADER_DELTA 20 + #define GECOSTERM(c) \ + ((c) == ',' || (c) == ';' || (c) == ':' || (c) == LPAREN) +- ++#define HEADER_STRLEN 998 + + typedef enum _HEADERTYPE { + HTobs, +@@ -121,7 +121,7 @@ + QuitServer(x) + int x; + { +- char buff[NNTP_STRLEN + 2]; ++ char buff[HEADER_STRLEN]; + char *p; + + if (Spooling) +@@ -344,9 +344,15 @@ + if (buff[0] == '.' && buff[1] == '\0') + break; + if (EQn(buff, "Sender:", 7)) +- (void)strcpy(remotefrom, TrimSpaces(&buff[7])); ++ { ++ (void)strncpy(remotefrom, TrimSpaces(&buff[7]), SMBUF); ++ remotefrom[SMBUF-1] = '\0'; ++ } + else if (remotefrom[0] == '\0' && EQn(buff, "From:", 5)) +- (void)strcpy(remotefrom, TrimSpaces(&buff[5])); ++ { ++ (void)strncpy(remotefrom, TrimSpaces(&buff[5]), SMBUF); ++ remotefrom[SMBUF-1] = '\0'; ++ } + } + if (remotefrom[0] == '\0') { + if (JustReturn) +@@ -357,7 +363,8 @@ + HeaderCleanFrom(remotefrom); + + /* Get the local user. */ +- (void)strcpy(localfrom, HDR(_sender) ? HDR(_sender) : HDR(_from)); ++ (void)strncpy(localfrom, HDR(_sender) ? HDR(_sender) : HDR(_from), SMBUF); ++ localfrom[SMBUF-1] = '\0'; + HeaderCleanFrom(localfrom); + + /* Is the right person cancelling? */ +@@ -449,7 +456,8 @@ + || EQ(ctrl, "sendsys") + || EQ(ctrl, "senduuname") + || EQ(ctrl, "version")) { +- (void)strcpy(name, pwp->pw_name); ++ (void)strncpy(name, pwp->pw_name, SMBUF); ++ name[SMBUF-1] = '\0'; + if (!AnAdministrator(name, (int)pwp->pw_gid)) { + (void)fprintf(stderr, + "Ask your news administrator to do the \"%s\" for you.\n", +@@ -485,6 +493,7 @@ + char outbuff[SMBUF]; + char *out; + char *p; ++ int left; + + #if !defined(DONT_MUNGE_GETENV) + (void)memset(outbuff, 0, SMBUF); +@@ -497,26 +506,40 @@ + + + #if defined(DONT_MUNGE_GECOS) +- (void)strcpy(outbuff, pwp->pw_gecos); ++ (void)strncpy(outbuff, pwp->pw_gecos, SMBUF); ++ outbuff[SMBUF-1] = '\0'; + #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); p++) { ++ for (out = outbuff; *p && !GECOSTERM(*p) && left; p++) { + if (*p == '&') { +- (void)strcpy(out, pwp->pw_name); ++ (void)strncpy(out, pwp->pw_name, left); + if (CTYPE(islower, *out) + && (out == outbuff || !isalpha(out[-1]))) + *out = toupper(*out); + while (*out) ++ { + out++; ++ left--; ++ } + } + else if (*p == '-' + && p > pwp->pw_gecos + && (isdigit(p[-1]) || isspace(p[-1]) || p[-1] == ']')) ++ { + out = outbuff; ++ left = SMBUF - 1; ++ } + else ++ { + *out++ = *p; ++ left--; ++ } + } + *out = '\0'; + #endif /* defined(DONT_MUNGE_GECOS) */ +@@ -527,9 +550,9 @@ + + out = TrimSpaces(outbuff); + if (out[0]) +- (void)sprintf(buff, "%s@%s (%s)", pwp->pw_name, node, out); ++ (void)snprintf(buff, sizeof (buff), "%s@%s (%s)", pwp->pw_name, node, out); + else +- (void)sprintf(buff, "%s@%s", pwp->pw_name, node); ++ (void)snprintf(buff, sizeof (buff), "%s@%s", pwp->pw_name, node); + return COPY(buff); + } + +@@ -597,13 +620,20 @@ + if ((p = GetConfigValue(_CONF_FROMHOST)) == NULL) + PerrorExit(TRUE, "Can't get host name"); + if (HDR(_from) == NULL) +- HDR(_from) = FormatUserName(pwp, p); ++ HDR(_from) = FormatUserName(pwp, p); + else { ++ if (strlen(pwp->pw_name) + strlen(p) + 2 > sizeof(buff)) { ++ fprintf(stderr, "Username and host too long\n"); ++ QuitServer(1); ++ } + (void)sprintf(buff, "%s@%s", pwp->pw_name, p); +- (void)strcpy(from, HDR(_from)); ++ (void)strncpy(from, HDR(_from), SMBUF); ++ from[SMBUF-1] = '\0'; + HeaderCleanFrom(from); ++#ifdef PRETTY_PLEASE_ADD_SENDER_HEADER + if (!EQ(from, buff)) + HDR(_sender) = COPY(buff); ++#endif + } + + /* Set Date. */ +@@ -616,7 +646,7 @@ + * printf's treat it %02 (two digits wide) .2 (zero-fill to at least + * two digits), while old versions treat it as %02 (zero-fill two + * digits wide) .2 (noise). You might want to check this on your +- * system. */ ++ * system. This shouldn't be able to overflow SMBUF... */ + if (Now.tzone < 0) { + p = &SIGNS[0]; + zone = -Now.tzone; +@@ -678,9 +708,20 @@ + i += strlen(p) + 1; + HDR(_path) = NEW(char, i + 1); + if (*p) ++ { ++ if (strlen(Exclusions) + strlen(p) + strlen(PATHFLUFF) + 2 <= sizeof(HDR(_path))) { ++ fprintf(stderr, "Path line too long\n"); ++ QuitServer(1); ++ } + (void)sprintf(HDR(_path), "%s%s!%s", Exclusions, p, PATHFLUFF); + else ++ { ++ if (strlen(Exclusions) + strlen(PATHFLUFF) +1 > sizeof(HDR(_path))) { ++ fprintf(stderr, "Path line too long\n"); ++ QuitServer(1); ++ } + (void)sprintf(HDR(_path), "%s%s", Exclusions, PATHFLUFF); ++ } + } + else if (GetFileConfigValue(_CONF_SERVER) != NULL) { + if ((p = GetFQDN()) == NULL) { +@@ -774,6 +815,10 @@ + + /* Open the file. */ + *linesp = 0; ++ if (strlen(homedir) > sizeof(buff) - 14) { ++ fprintf(stderr, "Home directory path too long\n"); ++ QuitServer(1); ++ } + (void)sprintf(buff, "%s/.signature", homedir); + if ((F = fopen(buff, "r")) == NULL) { + if (errno == ENOENT) +@@ -1088,7 +1133,7 @@ + { + (void)fprintf(ToServer, "post\r\n"); + SafeFlush(ToServer); +- if (fgets(buff, NNTP_STRLEN, FromServer) == NULL) ++ if (fgets(buff, HEADER_STRLEN, FromServer) == NULL) + PerrorExit(TRUE, + Authorized ? "Can't offer article to server (authorized)" + : "Can't offer article to server"); +@@ -1178,8 +1223,8 @@ + struct passwd *pwp; + char *article; + char *deadfile; +- char buff[NNTP_STRLEN + 2]; +- char SpoolMessage[NNTP_STRLEN + 2]; ++ char buff[HEADER_STRLEN]; ++ char SpoolMessage[HEADER_STRLEN]; + BOOL DoSignature; + BOOL AddOrg; + SIZE_T Length; +@@ -1269,23 +1314,33 @@ + if ((p = strchr(buff, '\r')) != NULL) + *p = '\0'; + (void)strcpy(SpoolMessage, buff[0] ? buff : NOCONNECT); ++ if (strlen(pwp->pw_dir) > sizeof(buff) - 14) { ++ fprintf(stderr, "Home directory path too long\n"); ++ exit(1); ++ } + (void)sprintf(buff, "%s/dead.article", pwp->pw_dir); + deadfile = COPY(buff); + } + else { ++ setbuf(FromServer, NEW(char, BUFSIZ)); ++ setbuf(ToServer, NEW(char, BUFSIZ)); + /* See if we can post. */ + i = atoi(buff); + + /* Tell the server we're posting. */ +- setbuf(FromServer, NEW(char, BUFSIZ)); +- setbuf(ToServer, NEW(char, BUFSIZ)); + (void)fprintf(ToServer, "mode reader\r\n"); + SafeFlush(ToServer); +- if (fgets(buff, NNTP_STRLEN, FromServer) == NULL) ++ if (fgets(buff, HEADER_STRLEN, FromServer) == NULL) + PerrorExit(TRUE, "Can't tell server we're reading"); + if ((j = atoi(buff)) != NNTP_BAD_COMMAND_VAL) + i = j; + ++ /* Authorize with password if required. */ ++ if (i == NNTP_AUTH_NEEDED_VAL) { ++ if (NNTPsendpassword((char *)NULL, FromServer, ToServer) < 0) ++ PerrorExit(TRUE, "Authorization error"); ++ i = NNTP_POSTOK_VAL; ++ } + if (i != NNTP_POSTOK_VAL) { + (void)fprintf(stderr, "You do not have permission to post.\n"); + QuitServer(1); +@@ -1324,22 +1379,22 @@ + QuitServer(1); + } + for (hp = Table; hp < ENDOF(Table); hp++) +- if (hp->Value && (int)strlen(hp->Value) + hp->Size > NNTP_STRLEN) { ++ if (hp->Value && (int)strlen(hp->Value) + hp->Size > HEADER_STRLEN) { + (void)fprintf(stderr, "\"%s\" header is too long.\n", hp->Name); + QuitServer(1); + } + for (i = 0; i < OtherCount; i++) +- if ((int)strlen(OtherHeaders[i]) > NNTP_STRLEN) { ++ if ((int)strlen(OtherHeaders[i]) > HEADER_STRLEN) { + (void)fprintf(stderr, + "Header too long (%d characters max):\n\t%40.40s...\n", +- NNTP_STRLEN, OtherHeaders[i]); ++ HEADER_STRLEN, OtherHeaders[i]); + QuitServer(1); + } + + /* Check the newsgroups. */ +- if ((F = CAlistopen(FromServer, ToServer, (char *)NULL)) == NULL) { ++ if ((F = CAopen(FromServer, ToServer)) == NULL) { + if (NNTPsendpassword((char *)NULL, FromServer, ToServer) >= 0) +- F = CAlistopen(FromServer, ToServer, (char *)NULL); ++ F = CAopen(FromServer, ToServer); + } + if (F != NULL) { + if (!ValidNewsgroups(HDR(_newsgroups), F, article)) { --- inn-1.7.2q.orig/debian/patches/inewsport +++ inn-1.7.2q/debian/patches/inewsport @@ -0,0 +1,16 @@ +diff -ruN inn-1.7.2.orig/frontends/inews.c inn-1.7.2/frontends/inews.c +--- inn-1.7.2.orig/frontends/inews.c 2003-08-20 03:17:50.000000000 +0200 ++++ inn-1.7.2/frontends/inews.c 2003-08-20 03:17:44.000000000 +0200 +@@ -1306,6 +1306,12 @@ + break; + } + ++ /* Figure the server port. */ ++ if ((p = GetConfigValue("inewsport")) != NULL) { ++ extern char *nntp_port; ++ nntp_port = COPY(p); ++ } ++ + /* Try to open a connection to the server. */ + if (NNTPremoteopen(&FromServer, &ToServer, buff) < 0) { + Spooling = TRUE; --- inn-1.7.2q.orig/debian/patches/inncheck +++ inn-1.7.2q/debian/patches/inncheck @@ -0,0 +1,142 @@ +--- inn-1.7.2.orig/samples/inncheck ++++ inn-1.7.2/samples/inncheck +@@ -99,16 +99,16 @@ + ## The modes of the config files we can check. + %modes = ( + 'active', 0644, +- 'control.ctl', 0440, +- 'expire.ctl', 0440, +- 'hosts.nntp', 0440, +- 'inn.conf', 0444, +- 'moderators', 0444, +- 'newsfeeds', 0444, +- 'overview.fmt', 0444, +- 'nnrp.access', 0440, +- 'nntpsend.ctl', 0440, +- 'passwd.nntp', 0440 ++ 'control.ctl', 0644, ++ 'expire.ctl', 0644, ++ 'hosts.nntp', 0640, ++ 'inn.conf', 0644, ++ 'moderators', 0644, ++ 'newsfeeds', 0644, ++ 'overview.fmt', 0644, ++ 'nnrp.access', 0640, ++ 'nntpsend.ctl', 0644, ++ 'passwd.nntp', 0640 + ); + + +@@ -804,7 +804,7 @@ + } + + @directories = ( +- 'archive', 'badnews', 'batchdir', 'ctlprogs', 'most_logs', 'newsbin', ++ 'archive', 'badnews', 'batchdir', 'ctlprogs', 'most_logs', # 'newsbin', + 'newslib', 'oldlogs', 'rnewsprogs', 'spooltemp', 'spool', 'spoolnews' + ); + @control_scripts = ( +@@ -812,7 +812,7 @@ + 'sendme', 'sendsys', 'senduuname', 'version' + ); + @rnews_programs = ( +- 'c7unbatch', 'decode', 'encode' ++ 'c7unbatch', 'decode', 'encode', 'gunbatch' + ); + @newsbin_public = ( + 'archive', 'batcher', 'buffchan', 'convdate', 'cvtbatch', 'expire', +@@ -822,8 +822,8 @@ + ); + @newsbin_private = ( + 'ctlinnd', 'expirerm', 'inncheck', 'innstat', 'innwatch', +- 'makegroup', 'news.daily', 'nntpsend', 'scanlogs', 'sendbatch', +- 'tally.control', 'tally.unwanted', 'updatemods', 'writelog' ++ 'news.daily', 'nntpsend', 'scanlogs', 'sendbatch', ++ 'tally.control', 'tally.unwanted', 'writelog' + ); + @newslib_private = ( + 'send-ihave', 'send-nntp', 'send-uucp' +@@ -834,12 +834,12 @@ + + ## The modes for the various programs. + %prog_modes = ( +- 'inews', 02555, +- 'innd', 0555, +- 'newsboot', 0550, +- 'nnrpd', 0555, +- 'parsectl', 0550, +- 'rnews', 02555 ++ 'inews', 02755, ++ 'innd', 0755, ++ 'newsboot', 0755, ++ 'nnrpd', 0755, ++ 'parsectl', 0755, ++ 'rnews', 02755 + ); + + ## Check the permissions of nearly every file in an INN installation. +@@ -852,13 +852,13 @@ + local ($newslib) = $paths{'newslib'}; + + foreach ( @directories ) { +- &checkperm($paths{$_}, 0775); ++ &checkperm($paths{$_}, $_ eq 'rnewsprogs' ? 0755 : 0775); + } +- &checkperm($paths{'innddir'}, 0770); ++ &checkperm($paths{'innddir'}, 0775); + foreach ( keys %prog_modes ) { +- &checkperm($paths{$_}, $prog_modes{$_}); ++ &checkperm($paths{$_}, $prog_modes{$_}, 'root'); + } +- &checkperm($paths{'inndstart'}, 0555, 'root', 'bin'); ++ &checkperm($paths{'inndstart'}, 04754, 'root', 'news'); + foreach ( keys %paths ) { + &checkperm($paths{$_}, $modes{$_}) + if defined $modes{$_}; +@@ -867,22 +867,22 @@ + &checkperm($paths{'history'} . ".dir", 0644); + &checkperm($paths{'history'} . ".pag", 0644); + foreach ( @newslib_private ) { +- &checkperm("$newslib/$_", 0550); ++ &checkperm("/etc/news/scripts/$_", 0755); + } + foreach ( @newslib_private_read ) { +- &checkperm("$newslib/$_", 0440); ++ &checkperm("$newsbin/$_", 0644, 'root', 'root'); + } + foreach ( @newsbin_private ) { +- &checkperm("$newsbin/$_", 0550); ++ &checkperm("$newsbin/$_", 0755, 'root', 'root'); + } + foreach ( @newsbin_public ) { +- &checkperm("$newsbin/$_", 0555); ++ &checkperm("$newsbin/$_", 0755, 'root', 'root'); + } + foreach ( @control_scripts ) { +- &checkperm("$ctlprogs/$_", 0550); ++ &checkperm("$ctlprogs/$_", 0755); + } + foreach ( @rnews_programs ) { +- &checkperm("$rnewsprogs/$_", 0555); ++ &checkperm("$rnewsprogs/$_", 0755); + } + + ## Also make sure that @rnews_programs are the *only* programs in there; +@@ -999,8 +999,15 @@ + print "$pfx$workfile:0: can't open $!\n"; + next action; + } +- &checkperm($file, $modes{$workfile}) +- if $noperms == 0 && !$perms && defined $modes{$workfile}; ++ if ($noperms == 0 && !$perms && defined $modes{$workfile}) { ++ if ($workfile eq 'active') { ++ &checkperm($file, $modes{$workfile}); ++ } elsif (grep($workfile eq $_, qw(passwd.nntp nnrp.access hosts.nntp))) { ++ &checkperm($file, $modes{$workfile}, 'root', 'news'); ++ } else { ++ &checkperm($file, $modes{$workfile}, 'root', 'root'); ++ } ++ } + $line = 0; + eval "&$checklist{$workfile}" || warn "$@"; + close(IN); --- inn-1.7.2q.orig/debian/patches/innd.c_init_TimeOut +++ inn-1.7.2q/debian/patches/innd.c_init_TimeOut @@ -0,0 +1,10 @@ +--- inn-1.7.2.orig/innd/innd.c ++++ inn-1.7.2/innd/innd.c +@@ -621,6 +621,7 @@ + + /* Set defaults. */ + TimeOut.tv_sec = DEFAULT_TIMEOUT; ++ TimeOut.tv_usec = 0; + ShouldFork = TRUE; + ShouldRenumber = FALSE; + ShouldSyntaxCheck = FALSE; --- inn-1.7.2q.orig/debian/patches/innwatch_ctlinnd_timeout +++ inn-1.7.2q/debian/patches/innwatch_ctlinnd_timeout @@ -0,0 +1,29 @@ +--- inn-1.7.2.orig/samples/innwatch ++++ inn-1.7.2/samples/innwatch +@@ -24,6 +24,8 @@ + ## Logfile to watch. Comment out if no logwatch. + LOGFILE=${MOST_LOGS}/news.crit + ++CTLINND_TMOUT=300 ++ + ## Parse JCL. + while [ $# -gt 0 ] ; do + case X"$1" in +@@ -127,7 +129,7 @@ + + ## 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 ++ if ctlinnd -s -t $CTLINND_TMOUT mode 2>/dev/null ; then + ${HASEXITED} && { + HASEXITED=false + ${MAILCMD} -s "INND is now running" ${NEWSMASTER} &1 \ --- inn-1.7.2q.orig/debian/patches/man_sections +++ inn-1.7.2q/debian/patches/man_sections @@ -0,0 +1,56 @@ +diff -ruNp inn-1.7.2.orig/dbz/dbz.3z inn-1.7.2/dbz/dbz.3z +--- inn-1.7.2.orig/dbz/dbz.3z 1997-12-09 00:48:50.000000000 +0100 ++++ inn-1.7.2/dbz/dbz.3z 2008-04-20 03:22:43.000000000 +0200 +@@ -1,5 +1,4 @@ +-.TH DBZ 3Z "3 Feb 1991" +-.BY "C News" ++.TH DBZ 3 "3 Feb 1991" "C News" + .SH NAME + dbminit, fetch, store, dbmclose \- somewhat dbm-compatible database routines + .br +diff -ruNp inn-1.7.2.orig/doc/fastrm.8 inn-1.7.2/doc/fastrm.8 +--- inn-1.7.2.orig/doc/fastrm.8 1997-12-09 00:48:50.000000000 +0100 ++++ inn-1.7.2/doc/fastrm.8 2008-04-20 03:22:43.000000000 +0200 +@@ -1,5 +1,5 @@ + .\" $Revision $ +-.TH FASTRM 1 ++.TH FASTRM 8 + .SH NAME + fastrm \- quickly remove a set of files + .SH SYNOPSIS +diff -ruNp inn-1.7.2.orig/doc/innxbatch.8 inn-1.7.2/doc/innxbatch.8 +--- inn-1.7.2.orig/doc/innxbatch.8 1997-12-09 00:48:50.000000000 +0100 ++++ inn-1.7.2/doc/innxbatch.8 2008-04-20 03:23:09.000000000 +0200 +@@ -100,8 +100,8 @@ is: + exit 1 + fi + +- ## =()<. @<_PATH_SHELLVARS>@>()= +-. /var/news/etc/innshellvars ++ ## =()< . @<_PATH_SHELLVARS>@>()= ++ . /var/news/etc/innshellvars + + site="$1"; host="$2"; shift; shift + +diff -ruNp inn-1.7.2.orig/doc/nnrpd.8 inn-1.7.2/doc/nnrpd.8 +--- inn-1.7.2.orig/doc/nnrpd.8 1997-12-09 00:48:50.000000000 +0100 ++++ inn-1.7.2/doc/nnrpd.8 2008-04-20 03:22:43.000000000 +0200 +@@ -114,7 +114,7 @@ command may be followed by the optional + .IR "``distributions''" , + .IR "``distrib.pats''" , + .IR "``newsgroups''" , +-.IT "``subscriptions''", ++.IR "``subscriptions''", + or + .IR "``overview.fmt''" + to get a list of when newsgroups where created, a list of valid distributions, +diff -ruNp inn-1.7.2.orig/doc/subst.1 inn-1.7.2/doc/subst.1 +--- inn-1.7.2.orig/doc/subst.1 1997-12-09 00:48:50.000000000 +0100 ++++ inn-1.7.2/doc/subst.1 2008-04-20 03:22:43.000000000 +0200 +@@ -1,5 +1,4 @@ +-.TH SUBST 1 local +-.DA 25 Feb 1990 ++.TH SUBST 1 "25 Feb 1990" + .SH NAME + subst \- substitute definitions into file(s) + .SH SYNOPSIS --- inn-1.7.2q.orig/debian/patches/misc_config_files +++ inn-1.7.2q/debian/patches/misc_config_files @@ -0,0 +1,67 @@ +--- inn-1.7.2.orig/samples/hosts.nntp.nolimit ++++ inn-1.7.2/samples/hosts.nntp.nolimit +@@ -2,5 +2,6 @@ + ## + ## Any hosts listed in this file will be permitted to connect past the + ## limits set up by the `-i' and `-X' flags to innd. ++## Listed hosts must be present in hosts.nntp too! + ## + localhost +--- inn-1.7.2.orig/samples/nnrp.access ++++ inn-1.7.2/samples/nnrp.access +@@ -15,7 +15,8 @@ + ## Default is no access, no way to authentication, and no groups. + *:: -no- : -no- :!* + ## Foo, Incorporated, hosts have no password, can read anything. +-*.foo.com:Read Post:::* ++#*.foo.com:Read Post:::* ++ + stdin:Read Post:::* + localhost:Read Post:::* + 127.0.0.1:Read Post:::* +--- inn-1.7.2.orig/samples/nntpsend.ctl ++++ inn-1.7.2/samples/nntpsend.ctl +@@ -10,6 +10,6 @@ + ## see shrinkfile(1). + ## 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: ++#nsavax:erehwon.nsavax.gov::-S -t60 ++#walldrug:walldrug.com:4m-1m:-T1800 -t300 ++#kremvax:kremvax.cis:2m: +--- inn-1.7.2.orig/samples/passwd.nntp ++++ inn-1.7.2/samples/passwd.nntp +@@ -11,4 +11,4 @@ + ##