The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Mail::Procmailrc - An interface to Procmail recipe files

SYNOPSIS

  use Mail::Procmailrc;

  ## create a new procmailrc object and initialize it
  $pmrc = new Mail::Procmailrc("$HOME/.procmail/rc.lists");

  ## same as above
  $pmrc = new Mail::Procmailrc;
  $pmrc->read("$HOME/.procmail/rc.spam");

  ## same as above
  $pmrc = new Mail::Procmailrc;
  $pmrc->file("$HOME/.procmail/rc.spam");
  $pmrc->read;

  ## same as above except the file attribute is left unset
  $pmrc = new Mail::Procmailrc;
  my $rcfile = `cat $HOME/.procmail/rc.spam`;
  $pmrc->parse($rcfile);

  ## same as above (i.e., file attribute is left unset)
  my $rcfile = `cat $HOME/.procmail/rc.spam`;
  $pmrc = new Mail::Procmailrc( { data => $rcfile } );

  ## add a new recipe
  $pmrc->push( new Mail::Procmailrc::Recipe($recipe) );

  ## add a new variable
  $pmrc->push( new Mail::Procmailrc::Variable("FOO=bar") );

  ## write this object to disk
  $pmrc->flush("$HOME/.procmail/rc.spam");

  ## same as above
  $pmrc->file("$HOME/.procmail/rc.spam");
  $pmrc->flush;

  ## same as above (assuming the file attribute was previously set)
  $pmrc->flush;

  ## same as above (same assumption)
  $filename = $pmrc->file;
  $pmrc->flush($filename);

DESCRIPTION

Mail::Procmailrc can parse procmail recipe files and store the contents in an object which can be later manipulated and saved. You may also start with a fresh, empty Mail::Procmailrc object, populate it with recipes and/or variables and write it to file.

Recipes and variables are written to the file in the order they're parsed and added. If you want to re-order the recipes you may do so by getting a handle on the variable or recipe list and ordering them yourself.

The Mail::Procmailrc object is primarily a list of procmail component objects (see below). When Mail::Procmailrc parses a procmail rc file, it decides which lines are variable assignments, which lines are comments, and which lines are recipes. It preserves the order in which it encounters these procmail components and stores them as a list of objects in the main Mail::Procmailrc object.

Mail::Procmailrc::Variable Objects

Mail::Procmailrc::Variable objects are easy to create and use. Normally, the Variable constructor is invoked by Mail::Procmailrc during parsing. If you are creating or modifying an existing procmail rc file, you might do something like this:

    my $var = new Mail::Procmailrc::Variable(["VERBOSE=off"]);

or you might wish to do it another way:

    my $var = new Mail::Procmailrc::Variable;
    $var->lval('VERBOSE');
    $var->rval('off');

You may get a handle on all Variable objects in an rc file with the variables method:

    ## change to verbose mode
    for my $var ( @{$pmrc->variables} ) {
        next unless $var->lval eq 'VERBOSE';
        $var->rval('yes');
        last;
    }

Mail::Procmailrc::Variable Methods

variable([$string])

$string, if present, is split on the first '='. The left half is assigned to lval and the right half to rval. If $string is false, lval and rval are concatenated with '=' and returned as a single string.

lval([$val])

Returns the current lvalue of the variable assignment, optionally setting it if $val is present.

rval([$val])

Returns the current rvalue of the variable assignment, optionally setting it if $val is present.

stringify

Returns the output of variable. Provides a consistent interface to all Mail::Procmailrc::* subclasses.

dump

Returns the output of stringify with a trailing newline. Suitable for inserting into a procmail rc file.

defaults([\%defaults [, $elem]])

Returns some internal object settings, currently not very useful or interesting except when parsing deeply nested recipes. Included here for completeness.

init(\@data)

Normally invoked by the constructor (new), but may be used to re-initialize an object.

Mail::Procmailrc::Literal Objects

Mail::Procmailrc::Literal objects are even easier to create and use than Variable objects. A Mail::Procmailrc::Literal is simply a string with a few methods wrapped around it for convenient printing.

You may get a handle on all Literal objects in an rc file with the literals method:

    ## change a comment in the rc file
    for my $lit ( @{$pmrc->literals} ) {
        next unless $lit->literal =~ /## spam follows/i;
        $lit->literal('## this is a nice spam recipe');
        last;
    }

Here is how to create a new literal:

   ## create a new literal
   my $lit = new Mail::Procmailrc::Literal('## this file is for filtering spam');

   ## same as above
   my $lit = new Mail::Procmailrc::Literal;
   $lit->literal('## this file is for filtering spam');

   ## print it
   $lit->dump;

Mail::Procmailrc::Literal Methods

literal([$string])

Get or set the literal object contents.

dump

Dump the contents of the object with a trailing newline.

Mail::Procmailrc::Recipe Objects

A recipe object is made up of a flags object, zero or more literal (comments or vertical whitespace) objects, zero or more condition objects, and an action object. A Mail::Procmailrc::Recipe object is made of four parts:

  • flags (required)

  • info/comment (optional)

  • conditions (optional)

  • action (required)

Normally, the Recipe object is created automatically during parsing. However, if you are constructing a new rc file or want to modify an existing procmailrc file, you will need to know a little about the Recipe object.

To create a recipe object from a string, you may do something like this:

    $recipe =<<'_RECIPE_';
    :0B:
    ## block indecent emails
    * 1^0 people talking dirty
    * 1^0 dirty persian poetry
    * 1^0 dirty pictures
    * 1^0 xxx
    /dev/null
    _RECIPE_

    $recipe_obj = new Mail::Procmailrc::Recipe([split(/\n/, $recipe)]);

The entire recipe in $recipe is now contained in the $recipe_obj. You could also piece together an object part by part:

    $recipe_obj = new Mail::Procmailrc::Recipe;
    $recipe_obj->flags(':0B');
    $recipe_obj->info([q(## block indecent emails)]);
    $recipe_obj->conditions([q(* 1^0 people talking dirty),
                             q(* 1^0 dirty persian poetry),
                             q(* 1^0 dirty pictures),
                             q(* 1^0 xxx),]);
    $recipe_obj->action('/dev/null');

You can get a handle on all recipes in an rc file with the recipes method:

    my $conditions;
    for my $recipe ( @{$pmrc->recipes} ) {
        next unless $recipe->info->[0] =~ /^\s*\#\# this recipe is for spam/io;
        $conditions = $recipe->conditions;
        last;
    }
    push @$conditions, '* 1^0 this is not SPAM';
    $pmrc->flush;  ## write out to file

CAVEATS

Parsing is lossy in two senses. Some formatting and stray lines may be lost. Also, array references fed to constructors will not be returned intact (i.e., data will be shifted out of them).

BUGS

Please let the author/maintainer know if you find any bugs (providing a regression test would also be helpful; see the testing format in the 't' directory).

  • We don't use any advisory locking on the procmail rc files. This wouldn't be hard to fix, but I'm not sure it is needed.

  • We suck in the entire procmailrc file into memory. This could be done more efficiently with a typeglob and reading the file line by line.

  • Comments on the flags line (e.g., ":0B ## parse body") or on an assignment line (e.g., "VAR=FOO ## make FOO be known") are quietly dropped when the rc file is parsed and they are not replaced when the file is rewritten. If you want to keep comments around, put them on a separate line.

  • We don't recursively parse file INCLUDE directives. This could be construed as a safety feature. The INCLUDE directives will show up, however, as Variable objects, so you could provide the recursion pretty easily yourself.

COPYRIGHT

Copyright 2002 Scott Wiersdorf.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHOR

Scott Wiersdorf <scott@perlcode.org>

SEE ALSO

perl.