You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@spamassassin.apache.org by Justin Mason <jm...@jmason.org> on 2006/01/04 02:06:31 UTC

Re: defining new rule types

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


"John Myers" writes:
> Justin Mason wrote:
> > Agreed that adding new rule types is *doable*, if not exactly intuitive.
> >
> >I've done it in the URIBL code, by simply adding eval rules on the fly,
> >and that seems to work OK.   It'd be nice to have a more intuitive method,
> >though.
> >
> I just call PerMsgStatus::got_pattern_hit() from the plugin's 
> parsed_metadata().  I suppose I'm missing the syntax checks and other 
> minor things done by Conf::Parser::add_test().
> 
> >>The one area that could 
> >>use work is in providing the default score.
> >
> >how so?  do you mean having a score of != 1.0, by default?
> >
> It appears that since my new type of rules never appear in 
> $conf->{tests}, they never get assigned a default score.

aha.  OK, the eval-rules trick works to avoid that issue. What you do
is...

1. Define the subroutine to parse the configuration settings for that new
rule type:

  my @cmds = ();

  push (@cmds, {
    setting => 'mimeheader',
    code => sub {
      my ($self, $key, $value, $line) = @_;

      [... parse the line of text]
      [... see next step]
        
    }
  });

  $conf->{parser}->register_commands(\@cmds);


2. In that config-parse callback, define and register an eval rule
*on the fly*, once the rule is parsed:

      my $evalfn = "_mimeheader_eval_$rulename";
      $evalfn =~ s/[^a-zA-Z0-9_]/_/gs;

      $self->{parser}->add_test($rulename, $evalfn."()",
                $Mail::SpamAssassin::Conf::TYPE_BODY_EVALS);
      my $evalcode = '
        sub Mail::SpamAssassin::Plugin::MIMEHeader::'.$evalfn.' {
          $_[0]->eval_hook_called($_[1], q{'.$rulename.'});
        }
      ';

      eval $evalcode;
      if ($@) {
        warn "mimeheader: plugin error: $@";
        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
      }

      $pluginobj->register_eval_rule($evalfn);


($Mail::SpamAssassin::Conf::TYPE_BODY_EVALS was chosen above, simply
because it's an eval type in an area of the message *similar* to what the
new rule type covers -- the body.)


3. In the plugin, define an eval_hook_called() method to deal with
implementing what the code does.

  sub eval_hook_called {
    my ($pobj, $scanner, $rulename) = @_;

    my $rule = $scanner->{conf}->{mimeheader_tests}->{$rulename};
    [... do stuff]

    return $match ? 1 : 0;
  }


Calling got_hit(), getting the right scores, etc. can then be left
to PerMsgStatus, as with a bundled rule.

This is based on lib/Mail/SpamAssassin/Plugin/MIMEHeader.pm ; take a look
at that for more.


> I do happen to need some of my newly defined tests to have a default 
> score of 0.  For example, suppose there are two lines in the .cf file 
> using a new rule type "foo":
> 
> foo BAR baz
> foo BAR quux
> 
> If a message matches either condition "baz" or "quux" (or both) then it 
> will fire the test BAR, which should have a default score of 1.  In 
> order to record the specific condition that caused BAR to be triggered, 
> it will also fire FOO_baz if "foo" was matched and/or fire FOO_quux if 
> "quux" was matched.  These latter tests are not intended to be weighted, 
> so should be assigned a default score of 0.  It may be worthwhile to 
> define a new prefix, e.g. "I_" for such informational tests.

sounds like a meta subrule: __FOO_baz.   Or am I missing something?

- --j.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Exmh CVS

iD8DBQFDux+XMJF5cimLx9ARAkg+AJ9yIhrAbFhb7IwbFnZeopF00B2yYQCeOtoE
UxRdAB0xv+SqJYfcuFbSruE=
=SUbh
-----END PGP SIGNATURE-----


Re: defining new rule types

Posted by John Myers <jg...@proofpoint.com>.
Justin Mason wrote:

> 2. In that config-parse callback, define and register an eval rule
>
>*on the fly*, once the rule is parsed:
>  
>
This isn't appropriate for my rule types.  I don't want to iterate over 
each possible rule definition, I want to do lookups in hash tables.

>sounds like a meta subrule: __FOO_baz.   Or am I missing something?
>  
>
Unlike subrules, I want the hit to be included in the list returned by 
PerMsgStatus::get_names_of_tests_hit().  The whole purpose of FOO_baz is 
to be visible, making diagnosis easier.