Listing 1: actgroups
#!/usr/bin/perl
#
# Active groups -- detecting actively accessed news groups and adjusting
# -- expire.ctl so that active groups stay longer
#
# Program Name: actgroups
# for INN 1.4, 1.5, 1.7, 1.8, 2.0
# Author: Yufan Hu ( yufan@recmail.com )
# Version: 1.0
# Release: Jan 28 1998
# This is a total rewrite of actgroups version 0.3 and its
# modified version activexp.pl floating around the net since 1994
# Copyright: by Yufan Hu. Freely redistribution, use and modification
# by anybody as long as the author is acknowledged and this
# copywrite notice preserved.
# Disclaim: Use at your own risk. No Warrantee.
# Fee: No. But appreciate an email acknowledge so I know
# who is using it.
#
#========================= Installation ========================
# 1. Copy this file to a directory of your choice. I put it in
# /usr/local/news/local
# 2. Change the values of $LastRead, $expire, $newslog according to
# your own news configuration
# 3. pass the path to actgroups to news.daily in your cron job entry,
# such as:
# 30 3 * * * /usr/local/news/bin/news.daily delayrm
# /usr/local/news/local/actgroups
# 4. Setting rules in expire.ctl file
#
#========================= expire.ctl configuration =================
# The expire.ctl file remains almost the same except that the original rules
# definition act as the default expiration rules for inactive groups.
# A new set of rules, beginning with "#% " define the adjustment
# for groups that are actively read.
# i.e.
# *:A:0:1:7
# #% *:A:10:30:45
# means that if a group is not actively read, its expire rule will be
# *:A:0:1:7
# and if a group is being read within 45 days, its expire time will be adjusted
# to:
# *:A:10:30:45
# The above two lines can be used as the simplest configuration. If you want
# finer control you can add more, such as:
# *:A:0:1:7
# #% *:A:10:30:45
# comp.*:A:7:7:10
# #% comp.*:A:30:60:90
# #% alt.binaries*:A:2:2:2
# You should include at least line "#% *:A:...". If no "#% " rule
# matches an actively read group it is treat the same as an inactive group.
# The "active period" of a group is defined by the <purge> field
# of the last matching "#% " rule. If no read happens with this period
# of time, the group is removed from the LastRead database
#
# actgroups will modify expire.ctl file for adding the adjustment. It must
# has read/write access to the directory expire.ctl resides. Original
# expire.ctl will be backuped to expire.ctl.day, where day is the day of
# the week the actgroups runs.
#
# WARNING: It may take a few days to collect the readership information.
# it is adviced that you keep the original "*:A:..." line with
# larger expire time for a period of time until the readership
# information is accumulated in LastRead.log database, if you
# use it at the first time.
#
# For actgroups version 0.3 and 0.4 users:
# The LastRead.log database should be compatible with this version.
#
###############################################################
#
# Configuration part
#
# $LastRead the DBM database to record the time a group was last
# seen read
# $expire the full path to expire.ctl file on your system
# $newslog the full path to news.notice file on your system
# this is the file where syslogd log all news.notice
# level message
#
##############################################################
$LastRead = "/usr/local/news/etc/LastRead.log";
$expire = "/usr/local/news/etc/expire.ctl";
$newslog = "/usr/local/news/log/news.notice";
# delimiters in expire.ctl
$start = "### Actively Accessed Groups Start ###";
$end = "### Actively Accessed Groups End ###";
# End of Configuration part
##################### No change needed ###########################
require 'getopts.pl';
# default options
$debug = 0;
# Get the command line options
Getopts('l:d');
$newslog = $opt_l if ($opt_l);
$debug = 1 if ($opt_d);
$warn .= "Logfile: $newslog\n" if $debug;
$expire_new = "$expire.new";
# open the database recording the time the group was last read
# access this database as an associated array
dbmopen(%LASTREAD, $LastRead, 0600);
# open the tempory expire.ctl.new file
open(EXP_NEW, ">$expire.new") || die "Cannot create $expire.new: $!\n";
# Seconds in a day
$day = 3600 * 24;
$now = time;
$total = $thrown = 0;
$date = qx{date};
chop $date;
scan_log();
scan_expire_ctl();
# now we have detected active group in %LASTREAD database
# we check the group agains the %rules to find any match.
# if a match is found, then the corresponding rule part is used
# for that group. If no match is found, the group is not adjusted
adjust_expire_ctl();
# close the database and the new expire.ctl file
close(EXP_NEW);
dbmclose(%LASTREAD);
$debug && ( $warn .= "## Total: $total, thrown: $thrown\n");
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
if( $debug )
{
$warn .= "Collecting group information only, $expire intacted.\n" .
"Expire list is in $expire.new\n";
}
else
{
system "mv $expire $expire.$wday; mv $expire_new $expire";
}
$debug && $warn && print "\nMessage from actgroups:\n$warn";
exit;
# scan the news.notice file and record any detected read group
# in LastRead DBMS
sub scan_log {
# open the news log file -- usually the news.notice
open(LOG, $newslog);
# scan through the log file, detecting any accessed groups within current
# day and store the current time in the database
while(<LOG>) {
if(/^(.*\d\d:\d\d:\d\d).*nnrpd.*:\s+(.*) \ \s+group\s+([^\s]+)\s(\d+)/){
$group = $3;
$arts = $4;
($warn .= "Adding: $group\n")
if( $debug && (! $LASTREAD{$group}) );
# if $arts == 0 then we will add \ $group in only
# if it is already there \ ($LASTREAD{$group} = $now) if( $arts \ || $LASTREAD{$group});
}
}
close(LOG);
}
# scan the expire.ctl, looking for adjustment ctl
# line in the format of
# "#% pat:?:(\d+)|never:(\d+)|never:(\d+)|never"
sub scan_expire_ctl {
open(EXP, $expire);
%rules = ();
@patterns = ();
while(<EXP>)
{
/$start/ && last;
print EXP_NEW;
chop;
# try to find the #% rules
/^#%\s*([^:]+)\s*:\s*([^:]+)\s*:\s*([^:]+) \ \s*:\s*([^:]+)\s*:\s*([^:]+)\s*/
|| next;
$rule = ":$2:$3:$4:$5";
$pat = $1;
$pat =~ s/\./\\./g;
$pat =~ s/([\*\+\?])/.$1/g;
$rules{$pat} = $rule;
push(@patterns, $pat);
}
close EXP;
}
sub adjust_expire_ctl {
print EXP_NEW "$start
###############################################
# Automatically generated by actgroups version # 1.0
# Author: Yufan Hu ( yufan\@rightiming.com )
# Date: $date
#
# Do not change anything below this line. Any # changes will be overwritten
# the next time actgroups runs
################################################
\n";
for $group ( sort (keys %LASTREAD) )
{
$total++;
# does the group match anything in $rules
$rule = "";
# find the last matching rule
for $pat ( @patterns )
{
($group =~ /$pat/) && ($rule = $rules{$pat});
}
if( $rule )
{
# we found a match, do the adjustment
($purge) = $rule =~ /:([^:]+)$/;
if( int($purge) != 0
&& ($now - $LASTREAD{$group}) > ($purge * $day) )
{
$debug && ($warn .= "$group inactive for $purge days\n");
delete $LASTREAD{$group};
$thrown++;
}
else
{
print EXP_NEW "$group" . $rule . "\n";
}
}
else
{
$debug && ( $warn .= "No adjustment rule for $group\n" );
delete $LASTREAD{ $group };
$thrown++;
}
}
print EXP_NEW "## Total: $total, thrown: $thrown\n";
print EXP_NEW "\n$end\n## Do not put anything after this line ###\n";
}
# End of File
|