#!/usr/bin/perl
#
# Author: Petter Reinholdtsen
# Date: 2005-12-28
# License: GNU Public License v2 or later
#
# Make it easier to report gmane messages as spam. List all new
# messages in a given group, and let the user mark a message as spam
# with a single keypress.
#
# Configuration is in ~/.gmanespam, with content like this:
# server news.gmane.org
# group gmane.linux.debian.devel.initscripts-ng
# group gmane.linux.debian.devel.java
#
# New version of this script is available from
#
use warnings;
use strict;
use Net::NNTP;
use LWP::UserAgent;
my $server = "news.gmane.org";
my $spamurl = "http://spam.gmane.org/{group}:{msgnum}";
# List of groups to process
my @groups;
# Msgnum of the last visited article in the key group.
my %grouplast;
my @configfiles = ("/etc/gmanespam", $ENV{HOME}."/.gmanespam");
my $statusfile = $ENV{HOME}."/.gmanespamrc";
loadconfig();
my $nntp = Net::NNTP->new($server);
unless ($nntp) {
print "error: Unable to connect to NNTP server '$server'.\n";
exit 1;
}
my $ua = LWP::UserAgent->new;
loadstatus($statusfile);
for my $group (@groups) {
process_gmane_group($group);
}
savestatus($statusfile);
$nntp->quit;
sub loadconfig {
for my $filename (@configfiles) {
open (CFG, "<$filename") || next;
while () {
chomp;
s/\#.*//g;
s/\s*$//g;
next if (/^$/);
$server = $1 if (m/^server (.+)$/);
$spamurl = $1 if (m/^spamurl (.+)$/);
push(@groups, $1) if (m/^group (.+)$/);
}
close(CFG);
}
}
sub loadstatus {
my $statusfile = shift;
open (STATUS, "<$statusfile");
while () {
chomp;
my ($groupname, $lastnum) = m/^(\S+): 1-(\d+)$/;
$grouplast{$groupname} = $lastnum;
}
close(STATUS);
}
sub savestatus {
my $statusfile = shift;
open(STATUS, ">$statusfile") || die "Unable to write to $statusfile";
for my $groupname (sort keys %grouplast) {
print STATUS "$groupname: 1-".$grouplast{$groupname}."\n";
}
close(STATUS);
}
sub process_gmane_group {
my $group = shift;
my ($msgcount, $msgfirst, $msglast, $groupname) = $nntp->group($group);
my $curmsgnum = $grouplast{$groupname};
my @spammsgs;
print "\n$groupname: $msgfirst -> $msglast ($msgcount)\n";
my $aktive = 1;
while ($aktive && ++$curmsgnum <= $msglast) {
print "\n[$curmsgnum/$msglast] ============ $groupname ===========\n";
my $headersref = $nntp->head($curmsgnum);
unless ($headersref) {
print "**** Message does not exist. Skipping.\n";
next;
}
my ($spam, $subject, $from) = process_header($headersref);
print "From: $from\n";
print "Subject: $subject\n";
if ($spam) {
print "**** Message already flagged as spam. Ignoring.\n";
next;
}
print "Non-spam/Spam/sKip/view Body/view Full/jump #/Help/Quit [N] ? ";
my $input = <>;
chomp $input;
$input = "\L$input";
if ("" eq $input || "n" eq $input) {
# Not spam, ignore
} elsif ("s" eq $input) {
# Report as spam
push(@spammsgs, $curmsgnum);
} elsif ("q" eq $input) {
print "Exiting\n";
savestatus($statusfile);
exit 0;
} elsif ($input =~ m/^(\d+)$/) {
$curmsgnum = $1 - 1;
$curmsgnum = $msglast if $curmsgnum > $msglast;
print "Jumping to message number $1\n";
next;
} elsif ("k" eq $input) {
# Skip this group and move to the next group
$aktive = 0;
} elsif ("f" eq $input) {
# View message header and body
my $articleref = $nntp->article($curmsgnum);
list_lines($articleref);
$curmsgnum--;
} elsif ("b" eq $input) {
# View message body
my $bodyref = $nntp->body($curmsgnum);
list_lines($bodyref);
$curmsgnum--;
} elsif ("h" eq $input) {
# print help
} else {
print STDERR "error: Unhandled choice '$input'\n";
}
}
if (@spammsgs) {
print "Submit changes? [yes] ";
my $input = <>;
chomp $input;
$input = "\L$input";
if ("" eq $input || "yes" eq $input) {
for my $msgnum (@spammsgs) {
report_spam($groupname, $msgnum);
}
}
}
$grouplast{$groupname} = --$curmsgnum;
print "Storing $curmsgnum as last read message in $groupname\n";
}
sub list_lines {
my $arrayref = shift;
for (@{$arrayref}) {
print " ", $_;
}
}
sub process_header {
my $headerref = shift;
my $subject;
my $from;
my $spam;
for (@{$headerref}) {
$from = $1 if m/^From: (.*)$/i;
$subject = $1 if m/^Subject: (.*)$/i;
$spam = 1 if m/Xref: .*gmane.spam.detected.*$/;
}
return ($spam, $subject, $from)
}
sub report_spam {
my ($groupname, $msgnum) = @_;
my $url = $spamurl;
$url =~ s/{group}/$groupname/g;
$url =~ s/{msgnum}/$msgnum/g;
my $response = $ua->get($url);
if ($response->is_success) {
print "Reported $groupname:$msgnum as spam.\n";
} else {
die $response->status_line;
}
}