#!/usr/bin/perl require "/usr/news/lib/innshellvars.pl"; # check this! # ----------------------------------------------------------------------------- =head1 NAME ngbatch - newgroup/rmgroup batcher for INN =head1 SYNOPSIS B I [ I [ I ] ] B I B [ B<-D> ] [ B<-w> I ] [ B<-h> I ] =head1 DESCRIPTION This program executes newgroup and rmgroup controls in a delayed way, to help against newgroup/rmgroup wars. The idea is that (a) rmgroups are remembered for some time, and (b) rmgroups get priority over newgroups, so that a newgroup will be ignored if a rmgroup for this group (from a trusted issuer) has already arrived. A newgroup is executed only after a wait period, in case it gets rmgrouped soon. Each newgroup/rmgroup control message is written into a batch file. A cron job collects commands from this batch file and executes only those newgroups for which no rmgroup was received. =head2 Setting Up Change your control scripts for newgroup and rmgroup so that they call B with the appropriate parameters instead of B (you probably should make that depend on hierarchies). Make sure that only trusted rmgroupers are active in the I file. Run B periodically from crontab. =head1 OPTIONS =over 8 =item B<-n> I [ I [ I ] ] Batch up a newgroup control for I. I defaults to "y", I defaults to nothing. =item B<-r> I Batch up and execute a rmgroup control for I. =item B<-e> Execute a batch run: for all batched newgroup commands, check if the wait time has elapsed. If yes, execute the newgroup command only if no rmgroup for the same group was batched. Rewrite the batch file with the commands still to be remembered. =item B<-D> Show the commands on standard output instead of executing B. =item B<-w> I Set the newgroup wait time to I (default 3). =item B<-h> I Set the rmgroup remember time to I (default 30). =back =head1 FILES =over 4 =item Finn::pathdbE/ng.batch> The batch file. It consists of one line per batched command. The lines are divided by an ASCII FS character into fields. The first field is the time the command arrived, the second field an "N" or "R" indicating the type, the third the newsgroup name. Newgroup commands can contain up to two additional fields giving the flags and creator. The lines are sorted by the first field among both the newgroup and the rmgroup lines. =back =head1 SEE ALSO L, L. =head1 NOTES For each group, the first newgroup in the batch file is relevant, but the rmgroup remember time is determined from the last rmgroup. Control characters are not allowed in the parameters and get silently deleted. The batch file is properly locked via I. =head1 BUGS Not too many, I hope. =head1 AUTHOR Olaf Titz . This software is in the public domain. =head1 HISTORY 1999-03-26 First version written. =cut # ----------------------------------------------------------------------------- require "getopts.pl"; $LOCK_EX=2; # for flock $bfile="$inn::pathdb/ng.batch"; $opt_w=3; $opt_h=30; &Getopts("nrew:h:D"); grep { tr/\000-\037//d; } @ARGV; # sanitize args if ($opt_n) { exit &batch("N", join($;, @ARGV)); } elsif ($opt_r) { $_=shift; &ctlinnd("rmgroup", $_) if ($_); exit &batch("R", $_); } elsif ($opt_e) { &runbatch; exit 0; } print STDERR "$0: nothing to do\n"; exit 1; sub batch { local($f,$g)=@_; return 1 unless ($g); open(B, ">>$bfile") || die "open $bfile: $!"; flock(B, $LOCK_EX); printf B ("%d$;%s$;%s\n", $^T, $f, $g); close B; return 0; } sub runbatch { open(B, "+<$bfile") || die "open $bfile: $!"; flock(B, $LOCK_EX); while () { chomp; ($t,$f,$g,$y,$c)=split(/$;/, $_, 5); if ($f eq "N") { unless (defined($n{$g})) { # first newgroup counts $n{$g}=$t; $y{$g}=($y || "y"); $c{$g}=$c; } } else { $r{$g}=$t; # last rmgroup counts } } seek(B, 0, 0); truncate(B, 0); foreach (sort {$n{$a}<=>$n{$b}} keys %n) { unless (defined($r{$_})) { if ($n{$_}+$opt_w*86400>$^T) { printf B ("%d$;N$;%s$;%s$;%s\n", $n{$_}, $_, $y{$_}, $c{$_}); } else { &ctlinnd("newgroup", $_, $y{$_}, $c{$_}); } } } foreach (sort {$r{$a}<=>$r{$b}} keys %r) { if ($r{$_}+$opt_h*86400>$^T) { printf B ("%d$;R$;%s\n", $r{$_}, $_); } } close B; } sub ctlinnd { if ($opt_D) { printf STDOUT ("ctlinnd -s %s\n", join(" ", @_)); } else { system "ctlinnd", "-s", @_; } } # -----------------------------------------------------------------------------