[oclug] Here is some useful software
David F. Skoll
dfs at roaringpenguin.com
Mon Feb 19 15:17:11 EST 2001
In order to make OCLUG usable for me, I finally went and wrote the
thread-killer I've been musing about.
Many mailing lists are useless because some people post noise or off-topic
stuff. Blacklisting people only goes so far, because you end up getting
followups.
The thread-killer kills all postings in a thread. It works by checking
the In-Reply-To: and References: fields of an e-mail, and keeping a Berkeley
database of messages to kill. Any message which references a blacklisted
message is itself killed and added to the blacklist database.
Here's how you use it in .procmailrc:
First, you have to explicitly kill the often-noisy posts:
:0
* ^From:.*person_who_posts_junk at wherever.com
| /usr/local/bin/killthread.pl kill
Then, I use this rule to kill the rest of the thread:
:0
* ^TO_.*oclug at lists.oclug.on.ca
{
:0 hw
| /usr/local/bin/killthread.pl check
:0
$DEFAULT
}
The "check" argument only kills the message if it refers to a
blacklisted message.
You want a cron job which cleans the database periodically; the following
command deletes message-ID's older than 30 days:
/usr/local/bin/killthread.pl clean 30
Finally, I'll attach killthread.pl at the bottom. This program is licensed
under the GNU General Public License, version 2.
Since I expect a lot of flamage to follow this posting, I have invoked
killthread.pl on my own message.
Regards,
David.
#!/usr/bin/perl
#***********************************************************************
#
# killthread.pl
#
# Kills entire threads on mailing lists
#
# Copyright (C) 2001 Roaring Penguin Software Inc.
#
# This program may be distributed according to the terms of the GNU
# General Public License, version 2 or (at your option) any later version.
#
# $Id: killthread.pl,v 1.3 2001/02/19 20:00:08 dfs Exp $
#***********************************************************************
use DB_File;
use Fcntl ':flock';
# DB file
$DBFile = $ENV{"HOME"} . "/.deadthreads";
# Look-ahead line
$Lookahead = "";
$EOH = 0;
#***********************************************************************
# %PROCEDURE: addMessageID
# %ARGUMENTS:
# msgid -- message-ID to add to database
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Adds a message ID with today's date to the database.
#***********************************************************************
sub addMessageID {
my($msgid) = @_;
my($now) = time();
$Database{$msgid} = $now;
}
#***********************************************************************
# %PROCEDURE: readHeader
# %ARGUMENTS:
# None
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Reads a single header from stdin
#***********************************************************************
sub readHeader {
my($line);
my($tmp);
if ($EOH) {
return "";
}
while ($line = <STDIN>) {
chomp($line);
if ($line eq "") {
$line = $Lookahead;
$Lookahead = "";
$EOH = 1;
return $line;
}
if ($line =~ /^\s/) {
$Lookahead .= $line;
} else {
$tmp = $Lookahead;
$Lookahead = $line;
if ($tmp ne "") {
return $tmp;
}
}
}
$tmp = $Lookahead;
$Lookahead = $line;
return $tmp;
}
#***********************************************************************
# %PROCEDURE: killThisEmail
# %ARGUMENTS:
# None
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Reads an e-mail message from STDIN; extracts Message-ID; adds it to
# database.
#***********************************************************************
sub killThisEmail {
my($line);
my($mid);
$mid = "";
while(($line = readHeader()) ne "") {
next unless ($line =~ /^Message-ID: (\S+)/i);
$mid = $1;
last;
}
exit(1) if ($mid eq "");
$Database{$mid} = time();
exit(0);
}
#***********************************************************************
# %PROCEDURE: conditionallyKill
# %ARGUMENTS:
# None
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Reads an e-mail message from STDIN; if it belongs to a killed thread,
# then returns 1 and adds its message-ID to the database. Otherwise,
# returns 0.
#***********************************************************************
sub conditionallyKill {
my($line, $mid, $shouldKill);
my($id, @ids);
$mid = "";
$shouldKill = 0;
while(($line = readHeader()) ne "") {
if (($line =~ /^Message-ID:\s(<\S+>)/i)) {
$mid = $1;
}
if (($line =~ /^In-Reply-To:\s(<\S+>)/i)) {
if ($Database{$1}) {
$shouldKill = 1;
}
}
if (($line =~ /^References:\s(.*)/i)) {
@ids = split(/\s/, $1);
foreach $id (@ids) {
if ($Database{$id}) {
$shouldKill = 1;
}
}
}
}
exit(1) if ($mid eq "");
if ($shouldKill) {
$Database{$mid} = time();
}
exit(!$shouldKill);
}
#***********************************************************************
# %PROCEDURE: cleanDB
# %ARGUMENTS:
# days -- any entries older than "days" days are removed from databas.
# %RETURNS:
# Nothing
# %DESCRIPTION:
# Removes old message-ID's from the database.
#***********************************************************************
sub cleanDB {
my($days) = @_;
my($k, $v);
my(@toKill);
my($secs) = $days * 86400;
my($now) = time();
while (($k, $v) = each %Database) {
push @toKill, $k if (($now - $v) > $secs);
}
foreach $k (@toKill) {
delete $Database{$k};
}
exit(0);
}
# Main program:
# Invoke as:
# killthread.pl kill -- KILL thread starting with this e-mail.
# killthread.pl check -- conditionally kill this e-mail if it's part of a dead
# thread
# killthread.pl clean <days> -- Clean database.
tie %Database, 'DB_File', $DBFile;
# Lock the DB file
open(DB, "<$DBFile") or die "Can't open $DBFile: $!";
flock(DB, LOCK_EX);
killThisEmail() if ($ARGV[0] eq "kill");
conditionallyKill() if ($ARGV[0] eq "check");
cleanDB($ARGV[1]) if ($ARGV[0] eq "clean" && $ARGV[1] > 0);
print STDERR <<"EOF";
Usage: killthread.pl kill -- Kill thread starting with this e-mail
killthread.pl check -- Kill this e-mail if part of a dead thread
killthread.pl clean days -- Remove entries older than "days" days.
EOF
exit(0);
More information about the OCLUG
mailing list