Email::Fingerprint::App::EliminateDups - Implements eliminate-dups functionality


Email-Fingerprint documentation Contained in the Email-Fingerprint distribution.

Index


Code Index:

NAME

Top

Email::Fingerprint::App::EliminateDups - Implements eliminate-dups functionality

VERSION

Top

Version 0.26

SYNOPSIS

Top

See the manpage for eliminate-dups. This module is not intended to be used except by that script.

METHODS

Top

new

  $app = new Email::Fingerprint::App::EliminateDups;

Create a new object. Takes no options.

BUILD

Internal helper method, not called by external users.

run

  $app->run(@ARGV);

Run the eliminate-dups application.

open_cache

Initialize, open and lock the cache.

close_cache

Close and unlock the cache.

dump_cache

Conditionally dump the cache contents and exit.

check_fingerprint

Conditionally check the fingerprint of the message on STDIN.

purge_cache

Purge the cache of old entries.

_process_options

Process command-line options.

_init

Basic initializer. Called from BUILD and also from _process_options.

die_usage

Exit with a usage message.

_exit_retry

Exit with qmail's "temporary error" status code. This forces qmail to abort delivery attempts and try again later.

AUTHOR

Top

Len Budney, <lbudney at pobox.com>

BUGS

Top

Please report any bugs or feature requests to bug-email-fingerprint at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Email-Fingerprint. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

Top

You can find documentation for this module with the perldoc command.

    perldoc Email::Fingerprint

You can also look for information at:

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/Email-Fingerprint

* CPAN Ratings

http://cpanratings.perl.org/d/Email-Fingerprint

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=Email-Fingerprint

* Search CPAN

http://search.cpan.org/dist/Email-Fingerprint

SEE ALSO

Top

See Mail::Header for options governing the parsing of email headers.

ACKNOWLEDGEMENTS

Top

Email::Fingerprint is based on the eliminate_dups script by Peter Samuel and available at http://www.qmail.org/.

COPYRIGHT & LICENSE

Top


Email-Fingerprint documentation Contained in the Email-Fingerprint distribution.
package Email::Fingerprint::App::EliminateDups;

use warnings;
use strict;

use Class::Std;

use Carp qw( croak );
use File::Basename;
use Getopt::Long;

use Email::Fingerprint;
use Email::Fingerprint::Cache;

our $VERSION = '0.26';

# Attributes

my %dbname      : ATTR( :get<dbname> );                 # Fingerprint DB name
my %cache       : ATTR( :get<cache> );                  # Actual fingerprint DB

my %dump        : ATTR( :get<dump>,     :default<0> );  # Dump cache contents
my %help        : ATTR( :get<help>,     :default<0> );  # Print usage
my %no_check    : ATTR( :get<no_check>, :default<0> );  # Only purge
my %no_purge    : ATTR( :get<no_purge>, :default<0> );  # Only check
my %strict      : ATTR( :get<strict>,   :default<0> );  # Include body

sub BUILD {
    my ($self, $obj_ID, $arg_ref) = @_;

    $self->_init;
}

sub run {
    my $self = shift;

    $self->_process_options(@_);
    $self->open_cache;
    $self->dump_cache;              # No-op if --dump wasn't specified
    $self->check_fingerprint;       # No-op if --no-check option was specified
    $self->purge_cache;             # No-op if --no-purge option was specified
    $self->close_cache;

    # Success
    exit 0;
}

sub open_cache {
    my $self   = shift;
    my $cache  = $self->get_cache;
    my $dbname = $self->get_dbname || '';

    return $cache if $cache;

    # Initialize the cache
    $cache    = new Email::Fingerprint::Cache({
        file     => $dbname,
    });

    # Validate
    if ( not $cache ) {
        $self->_exit_retry( "Couldn't initialize cache \"$dbname\"" );
    }

    # Lock it
    if ( not $cache->lock( block => 1 ) ) {
        $self->_exit_retry( "Couldn't lock \"$dbname\": $!" );
    }

    # Open it
    if ( not $cache->open ) {
        $cache->unlock;
        $self->_exit_retry( "Couldn't open \"$dbname\": $!" );
    }

    $cache{ ident $self } = $cache;
    return $cache;
}

sub close_cache {
    my $self  = shift;
    my $cache = delete $cache{ ident $self };

    if ($cache) {
        $cache->unlock;
        $cache->close;
    }

    1;
}

sub dump_cache {
    my $self = shift;

    return unless $self->get_dump;
    return unless $self->get_cache;

    # Dump the contents of the hashfile in a human readable format
    $self->get_cache->dump;

    $self->close_cache;
    exit 0;
}

sub check_fingerprint {
    my $self = shift;

    return if $self->get_no_check;

    my $checksum =  new Email::Fingerprint({
        input           => \*STDIN,
        checksum        => "Digest::MD5",
        strict_checking => $self->get_strict,
    });

    my $fingerprint = $checksum->checksum;

    # If there's a match, suppress it with exit code 99.
    if (defined $self->get_cache->get_hash->{$fingerprint})
    {
        # Fingerprint matches. Tell qmail to stop current delivery.
        $self->close_cache;
        exit 99;
    }

    # Record the fingerprint
    $self->get_cache->get_hash->{$fingerprint} = time;
}

sub purge_cache {
    my $self = shift;
    
    return if $self->get_no_purge;

    $self->get_cache->purge;
}

sub _process_options :PRIVATE {
    my ( $self, @args ) = @_;

    # Fool Getopt::Long. Sigh.
    local @ARGV = @args;

    $self->_init;

    $self->_die_usage if not GetOptions(
        "dump"      => \$dump{ident $self},
        "no-purge"  => \$no_purge{ident $self},
        "no-check"  => \$no_check{ident $self},
        "strict"    => \$strict{ident $self},
        "help"      => \$help{ident $self},
    );

    # Respond to calls for help
    $self->_die_usage if $self->get_help;

    # Set the filename. If omitted, a default is used.
    $dbname{ident $self} = shift @ARGV if @ARGV;
}

sub _init :PRIVATE {
    my $self   = shift;
    my $obj_ID = ident $self;

    $dbname{$obj_ID}   = '.maildups';
    $self->close_cache; # A no-op if we don't have a cache yet

    $dump{$obj_ID}     = 0;
    $help{$obj_ID}     = 0;
    $no_purge{$obj_ID} = 0;
    $no_check{$obj_ID} = 0;
    $strict{$obj_ID}   = 0;
}

sub _die_usage :PRIVATE {
    my $self     = shift;
    my $progname = basename $0;

    $self->_exit_retry(
         "usage:\t$progname [--strict] [--no-purge] [hashfile]\n"
       . "\t$progname [--dump] [hashfile]\n"
       . "\t$progname [--no-check] [hashfile]"
    );
}

sub _exit_retry :PRIVATE {
    my ( $self, $message ) = @_;

    warn "$message\n";
    exit 111;
}

1; # End of Email::Fingerprint