home *** CD-ROM | disk | FTP | other *** search
/ ftp.f-secure.com / 2014.06.ftp.f-secure.com.tar / ftp.f-secure.com / support / hotfix / fsis / IS-SpamControl.fsfix / iufssc / lib / Mail / SpamAssassin / Plugin.pm < prev    next >
Text File  |  2006-11-29  |  20KB  |  799 lines

  1. # <@LICENSE>
  2. # Licensed to the Apache Software Foundation (ASF) under one or more
  3. # contributor license agreements.  See the NOTICE file distributed with
  4. # this work for additional information regarding copyright ownership.
  5. # The ASF licenses this file to you under the Apache License, Version 2.0
  6. # (the "License"); you may not use this file except in compliance with
  7. # the License.  You may obtain a copy of the License at:
  8. #     http://www.apache.org/licenses/LICENSE-2.0
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # </@LICENSE>
  15.  
  16. =head1 NAME
  17.  
  18. Mail::SpamAssassin::Plugin - SpamAssassin plugin base class
  19.  
  20. =head1 SYNOPSIS
  21.  
  22. =head2 SpamAssassin configuration:
  23.  
  24.   loadplugin MyPlugin /path/to/myplugin.pm
  25.  
  26. =head2 Perl code:
  27.  
  28.   package MyPlugin;
  29.  
  30.   use Mail::SpamAssassin::Plugin;
  31.   our @ISA = qw(Mail::SpamAssassin::Plugin);
  32.  
  33.   sub new {
  34.     my ($class, $mailsa) = @_;
  35.     
  36.     # the usual perlobj boilerplate to create a subclass object
  37.     $class = ref($class) || $class;
  38.     my $self = $class->SUPER::new($mailsa);
  39.     bless ($self, $class);
  40.    
  41.     # then register an eval rule, if desired...
  42.     $self->register_eval_rule ("check_for_foo");
  43.  
  44.     # and return the new plugin object
  45.     return $self;
  46.   }
  47.  
  48.   ...methods...
  49.  
  50.   1;
  51.  
  52. =head1 DESCRIPTION
  53.  
  54. This is the base class for SpamAssassin plugins; all plugins must be objects
  55. that implement this class.
  56.  
  57. This class provides no-op stub methods for all the callbacks that a plugin
  58. can receive.  It is expected that your plugin will override one or more
  59. of these stubs to perform its actions.
  60.  
  61. SpamAssassin implements a plugin chain; each callback event is passed to each
  62. of the registered plugin objects in turn.  Any plugin can call
  63. C<$self-E<gt>inhibit_further_callbacks()> to block delivery of that event to
  64. later plugins in the chain.  This is useful if the plugin has handled the
  65. event, and there will be no need for later plugins to handle it as well.
  66.  
  67. If you're looking to write a simple eval rule, skip straight to 
  68. C<register_eval_rule()>, below.
  69.  
  70. =head1 INTERFACE
  71.  
  72. In all the plugin APIs below, C<options> refers to a reference to a hash
  73. containing name-value pairs.   This is used to ensure future-compatibility, in
  74. that we can add new options in future without affecting objects built to an
  75. earlier version of the API.
  76.  
  77. For example, here would be how to print out the C<line> item in a
  78. C<parse_config()> method:
  79.  
  80.   sub parse_config {
  81.     my ($self, $opts) = @_;
  82.     print "MyPlugin: parse_config got ".$opts->{line}."\n";
  83.   }
  84.  
  85. =head1 METHODS
  86.  
  87. The following methods can be overridden by subclasses to handle events
  88. that SpamAssassin will call back to:
  89.  
  90. =over 4
  91.  
  92. =cut
  93.  
  94. package Mail::SpamAssassin::Plugin;
  95.  
  96. use Mail::SpamAssassin;
  97. use Mail::SpamAssassin::Logger;
  98.  
  99. use strict;
  100. use warnings;
  101. use bytes;
  102.  
  103. use vars qw{
  104.   @ISA $VERSION
  105. };
  106.  
  107. @ISA =                  qw();
  108. $VERSION =              'bogus';
  109.  
  110. ###########################################################################
  111.  
  112. =item $plugin = MyPluginClass->new ($mailsaobject)
  113.  
  114. Constructor.  Plugins that need to register themselves will need to
  115. define their own; the default super-class constructor will work fine
  116. for plugins that just override a method.
  117.  
  118. Note that subclasses must provide the C<$mailsaobject> to the
  119. superclass constructor, like so:
  120.  
  121.   my $self = $class->SUPER::new($mailsaobject);
  122.  
  123. Lifecycle note: plugins that will need to store per-scan state should not store
  124. that on the Plugin object; see C<check_start()> below.  It is also likewise
  125. recommended that configuration settings be stored on the Conf object; see
  126. C<parse_config()>.
  127.  
  128. =cut
  129.  
  130. sub new {
  131.   my $class = shift;
  132.   my $mailsaobject = shift;
  133.   $class = ref($class) || $class;
  134.  
  135.   if (!defined $mailsaobject) {
  136.     die "plugin: usage: Mail::SpamAssassin::Plugin::new(class,mailsaobject)";
  137.   }
  138.  
  139.   my $self = {
  140.     main => $mailsaobject,
  141.     _inhibit_further_callbacks => 0
  142.   };
  143.   bless ($self, $class);
  144.   $self;
  145. }
  146.  
  147. # ---------------------------------------------------------------------------
  148. # now list the supported methods we will call into.  NOTE: we don't have
  149. # to implement them here, since the plugin can use "can()" to introspect
  150. # the object and determine if it's capable of calling the method anyway.
  151. # Nifty!
  152.  
  153. =item $plugin->parse_config ( { options ... } )
  154.  
  155. Parse a configuration line that hasn't already been handled.  C<options>
  156. is a reference to a hash containing these options:
  157.  
  158. =over 4
  159.  
  160. =item line
  161.  
  162. The line of configuration text to parse.   This has leading and trailing
  163. whitespace, and comments, removed.
  164.  
  165. =item key
  166.  
  167. The configuration key; ie. the first "word" on the line.
  168.  
  169. =item value
  170.  
  171. The configuration value; everything after the first "word" and
  172. any whitespace after that.
  173.  
  174. =item conf
  175.  
  176. The C<Mail::SpamAssassin::Conf> object on which the configuration
  177. data should be stored.
  178.  
  179. =item user_config
  180.  
  181. A boolean: C<1> if reading a user's configuration, C<0> if reading the
  182. system-wide configuration files.
  183.  
  184. =back
  185.  
  186. If the configuration line was a setting that is handled by this plugin, the
  187. method implementation should call C<$self-E<gt>inhibit_further_callbacks()>.
  188.  
  189. If the setting is not handled by this plugin, the method should return C<0> so
  190. that a later plugin may handle it, or so that SpamAssassin can output a warning
  191. message to the user if no plugin understands it.
  192.  
  193. Lifecycle note: it is suggested that configuration be stored on the
  194. C<Mail::SpamAssassin::Conf> object in use, instead of the plugin object itself.
  195. That can be found as C<$plugin-E<gt>{main}-E<gt>{conf}>.   This allows per-user and
  196. system-wide configuration to be dealt with correctly, with per-user overriding
  197. system-wide.
  198.  
  199. =item $plugin->finish_parsing_end ( { options ... } )
  200.  
  201. Signals that the configuration parsing has just finished, and SpamAssassin
  202. is nearly ready to check messages.
  203.  
  204. C<options> is a reference to a hash containing these options:
  205.  
  206. =over 4
  207.  
  208. =item conf
  209.  
  210. The C<Mail::SpamAssassin::Conf> object on which the configuration
  211. data should be stored.
  212.  
  213. =back
  214.  
  215. Note: there are no guarantees that the internal data structures of
  216. SpamAssassin will not change from release to release.  In particular to
  217. this plugin hook, if you modify the rules data structures in a
  218. third-party plugin, all bets are off until such time that an API is
  219. present for modifying that configuration data.
  220.  
  221. =item $plugin->signal_user_changed ( { options ... } )
  222.  
  223. Signals that the current user has changed for a new one.
  224.  
  225. =over 4
  226.  
  227. =item username
  228.  
  229. The new user's username.
  230.  
  231. =item user_dir
  232.  
  233. The new user's home directory. (equivalent to C<~>.)
  234.  
  235. =item userstate_dir
  236.  
  237. The new user's storage directory. (equivalent to C<~/.spamassassin>.)
  238.  
  239. =back
  240.  
  241. =item $plugin->services_authorized_for_username ( { options ... } )
  242.  
  243. Validates that a given username is authorized to use certain services.
  244.  
  245. In order to authorize a user, the plugin should first check that it can
  246. handle any of the services passed into the method and then set the value
  247. for each allowed service to true (or any non-negative value).
  248.  
  249. The current supported services are: bayessql
  250.  
  251. =over 4
  252.  
  253. =item username
  254.  
  255. A username
  256.  
  257. =item services
  258.  
  259. Reference to a hash containing the services you want to check.
  260.  
  261. {
  262.  
  263.   'bayessql' => 0
  264.  
  265. }
  266.  
  267. =item conf
  268.  
  269. The C<Mail::SpamAssassin::Conf> object on which the configuration
  270. data should be stored.
  271.  
  272. =back
  273.  
  274. =item $plugin->check_start ( { options ... } )
  275.  
  276. Signals that a message check operation is starting.
  277.  
  278. =over 4
  279.  
  280. =item permsgstatus
  281.  
  282. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  283.  
  284. Lifecycle note: it is recommended that rules that need to track test state on a
  285. per-scan basis should store that state on this object, not on the plugin object
  286. itself, since the plugin object will be shared between all active scanners.
  287.  
  288. The message being scanned is accessible through the
  289. C<$permsgstatus-E<gt>get_message()> API; there are a number of other public
  290. APIs on that object, too.  See C<Mail::SpamAssassin::PerMsgStatus> perldoc.
  291.  
  292. =back
  293.  
  294. =item $plugin->extract_metadata ( { options ... } )
  295.  
  296. Signals that a message is being mined for metadata.  Some plugins may wish
  297. to add their own metadata as well.
  298.  
  299. =over 4
  300.  
  301. =item msg
  302.  
  303. The C<Mail::SpamAssassin::Message> object for this message.
  304.  
  305. =back
  306.  
  307. =item $plugin->parsed_metadata ( { options ... } )
  308.  
  309. Signals that a message's metadata has been parsed, and can now be
  310. accessed by the plugin.
  311.  
  312. =over 4
  313.  
  314. =item permsgstatus
  315.  
  316. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  317.  
  318. =back
  319.  
  320. =item $plugin->check_tick ( { options ... } )
  321.  
  322. Called periodically during a message check operation.  A callback set for
  323. this method is a good place to run through an event loop dealing with
  324. network events triggered in a C<parse_metadata> method, for example.
  325.  
  326. =over 4
  327.  
  328. =item permsgstatus
  329.  
  330. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  331.  
  332. =back
  333.  
  334. =item $plugin->check_post_dnsbl ( { options ... } )
  335.  
  336. Called after the DNSBL results have been harvested.  This is a good
  337. place to harvest your own asynchronously-started network lookups.
  338.  
  339. =over 4
  340.  
  341. =item permsgstatus
  342.  
  343. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  344.  
  345. =back
  346.  
  347. =item $plugin->check_post_learn ( { options ... } )
  348.  
  349. Called after auto-learning may (or may not) have taken place.  If you
  350. wish to perform additional learning, whether or not auto-learning
  351. happens, this is the place to do it.
  352.  
  353. =over 4
  354.  
  355. =item permsgstatus
  356.  
  357. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  358.  
  359. =back
  360.  
  361. =item $plugin->check_end ( { options ... } )
  362.  
  363. Signals that a message check operation has just finished, and the
  364. results are about to be returned to the caller.
  365.  
  366. =over 4
  367.  
  368. =item permsgstatus
  369.  
  370. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  371. The current score, names of rules that hit, etc. can be retrieved
  372. using the public APIs on this object.
  373.  
  374. =back
  375.  
  376. =item $plugin->autolearn_discriminator ( { options ... } )
  377.  
  378. Control whether a just-scanned message should be learned as either
  379. spam or ham.   This method should return one of C<1> to learn
  380. the message as spam, C<0> to learn as ham, or C<undef> to not
  381. learn from the message at all.
  382.  
  383. =over 4
  384.  
  385. =item permsgstatus
  386.  
  387. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  388.  
  389. =back
  390.  
  391. =item $plugin->autolearn ( { options ... } )
  392.  
  393. Signals that a message is about to be auto-learned as either ham or spam.
  394.  
  395. =over 4
  396.  
  397. =item permsgstatus
  398.  
  399. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  400.  
  401. =item isspam
  402.  
  403. C<1> if the message is spam, C<0> if ham.
  404.  
  405. =back
  406.  
  407. =item $plugin->per_msg_finish ( { options ... } )
  408.  
  409. Signals that a C<Mail::SpamAssassin::PerMsgStatus> object is being
  410. destroyed, and any per-scan context held on that object by this
  411. plugin should be destroyed as well.
  412.  
  413. Normally, any member variables on the C<PerMsgStatus> object will be cleaned up
  414. automatically -- but if your plugin has made a circular reference on that
  415. object, this is the place to break them so that garbage collection can operate
  416. correctly.
  417.  
  418. =over 4
  419.  
  420. =item permsgstatus
  421.  
  422. The C<Mail::SpamAssassin::PerMsgStatus> context object for this scan.
  423.  
  424. =back
  425.  
  426. =item $plugin->bayes_learn ( { options ... } )
  427.  
  428. Called at the end of a bayes learn operation.
  429.  
  430. This phase is the best place to map the raw (original) token value
  431. to the SHA1 hashed value.
  432.  
  433. =over 4
  434.  
  435. =item toksref
  436.  
  437. Reference to hash returned by call to tokenize.  The hash takes the
  438. format of:
  439.  
  440. {
  441.  
  442.   'SHA1 Hash Value' => 'raw (original) value'
  443.  
  444. }
  445.  
  446. NOTE: This data structure has changed since it was originally introduced
  447. in version 3.0.0.  The values are no longer perl anonymous hashes, they
  448. are a single string containing the raw token value.  You can test for
  449. backwards compatability by checking to see if the value for a key is a
  450. reference to a perl HASH, for instance:
  451.  
  452. if (ref($toksref->{$sometokenkey}) eq 'HASH') {...
  453.  
  454. If it is, then you are using the old interface, otherwise you are using
  455. the current interface.
  456.  
  457. =item isspam
  458.  
  459. Boolean value stating what flavor of message the tokens represent, if
  460. true then message was specified as spam, false is nonspam.  Note, when
  461. function is scan then isspam value is not valid.
  462.  
  463. =item msgid
  464.  
  465. Generated message id of the message just learned.
  466.  
  467. =item msgatime
  468.  
  469. Received date of the current message or current time if received date
  470. could not be determined.  In addition, if the receive date is more than
  471. 24 hrs into the future it will be reset to current datetime.
  472.  
  473. =back
  474.  
  475. =item $plugin->bayes_forget ( { options ... } )
  476.  
  477. Called at the end of a bayes forget operation.
  478.  
  479. =over 4
  480.  
  481. =item toksref
  482.  
  483. Reference to hash returned by call to tokenize.  See bayes_learn
  484. documentation for additional information on the format.
  485.  
  486. =item isspam
  487.  
  488. Boolean value stating what flavor of message the tokens represent, if
  489. true then message was specified as spam, false is nonspam.  Note, when
  490. function is scan then isspam value is not valid.
  491.  
  492. =item msgid
  493.  
  494. Generated message id of the message just forgotten.
  495.  
  496. =back
  497.  
  498. =item $plugin->bayes_scan ( { options ... } )
  499.  
  500. Called at the end of a bayes scan operation.  NOTE: Will not be
  501. called in case of error or if the message is otherwise skipped.
  502.  
  503. =over 4
  504.  
  505. =item toksref
  506.  
  507. Reference to hash returned by call to tokenize.  See bayes_learn
  508. documentation for additional information on the format.
  509.  
  510. =item probsref
  511.  
  512. Reference to hash of calculated probabilities for tokens found in
  513. the database.
  514.  
  515. {
  516.  
  517.   'SHA1 Hash Value' => {
  518.  
  519.                          'prob' => 'calculated probability',
  520.  
  521.                          'spam_count' => 'Total number of spam msgs w/ token',
  522.  
  523.                          'ham_count' => 'Total number of ham msgs w/ token',
  524.  
  525.                          'atime' => 'Atime value for token in database'
  526.  
  527.                        }
  528.  
  529. }
  530.  
  531. =item score
  532.  
  533. Score calculated for this particular message.
  534.  
  535. =item msgatime
  536.  
  537. Calculated atime of the message just learned, note it may have been adjusted
  538. if it was determined to be too far into the future.
  539.  
  540. =item significant_tokens
  541.  
  542. Array ref of the tokens found to be significant in determining the score for
  543. this message.
  544.  
  545. =back
  546.  
  547. =item $plugin->plugin_report ( { options ... } )
  548.  
  549. Called if the message is to be reported as spam.  If the reporting system is
  550. available, the variable C<$options-<gt>{report}-><gt>report_available}> should
  551. be set to C<1>; if the reporting system successfully reported the message, the
  552. variable C<$options-<gt>{report}-><gt>report_return}> should be set to C<1>.
  553.  
  554. =over 4
  555.  
  556. =item report
  557.  
  558. Reference to the Reporter object (C<$options-<gt>{report}> in the
  559. paragraph above.)
  560.  
  561. =item text
  562.  
  563. Reference to a markup removed copy of the message in scalar string format.
  564.  
  565. =item msg
  566.  
  567. Reference to the original message object.
  568.  
  569. =back
  570.  
  571. =item $plugin->plugin_revoke ( { options ... } )
  572.  
  573. Called if the message is to be reported as ham (revokes a spam report). If the
  574. reporting system is available, the variable
  575. C<$options-<gt>{revoke}-><gt>revoke_available}> should be set to C<1>; if the
  576. reporting system successfully revoked the message, the variable
  577. C<$options-<gt>{revoke}-><gt>revoke_return}> should be set to C<1>.
  578.  
  579. =over 4
  580.  
  581. =item revoke
  582.  
  583. Reference to the Reporter object (C<$options-<gt>{revoke}> in the
  584. paragraph above.)
  585.  
  586. =item text
  587.  
  588. Reference to a markup removed copy of the message in scalar string format.
  589.  
  590. =item msg
  591.  
  592. Reference to the original message object.
  593.  
  594. =back
  595.  
  596. =item $plugin->whitelist_address( { options ... } )
  597.  
  598. Called when a request is made to add an address to a
  599. persistent address list.
  600.  
  601. =over 4
  602.  
  603. =item address
  604.  
  605. Address you wish to add.
  606.  
  607. =back
  608.  
  609. =item $plugin->blacklist_address( { options ... } )
  610.  
  611. Called when a request is made to add an address to a
  612. persistent address list.
  613.  
  614. =over 4
  615.  
  616. =item address
  617.  
  618. Address you wish to add.
  619.  
  620. =back
  621.  
  622. =item $plugin->remove_address( { options ... } )
  623.  
  624. Called when a request is made to remove an address to a
  625. persistent address list.
  626.  
  627. =over 4
  628.  
  629. =item address
  630.  
  631. Address you wish to remove.
  632.  
  633. =back
  634.  
  635. =item $plugin->spamd_child_init ()
  636.  
  637. Called when a new child starts up under spamd.
  638.  
  639. =item $plugin->spamd_child_post_connection_close ()
  640.  
  641. Called when child returns from handling a connection.
  642.  
  643. If there was an accept failure, the child will die and this code will
  644. not be called.
  645.  
  646. =item $plugin->finish ()
  647.  
  648. Called when the C<Mail::SpamAssassin> object is destroyed.
  649.  
  650. =back
  651.  
  652. =cut
  653.  
  654. sub finish {
  655.   my ($self) = @_;
  656.   delete $self->{main};
  657. }
  658.  
  659. =head1 HELPER APIS
  660.  
  661. These methods provide an API for plugins to register themselves
  662. to receive specific events, or control the callback chain behaviour.
  663.  
  664. =over 4
  665.  
  666. =item $plugin->register_eval_rule ($nameofevalsub)
  667.  
  668. Plugins that implement an eval test will need to call this, so that
  669. SpamAssassin calls into the object when that eval test is encountered.
  670. See the B<REGISTERING EVAL RULES> section for full details.
  671.  
  672. =cut
  673.  
  674. sub register_eval_rule {
  675.   my ($self, $nameofsub) = @_;
  676.   $self->{main}->{conf}->register_eval_rule ($self, $nameofsub);
  677. }
  678.  
  679. =item $plugin->inhibit_further_callbacks()
  680.  
  681. Tells the plugin handler to inhibit calling into other plugins in the plugin
  682. chain for the current callback.  Frequently used when parsing configuration
  683. settings using C<parse_config()>.
  684.  
  685. =cut
  686.  
  687. sub inhibit_further_callbacks {
  688.   my ($self) = @_;
  689.   $self->{_inhibit_further_callbacks} = 1;
  690. }
  691.  
  692. =item dbg($message)
  693.  
  694. Output a debugging message C<$message>, if the SpamAssassin object is running
  695. with debugging turned on.
  696.  
  697. I<NOTE:> This function is not available in the package namespace
  698. of general plugins and can't be called via $self->dbg().  If a
  699. plugin wishes to output debug information, it should call
  700. C<Mail::SpamAssassin::Plugin::dbg($msg)>.
  701.  
  702. =item info($message)
  703.  
  704. Output an informational message C<$message>, if the SpamAssassin object
  705. is running with informational messages turned on.
  706.  
  707. I<NOTE:> This function is not available in the package namespace
  708. of general plugins and can't be called via $self->dbg().  If a
  709. plugin wishes to output debug information, it should call
  710. C<Mail::SpamAssassin::Plugin::dbg($msg)>.
  711.  
  712. =cut
  713.  
  714. 1;
  715.  
  716. =back
  717.  
  718. =head1 REGISTERING EVAL RULES
  719.  
  720. Plugins that implement an eval test must register the methods that can be
  721. called from rules in the configuration files, in the plugin class' constructor.
  722.  
  723. For example,
  724.  
  725.   $plugin->register_eval_rule ('check_for_foo')
  726.  
  727. will cause C<$plugin-E<gt>check_for_foo()> to be called for this
  728. SpamAssassin rule:
  729.  
  730.   header   FOO_RULE    eval:check_for_foo()
  731.  
  732. Note that eval rules are passed the following arguments:
  733.  
  734. =over 4
  735.  
  736. =item - The plugin object itself
  737.  
  738. =item - The C<Mail::SpamAssassin::PerMsgStatus> object calling the rule
  739.  
  740. =item - standard arguments for the rule type in use
  741.  
  742. =item - any and all arguments as specified in the configuration file
  743.  
  744. =back
  745.  
  746. In other words, the eval test method should look something like this:
  747.  
  748.   sub check_for_foo {
  749.     my ($self, $permsgstatus, ...arguments...) = @_;
  750.     ...code returning 0 or 1
  751.   }
  752.  
  753. Note that the headers can be accessed using the C<get()> method on the
  754. C<Mail::SpamAssassin::PerMsgStatus> object, and the body by
  755. C<get_decoded_stripped_body_text_array()> and other similar methods.
  756. Similarly, the C<Mail::SpamAssassin::Conf> object holding the current
  757. configuration may be accessed through C<$permsgstatus-E<gt>{main}-E<gt>{conf}>.
  758.  
  759. The eval rule should return C<1> for a hit, or C<0> if the rule
  760. is not hit.
  761.  
  762. State for a single message being scanned should be stored on the C<$checker>
  763. object, not on the C<$self> object, since C<$self> persists between scan
  764. operations.  See the 'lifecycle note' on the C<check_start()> method above.
  765.  
  766. =head1 STANDARD ARGUMENTS FOR RULE TYPES
  767.  
  768. Plugins will be called with the same arguments as a standard EvalTest.
  769. Different rule types receive different information by default:
  770.  
  771. =over 4
  772.  
  773. =item - header tests: no extra arguments
  774.  
  775. =item - body tests: fully rendered message as array reference
  776.  
  777. =item - rawbody tests: fully decoded message as array reference
  778.  
  779. =item - full tests: pristine message as scalar reference
  780.  
  781. =back
  782.  
  783. The configuration file arguments will be passed in after the standard
  784. arguments.
  785.  
  786. =head1 SEE ALSO
  787.  
  788. C<Mail::SpamAssassin>
  789.  
  790. C<Mail::SpamAssassin::PerMsgStatus>
  791.  
  792. http://wiki.apache.org/spamassassin/PluginWritingTips
  793.  
  794. http://issues.apache.org/SpamAssassin/show_bug.cgi?id=2163
  795.  
  796. =cut
  797.