Courier-Filter

 view release on metacpan or  search on metacpan

lib/Courier/Filter.pm  view on Meta::CPAN

A boolean value controlling whether the I<whole> filter process should run in
"testing" mode.  In testing mode, planned message rejections will be logged as
usual, but no messages will actually be rejected.  Defaults to B<false>.

NOTE:  You may also enable testing mode on individual filter module objects,
see L<Courier::Filter::Module/"new">.  Enabling testing mode globally is not
the same as individually enabling testing mode on all filter modules, though.
When global testing mode is enabled, Courier::Filter only ignores the I<final>
result, but still follows the rules of the normal consideration process, e.g.
aborting as soon as a filter module states an B<explicit reject>, etc.  When an
individual filter module is in testing mode, its I<individual> result is
ignored, and the consideration process is continued with the next filter
module.  So individually enabling testing mode on all filter modules allows you
to thoroughly test the correctness and performance of all installed filter
modules, or even to gather stochastically indepent statistics on the hit/miss
rates of your filter modules.

=item B<debugging>

A boolean value controlling whether extra debugging information should be
logged by Courier::Filter.  Defaults to B<false>.  You need to enable debugging
mode for filter modules separately.

=for comment
TODO: Filter modules' debugging mode should really default to Courier::Filter's
global debugging mode.

=back

=cut

sub new {
    my ($class, %options) = @_;
    
    $0 =~ m{([^/]+)$};
    my $name        = $options{name} || $1;
    my $mandatory   = defined($options{mandatory}) ? $options{mandatory} : TRUE;
    my $threads     = $options{threads};
    my $logger      = $options{logger};
    my $modules     = [ @{$options{modules}} ] || [];
    my $trusting    = $options{trusting};
    my $testing     = $options{testing};
    my $debugging   = $options{debugging};
    
    my $socket_dir =
        Courier::Config->runtime_dir . '/' .
        ( $mandatory ? 'allfilters' : 'filters' );
    my $socket_dir_unused =
        Courier::Config->runtime_dir . '/' .
        ( !$mandatory ? 'allfilters' : 'filters' );
    
    my $socket_prename          = "$socket_dir/.$name";
    my $socket_name             = "$socket_dir/$name";
    my $socket_prename_unused   = "$socket_dir_unused/.$name";
    my $socket_name_unused      = "$socket_dir_unused/$name";
    
    if (-e $socket_name) {
        -S $socket_name
            or throw Courier::Error("$socket_name already exists but is not a socket");
        
        # Try to connect to socket to see if it is alive or
        # if it is left over from a crashed Courier::Filter:
        my $test_socket = IO::Socket::UNIX->new( Peer => $socket_name );
        
        not defined($test_socket)
            or throw Courier::Error("Live socket $socket_name found -- is Courier::Filter already running?");
        
        # Socket exists but is dead. Remove it:
        unlink($socket_name);
    }
    
    unlink($socket_prename);
    unlink($socket_prename_unused);
    unlink($socket_name_unused);
    
    my $socket = IO::Socket::UNIX->new(
        Local   => $socket_prename,
        Listen  => SOMAXCONN
    )
        or  throw Courier::Error("Unable to create socket $socket_prename");
    
    rename($socket_prename, $socket_name)
        or  unlink($socket_prename),
            throw Courier::Error("Unable to rename socket $socket_prename to $socket_name");
    
    chmod(0660, $socket_name)
        or  throw Courier::Error("Unable to chmod socket $socket_name");
    
    IO::Handle->new_from_fd(3, '>')->close();
    
    my $filter = {
        name        => $name,
        mandatory   => $mandatory,
        threads     => $threads,
        logger      => $logger,
        modules     => $modules,
        trusting    => $trusting,
        testing     => $testing,
        debugging   => $debugging,
        socket      => $socket,
        socket_name => $socket_name,
        terminate   => FALSE
    };
    
    return bless($filter, $class);
}

=back

=begin comment

=head2 Destructor

The following destructor is provided:

=over

=item B<destroy>

Removes the courierfilter socket when the B<Courier::Filter> object is
destroyed.  There is no need to call this explicitly.



( run in 2.542 seconds using v1.01-cache-2.11-cpan-98e64b0badf )