manitou-mdx Plugins Reference

1. Architecture

A plugin named 'myplugin' should provide a myplugin.pm file declaring a myplugin package matching this structure:
package myplugin;

sub init {
  my $dbh=shift;
  my @args=@_;	# user-supplied arguments

  # optionally do initialization stuff using $dbh and @args

  bless {}      # create the perl object and returns a reference to it
}

sub finish {
  # do optional cleaning
  1;
}

sub process {
  my ($self, $context) = @_;

  # $self=class pointer

  # $context=pointer to a hash set up by the caller and that contains those keys:
  #   stage: string whose value is "preprocess", "mimeprocess", "postprocess", "outgoing" or "maintenance"
  #   dbh: the DBI connexion object pointing to the mail database
  #   filename: full path of the mailfile (undef if $context->{stage} is "outgoing" or "maintenance")
  #   mail_id: an integer containing the unique id of the mail (undef if the stage is "preprocess" or "maintenance")
  #   mimeobj: the MIME object containing the mail (undef if the stage is "preprocess" or "maintenance")

  # The context is also used to communicate results to the caller and to the other plugins
  # along the chain. The keys that are going to be interpreted are:
  #   tags= perl array of tag names that should be assigned to the message.
  #   action: undef if no particular action (insert the incoming message as new)
  #     "discard" to discard an incoming message, "trash" to trash it


  # Process the mail...
  1;
}

1;   # the package should evaluate to 1
The plugin's name must not contain any non-ascii nor punctuation or space characters. Digits are allowed except for the first character of the name.

2. Declaration

Plugins are declared in the configuration file, through these directives: Example:
[common]
plugins_directory = /usr/local/manitou/plugins
maintenance_plugins = 5h vacuum \
		      23:30 reporting

[mailbox@domain.tld]
#  plugins for that mailbox
incoming_preprocess_plugins = spamc("tag for spam")
incoming_postprocess_plugins = guesslang("en","fr") \
                               anotherplugin(arg1,arg2,...)
outgoing_plugins = gpgsign

[mailbox2@domain.tld]
incoming_preprocess_plugins = spamc("another tag for spam")

Note that a declaration containing multiple plugins must be splitted across multiple lines, each line except the last one being ended by a backslash .

3. Loading and initialization

When manitou-mdx is launched, it searches the configuration file for all plugins and includes each corresponding perl module file once, using perl's require command. It means that in the example configuration shown, it would load these files from /usr/local/manitou/plugins:
guesslang.pm, anotherplugin.pm, spamc.pm, gpgsign.pm (note that spamc will be instantiated twice).

For each reference to a plugin, a new plugin perl class is instantiated, and its init() function called with the arguments from the config file along with a database handle. For the example configuration, the following instantiations would occur:

$pl1 = guesslang::init($dbh, "en","fr");
$pl2 = anotherplugin::init($dbh, arg1,arg2,...);
$pl3 = spamc::init($dbh, "tag for spam");
$pl4 = gpgsign::init($dbh);
$pl5 = spamc::init($dbh, "another tag for spam");

In the example above, since spamc is used by two different mailboxes, two separate spamc objects are instantiated and spamc::init is called on each of them. Variables used inside the spamc module may or may not be shared between different instances of a module: it is the responsibility of the plugin's writer to make the right choice between private variables inside the object ($self->var) or variables shared at the package level (my $var).

The user-supplied arguments for the init function are passed verbatim from the configuration file, and thus are to be considered as perl text. (technically, the call to the plugin's init function is embedded inside a perl eval call). Thus those user supplied arguments should be expressed as they would be inside a perl program, and every special character should be quoted according to perl syntax rules. Examples:

# @ sign quoted as per perl strings requirements
incoming_preprocess_plugins=spamc("tag\@cf")

# Simple quotes can be also used to avoid perl variables interpolation
# inside strings
incoming_preprocess_plugins=spamc('tag@cf$')

# On the other hand, we may want to use perl's interpreter to deference
# variables: here we're passing the value of the MAIL_ARCH_DIR environment
# variable.
incoming_postprocess_plugins=archivemsg($ENV{MAIL_ARCH_DIR})

4. Processing

Incoming mail

Each time a new message file appears in the mailfiles_directory of a mailbox, manitou-mdx carries out these actions:

  1. It changes the file suffix (the part at the right of the dot) from .received to .pid.processing
  2. If there are incoming_preprocess_plugins, it calls their process() functions, in the order of their declaration in the configuration file. The plugins are allowed to modify the mailfile if needed.
  3. If one of the plugins has marked the mail as "to be discarded", the mailfile suffix is changed to .discarded and the processing of this message is stopped.
  4. The mailfile is opened, parsed and put into a perl MIME object.
  5. If there are incoming_mimeprocess_plugins, their process() functions are called, in the order of their declaration in the configuration file. Plugins are allowed to modify the MIME object in memory in every way they see fit.
  6. Once again, if one of the plugins has marked the mail as "to be discarded", the mailfile suffix is changed to .discarded and the processing of this message is stopped.
  7. manitou-mdx does its own processing of the message, using the MIME object possibly modified by the plugins previously run. Then if no error has occured, it inserts it into the database and commits the transaction.
  8. It changes the mailfile's suffix from .pid.processing to .processed, or to .error if an error has occured during the previous step.
  9. If there are incoming_postprocess_plugins, it calls them in the order of their declaration in the configuration file. Once all the plugins have been called, it commits whatever changes have been made in the database.

Outgoing mail

When a message is ready to be sent (its status has the "Outgoing" bit and not the "Sent" bit), manitou-mdx does the following:
  1. If there are outgoing_plugins attached to the mailbox of the message, their process functions are called with the outgoing mail built as a perl MIME object in memory, and the unique mail identifier in the database (mail_id).
  2. Once all plugins have been run, the message will be passed from the MIME object in memory (possibly modified by the plugins) to the local mailer. Note that it is the plugin's responsibility to update the message in the database to reflect whatever change it makes in the MIME object in memory.

Mailbox import

When importing a mailbox with manitou-mdx (using the --mboxfile option), incoming_mimeprocess_plugins are called if:

Other kinds of plugins are not called. Each mail contained in the mailbox file goes through steps 4 to 7 of the incoming mail process described above.