=head1 NAME
-Debbugs::Log::Spam -- an interface to debbugs .log.spam files
+Debbugs::Log::Spam -- an interface to debbugs .log.spam files and .log.spam.d
+directories
=head1 SYNOPSIS
=head1 DESCRIPTION
+Spam in bugs can be excluded using a .log.spam file and a .log.spam.d directory.
+The file contains message ids, one per line, and the directory contains files
+named after message ids, one per file.
=head1 BUGS
use Carp;
use feature 'state';
use Params::Validate qw(:types validate_with);
-use Debbugs::Common qw(getbuglocation getbugcomponent);
+use Debbugs::Common qw(getbuglocation getbugcomponent filelock unfilelock);
=head1 FUNCTIONS
chomp;
$self->{spam}{$_} = 1;
}
- close ($fh);
+ close ($fh) or
+ croak "Unable to close bug log filehandle: $!";
+ }
+ if (-d $self->{name}.'.d') {
+ opendir(my $d,$self->{name}.'.d') or
+ croak "Unable to open bug log spamdir '$self->{name}.d' for reading: $!";
+ for my $dir (readdir($d)) {
+ next unless $dir =~ m/([^\.].*)_(\w+)$/;
+ $self->{spam}{$1} = 1;
+ }
+ closedir($d) or
+ croak "Unable to close bug log spamdir: $!";
}
return $self;
}
sub save {
my $self = shift;
- filelock($self->{name});
+ return unless keys %{$self->{spam}};
+ filelock($self->{name}.'.lock');
open(my $fh,'>',$self->{name}.'.tmp') or
croak "Unable to open bug log spam '$self->{name}.tmp' for writing: $!";
binmode($fh,':encoding(UTF-8)');
=cut
sub is_spam {
my ($self,$msgid) = @_;
+ return 0 if not defined $msgid or not length $msgid;
$msgid =~ s/^<|>$//;
if (exists $self->{spam}{$msgid} and
$self->{spam}{$msgid}