#!/usr/bin/perl
#
# threadkiller - kills any usenet thread started by specific posters.
#
# Copyright Paul Dwerryhouse <paul@dwerryhouse.com.au> 2007.
#
# This program is free software.  You may redistribute it and/or
# modify it under the terms of The GNU General Public License, as published 
# by the Free Software Foundation.
#          
# config files:
#
# $HOME/.threadkiller/names - list of names to blacklist (copy the entire
# 	From: line, without the 'From: ' itself)
# $HOME/.threadkiller/groups - list of newsgroups to apply blacklist to,
# 	one per line.
#
# This program requires nn and leafnode. Run from cron regularly (preferably
# just after leadnode sucks news down from the server). Append the output of
# this script onto your $HOME/.nn/kill file.
#

$SPOOL="/var/spool/news";
$HOME=$ENV{"HOME"};

$GROUPS="$SPOOL/interesting.groups";
$KILLNAMES="$HOME/.threadkiller/names";
$KILLGROUPS="$HOME/.threadkiller/groups";
$MAX="$HOME/.threadkiller/max";

opendir(GROUPS,$GROUPS);
@groups = grep { ! /^\./ && -f "$GROUPS/$_" } readdir(GROUPS);
closedir(GROUPS);

foreach $group (@groups) {
	$group{$group} = 1;
}

open(MAX,$MAX);

while(<MAX>) {
	chomp;
	($group,$max) = split(/ /,$_);
	$max{$group} = $max;
}

close(MAX);

open(KILLNAMES,$KILLNAMES);

while(<KILLNAMES>) {
	chomp;
	$kill{$_}=1;
}

close(KILLNAMES);

open(KILLGROUPS,$KILLGROUPS);

while(<KILLGROUPS>) {
	chomp;
	$killg{$_}=1;
}

close(KILLGROUPS);

foreach $group (keys(%group)) {
	$path = get_path($group);
	$max = $max{$group};
	if ( -d $path ) {
		opendir(DIR,$path);
		@files = grep { $_ > $max && /^[0-9]+$/ && -f "$path/$_" } readdir(DIR);
		closedir(DIR);

		foreach $file (@files) {
			($from,$subject) = read_article($group,$file);
			check_details($group,$from,$subject);
			$max = $file if ($file > $max);
		}
		$max{$group} = $max;
	}
}

open(MAX,">$MAX");

foreach $group (sort(keys(%max))) {
	printf MAX "%s %d\n", $group, $max{$group};
}

close(MAX);

sub get_path {
	my ($group) = @_;

	$group =~ s/\./\//g;

	return $SPOOL . "/" . $group;
}

sub check_details {
	my($group,$from,$subject) = @_;
	
	return if ($subject =~ /^Re: /);

	if (defined($kill{$from})) {
		my $time = time + 5184000;
		$subject =~ s/:/\\:/g;
		print "$time:$group:!s=:$subject\n";
	}

	elsif ( $from =~ /<(.*)>/ ) {
		if (defined($kill{$1})) {
			my $time = time + 5184000;
			$subject =~ s/:/\\:/g;
			print "$time:$group:!s=:$subject\n";
		}
	}
}

sub read_article {
	my($group,$number) = @_;
	my $file = get_path($group) . "/" . $number;

	my $subject, $from;

	open(FILE,$file);

	while(<FILE>) {
		if ( /^Subject: (.*)$/ ) {
			$subject = $1;
		}
		if ( /^From: (.*)$/ ) {
			$from = $1;
		}
		last if (/^$/);
	}

	close(FILE);

	return ($from,$subject);
}
