--- /dev/null
+#!/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
+# <URL:http://www.student.uit.no/~pere/linux/>
+
+use warnings;
+use strict;
+
+use Net::NNTP;
+use LWP::UserAgent;
+
+my $server = "news.gmane.org";
+
+# 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 (<CFG>) {
+ chomp;
+ s/\#.*//g;
+ s/\s*$//g;
+ next if (/^$/);
+ $server = $1 if (m/^server (.+)$/);
+ push(@groups, $1) if (m/^group (.+)$/);
+ }
+ close(CFG);
+ }
+}
+
+sub loadstatus {
+ my $statusfile = shift;
+ open (STATUS, "<$statusfile");
+ while (<STATUS>) {
+ 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";
+
+ while (++$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/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;
+ } else {
+ print STDERR "error: Unhandled choice '$input'\n";
+ }
+ }
+ for my $msgnum (@spammsgs) {
+ report_spam($groupname, $msgnum);
+ }
+ $grouplast{$groupname} = --$curmsgnum;
+ print "Storing $curmsgnum as last read message in $groupname\n";
+}
+
+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) = @_;
+ # Visit http://spam.gmane.org/gmane.linux.debian.devel.lsb:253
+ my $response = $ua->get("http://spam.gmane.org/$groupname:$msgnum");
+ if ($response->is_success) {
+ print "Reported $groupname:$msgnum as spam.\n";
+ } else {
+ die $response->status_line;
+ }
+}