Mail-Decency

 view release on metacpan or  search on metacpan

lib/Mail/Decency/Policy/Greylist.pm  view on Meta::CPAN

    $self->scoring_aware( 1 )
        if $self->config->{ scoring_aware };
    
    return;
}


=head2 handle

=cut

sub handle {
    my ( $self, $server, $attrs_ref ) = @_;
    
    # don bother with loopback addresses! EVEN IF ENABLED BY FORCE!
    #return if is_local_host( $attrs_ref->{ client_address } );
    
    #
    # CACHES
    #
    
    my @caches = ();
    
    # is on sender->recipient cache (has been send less then min-interval before ?!
    push @caches, "Greylist-SR-$attrs_ref->{ sender_address }-$attrs_ref->{ recipient_address }";
    push @caches, "Greylist-H-$attrs_ref->{ client_address }";
    push @caches, "Greylist-D-$attrs_ref->{ sender_domain }";
    
    my $pass = 0;
    foreach my $cache( @caches ) {
        my $cached = $self->cache->get( $cache );
        if ( $cached && ( $cached eq 'OK' || $cached - $self->min_interval <= time() ) ) {
            $pass++;
            last;
        }
    }
    
    # update databases
    unless ( $pass ) {
        $pass = $self->update_pass( $attrs_ref );
    }
    
    # pass
    if ( $pass ) {
        $self->go_final_state( $self->pass_code ) if $self->pass_code !~ /^(DUNNO|PREPEND)/;
    }
    else {
        
        # or not..
        $self->go_final_state( 450 => $self->reject_message )
    }
}


=head2 update_pass

Add counters to pass databases

=cut

sub update_pass {
    my ( $self, $attrs_ref ) = @_;
    
    my $pass = 0;
    
    # use host and domain whitelisting only if we don't care for hosting
    #   or the score of the mail looks like hame
    #   remark: in context with SPF beforehand we will not add sender
    #   domains or hosts to the whitelist if the look somewhat bogus
    if ( ! $self->scoring_aware || $self->session_data->spam_score >= 0 ) {
        
        my @update_policy;
        push @update_policy, [ hosts => client_address => 'H' ]
            if $self->has_hosts_policy;
        push @update_policy, [ domains => sender_domain => 'D' ]
            if $self->has_domains_policy;
        
        foreach my $ref( @update_policy ) {
            my ( $policy, $attr, $cache ) = @$ref;
            
            # read existing data .. attr: client_address | sender_domain
            my $data_ref = $self->database->get( greylist => $attr => {
                $attr => $attrs_ref->{ $attr }
            } ) || {
                total         => 0,
                max_unique    => 0,
                max_one       => 0,
                unique_sender => {},
                last_seen     => time()
            };
            
            # convert unique sender to hashref, if given in YAML
            eval {
                $data_ref->{ unique_sender } = YAML::Load( $data_ref->{ unique_sender } )
                    unless ref( $data_ref->{ unique_sender } );
            };
            $data_ref->{ unique_sender } = {} if $@;
            
            # increment total
            $data_ref->{ total }++;
            
            # increment unique sender policy
            unless ( $data_ref->{ unique_sender }->{ $attrs_ref->{ sender_address } }++ ) {
                $data_ref->{ max_unique }++;
            }
            
            # determine MAX "send by one sender"
            ( $data_ref->{ max_one } ) = sort { $b <=> $a } values %{ $data_ref->{ unique_sender } };
            
            # write  back
            $self->logger->debug3( "Write to $attr database: $attrs_ref->{ $attr }" );
            $self->database->set( greylist => $attr => {
                $attr => $attrs_ref->{ $attr }
            }, $data_ref );
            
            # write to cache if positive
            my $policy_meth = "${policy}_policy";
            my $do_cache = (
                $self->$policy_meth->{ unique_sender }
                && $self->$policy_meth->{ unique_sender } <= $data_ref->{ max_unique }
            ) || (



( run in 2.815 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )