message de-duping in an exim filter

nicholas on 2007-01-07T16:19:44

Following on from my previous entry, here's what I've put in place:

exim filter file
if ${readsocket{$home/var/seendb.sock}{$h_Message-ID:}} is "seen\n" then
  save $home/Mail/duplicates 0600
  logwrite " Folder: $home/Mail/duplicates"
  finish
endif
Perl daemon
#!/home/nick/bin/perl -w
use strict;
use Net::Server::Single;
use Fcntl;
use NDBM_File;

use vars qw(@ISA $timeout %seendb $prefix $log);

@ISA = 'Net::Server::Single';
$timeout = 5;
$prefix = "$ENV{HOME}/var/seendb";
$log = "$prefix.log";

tie %seendb, 'NDBM_File', $prefix, O_RDWR|O_CREAT, 0666
    or die "Couldn't tie NDBM file $prefix: $!; aborting";

my $self = main->new({
    port => "$prefix.sock|unix",
    user => $<, group => 0 + $(,
    pid_file => "$prefix.pid",
    @ARGV ? () : (log_file => $log, setsid => 1),
});
$self->run();
exit;


sub process_request {
    my $self = shift;
    local $SIG{ALRM} = sub { die "Timed Out!\n" };
    my $id;
    unless (eval {
        my $previous_alarm = alarm $timeout;
        sysread STDIN, $id, 1024 or die "Bad read: $!";
        alarm $previous_alarm;
        1;
    }) {
        $self->log(1, "Erk: $@");
        return;
    }
    chomp $id;
    if ($seendb{$id}) {
        print "seen\n";
    } else {
        $seendb{$id} = pack "N", time;
        print "new\n";
    }
}

At some point it will be upgraded to support a command to prune the NDBM file, but right now that's still only 16K, so I'm not that worried. During testing, it pleased me to discover that FreeBSD's telnet accepts a pathname as an address to connect to. telnet /home/nick/var/seendb.sock works. :-)