procmail
[Top] [All Lists]

Re: confusion about INCLUDERC

1996-12-19 22:03:40
Here is a small snippet from my own .procmailrc to do this kind of
prefiling:

  ...
  ADDR=procmail             DEST=info/procmail/.    INCLUDERC=mh-check.rc
  ADDR=SmartList            DEST=info/smartlist/.   INCLUDERC=mh-check.rc
  ADDR=mh-e(_at_)x(_dot_)org                DEST=info/mh/.          
INCLUDERC=mh-check.rc
  ...
  # Finally, after all that, save the message 
  INCLUDERC=mh-save.rc


This method you describe involves several INCLUDERC files.  I was
under the impression that only one include file is allowed, and once
flow goes an INCLUDERC file, then it does not return to the calling rc
file.

You can use INCLUDERC as many times as you like, and you can nest them
also (just don't make the nesting cyclic!).

Even if this was the case, wouldn't it be more efficient to only call
another rc file when an initial match is made and not for each check?

Each address must be checked, and "mh-check.rc" is the subroutine which
does the checking.

Of course, I could write a recipe for each check, but the whole purpose
of this is to use centralize the recipe into a "subroutine" recipe file
and pass the arguments to the subroutine in through the variables
ADDR and DEST.

Is the syntax of declaring multiple variables (separated by
whitespace) on the same line "legal"?

Sure; it is legal -- just like in the shell.  BTW, don't call it
"declaring a variable", call it "assigning a variable a value"--it is
more accurate.  Unlike the shell, though, you can clear the value of
a variable by simply naming the variable:

    ADDR DEST

will clear the values of ADDR and DEST.

Finally, the "snippet" of the recipe file above is from my *actual*,
*working* rc file called "prefile.rc".

The tutorial specifies INCLUDERC=pf-check.rc (mh-check.rc is not
included in your library) which basically consists of five lines
(which would otherwise need to be repeated for each ADDR/DEST pair):

mh-check.rc is a subset of "pf-check.rc", which works only for MH-style
filing.  I didn't include the "mh-check.rc" in my library, since
"pf-check.rc" fulfills that purpose more generally.

    :0
    * ADDR ?? .
    * DEST ?? .
    * $ ^TO$ADDR
    { PF_DEST="$PF_DEST $DEST" }

This is looking for a match on one character???  I don't understand
the symantics you have here of matching a variable against `.' (one
character).

This of the following condition:

    * SOMEVARIABLE ?? .

as a procmail colloquialism for the statement:

   if SOMEVARIABLE is set

So, the recipe above says:

    If ADDR is set, 
    and if DEST is set,
    and if the ADDR variable value occurs in some TO field header
    then append the value of DEST to the end of the current value
    of the PF_DEST variable.

The entire filtering process is a repetition of the above test,
with differing addresses and destinations, all building up one more
folders into PF_DEST, which, at the end of all the checking,
gets filed (or not, if it is not set) into multiple folders, of either
the MH kind or the BSD-file folder kind.

The reason why you want to accumulate all of the destinations and
file them all at once, together, is so that procmail can perform
the hard-linking between them all.

If you don't use MH-style filing, then there's not much reason
for accumulating all of the destination folders into a variable.

Your method certainly by-passes the question of using MATCH
to get the name of the destination folder - although I still think
that this would also be a valid approach which would negate the need
for calling a *-check.rc file.

If you can enforce a regularity of some part of the header content and
correlate that to a folder, then, sure, you can use $MATCH.  But, this
causes your recipe to rely on "good" mail content for the name of your
folder.  What happens if the mail header has "bad" content which
somehow happens to be used as a mail folder?  

Of course, you can apply some careful filtering to avoid this, but I
like avoiding the possibility altogether: I don't like my recipes
creating new folders on the fly:  so, I require myself to edit and
place the explicit folder names in my prefile.rc recipe file, in order
to get mail filed into it.

For example, I want to identify and explode digests (I use mh btw),
and handle any Cc's to me that are filed with these recipes by placing
copies into another separate folder (neither tasks are difficult to do
in the *-save.rc files).

That's one of the beauty's of procmail -- you can make it work however
you like!  And, it is easy to "adjust" an existing recipe.

For example, if you choose to use "pf-check.rc" and "pf-save.rc", you
can still have dynamic folder creation by modifying "pf-check.rc" so
that it does something like this:

    pf-check.rc:

     # If DEST == 'MATCH', then don't use DEST itself, but instead use
     # the value of the $MATCH variable, which will be set by the successful
     # matching of the $ADDR.   The variables DEST_PREFIX and DEST_SUFFIX
     # will then be used to create a folder name like this:
     #   
     #   ${DEST_PREFIX}${MATCH}${DEST_SUFFIX}
     #
     # And, if $ADDR does not have a "\/" operater embedded, be sure to
     # prefix it with one, so there is always a value assigned to the MATCH
     # variable.
     # 
     :0 D
     * ADDR ?? .
     * DEST ?? MATCH
     { :0
       * ! ADDR ?? ()\\/
       { ADDR="\/$ADDR" }
       :0
       * $ ^TO_$ADDR
       { PF_DEST="$PF_DEST ${DEST_PREFIX}$MATCH${DEST_POSTFIX}" }
     }
     :0E
     * ADDR ?? .
     * DEST ?? .
     * $ ^TO_$ADDR
     { PF_DEST="$PF_DEST $DEST" }

This modified recipe will allow you to use the "\/" match operator in
ADDR to assign a value to MATCH, or, if you do not have "\/" in ADDR,
the recipe will assume one at the beginning of $ADDR.

Then, you can write recipes like this:

    DEST=MATCH          # all of the following recipes use $MATCH for filing..

    DEST_PREFIX=info/   # these get filed into subfolders of the +info folder
    DEST_SUFFIX=/.      # and they are MH-style folders

    ADDR=procmail       INCLUDERC=pf-check.rc   # folder == info/procmail/.
    ADDR=perl-users     INCLUDERC=pf-check.rc   # folder == info/perl-users/.
    ADDR=info-gnu       INCLUEDRC=pf-check.rc   # folder == info/info-gnu/.
    ADDR=mh-users       INCLUDERC=pf-check.rc   # folder == info/mh-users/.

In fact, this is such a useful idea, that I'll incorporate it
into my recipes.  Thanks for the idea!

BTW, here are the all of the mh-*.rc files, straight from my
Mail directory.  Use at your own risk.

Nov  8 14:32 1996  /usr/people/aks/Mail/mh-check.rc Page 1

# mh-check.rc
#
# Procmail recipe file to check an address ADDR for MH filing.
# If the address matches, append DEST to MH_DEST.
#
# After all checks are complete, invoke mh-save.rc to save the
# message into the appropriate folders.
#
# Invoke mh-ckinit.rc at least once before invoking this recipe.
#
# Set these variables before invoking:
#
# ADDR  Address to which addressed mail will be filed
#       into the named folder.
#
# DEST  Destination into which addressed mail will be
#       dropped.
#
# INCLUDERC=mh-check.rc

:0
* ADDR ?? .
* DEST ?? .
* $! MH_DEST ?? $PREADDR$\DEST$POSTADDR
* $ ^TO_$ADDR$POSTADDR
{ MH_DEST="$MH_DEST $DEST" }


Nov  8 17:10 1996  /usr/people/aks/Mail/mh-ckaddr.rc Page 1

# mh-ckaddr.rc
#
# Procmail recipe file to check if an address is from a given
# address or, if it is from me, if it is *to* that same address.
#
# If the address matches, append DEST to MH_DEST.
#
# After all checks are complete, invoke mh-save.rc to save the
# message into the appropriate folders.
#
# Invoke mh-ckinit.rc at least once before invoking this recipe file.
#
# Set these variables before invoking:
#
# ADDR  Address to which addressed mail will be filed
#       into the named folder.
#
# DEST  Destination into which addressed mail will be
#       dropped.
#
# MY_ADDRS      a regexp which matches all addresses and names of the
#               user receiving the mail.
#
# INCLUDERC=mh-ckaddr.rc

:0
* ADDR ?? .
* DEST ?? .
* !$ MH_DEST ?? $PREADDR$\DEST$POSTADDR
{
  # Figure out who this mail is from
  :0
  * ! MH_FROM ?? .
  { # Get the best FROM
    :0
    * ! ^Reply-to: *\/[^ ].*
    * ! ^From: *\/[^ ].*
    * ! ^From +\/[^ ]+
    * ! ^Sender: *\/[^ ].*
    * ! ^X-Envelope: *\/[^ ].*
    { MH_FROM=nobody }
    :0E
    { MH_FROM=$MATCH }
  }
  # is this mail from the given $ADDR, and specifically to me?
  # if so, prefile it
  :0
  * $ ^TO_$MY_ADDRS$POSTADDR
  * $ MH_FROM ?? $PREADDR$ADDR$POSTADDR
  { MH_DEST="$MH_DEST $DEST" }  # file it

  # else, is this mail from me to the address?
  :0 E
  * $ MH_FROM ?? $PREADDR$MY_ADDRS$POSTADDR
  * $ ^TO_$ADDR$POSTADDR
  { MH_DEST="$MH_DEST $DEST" }  # file it
}

Nov  8 15:44 1996  /usr/people/aks/Mail/mh-ckinit.rc Page 1

# mh-ckinit.rc
#
# Recipe file to initialize for mh-check.rc and mh-ckaddr.rc
#
# Setup commonly used variables, and initialize the argument
# variables to the other subroutine recipe files.

:0
* ! MH_CKINIT ?? .
{ # provide a default MY_ADDRS regexp
  :0
  * ! MY_ADDRS ?? .
  { MY_ADDRS=${USER:-$LOGNAME} }

  # These will be used on '$' recipe conditions, so be sure to
  # escape correctly.
  NONADDR="[^a-zA-Z0-9_.-]"
  PREADDR="(^|$NONADDR)"
  POSTADDR="(\$|$NONADDR)"

  # Used to match domain addresses
  USERNAME="[-_.!%:/+0-9a-zA-Z]"
  HOSTNAME="[-_0-9a-zA-Z]+"
  DNSNAME="[-_.0-9a-zA-Z]+"

  :0                    # ensure at least 4096 bytes large
  * 4096^0
  * $ -$LINEBUF^0
  { LINEBUF=4096 }      # increase to this size

  MH_DEST                       # ensure that these are empty
  ADDR
  DEST

  MH_CKINIT=1
}

Nov  8 14:34 1996  /usr/people/aks/Mail/mh-file.rc Page 1

# mh-file.rc
#
# Procmail recipe file to file a message under DEST, by appending to
# MH_DEST
#
# After all checks are complete, invoke mh-save.rc to save the
# message into the appropriate folders.
#
# DEST  Destination into which addressed mail will be dropped.
#
# INCLUDERC=mh-file.rc

:0
* DEST ?? .
* $! MH_DEST ?? $PREADDR$\DEST$POSTADDR
{ MH_DEST="$MH_DEST $DEST" }

Nov  8 14:35 1996  /usr/people/aks/Mail/mh-save.rc Page 1

# mh-save.rc
#
# Procmail recipe file to save the current message to
# a list of one or more folders set by mh-check.rc.
#
# Set the variable MH_DEST before invoking.
#
# INCLUDERC=mh-save.rc
#
# If the message is filed into an MH folder, LOGABSTRACT is
# set to "off" so a duplicate log is not created.

:0
* MH_DEST ?? .
{
  :0 fh
  | formail -A "X-Filed: $MH_DEST"

  :0 c:
  $MH_DEST

  MH_DEST               # clear so we don't do it twice

  LOGABSTRACT=off
}


Thanks for any clarification of this.

You're welcome.  I hope this is useful.

___________________________________________________________
Alan Stebbens <aks(_at_)sgi(_dot_)com>      http://reality.sgi.com/aks