#!/usr/local/bin/perl -w ##--------------------------------------------------------------------------## ## File: ## $Id: mk-procmailrc,v 1.22 2003/01/10 21:58:00 ehood Exp $ ## Description: ## Program to create a procmail recipe file from lists.def. ## Run script with '-man' option to view manpage for this program. ##--------------------------------------------------------------------------## ## Copyright (C) 2001-2002 Earl Hood ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ## 02111-1307, USA ##--------------------------------------------------------------------------## package MHArc::mk_procmailrc; ##--------------------------------------------------------------------------## # BEGIN { die qq/CGI use FORBIDDEN!\n/ if (defined($ENV{'GATEWAY_INTERFACE'})); } my $Dir; BEGIN { $Dir = `dirname $0`; chomp $Dir; } use lib "$Dir/../lib"; # Add relative lib to search path # ##--------------------------------------------------------------------------## # use MHArc::Config; my $config = MHArc::Config->load("$Dir/../lib/config.sh"); # ##--------------------------------------------------------------------------## use Getopt::Long; use MHArc::ListDef; use MHArc::Util qw( usage ); MAIN: { my @htaccess = (); my %opt = ( ); my $clstatus = GetOptions(\%opt, 'catch-address=s', 'catch-archive=s', 'disable-catch-archive!', 'final-dest=s', 'home=s', 'mbox-dir=s', 'msgid-cache-size=i', 'out=s', 'procmail-path=s', 'verbose!', 'help', 'man' ); usage(0) unless $clstatus; usage(1) if $opt{'help'}; usage(2) if $opt{'man'}; my $basedir = $opt{'home'} || $config->{'SW_ROOT'} || "$Dir/.."; my $mbox_dir = $opt{'mbox-dir'} || $config->{'MBOX_DIR'} || join('/',$basedir,'mbox'); my $out_file = $opt{'out'} || $config->{'PROCMAILRC'} || join('/', $basedir, 'procmailrc.mharc'); my $procmail_path = $opt{'procmail-path'} || $config->{'PROCMAIL_PATH'}; my $cache_size = $opt{'msgid-cache-size'} || $config->{'MSGID_CACHE_SIZE'} || 16384; my $catch_addr = $opt{'catch-address'} || $config->{'CATCH_ADDRESS'} || ""; my $catch_arc = $opt{'catch-archive'} || $config->{'CATCH_ARCHIVE'} || '.catch'; my $nocatch = defined($opt{'disable-catch-archive'}) ? $opt{'disable-catch-archive'} : ($config->{'DISABLE_CATCH_ARCHIVE'} || 0); my $final_dest = $opt{'final-dest'} || $config->{'FINAL_MSG_DESTINATION'} || '/dev/null'; ## Read lists definition file my $file = shift(@ARGV) || $config->{'LISTS_DEF_FILE'} || "$basedir/lib/lists.def"; my $listdef = MHArc::ListDef->new($file); my $extract_date_prg = join('/', $basedir, 'bin', 'extract-mesg-date'); local(*OUTFILE); my $outfh; if (!defined($out_file) || ($out_file eq "") || ($out_file eq '-')) { $outfh = \*STDOUT; } else { open(OUTFILE, ">$out_file") || die qq/ERROR: Unable to create "$out_file": $!\n/; $outfh = \*OUTFILE; } ## Print procmailrc header print $outfh <{$name}{'address'})) { @addr = @{$listdef->{$name}{'address'}}; } else { @addr = ( ); } if (defined($listdef->{$name}{'from-address'})) { @from_addr = @{$listdef->{$name}{'from-address'}}; } else { @from_addr = ( ) } if (!scalar(@addr) && !scalar(@from_addr)) { # no addresses defined warn qq/Warning: No addresses defined for '$name'\n/; next; } # create procmail regex for list $pm_conditions = '* ('; if (scalar(@addr)) { $pm_conditions .= '^TO_'; $pm_conditions .= '(' if (scalar(@addr) > 1); $pm_conditions .= join('|', @addr); $pm_conditions .= ')' if (scalar(@addr) > 1); $pm_conditions .= '|(^(Delivered-To:|List-Post:).*'; $pm_conditions .= '(' if (scalar(@addr) > 1); $pm_conditions .= join('|', @addr); $pm_conditions .= ')' if (scalar(@addr) > 1); $pm_conditions .= ')'; } if (scalar(@from_addr)) { $pm_conditions .= '|(' if (scalar(@addr)); $pm_conditions .= '^From:(.*[^-a-zA-Z0-9_.])?'; $pm_conditions .= '(' if (scalar(@from_addr) > 1); $pm_conditions .= join('|', @from_addr); $pm_conditions .= ')' if (scalar(@from_addr) > 1); $pm_conditions .= ')' if (scalar(@addr)); } $pm_conditions .= ')'; if (defined($listdef->{$name}{'procmail-condition'})) { foreach $str (@{$listdef->{$name}{'procmail-condition'}}) { $pm_conditions .= "\n$str"; } } # check if doing monthly or yearly archives $period = lc($listdef->{$name}{'period'}[0]) || 'month'; $period = 'month' if ($name eq $catch_arc); if ($period eq 'year') { $time_fmt = '%Y'; } else { $time_fmt = '%Y-%m'; } # check if rule should not be final if matched if ($listdef->{$name}{'final'}) { $pm_copy = ''; } else { $pm_copy = ' c'; } # check if sender specified no archiving should be honored if ($listdef->{$name}{'check-no-archive'}) { $noarchive =<<'EOT'; :0 * ^(X-no-archive: yes|Restrict: no-external-archive) /dev/null EOT } else { $noarchive = ""; } # check if separating out cvs commits if ($check_cvs = $listdef->{$name}{'cvs-commits'}[0]) { $cvs_prefix = $listdef->{$name}{'cvs-subject-prefix'}[0] || 'CVS commit'; foreach $addr (@addr) { print $outfh < program. The procmailrc is generated from Cmharc-rootE/lib/lists.def>. This program is typically invoked by calling C from the mharc root directory with configuration options specified in Cmharc-rootE/lib/config.sh>. =head1 LIST DEFINITION FILE The list definition file, Cmharc-rootE/lib/lists.def>, controls how the procmailrc used by L is generated. The format of the file is simple and more convenient than writing the procmailrc file yourself. The basic format of the file is as follows: =over =item * Any blank links or lines starting with a C<#> are ignored. =item * Lines with the following format: Option-Name: Option-Value is an option. =back =head2 lists.def Supported Options =over =item Name Starts, and defines, the name of an archive. This name serves as the directory name containing archive data and the short-title for archive pages. A common practice is to use the list address, but this is not required, especially if the archive is a combination of multiple lists, or it is prefered to use a more abstract name for simplicity. =item Address Mail address of the list. Multiple C
options can be specified for an archive if a list has more than one known address (e.g. due to migration) or the archive is a collection of multiple lists. =item Check-No-Archive Boolean option (C<0> or C<1>) if author specified archiving permission is honored. The author can request no archiving should be done by defining one of the the following header fields: Restrict: no-external-archive X-no-archive: yes If C is enabled, a message to the list with either field defined will not be archived. =item CVS-Commits Boolean option (C<0> or C<1>) if CVS commit messages should be archived separately. Use this option for development lists that have CVS project commits mailed to the list, and you want to avoid cluttering regular discussion mail. =item CVS-Subject-Prefix Specifies the C prefix denoting CVS commits to the list. This option is only used if C is specified. =item Description Brief description of archive and serves as the main title of archive index pages. =item Final Boolean option (C<0> or C<1>) if generated rule should be final. I.e. If a message matches, further rules will not be examined. Use this option to short-circuit messages from being stored in multiple archives. For example, you may want to catch messages cross-posted to a special address to only be archived in a special archive and not any of the regular archives. Another example is if you use the special C "C<.catch>" (or the C<-catch-archive> setting described in L<"OPTIONS">). Using "C<.catch>" is handy for C definitions to pre-catch messages that should not be placed in any list archive. =item From-Address Mail address of the list. This option is an alternative to C
where a list can only be donoted by the C field of messages. This is fairly common for one-way lists, like newsletters, where subscribers receive list messages but cannot post to the list. Multiple C options can be specified if a list has more than one known address (e.g. due to migration) or the archive is a collection of multiple lists. =item MHonArc-Options Additional MHonArc command-line options. =item No-Raw-Link Boolean option (C<0> or C<1>) if links to raw archives should exist. If set to C<1>, links will not be created or disabled. The default value for this option is C<0>. Use this option if your HTML archives have been customized to obscure address to prevent address harvesting. =item No-Search Boolean option (C<0> or C<1>) if searching should be disabled. If set to C<1>, no search index is created and the C<$SEARCH-FORM$> custom MHonArc resource variable will be set to the empty string. =item Period If archive is a yearly or monthly archive. Legal values are C or C. If Period is not defined, C is the default. =item Procmail-Condition Additional condition to apply to base address check. The condition must be legal procmailrc syntax and should include any prefixing C<*>, C, et. al. This option can be specified multiple times. B Exercise caution when using this option, especially if C is true. When C is true, an additionaly rule already exists to check for the C setting. =back =head2 lists.def Example ## In this definition, we define multiple addresses to check. Name: mhonarc-users Description: MHonArc Users Address: mhonarc-users@mhonarc.org Address: mhonarc@ncsa.uiuc.edu Address: mhonarc@rosat.mpe-garching.mpg.de ## This definition defines a list that receives CVS commits and those ## commits should be separated into a special archive as to not ## pollute the discussion messages with cvs commit messages Name: mhonarc-dev Description: MHonArc Development Address: mhonarc-dev@mhonarc.org CVS-Commits: 1 CVS-Subject-Prefix: CVS: =head1 OPTIONS You should never have to invoke this program with any options since C specifies any options used by this program. However, for advanced uses, or you do not care if you mess things up, the following options are available: =over =item C<-catch-address> I The name of the email address to forward all unmatched message to. This is an alternative to C<-catch-archive>, and will supercede C<-catch-archive>, if defined. If this option is not specified, the C variable in C is used. =item C<-catch-archive> I The name of the I archive. The I archive collects all messages that do not match any list rules. If this option is not specified, the C variable in C is used, else the name "C<.catch>" is used. B If you use this option, it is recommended that the name starts with a C<.> (a dot). This insures that no search index is built and it will not be listed in the all-lists page. =item C<-disable-catch-archive> If specified, no I archive will be defined. B Care should be used when using this option since any message that does not match a normal rule will be lost. =item C<-final-dest> I The destination of messages that make it to the end of the procmailrc. It is normal for messages to make it to the end since the list matching rules create copies of the message during filtering. Hence, it is normal to see "C" destinations in the procmail log and it does not indicate that a message was lost. Message copying is done inorder to properly archive a message that has been cross-posted to multiple lists. Message copying is not done for archives with the C option set to 1, for CVS commit archives, or for messages that are captured by the catch archive. This option is generally only used for debugging purposes. If C<-final-dest> is not specified, the C variable in C is used, else C is used. =item C<-help> Print out usage information. =item C<-home> I B. Root pathname of software and archives. If not specified, C variable in C is used, else the parent directory that containing this program is used. =item C<-man> Print out entire manpage. =item C<-mbox-dir> I Root pathname containing raw mailbox archives. If not specified, C variable in C is used, else C/mbox> is used. =item C<-msgid-cache-size> I The maximum size, in bytes, of the message-id cache. The message-id cache helps avoid processing duplicate messages. If this option is not specified, the C variable in C is used, else 16384 will be used. =item C<-out> I Output filename. If this option is not specified, the C variable in C is used, else C/procmailrc.mharc> is used. If "-" is the I, then the procmailrc will be dumped to standard out. =item C<-procmail-path> I The search path for C to use. If this option is not specified, the C variable in C is used. =back =head1 FILES =over =item Cmharc-rootE/lib/lists.def> Mailing lists definition file. =item Cmharc-rootE/lib/config.sh> Main configuration file for mharc. =back =head1 VERSION $Id: mk-procmailrc,v 1.22 2003/01/10 21:58:00 ehood Exp $ =head1 AUTHOR Earl Hood, earl@earlhood.com This program is part of the mharc archiving system and comes with ABSOLUTELY NO WARRANTY and may be copied only under the terms of the GNU General Public License, which may be found in the mharc distribution. =cut