jaromail

a commandline tool to easily and privately handle your e-mail
git clone git://parazyd.org/jaromail.git
Log | Files | Refs | Submodules | README

commit 4266e7d860dbe909e5f364a13887a2bc193958f6
parent 2b52f1dbeb08c52d322eea4176061116859b4d60
Author: Jaromil <jaromil@dyne.org>
Date:   Mon, 19 Mar 2012 23:09:38 +0100

imported procmail-lib

Diffstat:
Ashare/procmail/COPYING | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/ackmail.rc | 298+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/comm-reply-file.rc | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/commands.rc | 366+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/correct-addr.rc | 411+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/date.rc | 485+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/dupcheck.rc | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/eg.spam-bounce-w-threshold.rc | 44++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/gen-spam-reply.rc | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/get-date.rc | 8++++++++
Ashare/procmail/get-from.rc | 46++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/guess-mua.rc | 48++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/headers.rc | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/list-addr.rc | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/newsgate.rc | 46++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pf-check.rc | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pf-chkto.rc | 25+++++++++++++++++++++++++
Ashare/procmail/pf-save.rc | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaaddr.rc | 484+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jabup.rc | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jacookie.rc | 460+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jacookie1.rc | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jacron.rc | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadaemon.rc | 423+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadate.rc | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadate1.rc | 224+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadate2.rc | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadate3.rc | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadate4.rc | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadate5.rc | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jadup.rc | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaempty.rc | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jafrom.rc | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jafwd.rc | 401+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jalist.rc | 1866+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jamime-decode.rc | 290+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jamime-kill.rc | 712+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jamime-recode.rc | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jamime-save.rc | 486+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jamime.rc | 245+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-janetmind.rc | 214+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-janslookup.rc | 395+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaorig.rc | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-japing.rc | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-japop3.rc | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jarandf.rc | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-check.rc | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-daemon.rc | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-err.rc | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-from.rc | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-msg.rc | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-multi.rc | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-req.rc | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv-send.rc | 333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasrv.rc | 704+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jastore.rc | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jasubject.rc | 573+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jatime.rc | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-keywords.rc | 785+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-annoyance-filter.rc | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-bmf.rc | 283+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-bogofilter.rc | 219+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-bsfilter.rc | 214+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-ifile.rc | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-runall.rc | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-spamassassin.rc | 236+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-spamoracle.rc | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube-prg-spamprobe.rc | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube.rc | 1575+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-jaube1.rc | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-javac.rc | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/pm-javar.rc | 562+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/unread-default.rc | 48++++++++++++++++++++++++++++++++++++++++++++++++
Ashare/procmail/unread-mh.rc | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
74 files changed, 19410 insertions(+), 0 deletions(-)

diff --git a/share/procmail/COPYING b/share/procmail/COPYING @@ -0,0 +1,71 @@ + +Upstream Author: + + Jari Aalto <jari.aalto@cante.net> + +Copyright + + lib-stebbens/: + Copyright (C) 1995-1997 Alan Stebbens <aks@sgi.com> + + <rest of the files>: + Copyright (C) 1997-2008 Jari Aalto <jari.aalto@cante.net> + +License + + From doc/license/LICENSE.txt: + + This program runs solely with Free Software. It does not rely + on any component of non-Free Software. + + Copyright (C) 1997-2008 Jari Aalto + + This program (referring to all files, including documentation, + distributed in project "Procmail Module Library") 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. + + Visit <http://www.gnu.org/copyleft/gpl.html> for more information. + + - - + + Exception: The documentation of project "Procmail Module Library" + (*.txt and *.html files) is DUAL LICENCED and may be + distributed under the terms of GNU General Public License (GNU + GPL) --see above--; *or*, at your option, distributed under + the terms of GNU Free Documentation License (GNU FDL). + + The end user can continue to distribute the documentation in + this dual licence form *or* select the other license (GNU GPL, + GNU FDL) and remove the unwanted one. + + Copyright (C) 1997-2008 Jari Aalto + + Permission is granted to copy, distribute and/or modify + this document under the terms of the GNU Free + Documentation License, Version 1.2 or any later version + published by the Free Software Foundation; with no + Invariant Sections, no Front-Cover Texts, and no + Back-Cover Texts. A copy of the license is included in the + section entitled "GNU Free Documentation License"; + see the file COPYING.GNU-GFDL. + + Visit <http://www.gnu.org/licenses/fdl.html> for more information. + +The Debian packaging is licensed under the GPL version 2 or, (at your +option) any later version, see below, and is: + + Copyright (C) 2008-2010 Jari Aalto <jari.aalto@cante.net> + Copyright (C) 2007 Michael Ablassmeier <abi@debian.org> + Copyright (C) 2001-2003 Elie Rosenblum <fnord@debian.org> + Copyright (C) 2000 Dr. Guenter Bechly <gbechly@debian.org> + Copyright (C) 1999 Raphael Hertzog <rhertzog@hrnet.fr> + Copyright (C) 1996-1998 Karl Sackett <krs@debian.org> + diff --git a/share/procmail/ackmail.rc b/share/procmail/ackmail.rc @@ -0,0 +1,298 @@ +# ackmail.rc -- procmail rc to acknowledge mail (with either a +# vacation message, or an acknowledgement) +# +# $Id: ackmail.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# Usage: +# +# After setting the variables below appropriately, add the following +# to your .procmailrc: +# +# INCLUDERC=ackmail.rc +# +# Features: +# +# If the file $VACAMSG exists, it is assumed that the user is in +# "vacation mode", and mail will be acknowledged with the contents of +# the $VACAMSG file, with the subject line appended with "[on +# vacation]". +# +# If $VACAMSG doesn't exist, and $ACKMSG does, mail will be +# acknowledged with the contents of $ACKMSG with the subject line +# appended with "[acknowledgment]". +# +# If neither the file $ACKMSG nor $VACAMSG exists, this recipe does +# nothing. +# +# Mail from any daemon or the usual set of mailing lists will not be +# acknowledged (uses ^FROM_DAEMON). +# +# Mail from any of a set of configured users ($NOACKS) will not be +# acknowledged (be default, this includes the user). +# +# Mail from any user will only be acknowledged once per day. +# +# Regardless of whether or not "ackmail.rc" acknowledges the mail, any +# recipes following the INCLUDERC will continue to filter the incoming +# mail (that is, it is not considered to be delivered). +# +# Before including the "ackmail.rc" file, be sure to setup the following +# variables: +# +# MY_ADDR - preferred email address for the user +# +# MY_NAMES - regex matcing personal names & alternatives; +# ultimately, only mail addressed to $MY_NAMES +# will be acknowledged; defaults to the +# contents of $SIGNATURE or $HOME/.signature, in +# that order. +# +# NOACKS - regex matching people from whom to NOT +# acknowledge mail; defaults to $MY_ADDR +# +# NOACKFILE - path to a file containing regexps of addresses to not +# acknowledge +# +# ACKS - file containing the acknowledgment cache; +# defaults to $MAILDIR/.acks.cache +# +# ACKMSG - file containing the message to reply with; +# defaults to ackmsg +# +# VACAMSG - file containing the message to reply with; +# defaults to vacation.msg +# +# FROMSIG - From: header to use in the auto-ack; defaults +# to "Mailer-Daemon of $USER" +# +# MUA - define as one of the keywords below to tell the +# recipe on how to calculate the unread mail: +# MUA=default - your unread mail sits in $DEFAULT (you don't filter +# mail into folders) +# MUA=mh - your mail is filtered into the MH +inbox; tries to +# use any Unseen-Sequence, or calculates it from the +# output of "folders +inbox". +# MUA=XXXXX - causes a recipe named "unread-XXXXX.rc" to be +# invoked (if it exists) to calculate the number +# of unread messages and returned in $UNREAD. +# +# +# And be sure PATH includes the directory containing "formail". + +# If the mail is directly to me, and not an auto-reply itself +# then do the auto-ack + +MY_NAMES=${MY_NAMES:-${SIGNATURE:-`cat $HOME/.signature 2>/dev/null`}} +ACKS=${ACKS:-ackmail.cache} +ACKMSG=${ACKMSG:-ackmsg} +VACAMSG=${VACAMSG:-vacation.msg} +FROMSIG=${FROMSIG:-"Mailer-Daemon of $USER"} +NOACKS=${NOACKS:-$MY_ADDR} +NOACKFILE=${NOACKFILE:-''} + +# Handy regexp patterns (taken from "headers.rc") +PRE_ADDR_SPAN='(.*[^-(.%@a-zA-Z0-9])?' +POST_ADDR_SPAN='(([^),.!:a-zA-Z0-9].*)?(,|$[^>]))' +FROMHDR="(^(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )$PRE_ADDR_SPAN)" + +# Begin the tests +# 1. Is it addressed to me (using any of my names)? +# 2. Is there an acknowledgement file or vacation message file? +# 3. Is the mail NOT from any kind of daemon +# 4. Is the mail NOT from a mailing list manager which procmail doesn't know +# 5. Does the subject NOT have any text indicating some kind of automatic +# reply mechanism has already taken place? +# 6. Is this NOT a message we generated (a bounce, maybe)? +# 7. Is the message NOT from anyone on our "noack" list? + +# If you need to debug your configuration of ackmail.rc, just "touch +# ackmail.log" and the recipe below will log the ackmail.rc activity to +# ackmail.log. When you are satisfied with your configuration, simply +# remove ackmail.log and logging will stop. + +:0 +* ? test -f ackmail.rc.log +{ + OLDACKLOGFILE=$LOGFILE + LOGFILE=ackmail.rc.log + LOGABSTRACT=all + VERBOSE=on +} + +# Get the best return address without names & comments. +# This will be the same address we respond to. +SENDER=`formail -rtzx To:` + +# Define a list of well-known list mailer addresses +LIST_MAILERS='((Mail(er)?-?)?daemon|root|LISTSERV|ListProc|\ +[a-zA-Z0-9-]+-(list|request|owner)|(owner-)?list-[a-zA-Z0-9-]+|\ +Majordomo|Mailagent|Postmaster|mmdf|news|n?uucp)' + +# This is the major condition by which we decide to respond +# or not. + +:0ch +* $ ^TO($USER|$MY_ADDR|$MY_NAMES) +* ? test -f $ACKMSG -o -f $VACAMSG +* !^FROM_DAEMON +* $! SENDER ?? $LIST_MAILERS +* $! $FROMHDR(Majordomo|Listserv) +* !^Subject: .*(\[(ack(nowledge?ment)?|on vacation)\]|\ + auto(matic)[- ]reply|\ + away from mail|\ + out of town|\ + can ?not (reply|answer)|\ + (on |via )vacation( program)?) +* $!^X-Loop: *$MY_ADDR +* $!$FROMHDR($NOACKS)$POST_ADDR_SPAN +{ + # Okay -- we're doing to do the auto-ack or vacation mail + # + # We're forking for the auto-ack, shut up comsat, and assume that, + # in this process, the mail is delivered + DELIVERED=yes + COMSAT=off + + # Don't output logfile info; the user can query $ACKS to see which + # users have been acknowledged. This only affects the child + # process. + LOGABSTRACT=no + + # Check for a NOACKFILE; if it exists, and if the sender matches one + # of the regexps within the NOACKFILE, then do not ack this mail + :0h + * ? test -n "$NOACKFILE" -a -f "$NOACKFILE" + * ? echo "$SENDER" | egrep -s -f "$NOACKFILE" + { HOST=_do_not_ack_this_user } + + # Check the mail to see if we have replied recently, and if so, if + # we should reply again + DATE=`date +'%D'` + + # Get the subject + :0 ch + SUBJ=| formail -zX'Subject:' | sed -e 's/["~]//g' -e 's/^ *[Rr]e: *//g' + SUBJ="${SUBJ:-'(no subject)'}" + + # Get which file: "vacation.msg" has precedence over "ackmsg" + :0 + * ? test -f $VACAMSG + { ACKFILE=$VACAMSG ACKM='on vacation' } + :0 E + { ACKFILE=$ACKMSG ACKM='acknowledgment' } + + # Check the cache for a recent ack (a successful grep "delivers" the + # mail) + LOCKFILE=$ACKS.lock + :0 Wh + | fgrep -i -s "$SENDER $DATE" $ACKS + + # Not in the $ACKS file; add it + JUNK=`(fgrep -i -v "$SENDER" $ACKS ; echo "$SENDER $DATE" ) >$ACKS.new ; + rm -f $ACKS ; mv $ACKS.new $ACKS ` + + # Release the lock + LOCKFILE + + # Replace the headers with a reply + + # (Note: do not use -k here; "h" recipes include the blank + # line in the headers, and formail -r generates a blank line + # also. If you use '-k', then the original blank line will + # be kept, and the additional will be added, resulting + # in two blank lines). + + :0 fhw + | formail -rtI"From: $FROMSIG" \ + -I"Reply-To: $MY_ADDR" \ + -I"Precedence: junk" \ + -I"Subject: Re: $SUBJ [$ACKM]" \ + -I"X-Loop: $MY_ADDR" \ + -I"References:" + + # If formail failed, it is because it couldn't be found + # avoid acks in this case + :0 e + { LOG="****Error: Formail failed in ackmail.rc at `date` +" + HOST=_stop_processing_now + } + + # Replace the body with the ack message + :0 fbw + | cat $ACKFILE + + # If the cat $ACKFILE failed, it is probably because ackfile can't + # be read; in this case, create a reasonable reply + :0 efb + | echo "Your mail concerning '$SUBJECT' was received." ; \ + echo "I'll reply to it as soon as I can." + + # Now maybe do some substitutions, depending upon whether or not the + # particular strings exist. + :0 fBb + * $SUBJECT + | sed -e "s~\$SUBJECT~$SUBJ~g" + + :0 fBb + * $SENDER + | sed -e "s~\$SENDER~$SENDER~g" + + # If the string $UNREAD is in the message, then figure out + # how many unread messages and substitute it + :0 B + * $UNREAD + { + UNREAD=no # by default + + # Define the MUA if it isn't defined already + :0 + * MUA ?? !.+ + * ? test -f guess-mua.rc + { INCLUDERC=guess-mua.rc } + + # For any MUA keyword, there should be a corresponding + # unread-$MUA.rc file. + :0 + * MUA ?? .+ + * ? test -f unread-$MUA.rc + { INCLUDERC=unread-$MUA.rc } + + # Finally, substitute UNREAD into the current body + :0 fb + | sed -e "s~\$UNREAD~$UNREAD~g" + } + + # Finally, deliver it + :0 w + ! -oi -t + + HOST=end_of_processing # just in case sendmail failed +} + +# Undo any debug logging +:0 +* LOGFILE ?? ackmail\.rc\.log +{ + VERBOSE=no + LOGABSTRACT=yes + LOGFILE=$OLDACKLOGFILE + OLDACKLOGFILE +} diff --git a/share/procmail/comm-reply-file.rc b/share/procmail/comm-reply-file.rc @@ -0,0 +1,66 @@ +# comm-reply-file.rc -*- text -*- +# +# procmail rc file to filter a reply message body with a given file, +# or report an error. +# +# $Id: comm-reply-file.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# Usage: +# +# REPLYFILE=file-to-be-sent +# REPLYERR="error message if file doesn't exist" +# + +:0 +* ! REPLYFILE ?? . +{ LOG="comm-send-file.rc: REPLYFILE not defined! +" +} + +# REPLYFILE is defined +:0 E +{ + + # On the assumption that the message body has been prepared, + # filter it and append the requested file. + :0 fbw + * ? test -f $REPLYFILE + | cat - $REPLYFILE + + # The file wasn't available, generate an error message + :0 E + { + # Provide for a default error message if $REPLYERR isn't set + :0 + * ! REPLYERR ?? . + { + # get the basename of the file (don't show any path) + :0 + * ! REPLYFILE ?? .*/\/[^/]+$ + * ! REPLYFILE ?? \/^.*$ + { REPLYERR="Sorry, the file you requested is not currently available." } + :0 E + { REPLYERR="Sorry, the file '$MATCH' is not currently available." } + } + + :0 fbw + | cat - ; echo "$REPLYERR" + } +} diff --git a/share/procmail/commands.rc b/share/procmail/commands.rc @@ -0,0 +1,366 @@ +# commands.rc -*- text -*- +# +# procmailrc file to check for commands in the subject line +# +# $Id: commands.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# Usage: +# +# HELPFILE=commands.help [optional] +# INFOFILE=commands.info [optional] +# PROCMAILINFO=procmail.info [optional] +# COMMANDLOG=commands.log [optional] +# NOACKFILE=noacks [optional] +# +# INCLUDERC=commands.rc +# +# Notes: +# +# * This recipe consumes the input if it successfully matches. +# Processing does not continue unless the subject is not a +# command. +# +# * HELPFILE should contain general help, and be relatively short. +# +# * INFOFILE should contain more detailed information on the +# supported commands. +# +# * All default filenames are relative to $MAILDIR. +# +# * NOACKFILE is used by "ackmail.rc", with the same default. +# +# * Processed commands are logged in $COMMANDLOG. The format of the +# logged information is: +# +# date : address : command +# +# * To debug your configuration, touch $MAILDIR/commands.rc.log and +# watch its contents for logged information. Remove this file when +# you no longer wish to have a detailed debug log. +# +# * This recipe file uses "comm-reply-file.rc" (which is part of the +# procmail library). +# +# Current commands are: +# +# (send | get) help +# (send | get) info(rmation)? +# (send | get) pgp key +# (send | get) procmail info +# (send | get) procmail lib(rary) +# (send | get) smartlist lib(rary) +# (send | get) emacs setup +# (send | get) procmailrc +# (en|dis)able (auto *)ack(nowledgments) +# +# Author: Alan K. Stebbens +# +# Check for any of the commands + +:0 +* ? test -f commands.rc.log +{ OLDCMDLOGFILE=$LOGFILE + LOGFILE=commands.rc.log + LOGABSTRACT=all + VERBOSE=yes +} + +:0 +* ^Subject: *['"]?\/\ + ((send|get) +(help|info(rmation)?|\ + procmailrc|\ + (procmail|smartlist) *(- *)?info(rmation)?|\ + (procmail|smartlist) *(- *)?lib(rary)?|\ + emacs(-| *)setup|\ + pgp *key)|\ + (en|dis)able +(auto *)?ack(nowledge?ment)?s?) +* ! ^FROM_DAEMON +* $ ! ^X-Loop: $MY_ADDR +{ + # We're forking at this point -- so shutup procmail + COMSAT=off + + # Tell sendmail we've got control + DELIVERED=yes + + # Save a copy just in case (in log mode) + :0 c: + * LOGFILE ?? commands\.rc\.log + commands.requests + + # Get the trigger subject + SUBJ=$MATCH + + # Get the best reply address (used for logging) + :0 + * ! ^Reply-to: *\/[^ ].* + * ! ^From: *\/[^ ].* + * ! ^Sender: *\/[^ ].* + * ! ^From *\/[^ ]+ + { FROM=nobody } + :0E + { FROM=$MATCH } + + # Just in case these aren't defined + FROMSIG="${FROMSIG:-\"The Mailer-Daemon of $USER\" <$USER>}" + MY_ADDR="${MY_ADDR:-<$USER>}" + + # The log file + COMMANDLOG=${COMMANDLOG:-commands.log} + + # The basic processing works like this: + # Now that we've captured the important information from the + # incoming mail, we replace the headers portion with an + # autoreply header. + # + # Then, as part of recognizing the SUBJECT command, we + # replace the body portion with the response + # + # After testing for all the possible subject commands, + # we then submit the mail unless it is empty. + + # Generate a reply header, and replace the headers + :0 fhw + | formail -rI"From: $FROMSIG" \ + -I"Reply-To: $MY_ADDR" \ + -I"Subject: Re: $SUBJ" \ + -I"Precedence: junk" \ + -I"X-Loop: $MY_ADDR" + + # Now, start a new message body + :0 fbw + | echo "This message was sent automatically in reponse to your recent" ; \ + echo "mail with the subject: \"$SUBJ\"." ; \ + echo "" + + # Now process each command + + ##### send procmailrc + ##### send procmail lib + :0 + * SUBJ ?? procmail(rc| *(- *)?lib(rary)?) + { + # **** This is very site specific **** + PROCMAILDIR=$HOME/src/mail/procmail/procmail-lib + :0 + * SUBJ ?? procmailrc + { + REPLYFILE=$PROCMAILDIR/procmailrc-example + INCLUDERC=comm-reply-file.rc + } + :0 E + { + REPLYFILE=$PROCMAILDIR/procmail-lib.shar + INCLUDERC=comm-reply-file.rc + } + } + + #### send procmail info + :0 E + * SUBJ ?? (procmail|smartlist) *(- *)?info + { + PROCMAILINFO=${PROCMAILINFO:-procmail.info} + REPLYFILE=$PROCMAILINFO + INCLUDERC=comm-reply-file.rc + } + + ##### send smartlist library + :0 E + * SUBJ ?? smartlist *(- *)?lib(rary)? + { + # **** This is very site specific **** + REPLYFILE=$HOME/src/mail/procmail/smartlist-lib/smartlist-lib.shar + INCLUDERC=comm-reply-file.rc + } + + ##### send information + :0 E + * SUBJ ?? info(rmation)? + { + # The information file with a suitable default + INFOFILE=${INFOFILE:-commands.info} + REPLYFILE=$INFOFILE + INCLUDERC=comm-reply-file.rc + } + + ##### send emacs setup + :0 E + * SUBJ ?? emacs(-| *)setup + { + # Send emacs setup (shar archive is several files) + EMACSSETUP="$HOME/emacs/site-setup.shar*" + count=`echo $EMACSSETUP | wc -w` + + # For this command, we are responding with several mails + # so we cannot use procmail to "hold" them all at the + # same time. So, we generate several sendmail invocations + # and leave the current mail buffer empty by filtering it + # with /dev/null + + :0 fw:tmp.reply.lock + * $ ? test -f $EMACSSETUP + | cat - > tmp.reply ; \ + i=1 ; \ + for file in $EMACSSETUP ; do \ + cat tmp.reply $file \ + | formail -I "Subject: Re: $SUBJ [part $i/$count]" \ + | $SENDMAIL -oi -t ; \ + i=`expr $i + 1` ; \ + done ; \ + cat /dev/null + + :0 Efbw + | cat - ; \ + echo "Sorry, the emacs setup archive file is not currently available." + } + + ##### send pgp key + :0 E + * SUBJ ?? pgp *key + { + # Add some more headers + :0 fhw + | formail -I"Mime-Version: 1.0" \ + -I"Content-Type: application/pgp; format=keys-only" \ + -I"Content-Description: PGP key of $MY_ADDR" \ + -I"Content-Transfer-Encoding: 7bit" + + # get the text for the body + :0 fbw + | cat - ; \ + sh -c "pgp -kxaf $MY_ADDR 2>/dev/null" + + # If PGP failed somehow, leave a nice return message + :0 efbw + | cat - ; \ + echo "Sorry, my PGP key is not available at the moment." + } + + ##### (disable|enable) ack(nowledgements) + :0 E + * SUBJ ?? (dis|en)able + { + # Be sure NOACKFILE is defined + NOACKFILE=${NOACKFILE:-noacks} + + # remove this address from NOACKS + WHO=`formail -zxTo:` + + # The content of NOACKS are regexps, so we must carefully convert + # the address into a regexp which *matches* a regexp. + REWHO=`echo "$WHO" | sed -e 's/[.]/\\\\\\\\\\\\./g'` + + # See if the user is currently in the list of NO-ACKs + LOCKFILE=$NOACKFILE.lock + + :0 + * ? grep -s "^$REWHO" $NOACKFILE + { + # It is -- If "enable", remove it. + :0 + * SUBJ ?? enable + { + JUNK=`grep -v "^$REWHO" $NOACKFILE > $NOACKFILE.new ; + mv $NOACKFILE.new $NOACKFILE` + } + + :0 Afbw + | cat - ; \ + echo "Future mail from $WHO will be auto-acknowledged." ; \ + echo "" ; \ + echo "If you wish to disable auto-acknowledgements, please" ; \ + echo "send me an email message with the subject: \"disable autoacks\"." + + :0 Efbw + | cat - ; \ + echo "Mail from $WHO is already not being auto-acknowledged." + } + + # Else, $WHO is not in the $NOACKs + :0 E + { + # If the command was disable, add it to the file + # We must convert the address to a regexp as part of adding it + # to the file. + :0 + * SUBJ ?? disable + { JUNK=`echo "$WHO" | sed -e 's/[.]/\\\\./g' >> $NOACKFILE` } + + :0 Afbw + | cat - ; \ + echo "Future mail from $WHO will not be acknowledged." ; \ + echo "" ; \ + echo "If you wish to enable auto-acknowledgements, please" ; \ + echo "send me an email message with the subject: \"enable autoacks\"." + + :0 Efbw + | cat - ; \ + echo "Mail from $WHO is already being acknowledged." + } + + # Remove the global lockfile + LOCKFILE + } + + ##### send help (explicitly or because of some other request) + :0 E + { + # This is a combined recipe -- both the "send help" recipe + # and the "unknown" command recipes result in the sending + # of the helpfile. + + # If an unknown subject, append an error message + :0 fbw + * ! SUBJ ?? help + | cat - ; \ + echo 'Sorry, I don't know how to do this request.' ; \ + echo '' + + # The help file with a suitable default + HELPFILE=${HELPFILE:-commands.help} + REPLYFILE=$HELPFILE + INCLUDERC=comm-reply-file.rc + } + + # Okay, procmail should be "holding" some headers and some body + # text. Send it (if it is not an empty mail) + + :0 cw + * > 1 + ! -oi -t + + # Don't log anything else + LOGABSTRACT=off + + # Log this request (and mark the mail as "delivered") + :0 hw: $COMMANDLOG$LOCKEXT + | echo "`date` : $FROM : $SUBJ" >> $COMMANDLOG + + HOST=end_of_processing +} + +:0 +* LOGFILE ?? commands\.rc\.log +{ LOGFILE=$OLDCMDLOGFILE + LOGABSTRACT=yes + VERBOSE=no +} + +# End of commands.rc diff --git a/share/procmail/correct-addr.rc b/share/procmail/correct-addr.rc @@ -0,0 +1,411 @@ +# correct-addr.rc +# +# $Id: correct-addr.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1996 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Procmail recipe file to help forward mail from an OLD address to a +# NEW address, and do some mailing list mail management. +# +# This recipe file is intended to make it easy for users to forward +# their mail from their old address to a new address, and, at the same +# time, educate their correspondants about it by CC'ing them with the +# mail. +# +# Only mail directly addressing the user at the old address will cause a +# "correction notice" to be sent. +# +# Mail *not* directly addressing the old address (eg: from a mailing list) +# is treated separately, according to the MAILLIST variable; it can be one +# or more of these values: +# +# drop This is the default behaviour, and is only defined to +# explicitly acknowledge this. In other words, "drop" +# and "forward" are mutually exclusive, and omitting +# "forward" implies "drop", but not vice versa. +# +# forward forward all mailing list mail to $NEWADDR, inserting +# "Resent-From:" and "Resent-To:" headers. Of course, +# $NEWADDR must also be defined. +# +# report report the headers of all mailing list mail to +# $POSTMASTER, so that the person handling this role can +# send the appropriate unsubscription requests. +# +# *** NOT IMPLEMENTED *** +# +# bounce return all mailing list mail with "User has moved!" to +# the "request" or "owner" address; great pains are taken +# to not respond to a general distribution list address. +# If the proper list address cannot be determined, then +# the ultimate fallback return address is "postmaster" at +# the originating domain. +# +# remove If the originating mailing list software type can be +# determined, automatically generate an "unsubscribe" +# address on the $OLDADDR. Currently, the recipe +# understands Majordomo, SmartList, and LISTSERV commands. +# If the mailing list software cannot be determined, then +# falls back to "report" action. +# +# change If the originating mailing list software type can be +# determined, automatically generate mails to the list +# request address to unsubscribe the old address and to +# subscribe the new address, if given. If the mailing +# list software cannot be determined, then falls back +# to "report" action. +# +# Multiple keywords can be given to accomplish several things on the +# mailing list mail. +# +# Without the "forward" keyword, mailing list mail will not ever be +# forwarded, even if NEWADDR is defined. Therefore, to have mailing +# list mail be both forwarded and bounced, use "forward,bounce". To +# have mailing list mail be forwarded, and have the subscription +# changed where possible, use "forward,change". +# +# +# Usage: +# +# These variables are *optional*, with the defaults as shown: +# +# OLDLOGIN=$LOGNAME +# The primary old login; this will be used in the +# correction notice sent to correspondants. +# +# OLDUSER=$FRIENDLY (see get-from.rc} +# The user's old real name, included in the correction +# notice. If not set by the user, FRIENDLY is used, which +# is determined by the procmail recipe file "get-from.rc". +# +# OLDLOGINS='$\LOGNAME' +# A regexp matching the old login name(s). If the user +# received mail at more than one login name, this should +# match them all. For most users, the default is fine. +# +# NOTLOGINS= +# A regexp matching logins mail to which should NOT be +# forwarded or corrected. This can be used to form +# a filter to correct mail addressed ambiguously. See +# the man page for examples. +# +# NOTSUBJECTS= +# Any mail containing subjects matching this regexp does +# not get corrected or filtered. +# +# DOMAIN= +# The domain in which this user resides; without this +# definition, this script can only match on the user +# name. +# +# HOSTS='[^. ]+' +# A regexp matching the hosts at which the OLDLOGIN +# receives mail. This is used in conjunction with $DOMAIN +# so don't place the domain in this regexp. +# +# NEWADDR= +# The address to which mail should be forwarded. There is +# no default, resulting in no forwarding; in this case, only +# reply with "no such user" notices. +# +# NEWUSER=$OLDUSER +# The new user name, defaulting to the old user name. This +# is used for correction notices. +# +# POSTMASTER=Postmaster <postmaster> +# This is used as the From: address for both the correction +# "no such user" notices. +# +# MAILLIST=[keyword,...] +# One or more keywords: forward, report, bounce, remove, +# or change, separated by spaces or commas. See the +# description above for details. +# +# INCLUDERC=correct-addr.rc +# +# Examples: +# +# a. John Carter has moved from his current location to "carter@mars.com", +# and he wishes to have his mailing mail forwarded. +# +# NEWADDR = carter@mars.com +# MAILLIST = forward +# INCLUDERC = correct-addr.rc +# +# b. Clark Kent has moved back to his hometown, and does not want his +# mail forwarded at all, especially his mailing lists. +# +# NEWADDR # guarantee no NEWADDR +# MAILLIST = bounce,remove +# INCLUDERC = correct-addr.rc +# +# c. Dennis Mitchell has been receiving mail by many aliases, and, having +# gone off to college, wishes to have all of his mail sent to his +# new email address. +# +# NEWADDR = menace@engineering.ucsb.edu +# OLDLOGINS = "(Dennis|D.Mitchell|Dennis.Mitchell|Menace)" +# MAILLIST = forward +# INCLUDERC = correct-addr.rc +# +# d. Lois Lane has gotten married, and wishes to have her mail forwarded +# to her new address, with her mailing list subscriptions changed, and +# she wishes to have any correction notices mention her new name. +# +# NEWADDR = lois@smallville.ia.us +# OLDLOGINS = "(Lois|Lane|L.Lane|Lois[._]Lane)" +# NEWUSER = "Lois Kent" +# MAILLIST = forward,change +# INCLUDERC = correct-addr.rc +# +# e. Tom, a clever system manager, has installed an automatic alias for +# users when their logins expires (and they no longer have a home +# directory in which to place a ~/.procmailrc file), which invokes +# a small shell script, called "correct-mail": +# +# olduser1: "|correct-mail olduser1" +# olduser2: "|correct-mail olduser2" +# +# The shell script looks like this: +# +# #!/bin/sh +# PATH=$PATH:/usr/local/bin ; export PATH +# procmail -m LOGNAME=$1 \ +# MAILLIST=bounce,report \ +# DEFAULT=/dev/null \ +# MAILDIR=/tmp \ +# LOGFILE=/usr/adm/correct-mail.log \ +# LOGABSTRACT=yes \ +# /etc/procmailrcs/correct-addr.rc +# + +# First let's do some optional logging +# If the file "correct-addr.rc.log" exists, we log extensively +# to it. + +:0 +* ? test -f correct-addr.rc.log +{ CA_LOGFILE=$LOGFILE + CA_LOGABSTRACT=$LOGABSTRACT + CA_VERBOSE=$VERBOSE + LOGFILE=correct-addr.rc.log + LOGABSTRACT=all + VERBOSE=yes +} + +# A temporary file used to hold mail being reported to the postmaster +REPORTMAIL=tmp.ca-mail.$LOGNAME + +# Make sure variables have default settings + +OLDLOGIN=${OLDLOGIN:-$LOGNAME} +HOSTS=${HOSTS:-'[^. >(),;]+'} +POSTMASTER="${POSTMASTER:-\"Postmaster <postmaster>\"}" +MAILLIST=${MAILLIST:-forward} + +DOMAIN="`echo \"$DOMAIN\" | sed -e 's/\\./\\\\./'`" + +# HOSTPART matches the entire hostname part of an address +HOSTPART="(@($HOSTS(\.$DOMAIN)?|$DOMAIN))?([,();> ]|$)" + +# Define a regexp matching the old addresses +:0 +* OLDLOGINS ?? . +{ OLDADDRS="($OLDLOGIN|$OLDLOGINS)$HOSTPART" } + +# There isn't a set of other logins +:0 E +{ OLDADDRS="$OLDLOGIN$HOSTPART" } + +# Okay -- now begin the basic tests. + +# Be sure we don't loop +:0 +* $ ^X-Loop: $LOGNAME@$HOST +{ } + +# Make sure that the negative filters do not apply + +# If there is a NOTLOGINS defined, and it matches the addressee +# then don't correct/forward +:0 E +* NOTLOGINS ?? . +* $ ! ^TO$NOTLOGINS$HOSTPART +{ } + +# If there is a NOTSUBJECTS defined, and it matches the subject +# then don't correct or forward +:0 E +* NOTSUBJECTS ?? . +* $ ! ^Subject: *$NOTSUBJECTS +{ } + +# Else, if the mail matches the OLDLOGINS, then correct and forward +:0 E +* $ ^TO$OLDADDRS +{ + # Begin the correction and forwarding part + OLDADDR=$MATCH + + :0 + * OLDADDR ?? [,(); >]$ + { OLDADDR="`echo \"$OLDADDR\" | sed -e 's/[,(); >]$//'`" } + + # First, save a copy + LOCKFILE=$REPORTMAIL.lock + + :0 c + $REPORTMAIL + + # Set OLDUSER to FRIENDLY if not already set + :0 + * ! OLDUSER ?? . + { INCLUDERC=get-from.rc + OLDUSER=$FRIENDLY } + + # Generate a new header + :0 fhw + | formail -rt -I"From: $POSTMASTER" \ + -I"Subject: Your mail to $OLDADDR" \ + -I"X-Loop: $LOGNAME@$HOST" + + # Is there a new address for forwarding? + :0 a + * NEWADDR ?? . + { + # Be sure NEWUSER is set + NEWUSER=${NEWUSER:-$OLDUSER} + + # Make sure the new user gets a copy of the correction notice + :0 afhw + | formail -A"Cc: $NEWADDR ($NEWUSER)" + + :0 afbi + | echo "Your mail to $OLDUSER at:" ; \ + echo "" ; \ + echo " $OLDADDR" ; \ + echo "" ; \ + echo "is no longer correct; ${NEWUSER} now receives mail at:" ; \ + echo "" ; \ + echo " $NEWADDR" ; \ + echo "" ; \ + echo "This message, with your original mail, is also being forwarded" ; \ + echo "to the new address." ; \ + echo "" ; \ + echo "Please remember to update the address you have for $NEWUSER in" ; \ + echo "any mail address database you may use." + } + + # If NEWADDR is not set, just tell the sender that this address + # is no longer valid + :0 Efbi + | echo "Your mail to $OLDUSER at:" ; \ + echo "" ; \ + echo " $OLDADDR" ; \ + echo "" ; \ + echo "is being returned because this user is no longer at this address" ; \ + echo "and no forwarding address has been provided." + + # Append the signature and the original mail, and send it + :0 fb + | cat ; \ + echo "" ; \ + echo "Regards, the $POSTMASTER" ; \ + echo "" ; \ + echo "Your original mail follows:" ; \ + echo "------------------------------------------------------------" ; \ + formail <$REPORTMAIL + + JUNK=`rm -f $REPORTMAIL` + + LOCKFILE + + # Now ship off the mail to sendmail + :0 + ! -oi -t +} + +# If the mail wasn't directly to $OLDLOGIN, it is mail from a +# mailing list, so don't send a correction notice, + +#### Mailing list mail #### + +:0 E +* MAILLIST ?? (forward|report|bounce|remove|change) +* $!^X-Loop: $LOGNAME@$HOST +{ + + # Both change and remove require some mailing list heuristics + # Use common code for this + :0 + * MAILLIST ?? (change|remove) + { + # get common header definitions + INCLUDERC=headers.rc + + # Try to determine the mailer address + INCLUDERC=list-addr.rc + + # ***** NOT YET IMPLEMENTED ***** + + } + + :0c + * MAILLIST ?? report + { + LOCKFILE=tmp.mail.lock + :0 chw # save a copy of the headers + | sed -en '1,/^[ ]*$/s/^/ /p' >tmp.mail + + :0 fhw # generate report header to Postmaster + | formail -I"From: Mailer-Daemon <mailer-daemon>" \ + -I"To: $POSTMASTER" \ + -I"Subject: Mailing list mail to old address: $OLDLOGIN" \ + -I"X-Loop: $LOGNAME@$HOST" + + :0 afbwi # make a report + | echo "Mail is still being sent to $OLDLOGIN indirectly, possibly" ; \ + echo "through a mailing list. The headers of the mail are supplied " ; \ + echo "below." ; \ + echo "" ; \ + echo "------------------- Original mail headers ------------------" ; \ + cat tmp.mail + + LOCKFILE + + :0 aw # file the report + ! -oi -t + } + + # forward it if NEWADDR defined, and MAILLIST includes "forward" + :0 + * MAILLIST ?? forward + * NEWADDR ?? . + { # Add new headers indicating the forwarding + :0 fhw + | formail -A"X-Loop: $LOGNAME@$HOST" \ + -i"Resent-From: $OLDADDR" \ + -i"Resent-To: $NEWADDR" + :0 aw + ! $NEWADDR + } + + # Otherwise, assume a drop + :0 + /dev/null + +} diff --git a/share/procmail/date.rc b/share/procmail/date.rc @@ -0,0 +1,485 @@ +# date.rc +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# $Id: date.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Procmail recipe to extract and create some variables related to +# the date in the message. If the message has no date reference, +# either the variables are returned undefined, or set using the +# current date depending upon DATE_DEFAULT_NOW. + +# Currently, this recipe file parses dates with these formats: +# +# 1. Tue(sday), 31 Dec 96 +# 2. Tue, 31 Dec 1996 +# 3. 12/31/96 +# 4. Tuesday, December 31, 1996 +# +# If DATE is not defined, then obtain the date from the current input message +# from the following headers, in decreasing priority: Resent-Date:, Date:, +# and "From ". +# +# If DATE is defined, it is simply used as the input. +# +# Thus to parse the date from the current mail message do this: +# +# DATE INCLUDERC=date.rc +# +# To make this even easier, use "get-date.rc": +# +# INCLUDERC=get-date.rc +# +# To parse a given date string, simply set DATE: +# +# DATE=12/31/96 INCLUDERC=date.rc +# +# +# These variables are set from the parsing of DATE: +# +# DATE # the original, complete date string from which +# # all other variables were derived +# DATE_WEEKDAY # the weekday name, if present +# DATE_WDAY # the short weekday name, if present +# DATE_DAY # the day of the month (eg: 1) +# DATE_DAY2 # the day of the month with two digits: (eg: 01) +# DATE_MONTH # the month of the year +# DATE_MONTH2 # the month of the year with two digits: (eg: 01) +# DATE_MONTHNAME # the long name of the month (eg: December) +# DATE_MONTHABBR # the abbreviated name of the month (eg: Dec) +# DATE_YEAR # the four-digit year (eg: 2001) +# DATE_YEAR2 # the last two digits of the year (eg: 96) +# +# DATE_MMDDYY # the date as MM/DD/YY (use DATE_SEP1 as separator) +# DATE_MMDDYYYY # the date as MM/DD/YYYY +# DATE_YYMMDD # the date as YY/MM/DD (use DATE_SEP1 as separator) +# DATE_YYYYMMDD # the date as YY/MM/DD (use DATE_SEP1 as separator) +# DATE_DDMMMYY # the date as DD MMM YY (use DATE_SEP2 as separator) +# DATE_DDMMMYYYY # the date as DD MMM YYYY +# +# DATE_UNIX # the date as WDAY, DD MMM YYYY (ala `date`) +# DATE_LONG # the date as WEEKDAY, MMMMM DD, YYYY +# DATE_DEC # the date as DD-MMM-YYYY +# DATE_MMMDDYYYY # the date as MMMMM DD, YYYY +# DATE_TIME # the date/time in `date` format: Fri Oct 11 12:52:48 PDT 1996 +# DATE_CTIME # the date/time in "ctime" format: Fri Sep 13 00:00:00 1986 +# +# DATE_SEP1 # the character used to separate digits/letters of +# # MMDDYY or YYMMDD +# DATE_SEP2 # the character used to separate DDMMMYY +# +# TIME # the orininal string from which the time variables +# # were derived. +# TIME_HOURS # hours (as given) +# TIME_HOURS2 # hours in 2 digits (as given) (eg: 01) +# TIME_HOURS12 # hours modulo 12 +# TIME_HOURS24 # military hours [00-23] +# TIME_MINS # minutes (eg: 34) +# TIME_SECS # seconds (eg: 56) +# TIME_AMPM # 'am' or 'pm' +# TIME_ZONE # The timezone JST, EST, EDT, etc. +# +# TIME_MILITARY # hhmm (0000-2359) eg: 0630 +# TIME_HHMM # hh:mm (eg: 12:03) +# TIME_HHMMSS # hh:mm:ss (eg: 12:03:45) +# TIME_12 # hh:mm am/pm +# TIME_24 # hh:mm (military style) +# +# These variables are used within date.rc but will not return +# meaningful values. +# +# DAYS_RE MONTHS_RE S Y N NN APM ZONE X D + +DAYS_RE='(Mon|Tues?|Wed(nes)?|Thu(rs)?|Fri|Sat(ur)?|Sun)(day)?' +MONTHS_RE='(Jan(uary)?|Feb(ruary)?|Mar(ch)?|Apr(il)?|May|June?|\ +July?|Aug(ust)?|Oct(ober)?|(Sept?|Nov|Dec)(ember)?)' +S='[/-,. ]+' +Y='[0-9][0-9][0-9][0-9]' +N='[0-9]+' +NN='[0-9][0-9]' +APM='[ap]m' +ZONE='([-+][0-9][0-9][0-9]( GMT)?|[PMCE][SD]T([45678][PMCE]DT)?|JST)' + +:0 +* ! DATE ?? . +{ :0 + * ^Resent-Date: *\/[^ ].* + { DATE=$MATCH } + :0 E + * ^Date: *\/[^ ].* + { DATE=$MATCH } + :0 E + * ^From *[^ ]+ +\/[^ ].* + { DATE=$MATCH } +} + +:0 +* ! DATE ?? . +* DATE_DEFAULT_NOW ?? . +{ DATE=`date` } + +# If there is a date to work with, let's begin to parse it +:0 +* DATE ?? . +{ # First, look for a weekday, and extract it + :0 + * $ DATE ?? ()\/$DAYS_RE + { DATE_WDAY=$MATCH + # See if the day was abbreviated or long + :0 + * DATE_WDAY ?? day + { DATE_WEEKDAY=$DATE_WDAY # get the long day name + # And, extract the short version from it + :0 + * DATE_WEEKDAY ?? ^\/... + { DATE_WDAY=$MATCH } + } + :0 E # okay, it was a short name + { :0 + * DATE_WDAY ?? Tue + { DATE_WEEKDAY=Tuesday } + :0 E + * DATE_WDAY ?? Wed + { DATE_WEEKDAY=Wednesday } + :0 E + * DATE_WDAY ?? Thu + { DATE_WEEKDAY=Thursday } + :0 E + * DATE_WDAY ?? Sat + { DATE_WEEKDAY=Saturday } + :0 E + { DATE_WEEKDAY=${DATE_WDAY}day } + } + } + + # Here's where we parse the date + :0 # MM/DD/YYYY? + * $ DATE ?? ()\/$N$S$N$S$Y + { X=$MATCH + :0 + * $ X ?? ()\/$N + { MM=$MATCH } + :0 + * $ X ?? $N$S\/$N + { DD=$MATCH } + :0 # try YYYY first + * $ X ?? $S\/$Y + { YYYY=$MATCH } + :0 E + * $ X ?? $N$S$N$S\/$N + { YY=$MATCH } + } + :0 E # YYYY/MM/DD? + * $ DATE ?? ()\/$Y$S$N$S$N + { X=$MATCH + :0 + * $ X ?? ()\/$Y + { YYYY=$MATCH } + :0 + * $ X ?? $Y$S\/$N + { MM=$MATCH } + :0 + * $ X ?? $Y$S$N$S\/$N + { DD=$MATCH } + } + :0 E # MM/DD/YY or YY/MM/DD? + * $ DATE ?? $N$S$N$S$N + { X=$MATCH + :0 + * $ X ?? ()\/$N + { MM=$MATCH } + :0 + * $ X ?? $N$S\/$N + { DD=$MATCH } + :0 + * $ X ?? $N$S$N$S\/$N + { YY=$MATCH } + + # Use heuristics to determine of MM/DD/YY or YY/MM/DD + # If MM > 12, it must be YY + :0 E + * MM ?? ^([2-9][0-9]|1[3-9]) + { X=$YY YY=$MM MM=$DD DD=$X X } # swap formats + } + :0 E # is it DD MMM YYYY ? + * $ DATE ?? ()\/$N$S$MONTHS_RE$S$N + { X=$MATCH + :0 + * $ X ?? ()\/$N + { DD=$MATCH } + :0 + * $ X ?? ()\/$MONTHS_RE + { MMM=$MATCH } + :0 # first try matching YYYY + * $ X ?? ()\/$Y + { YYYY=$MATCH } + :0 E # ok, use YY, but don't match the first pair + * $ X ?? $N.*$S\/$N + { YY=$MATCH } + } + :0 E # YYYY MMM DD? + * $ DATE ?? ()\/$Y$S$MONTHS_RE$S$N + { X=$MATCH + :0 + * $ X ?? ()\/$Y + { YYYY=$MATCH } + :0 + * $ X ?? ()\/$MONTHS_RE + { MMM=$MATCH } + :0 + * $ X ?? $Y$S.*$S\/$N + { DD=$MATCH } + } + :0 E # MMM DD, YYYY? + * $ DATE ?? ()\/$MONTHS_RE$S$N$S$Y + { X=$MATCH + :0 + * $ X ?? ()\/$MONTHS_RE + { MMM=$MATCH } + :0 + * $ X ?? ()\/$N + { DD=$MATCH } + :0 + * $ X ?? ()\/$Y + { YYYY=$MATCH } + } + # Okay, this might be a Unix date: MMM DD HH:MM:SS ZONE YEAR + # So, test the parts individually + :0 E # MMM DD ... YYYY? + * $ DATE ?? $MONTHS_RE$S$N.*$Y + { :0 # MMM DD? + * $ DATE ?? ()\/$MONTHS_RE$S$N + { X=$MATCH + :0 # get the month name + * $ X ?? ()\/$MONTHS_RE + { MMM=$MATCH } + :0 # get the day + * $ X ?? ()\/$N + { DD=$MATCH } + :0 E + { DD='??' } + } + :0 # is there a year? + * $ DATE ?? ()\/$Y + { YYYY=$MATCH } + } + + # Now match for any time + :0 # hh:mm(:ss) (a/pm) (+700 | pdt/pst...) + * $ DATE ?? ()\/$N:$NN(:$NN)?($S$APM)?($S$ZONE)? + { TIME=$MATCH # get any time string + # clear these variables + TIME_HOURS TIME_HOURS2 TIME_MINS TIME_SECS TIME_AMPM TIME_HOURS24 + :0 # get the hours + * $ TIME ?? ()\/$N + { TIME_HOURS=$MATCH TIME_HOURS2=$MATCH + :0 + * TIME_HOURS2 ?? ^.$ + { TIME_HOURS2=0$TIME_HOURS } + } + :0 + * $ TIME ?? $N:\/$NN + { TIME_MINS=$MATCH } + :0 + * $ TIME ?? $N:$NN:\/$NN + { TIME_SECS=$MATCH } + :0 + * $ TIME ?? ()\/$APM + { TIME_AMPM=$MATCH + :0 # if 01..09,10,11 pm? + * TIME_AMPM ?? pm + * TIME_HOURS ?? (0?[1-9]|1[01]) + { TIME_HOURS24=`expr $TIME_HOURS + 12` } + :0 E # if 12 am? + * TIME_AMPM ?? am + * TIME_HOURS ?? 12 + { TIME_HOURS24=00 } + TIME_HOURS12=$TIME_HOURS + } + # no AM/PM, create HOURS24, HOURS12 + :0 E # given time >= 13? + * TIME_HOURS ?? (1[3-9]|2.) + { TIME_HOURS24=$TIME_HOURS TIME_HOURS12=`expr $TIME_HOURS - 12` } + :0 E # no am/pm, and time < 12 + { TIME_HOURS24=$TIME_HOURS TIME_HOURS12=$TIME_HOURS } + + :0 # now, check for time zone + * $ TIME ?? ()\/$ZONE + { TIME_ZONE=$MATCH } + + # Create the remaining derived vars + TIME_HHMM="$TIME_HOURS:$TIME_MINS" + TIME_HHMMSS=$TIME_HHMM:${TIME_SECS:-00} + TIME_MILITARY=$TIME_HOURS24$TIME_MINS + } + X T # clear the variables we used + + # We now have three parts: MM or MMM, DD, and YY or YYYY. + + # If we have MMM, convert to MM (which will later be converted back to MMM) + :0 # is MMM defined? + * MMM ?? . + { :0 # is it the long name? + * MMM ?? ^.... + { DATE_MONTHNAME=$MMM + :0 # extract the abbreviation + * MMM ?? ^\/... + { DATE_MONTHABBR=$MATCH } + MM # clear MM + } + :0 E # nope, it must be an abbreviation + * MMM ?? Jan + { MM=01 } + :0E + * MMM ?? Feb + { MM=02 } + :0E + * MMM ?? Mar + { MM=03 } + :0E + * MMM ?? Apr + { MM=04 } + :0E + * MMM ?? May + { MM=05 } + :0E + * MMM ?? Jun + { MM=06 } + :0E + * MMM ?? Jul + { MM=07 } + :0E + * MMM ?? Aug + { MM=08 } + :0E + * MMM ?? Sep + { MM=09 } + :0E + * MMM ?? Oct + { MM=10 } + :0E + * MMM ?? Nov + { MM=11 } + :0E + * MMM ?? Dec + { MM=12 } + MMM # clear MMM + } + + # If we have MM, convert to MMM + :0 + * MM ?? . + { :0 # check on leading zero + * MM ?? ^0?\/[0-9]$ + { DATE_MONTH=$MATCH + DATE_MONTH2=0$MATCH + } + :0 E + { DATE_MONTH2=$MM DATE_MONTH=$MM } + MM=$DATE_MONTH + # Now, convert MM -> DATE_MONTHNAME + :0 + * MM ?? 10 + { DATE_MONTHNAME=October } + :0E + * MM ?? 11 + { DATE_MONTHNAME=November } + :0E + * MM ?? 12 + { DATE_MONTHNAME=December } + :0E + * MM ?? 1 + { DATE_MONTHNAME=January } + :0E + * MM ?? 2 + { DATE_MONTHNAME=February } + :0E + * MM ?? 3 + { DATE_MONTHNAME=March } + :0E + * MM ?? 4 + { DATE_MONTHNAME=April } + :0E + * MM ?? 5 + { DATE_MONTHNAME=May } + :0E + * MM ?? 6 + { DATE_MONTHNAME=June } + :0E + * MM ?? 7 + { DATE_MONTHNAME=July } + :0E + * MM ?? 8 + { DATE_MONTHNAME=August } + :0E + * MM ?? 9 + { DATE_MONTHNAME=September } + MM # clear MM + } + # Set the month abbreviation + :0 + * DATE_MONTHNAME ?? ^\/... + { DATE_MONTHABBR=$MATCH } + + # Now check on the day + :0 + * DD ?? ^0?\/[0-9]$ + { DATE_DAY=$MATCH DATE_DAY2=0$MATCH } + :0 E + { DATE_DAY=$DD DATE_DAY2=$DD } + DD # clear DD + + # Now check on the year: if YYYY is not available, use YY + YYYY=${YYYY:-$YY} + YY # clear YY + + # If YYYY only has two digits, derive the current year + :0 + * YYYY ?? ^..$ + { YYYY=`date +%Y | sed -e 's/..$/'$YYYY'/'` } + + DATE_YEAR=$YYYY + YYYY # clear YYYY + + :0 # get the last two digits of the year + * DATE_YEAR ?? ^..\/.. + { DATE_YEAR2=$MATCH } + + SEP1=${DATE_SEP1:-'/'} + SEP2=${DATE_SEP2:-' '} + + # Now, setup the formatted strings + DATE_MMDDYY="$DATE_MONTH2$SEP1$DATE_DAY2$SEP1$DATE_YEAR2" + DATE_MMDDYYYY="$DATE_MONTH2$SEP1$DATE_DAY2$SEP1$DATE_YEAR" + YYMMDD="$DATE_YEAR2$SEP1$DATE_MONTH2$SEP1$DATE_DAY2" + YYYYMMDD="$DATE_YEAR$SEP1$DATE_MONTH2$SEP1$DATE_DAY2" + DATE_DDMMMYY="$DATE_DAY2$SEP2$DATE_MONTHABBR$SEP2$DATE_YEAR2" + DATE_DDMMMYYYY="$DATE_DAY2$SEP2$DATE_MONTHABBR$SEP2$DATE_YEAR" + DATE_MMMDDYYYY="$DATE_MONTHNAME $DATE_DAY, $DATE_YEAR" + DATE_UNIX="$DATE_WDAY, $DATE_DAY$SEP2$DATE_MONTHABBR$SEP2$DATE_YEAR" + DATE_LONG="$DATE_WEEKDAY, $DATE_MONTHNAME $DATE_DAY, $DATE_YEAR" + DATE_TIME="$DATE_WDAY $DATE_MONTHABBR $DATE_DAY2 $TIME_HHMMSS" + DATE_CTIME="$DATE_WDAY $DATE_MONTHABBR $DATE_DAY2 $TIME_HOURS24:$TIME_MINS:${TIME_SECS:-00}" + :0 + * TIME_AMPM ?? . + { DATE_TIME="$DATE_TIME $TIME_AMPM" } + :0 + * TIME_ZONE ?? . + { DATE_TIME="$DATE_TIME $TIME_ZONE" DATE_CTIME="$DATE_CTIME $TIME_ZONE" } + DATE_TIME="$DATE_TIME $DATE_YEAR" + DATE_CTIME="$DATE_CTIME $DATE_YEAR" +} diff --git a/share/procmail/dupcheck.rc b/share/procmail/dupcheck.rc @@ -0,0 +1,222 @@ +# dupcheck.rc +# +# Copyright (C) 1997 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Usage: +# +# INCLUDERC=dupcheck.rc +# +# If the current mail has a "Message-Id:" header, run the +# mail through "formail -D", causing duplicate messages to +# be dropped. +# +# If the mail does not have a "Message-Id", or if the variable +# "dupcheck_use_md5" is set, then run the body through MD5SUM (defaults +# to "md5sum"), causing duplicate messages to be dropped. However, +# even if "dupcheck_use_md5" is set, the "formail -D" filter will +# still be applied if a Message-Id: exists. +# +# Currently, the only way to use *only* an "md5sum" duplicate check +# is to remove the Message-Id: before invoking this recipe file. +# Something like this: +# +# :0fh # remove the Message-Id: +# | formail -IMessage-Id: +# INCLUDERC=dupcheck.rc +# +# In my opinion, however, an MD5 checksum should be used in addition to using +# the Message-Id:, not instead of. The MD5 checksums can be used to +# detect and avoid redistributed or resent messages. +# +# The variable MD5SUM can be set to the program to perform the checksum +# on the message body. By default, it is set to "md5sum". +# +# This recipe has been enhanced with a "fail-safe" algorithm to avoid +# losing mail which has been "soft-failed" by some later part of the +# user's recipe file. This algorithm is only applied if the variable +# "dupcheck_failsafe" has been set to the number 1 or 2. +# +# There are two methods available to accomplish this, and selected by +# the variable "dupcheck_failsafe". +# +# 1. the simple way: remove the checksum files when procmail exits with +# an exitcode of 75. This is done by using a TRAP command. +# +# The disadvantage is that when any mail "soft fails" for any +# reason, duplicate mail arriving after the soft-failure for mail +# originally received before the soft-failure will not be detected. +# +# An advantage of this method is its simplicity. The worst case is +# that a few duplicates may not be detected. +# +# 2. the hard way: using an additional "pending" log file, when a new +# mail arrives and passes the checksum filters the first time, add it +# to the "pending" file. Using a TRAP command, remove the processed +# mail from the "pending" file, unless the exitcode was 75 +# (EX_TEMPFAIL). If the mail fails the checksum commands, but is +# still in the pending file, then do NOT drop the mail as a +# duplicate, and leave it in the pending file. Eventually, when the +# mail is finally delivered (by any means), it will be removed from +# the "pending" file. +# +# The disadvantage with this method is its complexity: an additional +# "pending" file is needed, and there is a small performance hit for +# each mail, in order to maintain the pending file. +# +# The advantage of this method is its completeness: all duplicates +# will still be detected and dropped. +# +# Both methods require the use of the TRAP command; they set additional +# commands into the TRAP variable. If the TRAP command has already been +# set, the new commands are added to the list of commands. +# +# *** Warning: if the user sets the TRAP command in a later recipe, care +# should be taken to avoid losing the commands installed by this recipe. +# The way to set TRAP with a new command, without losing the existing +# ones, if any is: +# +# TRAP="${TRAP:+${TRAP}; }new-command args ..." +# +# All the default filenames used by this recipe are relative to the +# current directory, $MAILDIR. + +msgids=.msgids # where we keep the message id's +md5sums=.md5sums # where the md5 checksums go +pendingids=.pendingids # pending mail cache + +dupcheck_failsafe=${dupcheck_failsafe:-2} + # set to 1, 2, or anything else, + # to indicate which method is + # preferred. Defaults to 2. + # If unset or not 1 or 2, then *no + # failsafe* method is applied. + +OLDCOMSAT=${COMSAT:-off} # Don't tell COMSAT anything +COMSAT=off + +# To keep the complexity of this recipe down, we'll separate the +# failsafe methods + +:0 # methods 1 or 0 (none) +* !dupcheck_failsafe ?? ^^2^^ +{ + :0 Wh: $msgids.lock # is there a Message-Id:? + * ^Message-Id: *\/[^ ].* + | formail -D 16384 $msgids + # mail is not a duplicate.. + :0 e # passed formail's check; failsafe it? + * dupcheck_failsafe ?? 1 + { TRAP="${TRAP:+${TRAP}; }test \$EXITCODE -eq 75 && rm -f $msgids" } + + :0 # derive a checksum if needed or requested + * 1^0 !^Message-Id: + * 1^0 dupcheck_use_md5 ?? . + { :0 b # scan only the body + MD5SUM=|${MD5SUM:-md5sum} # compute md5sum on the body + + LOCKFILE=$md5sums.lock # lock $md5sums + :0 aWhi # see if this is a duplicate message + |fgrep -s "$MD5SUM" $md5sums # if fgrep succeeds, we've tossed the mail + # Hurray! The mail is not a duplicate! + :0 echi # add the new checksum to the file + |echo "$MD5SUM" >>$md5sums + LOCKFILE # unlock $md5sums + + :0 # see if the msg already has a header + * ^X-MD5-Checksum: \/[^ ].* + * $? test "$MD5SUM" != "$MATCH" + { insert_opt='i' } # save the old flags on mismatch + :0 fh # insert (or replace) current checksum + |formail -${insert_opt:-'I'}"X-MD5-Checksum: $MD5SUM" + :0 # any failsafe? + * dupcheck_failsafe ?? 1 + { TRAP="${TRAP:+${TRAP}; }test \$EXITCODE -eq 75 && rm -f $md5sums" } + } +} +:0 E # fail-safe method 2: +* dupcheck_failsafe ?? ^^2^^ +{ # With method 2, we must maintain a file of "pending" mail using this + # recipe and a command in the TRAP variable. + + :0 chi:$pendingids.lock # ensure that the pending cache is writable + * !?test -w $pendingids + | rm -f $pendingids ; touch $pendingids + + pending # clear var + LOCKFILE=$pendingids.lock # lock $pendingids + # If there's a Message-Id and the mail is not pending + :0 # is there a message-id? + * ^Message-Id: *[^ ]\/.* + { MSGID=$MATCH # save for later + :0 # see if pending + * $!?fgrep -s '$MATCH' $pendingids + { :0 Wh:$msgids.lock # see if the mail is a duplicate + |formail -D 16384 $msgids + + :0 chi # it's not; update the pending cache + |echo "$MSGID" >>$pendingids + + } + :0 E # it is a pending mail + { pending=y } # mark it so + # Update the TRAP command list to remove the msgid from the + # pending cache on normal exits + TRAP="${TRAP:+${TRAP}; }\ + if test \$EXITCODE -ne 75 ; then \ + fgrep -v '$MSGID' $pendingids >$pendingids.new ; \ + mv $pendingids.new $pendingids ; \ + fi" + } + LOCKFILE # unlock $pendingids + + # if not already pending, derive a checksum if needed or requested + :0 + * 1^0 !^Message-Id: + * 1^0 dupcheck_use_md5 ?? . + { :0 b # checksum the desired headers and body + MD5SUM=|${MD5SUM:-md5sum} # see if this is a duplicate message + LOCKFILE=$pendingids.lock # check the pending cache + :0 # make sure it's not pending + * ! pending ?? y + * $!?fgrep -s '$MD5SUM' $pendingids + { :0 Whi:$md5sums.lock # see if mail is an MD5 duplicate + |fgrep -s "$MD5SUM" $md5sums + # Hurray! the mail is not a duplicate + :0 chi: # add the new checksum to the file + |echo "$MD5SUM" >>$md5sums + :0 achi # update the pending cache + |echo "$MD5SUM" >>$pendingids + } + LOCKFILE # maybe pending now + # Either we've updated the pending file, or the checksum was + # already in it. So, now we update the TRAP command list to + # remove the checksum on normal exits. + TRAP="${TRAP:+${TRAP}; }\ + if test \$EXITCODE -ne 75 ; then \ + fgrep -v '$MD5SUM' $pendingids >$pendingids.new ; \ + mv $pendingids.new $pendingids ; \ + fi" + :0 # see if the msg already has a header + * ^X-MD5-Checksum: \/[^ ].* + * $? test "$MD5SUM" != "$MATCH" + { insert_opt='i' } # save old headers on mismatch + :0 fh # in any case, set the new checksum + |formail -${insert_opt:-'I'}"X-MD5-Checksum: $MD5SUM" + } # end md5 check +} +COMSAT=$OLDCOMSAT # set COMSAT back to original value +OLDCOMSAT diff --git a/share/procmail/eg.spam-bounce-w-threshold.rc b/share/procmail/eg.spam-bounce-w-threshold.rc @@ -0,0 +1,44 @@ + SPAMSITES='(spam.com|foo.org|blah.com)' # sites to check + MAXFROM=10 # more than 10 mails/day from + :0 # check for mail from a spam site + * $ ^(From|Sender:|Reply-To:).*@.*$SPAMSITES + { # ok -- mail is from a possible spam site -- check # of occurances + FROM=`formail -rtzxTo:` # get the best from + DATE=`date +%Y%m%d` # get YYYYMMDD + SUBJ=`formail -zxSubject:` # get the subject + FROMLOG=from.log # logfile of FROM addresses + :0ci: # log this message + | echo "$FROM $DATE : $SUBJ" >>$FROMLOG + # Find out how many message have been received today + COUNT=`fgrep -c "$FROM $DATE" $FROMLOG` + :0 # see if we've received too many + * $ -$MAXFROM^0 + * $ $COUNT^0 + { # count was exceeded - generate a reply + :0 # clean up the subject + * SUBJ ?? Re: *\/[^ ].* + { SUBJ=$MATCH } + :0 fh # generate a reply header + * $ !^X-Loop: *$LOGNAME@$HOST + | formail -rt -I"From: ($LOGNAME's Mail-Agent) $LOGNAME" \ + -I"Subject: Re: $SUBJ" \ + -I"Precedence: junk" \ + -I"X-Loop: $LOGNAME@$HOST" + :0 afb # generate a reply body + | echo "Your message is being returned because you've sent me" ; \ + echo "too many message today. Your original message follows:" ; \ + cat - + :0 a # send it off + ! -t + :0 E # no reply generated + error.log # keep an error log + } + # mail count is okay, forge on + } + # normal mail processing follows + +The recipe works by keeping a log of all recieved mail, with a +single line of "$FROM $DATE : $SUBJ" being appended to the log file. +Then, if the number of lines with the "$FROM $DATE" string exceeds +a threshold, a reply is generated. If any error in the reply, or +if a mail loop is detected, file the mail to "error.log". diff --git a/share/procmail/gen-spam-reply.rc b/share/procmail/gen-spam-reply.rc @@ -0,0 +1,94 @@ +# gen-spam-reply.rc +# +# Copyright (C) 1997 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# $Id: gen-spam-reply.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# This is a sample procmail rc file which can be used +# to generate an automatic response to mail which has +# somehow been identified as being a source of spam. +# +# If the variables ADDR, TOADDR, or REGEXP match, then +# current message, then a response is generated to the +# originator of the message, stating that something about +# the message had been identified as a source of spam. +# The original message is returned as part of the response. +# +# +# This recipe file does not set the policy by which a +# "spam site" is selected, it merely implements whatever +# policy the user has chosen. +# +# Use this "subroutine" recipe file as follows: +# +# Set one or more of the following variables: +# +# ADDR=some-spam-source-address +# TOADDR=some-noisy-mailing-list +# REGEXP=a-regexp-which-matches-a-spam-mail +# INCLUDERC=gen-spam-reply.rc +# +# +# Our handy FROM_DOMAIN variable. If you *know* that this recipe will +# always have FROM_DOMAIN defined already, then you don't need to define +# it again. But, I've put it here, so that the recipe file can stand +# on its own and is more understandable. +# +# See "headers.rc" for a collection of header regexps. +# +:0 # pull in handy headers file, if needed +* ! HEADERS_RC ?? . +{ INCLUDERC=headers.rc } + +# See if the mail came by any source address from $ADDR +spam # flag to maybe set +:0 # ADDR set and matches? +* ADDR ?? . +* $${FROM_DOMAIN}${ADDR}\> +{ spam=1 } +:0 # TOADDR set and matches? +* TOADDR ?? . +* $^TO$TOADDR +{ spam=1 } +:0 # REGEXP set and matches? +* REGEXP ?? . +* $$REGEXP +{ spam=1 } +:0 # is the mail spam? +* spam ?? . +{ # yes, generate a reply header + SUBJ=`formail -zXSubject: | tr -d '"'` # get the subject (without quotes) + + :0 fhw # generate a reply header + | formail -rt -I"Subject: Re: $SUBJ" \ + -I"Precedence: junk" \ + -I"X-Loop: $LOGNAME@$HOST" + :0 afb # form the reply body + | echo "\ +Email from your site is being shunned because something about\n\ +it has been identified as a source of spam. If your mail\n\ +was, in fact, not spam, please resend it using the\n\ +keyword 'not-spam' in the subject. Unsolicited commercial\n\ +use of this mailbox will be billed at $500 per incident.\n\ +\n\ +Your original email follows:\n\ +----------------------------------------------------------" ; \ + cat - + + :0 a # now feed the reply to sendmail + ! -oi -t +} diff --git a/share/procmail/get-date.rc b/share/procmail/get-date.rc @@ -0,0 +1,8 @@ +# get-date.rc +# +# See date.rc for Copyright info. +# +# $Id: get-date.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +DATE +INCLUDERC=date.rc diff --git a/share/procmail/get-from.rc b/share/procmail/get-from.rc @@ -0,0 +1,46 @@ +# get-from.rc -- procmail rc file to get the "best" from address +# +# Sets FROM and FRIENDLY, the latter being the "friendly" user name +# sans any address. +# +# $Id: get-from.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# Get the best FROM +:0 +* ! ^Reply-to: *\/[^ ].* +* ! ^From: *\/[^ ].* +* ! ^Sender: *\/[^ ].* +* ! ^From +\/[^ ]+ +* ! ^X-Envelope: *\/[^ ].* +{ FROM=nobody } +:0E +{ FROM=$MATCH } + +# Get the "friendly" name part of the address, by +# 1. removing any bracketed address part, +# 2. removing any unbracketed address part, +# 3. unquoting any text +# 4. unparenthesizing any text +FRIENDLY=`echo $FROM | sed -e 's/ *<.*> *//' \ + -e 's/ *[^ ][^ ]*[\@\!][^ ][^ ]* *//' \ + -e 's/"\(.*\)"/\1/' \ + -e 's/(\(.*\))/\1/'` +FRIENDLY=${FRIENDLY:-$FROM} + diff --git a/share/procmail/guess-mua.rc b/share/procmail/guess-mua.rc @@ -0,0 +1,48 @@ +# guess-mua.rc +# +# Guess the Mail User Agent and set MUA +# +# $Id: guess-mua.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# First, let's check for MH + +# Make sure it's not already defined +:0 +* MUA ?? !.+ +{ + # See if mhpath works + MHPATH=`mhpath + 2>/dev/null` + + :0 + * MHPATH ?? .+ + { MUA=mh } + + # Else, see if ~/.pinerc works + :0 E + * test -f $HOME/.pinerc + { MUA=pine } + + # Else, check for ~/.mailrc (for BSD/mail) + :0 E + * test -f $HOME/.mailrc + { MUA=mail } + + # Add others as they are needed.. +} diff --git a/share/procmail/headers.rc b/share/procmail/headers.rc @@ -0,0 +1,100 @@ +# procmail rc to define patterns to recognize the headers +# +# $Id: headers.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# +# Use these is recipes like this: +# +# # If mail is from john or mary, then file in "+urgent" +# :0 +# * $ $FROM(john|mary)@ +# urgent/. +# +# # if the mail is directly to me, then file it +# :0 +# * $ $TO($USER)@ +# mymail/. +# +# # See which list this mail is from: +# :0 +# * $ $FROM_LIST_MAILER +# { LISTADDR=$MATCH } + + + # These patterns span any comment text before and after email addresses + # Use PRE_ADDR_SPAN before any names; it will span a string of non-address + # characters up to the beginning of a valid email address. + +PRE_ADDR_SPAN='(.*[^-(.%@a-zA-Z0-9])?' + + # Use POST_ADDR_SPAN after any names; it will span a string of non-address + # characters up to the a comma "," or the end of the line + +POST_ADDR_SPAN='(([^),.!:a-zA-Z0-9].*)?(,|$[^>]))' + + # These are to match RFC822 style addresses (not including UUCP addresses) + # Use $USERADDR to match a user name part of an email address + +USERADDR='[-a-zA-Z0-9_:.+=/]+' + + # Use $HOSTADDR to match the FQDN hostname part of an address + +HOSTADDR='[-a-zA-Z0-9_:.+=/]+' + + # Use $HOSTNAME to match the "plain" hostname (not include any domains) + +HOSTNAME='[-a-zA-Z0-9_:+=/]+' + + # Use $ADDR to match either an RFC 822 or UUCP email address + +ADDRESS="<?($USERADDR(@$HOSTADDR)?|($HOSTADDR!)+$USERADDR)>?" + + # Use $FROM to match mail from someone + +FROM="(^((Reply-To|(Resent-)?(From|Sender)|X-Envelope-From):|>?From )\ +$PRE_ADDR_SPAN)" + + # Use $TO to match mail to someone (but only "To:", not "Cc:") + +TO="(^((Original-)?(Resent-)?To|(X-Envelope|Apparently(-Resent)?)-To):\ +$PRE_ADDR_SPAN)" + + # Use $CC to match mail to someone (but only "Cc:", not "To") + +CC="(^((Original-)?(Resent-)?Cc|(X-Envelope|Apparently(-Resent)?)-Cc):\ +$PRE_ADDR_SPAN)" + + # For completeness, this should be roughly equivalent to ^TO + +TOCC="($TO|$CC)" + + # Pattern to recognize lists by precedence + +LIST_PRECEDENCE='(^Precedence:.*(junk|bulk|list))' + + # Names of common list mailers + # List the more specific mailers first, with generic names later + +LIST_MAILERS="(LISTSERV|ListProc|${USERADDR}-(l(ist)?|request|own[er]r)|\ +owner-${USERADDR}|Majordomo?|Mailagent|mmdf|news|n?uucp|\ +Post(mast(er)?|-?office)|procmail|SmartList|(Mailer-)?daemon|root)" + + # Pattern to put them all together, just to detect mail from a list + +FROM_LIST="($LIST_PRECEDENCE|$FROM$LIST_MAILERS$POST_ADDR_SPAN)" diff --git a/share/procmail/list-addr.rc b/share/procmail/list-addr.rc @@ -0,0 +1,75 @@ +# +# list-addr.rc +# +# Get a mailing list address, if possible. +# + +:0 +* DEBUG ?? . +{ SENDMAIL=true + LOGABSTRACT=all + VERBOSE=yes } + +INCLUDERC=headers.rc + +# There seems to be a new convention to provide sub/unsub info on +# informational headers. The following is an attempt to discover +# if there is any header which contains the patter .*-request. +# If so, it's a good bet that the string is the list request address. + +:0 H +* $\/${USERADDR}-request@$HOSTADDR +{ LISTADDR=$MATCH } + +# Okay, if that didn't work, now we do some heuristic lookups of +# well-known list mailer addresses. + +# However, we must do this carefully, because some mails have the +# "From:" or "Sender:" set to "BLAH-request" or "BLAH-owner", but +# the "From " header has "Daemon" or "Root". The problem is that +# just doing a "^$FROM\/$LIST_MAILERS" will always match the "From " +# header if it was from "root" or "daemon", even though the more +# useful address is on the subsequent "Resent-From:" or "Sender:" +# header. This is why the multi-line condition below + +:0 EH +* $!^Resent-Reply-To:$PRE_ADDR_SPAN\/$LIST_MAILERS@$HOSTADDR +* $!^Resent-Sender:$PRE_ADDR_SPAN\/$LIST_MAILERS$HOSTADDR +* $!^Resent-From:$PRE_ADDR_SPAN\/$LIST_MAILERS$HOSTADDR +* $!^Reply-To:$PRE_ADDR_SPAN\/$LIST_MAILERS$HOSTADDR +* $!^Sender:$PRE_ADDR_SPAN\/$LIST_MAILERS$HOSTADDR +* $!^From:$PRE_ADDR_SPAN\/$LIST_MAILERS$HOSTADDR +* $!^X-Envelope-From:$PRE_ADDR_SPAN\/$LIST_MAILERS@$HOSTADDR +* $!^From $PRE_ADDR_SPAN\/$LIST_MAILERS@$HOSTADDR +{ + :0 + * $ $FROM$LIST_MAILERS@$HOSTADDR + { LISTADDR=$MATCH } +} + +# Cool. We matched one of the headers from above +:0 E +{ LISTADDR=$MATCH } + +# This stuff only happens in DEBUG mode +# ie: procmail -DDEBUG -m list-addr.rc <testmail +# + +:0 +* DEBUG ?? . +{ + :0 + * LISTADDR ?? . + { LOG="List address = $LISTADDR +" } + + :0E + { SENDER=`formail -zxSender:` + :0 + * $ SENDER ?? @\/$HOSTADDR + { ORIGHOST=$MATCH + LOG="Postmaster = Postmaster@$ORIGHOST +" } + } + HOST=bye +} diff --git a/share/procmail/newsgate.rc b/share/procmail/newsgate.rc @@ -0,0 +1,46 @@ +# news-gate procmail recipe file +# +# Take mail and post it as a piece of news, after possibly +# inserting either a header or a trailer to the mail. +# +# The header or trailer only get added if the source address is from +# outside of the SGI domain. +# +# This file should be installed into /etc/procmailrcs, and the +# ownership set to the uid of the login by which the news postings +# will be accomplished. +# + +MAILDIR=/etc/procmailrcs # make this the current directory + +INEWS=/usr/local/bin/inews # or whatever program you have to insert news + +NEWSGROUP=$1 # the argument is the list name + +#LOGFILE=log # uncomment these for debugging +#VERBOSE=yes +#LOGABSTRACT=all + +FROM=`formail -rtzxTo:` # get who the mail is from +USER="[0-9a-zA-Z_.-]+" +HOST="[0-9a-zA-Z_-]+" +DOMS="(corp|engr|asd|nsd|esd|wcs|csd)" + +:0 # is this user not from SGI? +* $! FROM ?? ^^($USER|$USER@$HOST|$USER@($HOST)?$DOMS(\.sgi\.com)?|$USER@sgi\.com)^^ +{ + :0 fh # if header defined, prepend it + * ? test $LIST.header + | cat $LIST.header - + + :0 fh # if trailer defined, append it + * ? test $LIST.trailer + | cat - $LIST.trailer +} + +:0 fh # now do the header manipulation +| formail -R To: Originally-To: -INewsgroups: $NEWSGROUP + +:0 # now post the mail +| $INEWS + diff --git a/share/procmail/pf-check.rc b/share/procmail/pf-check.rc @@ -0,0 +1,49 @@ +# pf-check.rc +# +# $Id: pf-check.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# 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 PF_DEST. +# +# After all checks are complete, invoke pf-save.rc to save the +# message into the appropriate folders. See its comments for details. +# +# Clear these variables before invoking the first time: +# +# PF_DEST The destination of all filed mail. +# PF_FROM The derived FROM address. +# +# 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=pf-check.rc + +:0 +* ADDR ?? . +* DEST ?? . +{ + # Figure out who this mail is from + :0 + * ! PF_FROM ?? . + { PF_FROM=`formail -rtzxTo:` } + + # is this mail from the given $ADDR? + # if so, prefile it + :0 + * $ PF_FROM ?? $ADDR + { PF_DEST="$PF_DEST $DEST" } + + # if not directly from the address, see if it is from me, + # and to the address. + :0 E + * $ PF_FROM ?? ${USER:-$LOGNAME} + * $ ^TO$ADDR + { PF_DEST="$PF_DEST $DEST" } +} diff --git a/share/procmail/pf-chkto.rc b/share/procmail/pf-chkto.rc @@ -0,0 +1,25 @@ +# pf-chkto.rc +# +# $Id: pf-chkto.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Procmail recipe file to check a To: address ADDR for Mail folder +# filing. If the address matches, append DEST to PF_DEST. +# +# After all checks are complete, invoke pf-save.rc to save the +# message into the appropriate folders. See its comments for details. +# +# 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=pf-chkto.rc + +:0 +* ADDR ?? . +* DEST ?? . +* $ ^TO$ADDR +{ PF_DEST="$PF_DEST $DEST" } diff --git a/share/procmail/pf-save.rc b/share/procmail/pf-save.rc @@ -0,0 +1,64 @@ +# pf-save.rc +# +# $Id: pf-save.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Author: Alan K. Stebbens <aks@sgi.com> +# +# Procmail recipe file to save the current message to +# a list of one or more folders set by pf-check.rc. +# +# You may wish to set the variable PF_DEST before invoking. +# +# INCLUDERC=pf-save.rc +# +# If the message is filed into a folder, LOGABSTRACT is +# set to "off" so a duplicate log is not created. + +:0 +* PF_DEST ?? . +{ + + # Add a new X-Filed if necessary + :0 fh + * !^X-Filed: + | formail -A "X-Filed: $PF_DEST" + + # Else, if there is already a header, possibly append to it + :0 E + { + OLD_PF_DEST=`formail -zxX-Filed:` + :0 fh + * $!^X-Filed:.*$PF_DEST + |formail -I"X-Filed: $OLD_PF_DEST $PF_DEST" + } + + # If filing into MH folders, use one copy and procmail will take + # care of linking. + :0 c + * PF_DEST ?? /\.$ + $PF_DEST + + # If not filing into MH folders, use recursive filing + :0 E + { + DEST=`echo $PF_DEST | cut -d' ' -f1` + PF_DEST=`echo $PF_DEST' ' | cut -d' ' -f2-` + + # File into the first folder now + :0 c: + $DEST + + # Possibly file into the 2nd and other folders with recursion + # It must be non-blanks, and not identical to the already filed DEST + :0 c + * PF_DEST ?? [^ ] + * $! DEST ?? $PF_DEST + |procmail -pm PF_RECURSE=yes pf-save.rc + + # If we were recursing, don't file multiple copies into DEFAULT + :0 + * PF_RECURSE ?? yes + { HOST=_stop_now_ } + } + LOGABSTRACT=off +} diff --git a/share/procmail/pm-jaaddr.rc b/share/procmail/pm-jaaddr.rc @@ -0,0 +1,484 @@ +# pm-jaaddr.rc -- extract 'foo@some.com' email address from variable INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc extracts the various components of email address +# from variable `INPUT'. You can do quite a lot interesting things with +# your email address. One of the tricks that you could use if you +# don't have sendmail plus addressing capabilities, is that you put +# the additional infomation to the RFC comment. Eg. If you read and +# followup to posts in usenet games groups, you could use: +# +# From: <login@site.com> (John Doe+usenet.games) +# +# Or if your email address's localpart (that's characters before @) +# already signify your First and surname, you don't need to repeat it +# in comment. However, place special marker "+" to mark +# additional information part for your procmail recipes: +# +# From: <first.surname@site.com> (+usenet.games) +# +# The use of RFC comment should work everywhere because RFC requires +# that comments are preserved along with the address information. +# If you would have sendmail plus addressing capabilities you would +# have used: +# +# From: <login+usenet.games@site.com> (John Doe) +# +# The idea is that the list infomation is readily available from +# the email. The following recipe will derive the plus information +# and use it directly as a mailbox where to drop the message. If +# The Editor: Emacs, means anything to you, you can program it +# to generate the appropriate From headers automatically when you +# send mail from Gnus Mail/Newsreader MUA. Drop me a message if +# you need an example how a piece of Emacs lisp code makes those +# magic RFC plus addresses in the background while you compose the +# body of the message. +# +# RC_EMAIL = $PMSRC/pm-jaaddr.rc +# TOME = "(login1|login2)" +# +# :0 +# *$ ^TO\/.*$TOME.* +# { +# INPUT = $MATCH +# INCLUDERC = $RC_EMAIL +# PLUS = $COMMENT_PLUS +# +# # If COMMENT_PLUS was defined, we found "+" +# # address which contain "usenet.games". Save it to +# # folder. +# +# :0 : +# * PLUS ?? [a-z] +# $PLUS +# } +# +# Notes +# +# 1998-05 David Hunt <dh@west.net> also mentioned that "you need to +# remember that some MTAs, (qmail for one, and soon vmail) use a dash +# ( - ) as the subaddress delimiter. So you'll want to allow for that +# in your code". For this reason the email part accepts both +# "-" and "+". The RFC comment however accepts only "+" and "--". +# +# Example input +# +# "From: foo+procmail@this.site.com (Mr. foo)" traditional +# "From: foo-procmail@this.site.com (Mr. foo)" new styled +# +# NOTE: M$SOFT mailers tend to send idiotic smart quotes "'Mr. foo'" +# and this recipe ignores these two quotes ["'] as if message had +# only the standard ["] +# +# Returned values +# +# ADDRESS "foo+procmail@this.site.com" +# containing the email address without <> +# +# ACCOUNT "foo+procmail" +# all characters before @ +# +# ACCOUNT1 "foo" +# characters before plus: account1+account2@site +# Note, if there is no "+", this is same as ACCOUNT. +# +# ACCOUNT2 "procmail" +# _only_ set if plus found: account1+account2@site +# +# SITE "this.site.com" +# all characters after @ +# +# DOMAIN "site.com" +# the main domain, preceding words in site are +# considered subdomain (local) addresses. +# +# sub.sub.domain.net +# +# SUB "this.site" +# all the sub-domain names without the NET part. +# +# SUB1 "site" +# The first subdomain counted from the _RIGHT_ after NET +# +# SUB2 "this" +# Second subdomain. +# +# SUB3 "" +# Third subdomain. +# +# SUB4 "" +# Fourth subdomain. +# +# NET "com" +# last characters after last period ( net,com,edu ...) +# +# COMMENT Anything unside parenthesis (Mr. Foo) or if no +# parentheses found, then anything between quotes +# "Mr. Foo" +# +# COMMENT_PLUS Anything after the "+" in the comment, like +# "Mr Foo+mail.usenet" --> "mail.usenet" +# +# Note: some MTA's don't allow + character, so use +# alternatively '--': +# "Mr Foo--mail.usenet" --> "mail.usenet" +# +# Additionally there is variables DOT1 DOT2, which behave like +# ACCOUNT1 and ACCOUNT2, but in respect to dotted firstname.surname +# type address: +# +# john.doe@site.com +# +# ACCOUNT1 = john.doe +# ACCOUNT2 = <empty> +# DOT1 = john +# DOT2 = doe +# +# If there is plus, the ACCOUNT2 is defined +# +# john.doe+foo@site.com +# +# ACCOUNT1 = john.doe +# ACCOUNT2 = foo +# DOT1 = john (in respect to ACCOUNT1) +# DOT2 = doe (in respect to ACCOUNT1) +# +# +# Variable ERROR is set to "yes" if INPUT wasn't recognized or parsing +# the address failed. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. +# +# Call arguments (variables to set before calling) +# +# INPUT = string-to-parse +# +# Usage example +# +# Read From field and address from it. This is lot faster than using +# external `formail' call. +# +# PMSRC = $HOME/pm +# RC_ADDR = $PMSRC/pm-jaaddr.rc +# +# :0 +# * ^From:\/.*@.* +# { +# INPUT = $MATCH +# +# # Turn off the logging while executing this part +# VERBOSE="off" INCLUDERC = $RC_ADDR VERBOSE="on" +# +# :0 +# * ERROR ?? yes +# { +# # Hmm, no std email address found. Any other ideas? +# } +# } +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = " pm-jaaddr.rc" +dummy = " +====================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables. Defining them on their own kills them + +ADDRESS + +ACCOUNT +ACCOUNT1 +ACCOUNT2 +DOT1 +DOT2 + +SITE + +DOMAIN +SUB1 +SUB2 +SUB3 +SUB4 + +NET + +COMMENT +COMMENT_PLUS + +ERROR = "yes" # set defualt value + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 + +dummy = "$NL$NL$id: start: Parsing $INPUT $NL" + +charset_jaaddr = "[^$WSPC@(){}&?,;:<>\"']+" + +# ... ... ... ... ... ... ... ... ... ... ... ... ... . catch comment ... + + +dummy = "$NL$id: :::::::::::::::::::::::: COMMENT $NL" + +:0 # Catch anything inside parentheses +* INPUT ?? [(]()\/[^)]+ +{ + COMMENT = $MATCH +} + + + :0 E # Else, Try catching "'Mr. Foo'" in Microsoft smart quotes + * INPUT ?? \"'()\/[^\']+ + { + dummy = "$id: Comment catched from inside Microsoft smart quetes.." + COMMENT = $MATCH + } + + dummy = "$NL$id: normal quotes $NL " + + :0 E # Else, Try catching "Mr. Foo" in quotes + * INPUT ?? \"()\/[^\"]+ + { + dummy = "$id: Comment catched from double quotes.." + COMMENT = $MATCH + } + + +dummy = "$NL$id: :::::::::::::::::::::::: COMMENT_PLUS $NL" + +:0 # derive plus address, if RFC comment trick +* COMMENT ?? (\++|--)\/.* +{ + COMMENT_PLUS = $MATCH +} + +# ... ... ... ... ... ... ... ... ... ... ... ... ... catch address .. + +dummy = " $NL$id: Find <login@site.com> $NL " + +# Try strict address first <> + +:0 +*$ INPUT ?? $s*<\/$charset_jaaddr@$charset_jaaddr> +{ + INPUT = $MATCH + + # Drop the trailing ">" too + # + :0 + *$ INPUT ?? ^\/$charset_jaaddr@$charset_jaaddr + { + ADDRESS = $MATCH + } +} + +dummy = "$NL$id: :::::::::::::::::::::::: INPUT --> ADDRESS [$INPUT] $NL" + +# No joy, then try to locate @ character + +:0 E +*$ INPUT ?? $s*\/$charset_jaaddr@$charset_jaaddr +{ + ADDRESS = $MATCH +} + + +# ... ... ... ... ... ... ... ... ... ... ... ... ... ... .. explode .. +# If we got the address, derive other parts + + +dummy = "$NL$id: :::::::::::::::::::::::: ADDRESS [$ADDRESS] $NL" + + +:0 +* ADDRESS ?? @\/.* +{ + SITE = $MATCH + + :0 # Get last three characters + * SITE ?? (\.)\/...^^ + { + NET = $MATCH + } + :0 E # Nope, it was two (like .us) + * SITE ?? \.\/..^^ + { + NET = $MATCH + } + + + # If next recipe does not match, ie. there is no two components in + # the address. Eg: + # + # foo@a.b.com -> DOMAIN = b.com + # foo@this.com -> DOMAIN = this.com + + DOMAIN = $SITE + + :0 + *$ SITE ?? (\.)\/[^.]+\.$NET + { + DOMAIN = $MATCH + } + + # It's a bit tricky to count backward with procmail, but in this + # case it it possible, because there is "." separating the parts. + # + # this.site.here.com : Get everything until period, delete period + # -> SUB this.site.here + # + # Next; we repeate following 3 times + # + # this.site.here : get everything until period, delete period + # -> this.site : save this to `tmp' + # + # If there is no matches, reset `tmp' to empty to prevent next recipes to + # match. If there is no more matches, the ":0 E" recipe assigns the last + # + # --> this : into last SUB + + :0 + * SITE ?? ()\/.*\. + * MATCH ?? ()\/.*[^.] + { + SUB = $MATCH + SUB1 = $SUB # suppose only one subdomain. @this.com + tmp = "" + + :0 + * SUB ?? .*\.\/[^.]+^^ + { + SUB1 = $MATCH + } + + tmp + + :0 + * SUB ?? ()\/.*\. + * MATCH ?? ()\/.*[^.] + { + tmp = $MATCH + + :0 + * tmp ?? .*\.\/[^.]+^^ + { + SUB2 = $MATCH + } + :0 E + { + SUB2 = $tmp tmp = "" + } + } + + :0 + * tmp ?? ()\/.*\. + * MATCH ?? ()\/.*[^.] + { + tmp = $MATCH + + :0 + * tmp ?? .*\.\/[^.]+^^ + { + SUB3 = $MATCH + } + :0 E + { + SUB3 = $tmp tmp = "" + } + } + + :0 + * tmp ?? ()\/.*\. + * MATCH ?? ()\/.*[^.] + { + tmp = $MATCH + + :0 + * tmp ?? .*\.\/[^.]+^^ + { + SUB4 = $MATCH + } + :0 E + { + SUB4 = $tmp tmp = "" + } + } + + + + } + + + :0 + * ADDRESS ?? ^^\/[^@]+ + { + ACCOUNT = $MATCH + + # Handle plus addresses and explode it + + :0 + * ACCOUNT ?? [-+]\/.* + { + ACCOUNT2 = $MATCH + } + + :0 + * ACCOUNT ?? ()\/[^+]+ + { + ACCOUNT1 = $MATCH + } + + + # Handle firstname.surname + + :0 + * ACCOUNT1 ?? [.]\/.* + { + DOT2 = $MATCH + } + + :0 + * ! DOT2 ?? ^^^^ + * ACCOUNT1 ?? ()\/[^.]+ + { + DOT1 = $MATCH + } + + + } + +} + +dummy = "$NL$NL$id: end: $ERROR $NL" + +# end of file pm-jaaddr.rc diff --git a/share/procmail/pm-jabup.rc b/share/procmail/pm-jabup.rc @@ -0,0 +1,140 @@ +# pm-jabup.rc -- Keeep N arriving message backup in separate directory +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# Preserve last N arriving messages in a separate sub-directory. +# This should be your safety-belt recipe that you put to the beginning +# of your .procmailrc. +# +# Procmail saves the backup files with names like: msg.rcG msg.scG +# msg.3YS1, msg.4YS1, msg.VYS1, msg.fYS1 to the backup directory. +# +# Note: this recipe will alawys call shell commands for each message +# you recive. That is needed because cleaning of the backup directory. +# If you receive only small number of messages per day, the performance +# drop of your .procmailrc is not crucial. But if you store many messages +# per day, then the shell calls may be a performance problem. +# +# In that case, consider moving the cleanup to the pm-jacron.rc +# module (The cleanup is run only once a day, not for every message) +# +# John Gianni send his simple bsckup script to Jari, who packaged +# and generalized the code. The code is reused with John's permission +# and maintaining responsibility was transferred to Jari +# +# Required settings +# +# (none) +# +# Call arguments (variables to set before calling) +# +# o JA_BUP_MAX, How many messages to keep at maximum. 32 is default +# o JA_BUP_DIR, Where to store the messages. $HOME/Mail/bup by default +# o JA_BUP_FILES, regexp to match the saved files. Procmail default. +# o JA_BUP_CHECK_DIR. Once you have verified that this recipe works, +# that directories are ok, please set this flag to "no" to prevent +# running unnecessary `test' command for each email. +# +# Usage example +# +# You only want to keep backup of messages that are not from mailing +# lists. You may want to use TO_ macro to detect addresses better, +# this example matches against all headers +# +# LISTS = "(procmail|list-1|list-2)" +# JA_BUP_DIR = $HOME/Mail/backup/. # Create the path too +# JA_BUP_MAX = 42 # this should be enough +# +# :0 +# *$ ! $LISTS +# { +# INCLUDERC = $PMSRC/pm-jabup.rc +# } +# +# If you get many messages, please don't use this module. Instead +# see pm-jacron.rc where similar backup work is done better. +# +# Change Log (none) + +# .................................................... &initialising ... +id = " pm-jabup.rc" +dummy = "subroutine: $id start" + +# .......................................................... &public ... + +default = "$HOME/Mail/bup" +JA_BUP_DIR = ${JA_BUP_DIR:-$default} +JA_BUP_MAX = ${JA_BUP_MAX:-32} +JA_BUP_FILES = ${JA_BUP_FILES:-"msg.*"} +JA_BUP_CHECK_DIR = $JA_BUP_CHECK_DIR:-"yes"} + +# ........................................................... &check ... + +:0 +* JA_BUP_CHECK_DIR ?? yes +{ + # - If we're using the default directory, check that it exists. + # - Create one if needed and exit if create was unsuccessfull + + :0 + *$ JA_BUP_DIR ?? $default + *$ ! ? $IS_DIR $default || $MKDIR $default + { + EXITCODE = 217 # just some code, doesn't mean anything + HOST # stop immediately + } + + + :0 + *$ ! ? $IS_DIR $JA_BUP_DIR + { + dummy = "$id: $JA_MSG_ERROR $JA_BUP_DIR is not a directory" + EXITCODE = 217 + HOST + } +} + +# ........................................................... &do-it ... + +dummy = "subroutine: pm-jabup.rc delivering backup." + +:0 c: +$JA_BUP_DIR + +# i = ignore write errors +# +# - The 'rm -f dummy' makes sure that rm always has at least one argument, +# because there may not be files in the directory. +# - 'ls -t' returns files sorted by date, newest first +# - 'sed' just chops first N files from the ls listing, leaving list +# of old files +# +# NOTE +# +# - If you get lot of mail, it is too expensive to run this after +# every message. Plese use cron(1) or pm-jacron.rc module to run something +# only once a day. + +:0 hwic +| cd $JA_BUP_DIR \ + && $RM -f dummy `$LS_BY_DATE $JA_BUP_FILES | $SED -e 1,${JA_BUP_MAX}d` + + +dummy = "subroutine: $id end." + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-jacookie.rc b/share/procmail/pm-jacookie.rc @@ -0,0 +1,460 @@ +# pm-jacookie.rc -- Handle cookie (unique id) confirmations +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 program. If not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# Visit <http://www.gnu.org/copyleft/gpl.html> +# +# Overview of features +# +# o Each user must register himself to cookie cache before he +# is considered "known" +# o Unless user return the generated cookie string; which is +# typically a decimal or hex number, he is not considered as +# known and should not have access to services you provide. +# o Can be used as a "doorbell" spam/UBE shield +# +# Description +# +# This recipe handles generating the cookie to new users, comparing +# the returned cookie against the original one and passing known +# users through if they already had returned their cookie. +# +# When you run automatised scripts, eg. to manage mailing lists +# where users can subscribe and unsubscribe, you have better to +# install safety measure so that someone can not subscribe his enemy +# to 30 mailing lists. +# +# The *cookie* is any continuous block of random characters that +# is sent to person who wanted to use the service. He must send +# back the *cookie* before the service starts an action, like +# subscribe. If someone forges the From address to pretend to be +# someone else and then subscribes as-beeing-someone-else to a +# mailing list, the cookie protects this from happening. +# +# The cookie is sent to someone-else, and he must return the cookie +# before the "subscribe" service is activated. Obviously this +# someone-else will not be interested in sending back the cookie and +# thus the forgery fails. Isn't that simple, but efective protection +# against misuse? +# +# Should I use this as Challenge-Response Spam shield? +# +# Unsolicited Bulk Email aka Spam is crawling from every possible +# domain thinkable, so you might think that a challenge-response +# policy could be deployed to regular email communication as well. +# The idea would be that unknown people are requested to +# "join" to a white list, before discussion is initiated with them. +# Bulk email shotguns do not reply to challenges (here: cookies), +# so confirmations are not returned. Individual people that want to +# talk, *may* want to return the cookies. +# +# Sounds like a perfect Unsolicited Bulk Email shield? No more +# non-invited mail? Wrong. Don't use this module for that. The +# whole idea of challenge-response is flawed and causes trouble +# for every person who tries to contact. Imagine for 10 people +# using C-R systems; they would all need to authenticate +# themselves. Who is going to believe that he is not replying to +# a spammer who is collecting email addresses? And what about +# automatic messages that might be received -- there is no +# artificial intelligence to deparate "human" messages from +# automatically generated messages, so challenges just +# increase the overall mail traffic. Every C-R system doubles +# the mail traffic and becomes spam problem by itself. +# +# In short, don't use this module for implementing a C-R system +# to block regular mail to you. +# +# How it works +# +# By default the cookie generated uses CRC 32 `cksum', but if you have +# md5, you should use it. The cookie is generated from the reply +# address and immediately stored to cookie database file with entry +# +# DATE FROM-a COOKIE-a +# DATE FROM-b COOKIE-b +# +# If this was a new user or an old user, who has not registered his +# cookie yet, then original message is sent back to the sender with +# instructions: "please place the magic string to Subject line and +# resent the message." +# +# When cookie is returned back, a new line to the database is added, +# simply by adding a duplicate entry. The file now looks like this: +# +# DATE FROM-a COOKIE-a +# DATE FROM-b COOKIE-b +# DATE FROM-a COOKIE-a +# +# When there is two or more same entries, like FROM-a, the address +# is supposed to be known and person behind it "cleared". +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jadate.rc +# o pm-jacookie1.rc +# o pm-jastore.rc +# +# Call arguments (variables to set before calling) +# +# o JA_COOKIE_SEND, flag. Default is "yes". Set to "no" if you want +# to take full control of the message returned to user. You can check +# variable `ERROR' and use `key' which holds the unique `cookie' +# o JA_COOKIE_CACHE, cache to determine if this is new user or not. +# o JA_COOKIE_AUTO_KEY, flag. If set to "yes"; the cookie is +# initially put to the Subject when the message is bounched back. +# Receiver only has to press "r" to reply to send the cookie +# and message back (convenient). You set this flag to "no" when +# you want to avoid accidnebts eg. when receiver is about to +# subscribe to a mailing lists: he has to manually insert the cookie +# into subject. But keep flag to "yes" if you use this module to +# get your friends registered easily. +# o JA_COOKIE_KEYS, the cookie database. Email address and person's +# access cookie. +# o JA_COOKIE_RC, dubroutine to generate the cookie id from INPUT. +# By default uses CRC 32. +# o JA_COOKIE, the string from which the cookie will be generated. +# If you already have the return addres for the sender derived, +# you should assing a value to this to save unnecessary formail call. +# +# Returned values +# +# ERROR will contain the efective action when this recipe file ends +# +# o "new-user", This is first message from sender. +# o "known-user", message has email that has been "cleared" ie. +# cookie had been returned and user registered. +# o "key-mismatch", This is at least second message from sender. +# But he dind't send the confirmation in this message. +# +# `key' is an internal variable in this recipe file and will hold the +# cookie id in case of "new-user" and "key-mismatch". You may want to +# use it if you generate your own reply. +# +# Example usage for UBE shield +# +# This is what I use to prevent unknown people from sending me UBE. +# It takes a bit extra, but they can easily return the message. +# Fill in the missing variables, this won't work out of the box for you. +# +# WORK = "(domain1|domain2|domain3)" +# LISTS = "(procmail|list-2|list-3|list-4)" +# VALID = "(postmaster|abuse|$LISTS|$WORK)" +# RC_COOKIE = $PMSRC/pm-jacookie.rc +# UBE_SPOOL = $HOME/Mail/junk.ube.spool # Save spam here +# +# :0 +# *$ ! From:.*$VALID +# *$ ! ^FROM_DAEMON +# { +# JA_COOKIE_SEND = "yes" # Activate it +# INCLUDERC = $RC_COOKIE +# +# :0 : +# * ! ERROR ?? known-user +# $UBE_SPOOL +# +# # ... Past this point: it was user in whitelist, so the +# # recipes after this block will take care of it +# } +# +# Example usage for subscriptions +# +# $RC_COOKIE = $PMSRC/pm-jacookie.rc +# +# ...Mailing lists handled here... +# ...Your work messages filed here.. +# +# TO = `formail -rt -zxTo:` # We need this elswhere +# JA_COOKIE_TO = $TO +# +# # For List-X all subscribe requests must +# # be confirmaed +# +# * ^TO_()list-x +# * ^Subject: +subscribe\> +# { +# JA_COOKIE_SEND = "no" +# INCLUDERC = $RC_COOKIE +# +# :0 +# * ERROR ?? known-user +# { +# # User sent the subsribe request again, allow joining +# # immediately. +# } +# :0 E +# { +# # Because the Send was set to "no"; we're in charge +# # to send a reply to the user. +# # ...generate suitable message with formail -rt +# } +# +# } +# +# # End of example +# +# Change Log: (none) + +# ............................................................ &init ... + +dummy = " +====================================================================== +pm-jacookie.rc: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +:0 +*$ ! YYYY ?? ^^$d$d$d$d^^ +{ + INCLUDERC = $PMSRC/pm-jadate.rc +} + +JA_COOKIE_SEND = ${JA_COOKIE_SEND:-"yes"} +JA_COOKIE_AUTO_KEY = ${JA_COOKIE_AUTO_KEY:-"yes"} + +JA_COOKIE_CACHE = ${JA_COOKIE_CACHE:-$HOME/.cookie-cache-new-user} +JA_COOKIE_CACHE_SIZE = ${JA_COOKIE_CACHE_SIZE:-8192} +JA_COOKIE_KEYS = ${JA_COOKIE_KEYS:-$HOME/.cookie-cache-keys} +JA_COOKIE_WHITELIST = ${JA_COOKIE_WHITELIST:-$HOME/.cookie-cache-whitelist} + +JA_COOKIE_RC = ${JA_COOKIE_RC:-$PMSRC/pm-jacookie1.rc} + +JA_COOKIE_XLOOP = ${JA_COOKIE_XLOOP:-"\ +Procmail Authentication service (PAS)"} + +JA_COOKIE_SUBJECT_TAG= ${JA_COOKIE_SUBJECT_TAG:-"PAS-cookie-"} +JA_COOKIE_HEADER = ${JA_COOKIE_HEADER:-"X-PAS-Auth-Key:"} +cookie = "" + +JA_COOKIE_MSG = ${JA_COOKIE_MSG:-"\ +Your message need to be authenticated. Include the authentication key +at the end of Subject header and resend your message."} + +# - If not set, set the variable. We use `r' instead of `rt' +# because of `-rD' later. +# - User can preset the JA_COOKIE to his liking if the "to" field's +# string is not enough to generate a unique cookie from it. + +JA_COOKIE_FROM = ${JA_COOKIE_FROM:-`$FORMAIL -r -zxTo:`} + +# - Should non-authenticated messages be saved? Change this +# to mailbox name as needed. + +JA_COOKIE_DEVNULL = ${JA_COOKIE_DEVNULL:-/dev/null} + +# ..................................................... &read-cookie ... + +jaCookieData = "" +jaCookieKey = "" + +:0 +*$ $SUPREME^0 H ?? ^Subject:()\/.* +$JA_COOKIE_SUBJECT_TAG[0-9]+ +*$ $SUPREME^0 B ?? ^Subject:()\/.* +$JA_COOKIE_SUBJECT_TAG[0-9]+ +{ + jaCookieSubject = $MATCH + + :0 + * ^FROM_DAEMON + { + # The sender is not there, drop this message + + :0 h + * JA_COOKIE_DEVNULL ?? /dev + $JA_COOKIE_DEVNULL + + # For mailbox, use lock + + :0 : + $JA_COOKIE_DEVNULL + } + + :0 + *$ jaCookieSubject ?? $JA_COOKIE_SUBJECT_TAG\/[0-9]+ + { + jaCookieData = $MATCH + } + + # Remove cookie from subject + + :0 + *$ jaCookieSubject ?? ^()\/.* +$JA_COOKIE_SUBJECT_TAG + *$ MATCH ?? ^()\/.*[ ] + *$ MATCH ?? ^()\/.*[^ ] + { + jaCookieSubject = $MATCH + } +} + +# No cookie was in the subject + +:0 E +* ^Subject: \/.* +{ + jaCookieSubject = $MATCH +} + +# ....................................................... &whitelist ... + +# Is this user in whitelist already? + +ERROR = "" +jaCookieWhitelist = "" + +:0 +* jaCookieData ?? ^^^^ +* ? $GREP '\<$JA_COOKIE_FROM\>' $JA_COOKIE_WHITELIST +{ + jaCookieWhitelist = "yes" + ERROR = "known-user" +} + +# ........................................................... &do-it ... + +jaCookieNewUser = "yes" +jaCookieDate = $YYYY-$MM-$DD + +# - Mail arrived, check cache. Use regional lock because formail +# is in the condition line. +# - If user was there already, formail returns success +# - Options -rD cause adding the email to the cache. + +LOCKFILE = ${JA_COOKIE_CACHE}.lock +dummy = "pm-jacookie.rc: Testing new user" + +:0 +* jaCookieWhitelist ?? ^^^^ +* ? $FORMAIL -rD $JA_COOKIE_CACHE_SIZE $JA_COOKIE_CACHE +{ + jaCookieNewUser = "no" +} + +LOCKFILE +mail = "" + +# He is not in whitelist (ERROR="") and he did not return +# the cookie (cookie="") + +dummy ="pm-jacookie.rc: Check if white [$jaCookieWhitelist] ERROR [$ERROR] cookie [$cookie]" + +:0 +* jaCookieWhitelist ?? ^^^^ +* jaCookieNewUser ?? no +{ + dummy = "pm-jacookie.rc: Old user, did he return a cookie [$jaCookieData]" + + :0 + * jaCookieData ?? [0-9] + { + # This user has returned confirmation. Check that it is correct + + dummy = "pm-jacookie.rc: confirming the cookie" + + :0 + *$ ? $GREP ".*$JA_COOKIE_FROM.+$jaCookieData" $JA_COOKIE_KEYS + { + dummy = "pm-jacookie.rc: Adding to whitelist" + msg = "$JA_COOKIE_FROM" + + :0 hwc : $JA_COOKIE_WHITELIST$LOCKEXT + | echo "$msg" >> $JA_COOKIE_WHITELIST + + ERROR = "known-user" + } + + :0 E + { + # Ask to send again + + ERROR = "cookie-error" + jaCookieKey = $jaCookieData + jaCookieMail = "yes" + } + } + + :0 E + { + dummy = "pm-jacookie.rc: Unknown user. Generate new key" + jaCookieNewUser = "yes" + } +} + +:0 +* jaCookieNewUser ?? yes +{ + saved = $ERROR + + INPUT = $JA_COOKIE_FROM + INCLUDERC = $JA_COOKIE_RC + jaCookieKey = $OUTPUT + + ERROR = $saved # restore value that got changed in subroutine + + jaCookieMail = "yes" + jaCookieMsg = "$jaCookieDate $JA_COOKIE_FROM $jaCookieKey" + dummy = `echo "$jaCookieMsg" >> $JA_COOKIE_KEYS` +} + +dummy = "pm-jacookie.rc: If new user/mismatched key, maybe send mail [$jaCookieMail]" + +:0 +* jaCookieMail ?? yes +* jaCookieWhitelist ?? ^^^^ +* JA_COOKIE_SEND ?? yes +* ! jaCookieKey ?? ^^^^ +*$ ! ^X-Loop:.*$JA_COOKIE_XLOOP +*$ ! $JA_FROM_DAEMON +{ + dummy = "pm-jacookie.rc: Request authentication $JA_COOKIE_FROM" + + # - If auto-mode is "on"; then put the key in the subject + # - Sender only has to reply to message. + + jaCookieKey = "$JA_COOKIE_SUBJECT_TAG$jaCookieKey" + + :0 fhw + * JA_COOKIE_AUTO_KEY ?? yes + | $FORMAIL -I "Subject: $jaCookieSubject $jaCookieKey" + + # Add extra header as well to message that go past the next one + + :0 fhw + | $FORMAIL -A "$JA_COOKIE_HEADER $jaCookieKey" + + :0 hbw c: $JA_COOKIE_CACHE$LOCKEXT + | ( $FORMAIL -rk -b \ + -A "X-Loop: $JA_COOKIE_XLOOP"; \ + echo "You Authentication key is: $jaCookieKey"; \ + echo "$JA_COOKIE_MSG"; \ + ) | $SENDMAIL $SENDMAIL_FLAGS + +} + +dummy = "pm-jacookie.rc: end: $ERROR" + +# pm-store.rc ends here diff --git a/share/procmail/pm-jacookie1.rc b/share/procmail/pm-jacookie1.rc @@ -0,0 +1,81 @@ +# pm-jacookie1.rc -- Generate unique id from INPUT variable. +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# When given a string, this subroutine returns a unique number +# representing a string, a cookie. +# +# Required settings +# +# (none) +# +# Call arguments (variables to set before calling) +# +# o INPUT, String from which the magic-cookie is calculated +# o JA_COOKIE_CMD: shell command to read INPUT and return decimal +# or hex cookie string as one continuous block of characters. +# It decaults to HP-UX `cksum', but your system may have `md5' +# or `chksum' +# +# Return values +# +# o Variable OUTPUT will contain the cookie. +# +# Example usage +# +# INPUT = "foo@site.com" +# JA_COOKIE_CMD = "md5" # or chksum +# INCLUDERC = $PMSRC/pm-jacookie1.rc +# cookie = $OUTPUT +# +# Change Log: (none) + + +id = "pm-jacookie1.rc" +dummy = " +====================================================================== +$id: init: +" + + +# ........................................................... &input ... + +# This is standard CRC 32 + +JA_COOKIE_CMD = ${JA_COOKIE_CMD:-"cksum"} + +# ........................................................... &do-it ... + +# Generate new key for this new user + +OUTPUT = `echo $INPUT | $JA_COOKIE_CMD` + + +# - At least HP-UX cksum produces two values: CRC DATA-LEN +# - We're only interested in the CRC part +# +:0 +* OUTPUT ?? ^^\/[0-9a-f]+ +{ + OUTPUT = $MATCH +} + +dummy = "$id: end:" + + +# pm-store.rc ends here diff --git a/share/procmail/pm-jacron.rc b/share/procmail/pm-jacron.rc @@ -0,0 +1,210 @@ +# pm-jacron.rc -- Procmail: Run cron once a day +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html> +# +# Description +# +# Framework for all cron tasks that can be run once a day. +# This is a wrapper recipe to your cron task list: when the day changes, +# you cron includerc is called. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This recipe +# will include +# +# o pm-javar.rc +# o pm-jadate.rc +# +# Call arguments (variables to set before calling) +# +# o JA_CRON_RUN_FLAG, You _must_ define this flag file. +# o JA_CRON_DATE_FILE, File where the date information, last cron run, +# is kept. Defaults to $HOME/.yymmdd +# o JA_CRON_RC, your includerc which is run when cron triggers. +# +# A file `JA_CRON_RUN_FLAG' which defaults to ~/.yymmdd.run is created +# when your includerc, that contains list of cron tasks, is run. If new +# mail arrives while your cron recipes are still running, you should +# prevent invoking the cron again by checking if this file exists. +# When all the cron tasks have been run, this flag file is removed. +# Remember to use "w" flag in your cron recipes where necessary +# to serialize the work. +# +# Return values +# +# (none) +# +# Usage example +# +# Save backups to separate directory, but do cleaning only once a day +# We do not keep backups from mailing list messages +# +# LISTS = "(procmail|list-1|list-2)" +# BACKUP_DIR = "$HOME/Mail/backup/." +# +# # Store backups: separate files to directory +# +# :0 c: +# *$ ! $LISTS +# $BACKUP_DIR +# +# # Run JA_CRON_RC once a day. It contains all daily cron tasks +# +# CRON_RC = $PMSRC/pm-jacron.rc # the framework +# JA_CRON_RC = $PMSRC/pm-mycron.rc # the tasks to do +# JA_CRON_RUN_FLAG = $HOME/.cron-running # define this! +# +# # Do not enter here if message arrived at the same day when +# # the cron is already running. The CRON_RC takes care +# # of deleting the file when cron has finished. +# +# :0 +# *$ ! ? $IS_EXIST $JA_CRON_RUN_FLAG +# { +# INCLUDERC = $CRON_RC +# } +# +# The *pm-jacron.rc* file may contain anything. For example to clean +# the backup directory; you add these statements there +# +# # rm dummy: if ls doesn't return files, make sure rm has +# # at least one argument. +# # +# # ls -t: list files; newest first +# # +# # sed: chop $max newest files from the listing, leaving the +# # old ones +# +# max = 32 +# +# :0 hwic +# | cd $BACKUP_DIR && $RM -f dummy `ls -t msg.* | $SED -e 1,${max}d` +# +# # End of file pm-mycron.rc +# +# Change log (none) + +# ............................................................ &init ... + + +id = "pm-jacron.rc" +dummy = " +======================================================================== +$id: init: +" + +# .......................................................... &public ... + +JA_CRON_DATE_FILE = ${JA_CRON_DATE_FILE:-$HOME/.yymmdd} +JA_CRON_RC = ${JA_CRON_RC:-""} +JA_CRON_RUN_FLAG = ${JA_CRON_RUN_FLAG:-${JA_CRON_DATE_FILE}.cron-running} + +# ........................................................ &settings ... + +:0 +*$ ! ? $IS_EXIST $JA_CRON_RUN_FLAG +{ + + + :0 + * ! WSPC ?? ( ) + { + INCLUDERC = $PMSRC/pm-javar.rc + } + + dummy = "$id: Define date variables if not yet set" + + :0 + *$ ! YYYY ?? ^^[0-9]+^^ + { + INCLUDERC = $PMSRC/pm-jadate.rc + + } + + + error = "no" + + :0 + *$ ! YYYY ?? ^^[0-9]+^^ + { + error = "$id: $JA_MSG_ERROR_FATAL Loading of pm-jadate.rc failed." + } + + # ......................................................... &private ... + + yymmdd = $YYYY-$MM-$DD # ISO 18 + + # Create initial .yymmdd file if it doesn't exist. + + :0 + *$ ! ? $IS_EXIST $JA_CRON_DATE_FILE + * error ?? no + { + + :0 hwic: $JA_CRON_DATE_FILE$LOCKEXT + | echo $yymmdd > $JA_CRON_DATE_FILE + } + + + # Read previously saved value + + yymmdd_prev = "" + + :0 hwic + * error ?? no + yymmdd_prev=| $CAT $JA_CRON_DATE_FILE + + + # ............................................................ do-it ... + + dummy = "$id: test if it is time to run cron?" + + # - If RC file is defined + # - if different date then enter this block + # - If cron flag is not up: another procmail instance is not + # already running this cron recipe. + + :0 + *$ JA_CRON_RC ?? [a-z] + *$ ! yymmdd ?? ^^$yymmdd_prev^^ + * error ?? no + *$ ! ? $IS_EXIST $JA_CRON_RUN_FLAG + { + dummy = "$id: CRON-TRIGGERED" + + # Update timestamp to tell that we're running cron job now. + + :0 hwic: $JA_CRON_DATE_FILE$LOCKEXT + | echo $yymmdd > $JA_CRON_DATE_FILE + + :0 hwic + | $TOUCH $JA_CRON_RUN_FLAG + + INCLUDERC = $JA_CRON_RC # The user's task list for this day + + # Free the cron flag. Cron ended + + :0 hwic + *$ ? $IS_EXIST $JA_CRON_RUN_FLAG + | $RM -f $JA_CRON_RUN_FLAG + + } +} + +dummy = "$id: end:" + +# end of file diff --git a/share/procmail/pm-jadaemon.rc b/share/procmail/pm-jadaemon.rc @@ -0,0 +1,423 @@ +# pm-jadaemon.rc -- Handle DAEMON messages by changing subject +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# When you send a message to a address that had delivery troubles, +# you get a DAEMON message back explaining the error problem. I +# usually want to save these daemon mesaages to a different folder +# and check the folder from time to time. A typical daemon message +# is like this (shortened) +# +# From: Mail Delivery Subsystem <MAILER-DAEMON@my.domain.com> +# Subject: Warning: could not send message for past 4 hours +# +# The original message was received at... +# ----- Transcript of session follows ----- +# Deferred: Connection timed out +# ----- Original message follows ----- +# [YOUR MESSAGE AS YOU SENT IT WITH HEADERS] +# +# Well, when I read the subjects, I do not like the standard error +# messages, but I also like to know to which address the delivery +# failed and what was the original subject. This small recipe changes +# the daemon message's Subject to +# +# Subject BRIEF-ERROR-REASON, SENT-TO-ADDRESS, ORIGINAL-SUBJECT +# +# and from that you can immediately tell if you should be worried Eg. +# if SENT-TO-ADDRESS was your friend's, then you want to take actions +# immediately, but if it were your complaint to UBE message to +# postmaster, you don't want to bother reading that daemon message. +# Here are some real examples: +# +# fatal errors,postmaster,ABUSE (Was: Super Cool Site!) +# Host unknown,postmaster,ABUSE (Was: A-Credit Information) +# undeliverable,postmaster,Could you investigate this spam +# Warning-Returned,friend,Have you looked at this +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# needs scrips +# +# o pm-javar.rc +# +# Call arguments (variables to set before calling) +# +# o `JA_DAEMON_SAVE'. This is by default `yes' which causes the +# original subject to be saved under header field `X-Old-Daemon-Subject'. +# If you don't want that extra header generated, set this variable to `no' +# o `JA_DAEMON_REGEXP', which messages to trigger +# +# Return values +# +# o Variable ERROR will be set to "yes" if daemon message was handled +# otherwise; value is "no" +# +# Usage example +# +# Just add this recipe somewhere in your .procmailrc. The place where +# you would put this daemon message trapper subroutine is crucial: +# think carefylly how you order your recipes. One suggested order +# could be: backup important messages, cron-subroutine, +# handle duplicates, DAEMON MESSAGES, plus addressed message, +# server message (file server, ping responder...), MAILING LISTS, +# send possible vacation replies only after all above, apply +# kill file, detect mime, save private messages and las FILTER UBE. +# +# +# PMSRC = $HOME/pm +# RC_DAEMON = $PMSRC/pm-jadaemon.rc +# DAEMON_MBOX = $HOME/Mail/junk.daemon.mbox +# +# ... +# +# INCLUDERC = $RC_DAEMON +# +# :0 : # If that was a daemon message, save it +# * ERROR ?? yes +# $DAEMON_MBOX +# +# Change Log: (none) + +dummy = " +======================================================================== +pm-jadaemon.rc: init:" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ........................................................... &input ... + +JA_DAEMON_SAVE = ${JA_DAEMON_SAVE:-"yes"} + +# ----- The following addresses had permanent fatal errors ----- +# <joe@example.com> +# +# ----- Transcript of session follows ----- +# ... while talking to 168.231.153.98: +# 550 5.1.2 <joe@example.com>... Host unknown (Name server: host not found) +# <<< 501 healy!me@example.com... Refused +# +# ----- The following addresses had transient non-fatal errors ----- +# <nobody@mail14.example.com> +# <<< 550 5.1.1 unknown or illegal alias: email.jdoe@example.com +# 550 <email.jdoe@example.com>... User unknown + +JA_DAEMON_REGEXP = ${JA_DAEMON_REGEXP:-"\ +^From.*(MAILER-DAEMON|abuse@|postmaster@|daemon@)\ +|(Transcript of session follows\ +|permanent fatal errors\ +|MAILBOX NOT FOUND\ +|Invalid recipient\ +|Service unavailable\ +|Message is too large\ +|550.*User unknown\ +|550.*illegal alias\ +|message was not delivered\ +|blocked using.*spamcop\ +|quota exceed\ +|501.*refused\ +|Domain blacklisted\ +|transient non-fatal errors\ +|user.*doesn't exist\ +|Deferred: Connection timed out\ +)\ +" +# ......................................................... &output ... + +ERROR = "no" + +# ........................................................... &do-it ... + +errTo = "" +charset = "[^ @(){}<>]" +daemon = ! + +# Novell Mercury MTA send Broken message headers, The "From " is all wrong. +# +# From mmokrejs Wed Aug 14 16:48:53 2002 +# Received: from SpoolDir by OKBDELL (Mercury 1.44); 14 Aug 02 16:33:29 +0100 (MET) +# 14 Aug 02 16:33:51 +0100 (MET) +# From: Mail Delivery System <postmaster.mustela@lfmotol.cuni.cz> +# Subject: Delivery failure notification +# Message-ID: <5C4D0D00E16@mustela.lfmotol.cuni.cz> +# X-Diagnostic: Possible loopback problem +# X-Envelope-To: montana-request + +:0 +*$ ()\/^From:$s+Mail Delivery System.* +* ^X-Diagnostic: +{ + daemon = "yes" +} + +# If you wonder why ()\/ and non-sensical ".*" at the end is used, +# it is only for logging purposes. It's easier if you can look from log file +# what the regexp actually matched. + +:0 +*$ ()\/$JA_DAEMON_REGEXP.* +{ + daemon = "yes" +} + +dummy = "Check for DAEMON status [$daemon]" + +:0 +*$ daemon ?? ^^yes^^ +{ + errText # Kill variable + + # Read the reason from MAIL DAEMON (subject field) + + :0 + * B ?? THIS IS A WARNING MESSAGE + { + errText = "Warn-Returned," + + # ----- The following addresses had transient non-fatal errors ----- + # <foo@d255f016.mch.sni.de> + + :0 + * B ?? The following addresses.*($)\/.*@ + { + match = $MATCH + } + } + + # ......................................... sendmail-error-codes ... + + :0 E + * B ?? ()\/550.*User unknown + { + errText = "Err-Unknown," + match = $MATCH + } + + :0 E + * B ?? ()\/554.*Mail loop detected + { + errText = "Err-Loop," + match = $MATCH + } + + # TO: foo@bar [552 Requested mail + # operation aborted: Cannot be routed.] + + :0 E + * B ?? ()\/.*552 .*mail operation.* + { + errText = "Err-Unknown," + match = $MATCH + } + + :0 E + *$ $SUPREME^0 B ?? following addresses have delivery notifications + *$ $SUPREME^0 B ?? has encountered a delivery problem. + *$ $SUPREME^0 B ?? Mailbox disk quota exceeded + *$ $SUPREME^0 B ?? did not reach the following recipient + *$ $SUPREME^0 B ?? Your message was refused by recipient + *$ $SUPREME^0 B ?? was not delivered to: + *$ $SUPREME^0 B ?? Delivery of the email was stopped + *$ $SUPREME^0 B ?? User mailbox exceed + *$ $SUPREME^0 B ?? Mailbox full + *$ $SUPREME^0 B ?? Our virus detector + { + errText = "Warn-Delivery," + } + + :0 E + * B ?? ()\/(not.*delivered.*($).*after.*hours\ + |still undelivered after.*(hours|days)\ + ).* + { + errText = "Warn-Returned," + } + + # ...................................................... unknown ... + + :0 E + *$ $SUPREME^0 H ?? ^Subject:.*(could not send|returned) + *$ $SUPREME^0 B ?? ()\/(message.*undeliverable\ + |could not be delivered\ + |no longer a valid address\ + |addresses had permanent fatal errors\ + | User unknown\ + ).* + { + # The message that you sent was undeliverable to the following: + # postmaster (user not found) + + # This e-mail address, `abc', is no longer a valid address. You can + # reach Mr Foo at his new email address: + # + # foo@bar.com + # + # <ORIGINAL MESSAGE FOLLOWS> + + # Subject: Returned mail: Cannot send message + # The following addresses had permanent fatal errors + + errText = "err-Unknown," + } + + # ........................................................ other ... + + :0 E + * ^Subject:.*\/Host unknown + { + errText = "$MATCH," + + :0 + * B ?? THIS IS A WARNING + { + errText = "Warn-$errText" + } + } + + :0 E + * ^Subject:.*\/Too many hops + { + errText = "MaxHops," + } + + :0 E B + * Connection to.*failed + { + errText = "Err-connection," + } + + # ........................................................ qmail ... + + # Hi. This is the qmail-send program at master.debian.org. + # I'm afraid I wasn't able to deliver your message to the ... + # This is a permanent error; I've given up. Sorry it didn't work out. + # + # <address>: + # Sorry, no mailbox here by that name. (#5.1.1) + + :0 E + * B ?? wasn't able to deliver your message to.*addresse + { + errText = "err-Unknown," + + :0 + * B ?? it didn't work out.($)+\/.* + { + match = $MATCH + } + } + + # ................................................... Novel MTA ... + + :0 E + *$ ^X-Diagnostic:$s+\/.* + { + errText = "err-Unknown," + match = $MATCH + } + + # .................................... daemon message known now? ... + # If the previous recipes didn't set errText, + # then this message was from a postmaster that sent it to + # the spam-l or to some other mailing list where it's okay + # to post copies of UBE. + + :0 + * ! errText ?? ^^^^ + { + # Read the old subject from body of original message + + :0 B + *$ $SUPREME^0 ^Subject: \/.* + *$ $SUPREME^0 The subject of the message is: \/.* + { + errSubj = $MATCH + } + + # Hm, no copy in the body of message? Look at headers then. + + :0 E + *$ $SUPREME^0 match ?? $a + { + errSubj = $match + } + + # Nothing matched, so take subject + + :0 E + * ^Subject:()\/.* + { + errSubj = $MATCH + } + + # To whom we tried to mail the message. Find it out + # + # login@site.com + # | + # This part will be derived, there must be leading space + + :0 + * errTo ?? ^^^^ + { + :0 + *$ match ?? [<]()\/$charset+ + { + errTo = "$MATCH," + } + + :0 E B + *$ ^To:.*\/$charset+@ + *$ MATCH ?? ()\/$charset+ + *$ MATCH ?? ^^\/[^@]+ + { + errTo = "$MATCH," + } + + :0 E B + *$ ()\/$charset+@ + *$ MATCH ?? ^^\/[^@]+ + { + errTo = "$MATCH," + } + } + + dummy = "$NLpm-jadaemon.rc: recognized message: $errText ($errSubj)" + + # Now make new, combined, subject: + # --> short error reason + original subject + + :0 fhw + * JA_DAEMON_SAVE ?? yes + * ^Subject: \/.* + | ${FORMAIL:-formail} -I "X-Old-Daemon-Subject: $MATCH" + + :0 fhw + | ${FORMAIL:-formail} -I"Subject: ${errText}${errTo}${errSubj}" + + ERROR = "yes" # Raise the flag + } +} + +dummy = "pm-jadaemon.rc: end: (DAEMON detect status = $ERROR)" + +# end of file pm-jadaemon.rc diff --git a/share/procmail/pm-jadate.rc b/share/procmail/pm-jadate.rc @@ -0,0 +1,146 @@ +# pm-jadate.rc -- Read date from the message hdrs: From_, Receved: +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This recipe will scan several headers to find the date string. +# When suitable header is found and the parsing has succeeded, the +# return variables are set. The Date values reflects the arrive time +# of the message; not the sending time. If nothing works, a shell call +# `date' is used as a last resort. +# +# Returned values +# +# YYYY = 4 digits +# YY = 2 digits +# MON = 3 characters +# MM = 2 digits +# DAY = 3 characters +# DD = 2 digits +# hh = 2 digits if available +# mm = 2 digits if available +# ss = 2 digits if available +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jadate1.rc +# o pm-jadate3.rc +# o pm-jadate4.rc +# +# Call arguments (variables to set before calling) +# +# (none) +# +# Usage example +# +# INCLUDERC = $PMSRC/pm-jadate.rc +# # now we have all date variables that we need +# # +# $TODAY = $YYYY-$MM-$DD +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jadate.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables, these actually come from the another subroutine, +# but let's mention them here too +# +# DATE YYYY MM MON DD DAY hh mm ss + +ERROR = "yes" + +# ........................................................... &do-it ... + +# Try MDA From_ header first +# From foo@bar.com Tue Nov 18 12:43:56 1997 + +fromRegexp = "...$s+...$s+$d+$s+$d$d:.*" + +dummy = "$id: From_ date test" + +:0 +*$ ^From$s+$NSPC+\/$s+$fromRegexp +{ + dummy = "$id: Standard From_ header matched" + INPUT = $MATCH + INCLUDERC = $PMSRC/pm-jadate3.rc # Date parser +} + +# Get time from first header, which is in some systems is +# Received: ... ; Thu, 13 Nov 1997 11:43:50 +0200 + +dummy = "$id: Received date test" + +:0 +*$ ! YYYY ?? $d +*$ ^Received:.*;$s+\/...,$s+$d+$s+...$s$d$d$d$d.* +{ + dummy = "$id: First Received header matched" + INPUT = $MATCH + INCLUDERC = $PMSRC/pm-jadate1.rc # Date parser +} + +# Emacs Gnus add X-From-line to the message +# Emacs Rmail adds Mail-from line to the message +# This is same as From_ + +dummy = "$id: MUA date test" + +:0 +*$ ! YYYY ?? $d +*$ ^(X-From-Line|Mail-from):$s+$NSPC+\/$s+$fromRegexp +{ + dummy = "$id: Other possible From_ header matched" + INPUT = $MATCH + INCLUDERC = $PMSRC/pm-jadate3.rc # Date parser +} + + +# Still no luck, I should add more tests to the above but I don't +# know what. Call sh 'date' as a last resort +# + +dummy = "$id: sh date test" + +:0 +*$ ! YYYY ?? $d +{ + dummy = "$id: Last chance, calling sh date " + INCLUDERC = $PMSRC/pm-jadate4.rc +} + +dummy = "$id: end:" + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-jadate1.rc b/share/procmail/pm-jadate1.rc @@ -0,0 +1,224 @@ +# pm-jadate1.rc -- 'Tue, 31 Dec 1997' date parser from variable INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc parses date from variable `INPUT' which has string +# +# "Week, Daynbr Month Year" +# +# Example input +# +# "Tue, 31 Dec 1997" -- without comma +# "Tue 31 Dec 1997" -- with comma +# +# Returned values +# +# YYYY = 4 digits +# YY = 2 digits +# MON = 3 characters +# MM = 2 digits +# DAY = 3 characters +# DD = 2 digits +# hh = 2 digits If available +# mm = 2 digits If available +# ss = 2 digits If available +# TZ = 5 characters If available +# +# Variable ERROR is set to `yes' if it couldn't recognize the INPUT +# and couldn't parse the basic YYYY, YY, MM, DD variables. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. +# +# Call arguments (variables to set before calling) +# +# INPUT = string-to-parse +# +# The INPUT can have anything after "Week, dayNbr Month Year", or +# before it: you can pass a string like +# "Thu, 13 Nov 1997 11:43:23 +0200". +# +# Usage example +# +# The first *Received* header will tell when the message was received +# by your mailserver. We parse the date and avoid calling expensive +# `date' command. +# +# PMSRC = $HOME/pm +# RC_DATE_WDMY = $PMSRC/pm-jadate1.rc #Week-Day-Month-Year parser +# +# # Get time from first header, it ends like this: +# # +# # Received: ... ; Thu, 13 Nov 1997 11:43:50 +0200 +# +# :0 +# *$ ^Received:.*;$s+\/...,$s+$d.* +# { +# INPUT = $MATCH +# +# # Turn off the logging while executing this part +# +# VERBOSE=off INCLUDERC = $RC_DATE_WDMY VERBOSE=on +# +# :0 +# * ERROR ?? yes +# { +# # Use some other way to get the time or shout loudly +# } +# } +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jadate1.rc" +dummy = " +======================================================================== +$id: init: +" + + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + +YYYY MM MON DD DAY hh mm ss TZ +ERROR = "yes" # set defualt value + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 + +dummy = "$id: Parse date like [Tue, 31 Dec 1997]" +dummy = "$id: INPUT = $INPUT" # show what we try to match + +:0 D +*$ INPUT ?? $s*\/[SMTWF]$a$a[,$WSPC]+$d+$s+$a$a$a.* +{ + INPUT = $MATCH + + :0 + * INPUT ?? ^\/... + { + DAY = $MATCH + } + + # Move to the DD MON section + + :0 + *$ INPUT ?? [SMTWF]$a$a[,$WSPC]+\/$d.* + { + INPUT = $MATCH + } + + + :0 + *$ INPUT ?? ^\/$d$d + { + DD = $MATCH + } + :0 E # else + *$ INPUT ?? ^\/$d + { + DD = "0$MATCH" + } + + :0 + *$ INPUT ?? ^$d+$s+\/... + { + MON = $MATCH + } + + # ........................................................ &year ... + + :0 + *$ INPUT ?? ^$d+$s+...$s+\/.... + { + YYYY = $MATCH + } + + + # If this last recipe succeeds, then the whole string has been parsed. + # + :0 + * YYYY ?? ..\/.. + { + YY = $MATCH + ERROR = "no" + } + + + # ........................................................ &time ... + # Change INPUT + + in = $INPUT + + :0 + *$ INPUT ?? ^$d+$s+...$s+....$s+\/.* + { + INPUT = $MATCH + } + + + :0 + *$ INPUT ?? ^\/$d$d + { + hh = $MATCH + } + + :0 + *$ INPUT ?? ^$d$d:\/$d$d + { + mm = $MATCH + } + + + :0 + *$ INPUT ?? ^$d$d:$d$d:\/$d$d + { + ss = $MATCH + } + + :0 + *$ INPUT ?? ^$d$d:$d$d:$d$d$s+\/[-+].... + { + TZ = $MATCH + } + + + # Now reverse engineer to the numer, David Tamkin <dattier@miso.wwa.com> + # technically one should use $\monthnym but here it doesn't matter + # If user gave invalid input, will not match + + :0 + * $ mm2nbr ?? $MON\/.. + { + MM = $MATCH + } +} + +dummy = "$id: end:" + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-jadate2.rc b/share/procmail/pm-jadate2.rc @@ -0,0 +1,162 @@ +# pm-jadate2.rc -- 'YYYY-MM-DD' ISO date parser from variable INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc parses date in format "YYYY-MM-DD hh:mm:ss" +# like `1997-12-01' and sets following variables whenever called +# +# YYYY = 4 digits +# YY = 2 digits +# MON = 3 characters +# MM = 2 digits +# DD = 2 digits +# hh = 2 digits If avaliable +# mm = 2 digits If avaliable +# ss = 2 digits If avaliable +# +# Variable ERROR is set to `yes' if it couldn't recognize the INPUT +# and couldn't parse the basic YYYY, YY, MM, DD variables. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. +# +# Call arguments (variables to set before calling) +# +# INPUT = string-to-parse +# +# Last string in INPUT that matches number sequence `NNNN-NN-NN' is +# parsed. +# +# Usage example +# +# PMSRC = $HOME/pm +# RC_DATE_ISO = $PMSRC/pm-jadate2.rc # ISO date parser +# +# INPUT = "This is 1800-10-11, a very old date" +# +# # Turn off the logging while executing this part +# +# VERBOSE="off" INCLUDERC=$RC_DATE_ISO VERBOSE="on" +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jadate2.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + +YYYY MM MON DD hh mm ss +ERROR = "yes" + +# ........................................................... &do-it ... + +dummy = "$id: Parsing date like [YYYY-MM-DD]" +dummy = $INPUT # show what we try to match + +:0 +* INPUT ?? $ ().*\/$d$d$d$d-$d$d-$d$d.* +{ + INPUT = $MATCH + + :0 + * INPUT ?? ^\/.... + { + YYYY = $MATCH + } + + :0 + * INPUT ?? ^..\/.. + { + YY = $MATCH + } + + :0 + * INPUT ?? ^....-\/.. + { + MM = $MATCH + } + + :0 + * INPUT ?? ^....-..-\/.. + { + DD = $MATCH + } + + + # ........................................................ &time ... + # Change INPUT + + in = $INPUT # this is no-op, but now we see the value in the logfile + :0 + *$ INPUT ?? ^....-..-..$s+\/.* + { + INPUT = $MATCH + } + + :0 + *$ INPUT ?? ^\/$d$d + { + hh = $MATCH + } + + :0 + *$ INPUT ?? ^$d$d:\/$d$d + { + mm = $MATCH + } + + + :0 + *$ INPUT ?? ^$d$d:$d$d:\/$d$d + { + ss = $MATCH + } + + # .................................................. &month-name ... + + # If user gave invalid YYYY-MM-DD spec, then the next recipe will + # not match: eg 1111-22-33 + + :0 + * $ nbr2mm ?? $MM\/... + { + MON = $MATCH + ERROR = "no" + } + +} + + +dummy = "$id: end:" + +# end of file pm-jadate2.rc diff --git a/share/procmail/pm-jadate3.rc b/share/procmail/pm-jadate3.rc @@ -0,0 +1,201 @@ +# pm-jadate3.rc -- 'Tue Nov 25 19:32:57' date parser from variable INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc parses date from variable INPUT which has string +# +# "Week, Month dayNbr hh:mm:ss yyyy", +# +# Example +# +# Tue Nov 25 19:32:57 1997 +# +# Returned values +# +# YYYY = 4 digits +# YY = 2 digits +# MON = 3 characters +# MM = 2 digits +# DAY = 3 characters +# DD = 2 digits +# hh = 2 digits +# mm = 2 digits +# ss = 2 sigits +# +# Variable ERROR is set to "yes" if it couldn't recognize the INPUT. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. +# +# Call arguments (variables to set before calling) +# +# INPUT = string-to-parse +# +# Usage example +# +# The first *Received* header will tell when the message was received +# by the mailserver. Parse the date and avoid calling expensive `date' +# command. +# +# PMSRC = $HOME/pm +# RC_DATE_WMDT = $PMSRC/pm-jadate4.rc #Week-Month-Day-Time parser +# +# # Get time from X-From-Line: Which was added by my MDA +# # X-From-Line: procmail-request@informatik.rwth-aachen.de \ +# # Tue Nov 25 19:32:57 1997 +# +# :0 c +# *$ ^X-From-Line:\/.* +# { +# INPUT = $MATCH +# +# # Turn off the logging while executing subroutine +# +# VERBOSE=off INCLUDERC = $RC_DATE_WMDT VERBOSE=on +# +# :0 +# * ERROR ?? yes +# { +# # Use some other way to get the time or shout loudly +# } +# } +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jadate3.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + + +# Kill following variables, listed one by one here: + +YYYY MM MON DD DAY hh mm ss + +ERROR = "yes" # set defualt value + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 + +dummy = "$id: Parse date like [Tue Nov 25 19:32:57 19:00:00 1997]" +dummy = "$id: INPUT = $INPUT" # show what we try to match + +:0 D +* INPUT ?? $ $s*\/[SMTWF]$a$a[,$WSPC]+$a$a$a$s+$d+$s+$d$d:.* +{ + + INPUT = $MATCH + + :0 D + * INPUT ?? ^\/[A-Z].. + { + DAY = $MATCH + } + + :0 D + *$ INPUT ?? ^...[,$WSPC]\/[A-Z].. + { + MON = $MATCH + } + + + :0 + *$ INPUT ?? ^...[,$WSPC]...$s+\/$d$d + { + DD = $MATCH + } + :0 E # else + *$ INPUT ?? ^...[,$WSPC]...$s+\/$d + { + DD = "0$MATCH" + } + + + # ........................................................ &time ... + # Move to hh:mm:ss section + + :0 + *$ INPUT ?? ^...[,$WSPC]...+$s$d+$s+\/.* + { + INPUT = $MATCH + } + + :0 + *$ INPUT ?? ^\/$d$d + { + hh = $MATCH + } + + :0 + *$ INPUT ?? ^..:\/$d$d + { + mm = $MATCH + } + + + :0 + *$ INPUT ?? ^..:..:\/$d$d + { ss = $MATCH } + + + # ........................................................ &year ... + + :0 + *$ INPUT ?? ^..:..:..$s+\/$d$d$d$d + { + YYYY = $MATCH + } + + # If this last recipe succeeds, then the whole string has been parsed. + + :0 + * YYYY ?? ^..\/.. + { + YY = $MATCH ERROR = "no" + } + + + # Now reverse engineer to the numer, David Tamkin <dattier@miso.wwa.com> + # technically one should use $\monthnym but here it doesn't matter + # If user gave invalid input, will not match + + :0 + *$ mm2nbr ?? $MON\/.. + { + MM = $MATCH + } +} + +dummy = "$id: end:" + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-jadate4.rc b/share/procmail/pm-jadate4.rc @@ -0,0 +1,125 @@ +# pm-jadate4.rc -- make RFC 'Mon, 1 Dec 1997 17:41:09' and parse values +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine calls shell command date once and prses the values. +# This should be your last resort if you haven't got the date values +# by any other means. This subroutine assumes that the DATE command +# knows the following % specifier formats (HP-UX) +# +# Y NNNN year +# h MON month +# d NN day +# a WEEK Like "Mon" +# H NN hour +# M NN min +# S NN sec +# +# Returned values +# +# DATE = RFC date in format "Mon, 1 Dec 1997 17:41:09" +# This is same as what you would see in From_ +# +# YYYY = 4 digits +# YY = 2 digits +# MON = 3 characters +# MM = 2 digits +# DAY = 3 characters +# DD = 2 digits +# hh = 2 digits +# mm = 2 digits +# ss = 2 sigits +# +# Variable ERROR is set to "yes" if values couldn't be set +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jadate1.rc +# +# Call arguments (variables to set before calling) +# +# (none) +# +# Usage example +# +# The First Received line will tell when the message was received by +# the MDA. If thata fails, then get date from the system. If you send +# test messages to # yourself, you don't usually put From_ header in +# it and thus there is # no date information in 'dry run' tests. +# +# # Get time from first eader, which is always same in my system +# # Received: ... ; Thu, 13 Nov 1997 11:43:50 +0200 +# +# INCLUDERC = $PMSRC/pm-javar.rc # to get $s $d definitions +# TODAY # Clear it +# +# :0 +# *$ ^Received:.*;$s+\/...,$s+$d.* +# { +# INPUT = $MATCH +# INCLUDERC = $PMSRC/pm-jadate1.rc +# TODAY = "$YYYY-$MM-$DD" +# } +# +# # Check that variable did get set, if not then we have to call +# # another date subroutine: Call shell then to find out date +# # +# # You could also do this with ':0 E', but this is more +# # educational +# +# :0 +# *$ ! $TODAY^0 +# { +# INCLUDERC = $PMSRC/pm-jadate4.rc # Get date from Shell then +# TODAY = $YYYY-$MM-$DD +# } +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jadat4.rc" +dummy = " +======================================================================== +$id: init: +" + +# ..................................................... &output-vars ... +# output variables, these actually come from the another subroutine, +# but let's mention them here too + +# DATE YYYY MM MON DD DAY hh mm ss + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 + +dummy = "$id: Calling shell to get date" + +date = `$DATE "+%a, %d %h %Y %H:%M:%S"` +INPUT = $date + +INCLUDERC = $RC_DATE1 # ...And parse into return variables + +dummy = "$id: end:" + +# end of file pm-jadate4.rc diff --git a/share/procmail/pm-jadate5.rc b/share/procmail/pm-jadate5.rc @@ -0,0 +1,227 @@ +# pm-jadate5.rc -- 'Fri Jun 19 18:51:56 1998' date parser from var INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc parses date from variable INPUT which has string +# +# "WeekDay Month dayNbr Year" +# +# Example input +# +# "Fri Jun 19 18:51:56 1998" -- without comma +# "Fri, Jun 19 18:51:56 1998" -- with comma +# +# Returned values +# +# YYYY = 4 digits +# YY = 2 digits +# MON = 3 characters +# MM = 2 digits +# DAY = 3 characters +# DD = 2 digits +# hh = 2 digits If available +# mm = 2 digits If available +# ss = 2 digits If available +# TZ = 5 characters If available +# +# Variable ERROR is set to "yes" if it couldn't recognize the INPUT +# and couldn't parse the basic YYYY,YY,MM,DD variables. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. +# +# Call arguments (variables to set before calling) +# +# INPUT = string-to-parse +# +# The INPUT can have anything after "Week, dayNbr Month Year", or +# before it: you can pass a string like +# "Fri Jun 19 18:51:56 1998 11:43:23 +0200". +# +# Usage example +# +# The first *Received* header will tell when the message was received +# by your mailserver. We parse the date and avoid calling expensive +# `date' command. +# +# PMSRC = $HOME/pm +# RC_DATE_WDMY = $PMSRC/pm-jadate5.rc #Week-Day-Month-Year parser +# +# # Get time from first header, it ends like this: +# +# :0 +# *$ ()\/From .* +# { +# INPUT = $MATCH +# # Turn off the logging while executing this part +# +# VERBOSE=off INCLUDERC = $RC_DATE_WDMY VERBOSE=on +# +# :0 +# * ERROR ?? yes +# { +# # Use some other way to get the time or shout loudly +# } +# } +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jadate5.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + +# Kill following variables + +YYYY MM MON DD DAY hh mm ss TZ + +# Set to default + +ERROR = "yes" # set defualt value + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 + +dummy = "$id: Parse: Fri Jun 19 18:51:56 1998" +dummy = "$id: INPUT = $INPUT" # show what we try to match + +:0 D +*$ INPUT ?? ()\/[SMTWF]$a$a[,$WSPC]+$a$a$a$s$d+$s+.* +{ + INPUT = $MATCH + + :0 + * INPUT ?? ^\/... + { + DAY = $MATCH + } + + :0 + *$ INPUT ?? ^...[,$WSPC]+\/... + { + MON = $MATCH + } + + # Move to the DD MON section + + :0 + *$ INPUT ?? ^...[,$WSPC]+...$s+\/.* + { + INPUT = $MATCH + } + + # ........................................................ &date ... + + :0 + *$ INPUT ?? ^\/$d$d + { + DD = $MATCH + } + :0 E # else + *$ INPUT ?? ^\/$d + { + DD = "0$MATCH" + } + + + # ........................................................ &time ... + # Change INPUT + + in = $INPUT # just for logging purposes + + :0 + *$ INPUT ?? ^$d+$s+\/.* + { + INPUT = $MATCH + } + + + :0 + *$ INPUT ?? ^\/$d$d + { + hh = $MATCH + } + + :0 + *$ INPUT ?? ^$d$d:\/$d$d + { + mm = $MATCH + } + + + :0 + *$ INPUT ?? ^$d$d:$d$d:\/$d$d + { + ss = $MATCH + } + + :0 + *$ INPUT ?? ^$d$d:$d$d:$d$d$s+\/[-+].... + { + TZ = $MATCH + } + + + # ........................................................ &year ... + + :0 + *$ INPUT ?? ^$d+:$d+:$d+$s+\/.... + { + YYYY = $MATCH + } + + + # If this last recipe succeeds, then the whole string has been parsed. + # + :0 + * YYYY ?? ..\/.. + { + YY = $MATCH + ERROR = "no" + } + + + # Now reverse engineer to the numer, David Tamkin <dattier@miso.wwa.com> + # technically one should use $\monthnym but here it doesn't matter + # If user gave invalid input, will not match + + :0 + * $ mm2nbr ?? $MON\/.. + { + MM = $MATCH + } +} + +dummy = "$id: end:" + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-jadup.rc b/share/procmail/pm-jadup.rc @@ -0,0 +1,138 @@ +# pm-jadup.rc -- Procmail: Handle duplicates; store to separate folder +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This recipe stores duplicate messages to separate folder +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jastore.rc +# +# Call arguments (variables to set before calling) +# +# o JA_ID_CACHE, Where to keep the Message-Id cache. +# o JA_ID_CACHE_SIZE, how big cache, defualt is 8192 +# o JA_ID_MBOX, where to store duplicate messages +# when delivering message to duplicate mbox. +# o JA_ID_IGNORE, if set to "yes", then ignore duplicate check +# +# Return values +# +# o Variable ERROR is set to "yes" if duplicate message was trapped, +# otherwise value is "no" +# +# Usage Example +# +# For simple usage, just put this somewhere after backup recipes +# +# RC_DUP = $PMSRC/pm-jadup.rc +# ... +# INCLUDERC = $RC_DUP +# +# When you are testing messages, you send them over and over to +# .procmailrc; which means that same message should not be trapped by +# duplicate check. You can call `procmail' with option "-a test" which will +# set pseudo variable `$1'. The recipe below sets flag `JA_ID_IGNORE' +# to "yes" if test is on going and the duplicate filter should be +# bypassed. +# +# RC_DUP = $PMSRC/pm-jadup.rc +# ARG = $1 # Copy pseudo variable to $ARG +# +# :0 +# * ARG ?? test +# { +# JA_ID_IGNORE = "yes" +# } +# +# # Some microsoft product is known to send same message ids +# # over and over. If we detect one, tunr off the duplicate test, +# # because it would trash every message. +# # <MAPI.Id.0016.00666479202020203030303430303034@MAPI.to.RFC822> +# +# :0 +# * ! ^X-msmail +# * ! ^Message-ID: *<MAPI.*@MAPI.to.RFC822> +# { +# JA_ID_IGNORE = "yes" +# } +# +# # Run this command every time a duplicate message is found. +# # It writes a small log entry to MY_LOG +# +# INCLUDERC = $RC_DUP +# +# :0 hwic: +# * ERROR ?? yes +# | echo " [duplicate]" >> $BIFF +# +# Change Log: (none) + +# ............................................................ &code ... + + +id = "pm-jadup.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + +ERROR = "no" + +# .......................................................... &public ... + +JA_ID_CACHE = ${JA_ID_CACHE:-"$HOME/pm-msgid.cache"} +JA_ID_CACHE_SIZE = ${JA_ID_CACHE_SIZE:-8192} +JA_ID_MBOX = ${JA_ID_MBOX:-"junk.duplicates"} +JA_ID_IGNORE = ${JA_ID_IGNORE:-"no"} + +# ........................................................... &do-it ... + +# We need regional lock, because `formail' is run in condition statement. + +jaDupLOCKFILE = $LOCKFILE # save old lockfile +LOCKFILE = ${JA_ID_CACHE}.lock + +:0 +* ^Message-Id: +* JA_ID_IGNORE ?? no +* ? $FORMAIL -D $JA_ID_CACHE_SIZE $JA_ID_CACHE +{ + ERROR = "yes" # Flag duplicate to caller + MBOX = $JA_ID_MBOX + INCLUDERC = $PMSRC/pm-jastore.rc +} + +LOCKFILE = $jaDupLOCKFILE # restore value + +dummy = "$id: end: (DUPLICATE status = $ERROR)" + +# end of file diff --git a/share/procmail/pm-jaempty.rc b/share/procmail/pm-jaempty.rc @@ -0,0 +1,86 @@ +# pm-jaempty.rc -- check if message body is empty +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This simple includerc will define variable BODY_EMPTY to "yes" or +# "no" when called like this You can file empty messages to separate +# folder based on this value +# +# INCLUDERC = $PMSRC/pm-jaempty.rc +# +# :0 +# * BODY_EMPTY ?? yes +# the-empty-mail-folder +# +# This is more designed to be part of other modules. If you just want +# to check for empty message, a simpler recipe like this might be +# better: +# +# INCLUDERC = $PMSRC/pm-javar.rc +# +# :0 B: # if body has only whitespace characters +# *$ ! $NSPC +# the-empty-mail-folder +# +# Required settings +# +# (none) +# +# Change Log (none) + +# ............................................................ &init ... + + +id = "pm-jaempty.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ........................................................... &do-it ... + +BODY_EMPTY = "yes" + +# Every empty line or signarure start is a -1 +# +# Every non-empty line that has characters is +10 +# +:0 +*$ B ?? -1^1 ^$s*$|^-- +* B ?? 10^1 ^.*[a-z] +{ + # no-op. We just count the score value. +} + +SCORE = $= + +:0 +*$ ${SCORE}^0 +{ + BODY_EMPTY = "no" +} + +dummy = "$id: end:" + +# end of file pm-jaempty.rc diff --git a/share/procmail/pm-jafrom.rc b/share/procmail/pm-jafrom.rc @@ -0,0 +1,93 @@ +# pm-jafrom.rc -- get message's best FROM field without calling `formail' +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc extracts the most likely FROM address from the +# message. The order of the search is Reply-to, From_, Sender, From +# and if none found, then as a last resort, call `formail'. You would +# usually use the returned value for logging purposes. +# +# Avoiding extra formail call could be usefull if you receive lot +# of messages per day. +# +# Example input +# +# (none) +# +# Returned values +# +# OUTPUT, containing the derived FROM field +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. You nee procmail 3.11pre7 in +# order to use this subroutine. (due to formail -z switch) +# +# Call arguments (variables to set before calling) +# +# (none) +# +# Usage example +# +# INCLUDERC = $PMSRC/pm-jafrom.rc +# FROM = $OUTPUT # now we have the 'best' FROM field +# +# Change Log (none) + +# .................................................... &initialising ... + +id = "pm-jafrom.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + +OUTPUT + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 + +dummy = "$id: Get message's FROM field." + +:0 +*$ ! ^Reply-to: *\/$NSPC.* +*$ ! ^From: *\/$NSPC.* +*$ ! ^Sender: *\/$NSPC.* +*$ ! ^From *\/$NSPC+ +{ + OUTPUT = `formail -zxFrom:` +} +:0 E +{ + OUTPUT = $MATCH +} + + +dummy = "$id: end:" + +# end of file pm-jafrom.rc diff --git a/share/procmail/pm-jafwd.rc b/share/procmail/pm-jafwd.rc @@ -0,0 +1,401 @@ +# pm-jafwd.rc -- Controlling forwarding remotedly +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Overview of features +# +# o Requires latest procmail (formail -z switch) +# o You can send forward-on and forward-off control +# messages via email to control the forwarding in remote site. +# +# Description +# +# This includerc makes it possible to control your message forwarding +# via simple remote email message. Thanks to Era Eriksson and Timothy +# J Luoma who gave the initial idea to this forwarding module in the +# procmail mailing list 1997-10-07. +# +# Activating the forwarding by hand +# +# If you want to activate the forwarding from the local site where +# this module is, then you could simply write the forward address +# to the file pointed by *JA_FWD_FILE* which is `~/.forward-address' +# by default. +# +# % echo Me@somewhere.com > ~/.forward-address +# +# and when you no longer need forwarding, then remove that file. +# But really, this module is not used for that purpose, because it is +# lot easier to write +# +# :0 +# ! Me@somewhere.com +# +# as a first statement in your .procmailrc when you want to forward +# your mail to another account. +# +# Activating the forwarding by remote email +# +# Suppose you're on the road and suddenly realize that you want your +# mail forwarded to the current account, then you send following +# control message +# +# Subject: forward-on password new-address@bar.com +# To: my-account@bar.com +# From: onTheRoad@some.com +# +# That message is is enough to get the mail forwarded to the address +# new-address@bar.com This script will respond to address From that +# the current forwarding is now pointing to address +# "new-address@bar.com". +# +# Deactivating forwarding by remote email +# +# The message is very similar, but the Subject header says +# +# Subject: forward-off password +# +# And no other fields are checked. Not even Reply-To. In this case +# the confirmation message is sent directly back to From address. +# +# Activating forwarding via body message +# +# If for some reason you have no control over the headers of email, +# eg when you send GSM-Mail message from your phone to your account: +# +# EMAIL foo@bar.com FORWARD-ON PASSWORD new-address@bar.com +# +# The email message looks like this: +# +# From: GenEmail <sms@FooBar.net> +# Date: Thu Sep 17, 11:42am +0200 +# To: "'Foo.Bar'" <foo@bar.com> +# Subject: Message 03384874987 +# +# FORWARD-ON PASSWORD new-address@bar.com +# +# Instead of looking at the `Subject' field, you can get this module +# to look at the first words in the body field. See variable +# `JA_FWD_CONTROL_FIELD' which you want to set to "body". +# +# Restricting the control message aceptance +# +# If you only have persistent accounts, then you should set the +# *JA_FWD_FROM_MUST_MATCH* to match those addresses that you have. +# The following setting says that only control messages sent from +# these addresses are accepted. Nobody else can't change your +# forwarding settings. +# +# JA_FWD_FROM_MUST_MATCH = ".*(acc1@a.com|acc2@b.com)" +# +# Hm, that's not a bullet proof, because someone may in theory forge +# the From address. You probably should also set this variable to +# point to accounts where the mail can be legally forwarded to. Then, +# even if the imposter forges the From address; he can't get the +# email forwarded anywhere else than to the valid locations. +# +# JA_FWD_TO_MUST_MATCH = $JA_FWD_FROM_MUST_MATCH +# +# Consider also setting *JA_FWD_PASSWORD_CASE* to Procmail flag +# `D' which causes your control word "forward-on" and password +# to be case sensitive. +# +# Diagnostics +# +# If you don't receive confirmation message, then your control +# message was ill formed or you're not in the *JA_FWD_FROM_MUST_MATCH* +# list. There is no notification sent on failure, so that no attacker +# can draw conclusions. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# +# Installation +# +# You should preset all necessary variables prior adding the +# includerc command to your .procmailrc. Here is one simple setup +# +# #JA_FWD_SENDMAIL = "tee $HOME/test.mail" # Uncomment if testing +# JA_FWD_COPY = no # no copies stored while forwarding +# JA_FWD_PASSWORD_CASE= "D" # case sensitive +# JA_FWD_PASSWORD = "MyMagicString" +# JA_FWD_FROM = $FROM # This is already known. +# INCLUDERC = $PMSRC/pm-jafwd.rc +# +# Comments from the author +# +# Please realise that when you set the forwarding from a remote site, +# be very carefull when you type in the forward address or your mail +# ends up to somebody else's mailbox. Also I recommend that you keep +# *JA_FWD_COPY* to *yes* so that your local account always keep the +# copy of forwarded message. +# +# A step further would conventionally encrypt(1)'ing your forwarded +# messages. This way even your top secret messages would be mostly safe +# even if they end up to someone else's mailbox. +# +# File layout +# +# The layout of this file is managed by Emacs packages folding.el/{{{}}} +# tinybm.el/&tags and tinytab.el for the 4 tab text placement. +# +# Change Log (none) + + +# {{{ Variables +# .................................................... &initialising ... + + +id = "pm-jafwd.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ....................................................... &variables ... + +# If you're testing, set this to "tee FILE", and the sent confirmation +# messages are stored to your disk and not actually mailed. + +JA_FWD_SENDMAIL = ${JA_FWD_SENDMAIL:-"sendmail -oi -t"} + +# File to hold the forward address. When forward is off, this file does +# not exist. + +JA_FWD_FILE = ${JA_FWD_FILE:-"$HOME/.forward-address"} + +# The password needed after the control command. + +JA_FWD_PASSWORD = ${JA_FWD_PASSWORD:-"password"} + +# If you want case sensitive control messages and passwords, +# set this variable to procmail flag "D". Then commands like below +# are different. You should use flag `D' for your own security. +# +# forward-on password +# Forward-on password + +JA_FWD_PASSWORD_CASE = ${JA_FWD_PASSWORD_CASE:-""} + +# Set this to account names and addresses that you use if you want some +# protection. The control messages can be sent only from the matched +# addresses only. The default "." accepts control message from anywhere +# and to be forwarded anywhere. + +JA_FWD_FROM_MUST_MATCH = ${JA_FWD_FROM_MUST_MATCH:-"."} +JA_FWD_TO_MUST_MATCH = ${JA_FWD_TO_MUST_MATCH:-"."} + +# Should the messages stored locally to this account too while forwarding +# messages? a good idea is to keep this "yes", because you never know if +# the forward address was faulty. + +JA_FWD_COPY = ${JA_FWD_COPY:-"yes"} + +# The accepted control messages in Subject field + +JA_FWD_ON = ${JA_FWD_ON:-"forward-on"} +JA_FWD_OFF = ${JA_FWD_OFF:-"forward-off"} + +# Initialize these variables unless they're already set. please set +# before this module, so that you save extra formail call, if you have +# already read the value. +# +# JA_FWD_FROM = $FROM + +JA_FWD_FROM = ${JA_FWD_FROM:-`$FORMAIL -zxFrom:`} + +# From which header to find the password information. +# +# o "header" Look Subject field. +# o "body" Look first words in the body of message +# + +JA_FWD_CONTROL_FIELD = ${JA_FWD_CONTROL_FIELD:-"subject"} + +# This has only meanng if `JA_FWD_CONTROL_FIELD' is set to "body" +# +# "^^" "forward-on password" must be at the very beginning +# of the body +# ".*" "forward-on password" can be anywhere in the body + +JA_FWD_CONTROL_REGEXP = ".*" + +# If the address where we're forwarding bounces, make sure +# we don't get into loop. + +JA_FWD_XLOOP = ${JA_FWD_XLOOP:-"$LOGNAME@$HOST"} + +# }}} +# {{{ Code + +dummy = "Check forward-off control message" + +# ..................................................... &state-check ... + +forward = "" +address = "" + +dummy = "$id: Check if control message is in the Subject" + +:0 +* JA_FWD_CONTROL_FIELD ?? subject +*$ ^From:$JA_FWD_FROM_MUST_MATCH +{ + + :0 $JA_FWD_PASSWORD_CASE + *$ ^Subject: $JA_FWD_OFF ${JA_FWD_PASSWORD}$ + { + forward = "off" + } + + :0 E $JA_FWD_PASSWORD_CASE + *$ ^Subject: $JA_FWD_ON ${JA_FWD_PASSWORD} \/.* + *$ MATCH ?? $JA_FWD_TO_MUST_MATCH + { + forward = "on" + address = "$MATCH" + } +} + +dummy = "$id: Check if control message is in the body" + +:0 E +* JA_FWD_CONTROL_FIELD ?? body +*$ ^From:$JA_FWD_FROM_MUST_MATCH +{ + :0 $JA_FWD_PASSWORD_CASE + *$ B ?? $JA_FWD_CONTROL_REGEXP$JA_FWD_OFF ${JA_FWD_PASSWORD} + { + forward = "off" + } + + :0 E $JA_FWD_PASSWORD_CASE + *$ B ?? $JA_FWD_CONTROL_REGEXP$JA_FWD_ON ${JA_FWD_PASSWORD} \/.* + *$ MATCH ?? $JA_FWD_TO_MUST_MATCH + { + forward = "on" + address = "$MATCH" + } +} + +# ............................................................. &off ... + +dummy = "$id: check forward OFF" + +:0 +* forward ?? off +{ + :0 hwic + * ? $IS_EXIST $JA_FWD_FILE + | $RM $JA_FWD_FILE + + # Kill all fields except the From and make reply to that address. + + subject = "Forward is now off." + + :0 wc + | ( $FORMAIL -X From: | \ + $FORMAIL -rt -I"Subject: $subject" \ + ) | $JA_FWD_SENDMAIL + +} + + +# .............................................................. &on ... +# It's important that we don't forward mailer daemon messages +# of self bounces. The X-Loop was attached by us and while +# the FROM_DAEMON would already trigger bounce message, we double +# check with X-Loop + + +dummy = "$id: check forward ON $address" + +:0 E +* forward ?? on +*$ ! ^X-Loop: $JA_FWD_XLOOP +*$ ! $JA_FROM_DAEMON +{ + + # Beware invalid address. The required @ character prevents from + # at least some mistakes. + + :0 c + *$ address ?? [^$WSPC]+@ + | echo "$address" > $JA_FWD_FILE + + # - formail -rt will use Reply-To but we also CC to the 'From:' address. + # - If the From and Reply to are the same, then this sends two messages + # but that's not a bad thing. + # - The `A' says that this recipe is executed only if the + # previous recipe put the `address' to `JA_FWD_FILE' + + subject = "Forwarding to [$address]" + + :0 Ahwc + | ( $FORMAIL -IReply-To: | \ + $FORMAIL -rt \ + -I"Subject: $subject" -I"CC: $JA_FWD_FROM"; \ + -i"X-Loop: $JA_FWD_XLOOP" \ + echo "Forwarding has been activated" \ + ) | $JA_FWD_SENDMAIL + +} + +# .................................................... do-forwarding ... +# Now do the forwarding +# File tests: +# +# s => file exists and has a size greater than zero +# r => file must be readable by us + +dummy = "$NL$NL$id: Check if forward is activated $NL" + +:0 +* forward ?? ^^^^ +*$ ? $IS_NOT_EMPTY $JA_FWD_FILE +*$ ? $IS_READABLE $JA_FWD_FILE +{ + # If the copy option is on, store the mail also locally + # and send a copy to forwarded address. + # + # The `E' Receipe only forwards and does not keep local copy. + + :0 + *$ JA_FWD_COPY ?? yes + { + :0 c + ! `$CAT $JA_FWD_FILE` + } + :0 E + ! `$CAT $JA_FWD_FILE` +} + +dummy = "$id: end:" + +# }}} + + +# pm-jafwd.rc ends here diff --git a/share/procmail/pm-jalist.rc b/share/procmail/pm-jalist.rc @@ -0,0 +1,1866 @@ +# pm-jalist.rc -- Subroutine to detect mailing LIST from message. +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine tries to detect and derive the mailing list name as +# it appears in some of the known methods that ezlm, smarlist, +# listserv, majordomo etc. normally use. After this subroutine has +# been applied to message the variable `LIST' contains the mailing +# list name. Subroutine adaptively finds new new mailing lists +# from the messages. +# +# The alternative to subscribing to many mailing lists is to read +# them from web archives. Even better way is to use NNTP server at +# http://www.gmane.org which allows you to post as you would to a +# regular newsgroup. Consider using the NNTP interface and you may +# save you from receiving lot of messages that can already be found +# from Gmane's server. +# +# Quick start +# +# If you just want to jump in and use this module and you +# noteice that some list isn't trapped, please set +# +# o JA_LIST_HEADER_REGEXP to match the From: field +# +# If you want to make some list more unique, like if name "Alert" +# was detected as a list name, please set +# +# o JA_LIST_MAKE_UNIQUE to match the list name, like "Alert". +# After that the list name will be converted to HOST-LIST format. +# +# Sendmail plus type method for list subscription +# +# If you can use sendmail type PLUS addressing capabilities, you may +# not be interested in this module, because you have an alternative +# way to handle mailing list messages. The extra information after +# "+" is available to procmail scripts via `$ARG' pseudo variable +# when procmail is the LDA. Let's suppose you want to subscribe to +# procmail mailing list and want to save all messages to folder +# list.procmail, then you'd subscribe with address: +# +# login+list.procmail@site.com +# +# If your email host doe snot provide the plus addressing then it the +# traditiona approach have been to add a piece of recipe to +# `~/.procmailrc' to catch each list. But that's manual work for +# every list. When you use this subroutine, you no longer need to +# write separate mailing list recipes to your `~/.procmailrc' every +# time you subscribe to a new mailing list. The detection of a new +# list will happen automatically. +# +# What you need to know before using this module +# +# There is lot of heuristics going on in this module and one thing +# that you must note: +# +# If 'To:' domain is same as `From/Sender:/Reply-to:' domain +# then it is considered a mailing list message. +# +# This causes certain messages to be treated as mailing list messages. +# The module can't possibly know that the following is not from +# mailing list, because it doesn't know "what is mailing list", only +# "how it probably looks like it". This is definitedly categorized as +# mailing list message, because `From' and even `Reply-to' has the same +# domain `foo.bar.net' as in `To'. +# +# To: support@foo.bar.net +# From: message@foo.bar.net +# Reply-to: support@foo.bar.net +# Subject: Vmail See message to Eric +# +# You must prevent checking messages like this by surrounding call +# to this subroutine with a check statement: +# +# # Do not check these messages +# +# noList = "From.*(foo.bar.net|support.my.com)" +# +# :0 +# *$ ! $noList +# { +# INCLUDERC = $RC_LIST +# # ... save messsag by examining variable LIST (which see) +# } +# +# Ask for help +# +# If you find mailing lists that this subroutine does not detect, but +# which could have been detected by looking the headers in standard +# way, please send a email to maintainer. There may be cases where it +# is impossible to detect the mailing list and in those cases you +# just has to carve a new entry to your `~/.procmailrc'. +# When you keep your procmail log running, you may see message +# +# *** potential list *** +# +# Which is an indication that some new recipe could be added to +# to this subroutine to detect that mailing list. If the message +# you received _was_ from a mailing list, please send all the headers +# to the maintainer so that support can be added. +# +# Further reading +# +# You can search for mailing list that interests you at: +# +# http://www.lsoft.com/lists/listref.html +# +# Python based mailing list manager; the mailman: +# +# http://www.list.org/ +# +# Code note: Errors-To +# +# Bill Houle sent interesting headers which caused to add +# more heuristic than was feasible to solve the list detection. +# From the below headers it is practically impossible to derive the +# original list name. So, the list name is artificially constructed +# by combining Reply-To's LOGIN with Errors-To field's first host +# name +# +# Reply-To: news@doodle.foo.net +# Errors-To: bounced@doodle.foo.net +# +# The list name formed is "news-doodle". So, If you happen to see +# an odd name like this which doesn't remind the original list +# name, it may be due to poor headers that have no clue about +# the real name. No problem, check below how you would convert +# this name to better mailbox name. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will followign extra module, which must have been installed. +# +# o pm-javar.rc +# +# Variable JA_LIST_FROM_TO_IGNORE +# +# This is regexp of sender addresses to ignore so that the if To and +# From are identical, it is not considered a list messages. This is +# typical for system generated messages that take form: +# +# From: root@host (Cron Daemon) +# To: root@host +# +# Variable JA_LIST_SAVE +# +# If set to "yes" then the list name information detected is saved to +# separate header. The `LIST_DETECTED' is the original grabbed word from +# the headers and the 'LIST' is the final name after possible +# list name conversions. According to RFC the X- can be user for +# user headers. +# +# X-List-Detected: $LIST_DETECTED mapped to $LIST +# +# Variable JA_LIST_KILL_POSTFIX +# +# If grabbed `LIST' match this regexp at the end of list name, then +# the postfix match will be removed. It is traditional that many +# list names are like list1-info, list2-beta, list3-L and ut would +# be preferable to see names like list1, list2 and list3. The +# default value will ditch "-(info|beta|L)". +# +# Variable JA_LIST_KILL_PREFIX +# +# Just like the postfix variable. If this string is matched at the +# beginning of the LIST, it is removed. +# +# Variable JA_LIST_DISREGARD_EMAIL +# +# In some cases this list detection recipe "thinks" that the address +# picked is the list sender. You may have a dedicated address where +# all you mailing list mails arrive and you have named it like +# mailing-list@me.here.at, which will effectively trigger: Ah, +# you have -list in email address, so this message must be from +# mailing list name 'mailing'. Of course it is not and you have to +# disallow the heuristics to make such assumption by defining a +# regexp that rejects a possible choice. For the above example, you +# would define: +# +# JA_LIST_DISREGARD_EMAIL = "posting-list@me.here.at" +# +# If you have several such addresses, just add them to the +# variable separating with normal regular expression "|" OR +# statement. +# +# Variable JA_LIST_HEADER_REGEXP +# +# This is *optional* variable, which you can set to match regexp of +# the mailing list domain address if it slipped through the tests +# in this module. There are some lists that send messages that don't +# carry enough information in headers to determine their list status. +# If you narrow the group by setting JA_LIST_HEADER_REGEXP, then for +# example lists like these, that identify themselves only through +# two headers, can be found: +# +# Reply-To: dispatch-faq@cnet.com +# From: CNET Digital Dispatch <dispatch@cnet.com> +# +# For that list you would set +# +# JA_LIST_HEADER_REGEXP = "(@cnet\.com)" +# +# Don't worry. all the other list detection recipes has already +# been tried, so this is last test that are carried out and variable +# JA_LIST_HEADER_REGEXP helps eliminating possible mishist +# +# You don't need set this variable to include all mailing list +# domains. Only to those ones that were not trapped. The default +# value for this is: +# +# "(amazon\.com|bookpool\.com)" +# +# Variable JA_LIST_MAKE_UNIQUE +# +# If you're subscribed to many mailing lists, that simply tell that +# they are *news* or *newsletter*, it will be impossible to +# differiantiate A *news* from B *news*. This variable holds regular +# expression that, if matched, prepend the first host name to the +# beginning of list name, thus making the list unique: +# +# news@some.com --> some-news +# news@here.com --> here-news +# +# The default value matches lists that contain word *news*, but you +# may need to set this to more matches. +# +# Variable JA_LIST_CONVERSION +# +# Note: before using this feature, make sure your `LINEBUF' +# is big enough, say 4096 or otherwise the variable's content +# is truncated. +# +# Many times the grabbed `LIST' name is not what you would like to +# use for your mailbox name. You want to make the name perhaps +# more shorter, more descriptive or categorize the messages according +# to hierarchy. Let's say that you have subscribed to following mailing +# lists: +# +# LIST LIST name Description of mailing list +# (as grabbed) you want +# ------------------------------------------------------------- +# jde java.jde Java Development Env +# java java.lang Java programming +# FLAMENCO flamenco Flamenco music +# tango-l tango Argentine Tango dancing +# tm-en-help tm-en Emacs TM mime package mailing list +# w3-beta w3 Emacs WWW mailing list +# +# First, remember that the variable `JA_LIST_KILL_POSTFIX' is first +# applied, so the actual `LIST' appears as follows: +# +# jde, java, FLAMENCO, tango, tm-en, w3 +# +# Ok, now we apply the conversion table by defining it as follows. +# The grabbed LIST name is first, then comes space(s), new name +# _and_ terminating colon. Repeat this for each list you want to +# convert. +# +# LIST CONVERSION[,LIST CONVERSION ...] +# +# This gives us table below: notice that entries tango-l, w3-beta +# were not included, because the `JA_LIST_KILL_POSTFIX' already got +# rid of the postfixes. Also note how the uppercase match FLAMENCO is +# converted to more suitable lowercase mailbox name. After you have +# set up this variable you can start saving messages to folders. +# +# JA_LIST_CONVERSION = "\ +# jde java.jde,\ +# java java.lang,\ +# FLAMENCO flamenco,\ +# " +# +# The list conversion is done with pure procmail means, so it is very +# fast. It also means that the conversion is limited to FROM-STRING +# TO-STRING syntax. No wild cards or regular expressions are allowed. +# +# If you consider using an external process, like `sed' or `perl' +# to convert the grabbed list name to something else (when +# `JA_LIST_CONVERSION' method was not enough); think again. For +# each incoming mailing list message you launch external process. +# It is not unusual to receive 700 messages from various mailing +# lists a day, it can be imagined how much load any external +# process would add to the server. Use the grabbed mailing list +# name and `JA_LIST_CONVERSION' table if you care about system +# load. +# +# If you have many mailing lists that use uppercase names, it may be +# tedious to add each mailing list name to `JA_LIST_CONVERSION'. +# Possible alternative is to use very efficient `tr' program +# to convert characters to lowercase. Again; think twice, +# because any extra process could be avoided if `JA_LIST_CONVERSION' +# was used. +# +# :0 +# * ! LIST ?? ^^^^ +# { +# :0 D # still uppercase list name? +# * LIST ?? [A-Z] +# { +# LIST = `echo $LIST | tr A-Z a-z` +# } +# +# :0 : +# list.$LIST +# } +# +# List name is not always the same +# +# One important thing to keep in mind is that when mailing list +# manager sends out list messages, the headers may change. +# This means that the list name grabbed previously changes too. +# This is unfortunate, but it sometimes happens. Let's see an example. +# I was previously receiving messages from Cygwin mailing list named +# `gnu-win32' +# +# To: <gnu-win32@cygnus.com>, "Foo Bar" <foo@example.com> +# +# However, one day that same list was grabbed under name "cygwin", due +# to new header +# +# Mailing-List: contact cygwin-help@sourceware.cygnus.com; run by ezmlm +# Now I had two list names that both should be going to the same +# mailbox. No worries, just add new entry to the translate +# table to convert the new list name to mailbox name: +# +# JA_LIST_CONVERSION = "\ +# gnu-win32 cygwin32,\ +# cygwin cygwin32,\ +# " +# +# Example: basic installation +# +# Here is recipe to save all your mailing list to separate folders. +# If you subscribe to new lists or unsubscribe to lists, you don't +# need to change anything. The grabbed list name will appear +# in variable `LIST' +# +# RC_LIST = $PMSRC/pm-jalist.rc # name the subroutine +# +# ... +# +# # Handle all mailing lists with one subroutine and recipe +# # following it. Set also JA_LIST_CONVERSION before +# # calling this subroutine to cnvert the found list names. +# +# INCLUDERC = $RC_LIST +# imap = # Kill var. Set to "/" to enable +# +# :0 # if list name was grabbed +# * LIST ?? [a-z] +# { +# dummy = "Saving mailing list: $LIST" +# +# :0 w: +# ${imap+".INBOX."}list.$LIST$imap +# } +# +# What's that IMAP thing there, you may wonder. Normally +# procmail delivers to standard mailbox, so the name is +# something like '$MAILDIR/list.abc'. For IMAP, the delivery +# must happen using principle "one file, one message", so +# procmail must deliver to a directory. That's what the added +# `$imap' is there for. It is also customary that IMAP folders +# are prefixed with ".INBOX", so the actual name becomes +# `$MAILDIR/.INBOX.list.abc'. For IMAP there should also +# be proper `MAILDIR=$HOME/Maildir' setting. +# +# Change Log (none) +# +# [Not updated any more - See project's ChangeLog file] +# +# 1998-06-16 dattier@wwa.com (David W. Tamkin) in list.procmail +# Message-Id: <m0ym1M3-001HE1C@tekka.wwa.com> replied to my +# my first announcement of list detection module. I used to use +# `expr' to delete -(help|owner) suffixes in complicated cases, +# but David showed that procmail could do that also. +# +# Now this subroutine does not use shell anywhere and is therefore +# as lightweight as possible and suitable for heavy mailing lists. +# +# 1998-06-30 Teresa Nunes <icecream@alaska.net> reported that +# more list were not trapped. Added new rule to match servers +# that use "@lists." id. Added "estimation" rule. +# +# 1998-08-10 Teresa Nunes <icecream@alaska.net> reported that +# more list were not trapped and <Bill.Houle@sandiegoca.ncr.com> +# sent cases which he labelled "Probably nothing can be done for this +# and this...". Well, suprise to your both. All the examples could +# be detected and list name derived. +# +# 1998-11 and 199-12 Bill Houle <bhoule@sandiegoca.ncr.com> sent +# me numerous new mailing ist message headers that improved detecting +# new mailing lists format a great deal. Thank you very much. +# +# 1999-01 Bill Houle <bhoule@sandiegoca.ncr.com> Still kept +# subscribing to mailing list that were not triggered by this module :-) +# Thank Bill for the samples. +# +# 1999-04 Tony Lam <Tony.Lam@Eng.Sun.Com> suggested adding +# X-List-Detected header and storing the original grabbed word +# to LIST_DETECTED. He also suggested new Received: "for" header +# check for possible mailing list names that contains dash(-). + +# .................................................... &initialising ... + +dummy = " +======================================================================== +pm-jalist.rc: init:" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# .......................................................... &public ... +# tango-l, spam-list-d (discussion) + +# These pre/postfix regexps and they must _not_ contain leading slashes: +# +# "-(help|beta)" Wrong +# "(help|beta)" Right + +JA_LIST_KILL_PREFIX = ${JA_LIST_KILL_PREFIX:-"\ +(return|owner|info|beta|help|announce|users|subscribers)"} + +JA_LIST_KILL_POSTFIX = ${JA_LIST_KILL_POSTFIX:-"\ +(return|owner|info|beta|help|request|digest\ +|announce|users|subscribers|maint\ +|unjoin|join\ +|discuss\ +|errors\ +|on|off|[ld])"} + +# See installation + +JA_LIST_CONVERSION = ${JA_LIST_CONVERSION:-""} +JA_LIST_HEADER_REGEXP = ${JA_LIST_HEADER_REGEXP:-"\ +(amazon\.com|bookpool\.com)"} + +# If we detect plain list name line "news" "announce" or "daily", +# that is too general, because same name can come from several sites. + +JA_LIST_MAKE_UNIQUE = ${JA_LIST_MAKE_UNIQUE:-"\ +^^(news(letters?|[0-9]+)?\ +|talk(tous)?\ +|unjoin|join\ +|announce(ments?)?\ +|daily|scripts?\ +|modules?)\ +^^"} + +JA_LIST_DISREGARD_EMAIL = ${JA_LIST_DISREGARD_EMAIL:-""} + +# Messages that have identical From-To and match this regexp are ignored. + +JA_LIST_FROM_TO_IGNORE = ${JA_LIST_FROM_TO_IGNORE:-\ +"(root|postmaster|webmaster|abuse|spam)"} + +# returned value + +LIST_DETECTED # Kill variable +LIST # Kill variable + +# ........................................................... &check ... + +pfx = "( *<?(mailto:)?)?" +abc = "[^][<>(){}$WSPC?&,@\"\'=]" + +# THIS LINE: Emacs font-lock.el fix to close previous quote(") + + +# Words that are included in the list name, like "food-discuss" + +trigger = "(\ +[ld]\ +|admin\ +|announce\ +|apps\ +|beta\ +|digest\ +|discuss\ +|errors\ +|help\ +|info\ +|join\ +|maint\ +|off +|on +|owner\ +|return\ +|request\ +|subscribers\ +|unjoin\ +|users\ +)" + +from = "(X-From-Line:|X-From:|From:|From )" +from1 = "(X-From-Line:|X-From:|From:)" +to = "((Apparently-)?To:)" + +email = $abc+@$abc+ +agent = (owner|info|errors) + +rc_email = $PMSRC/pm-jaaddr.rc + +# .................................................... &setting-vars ... + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::::::: #FROM" + +# This variable is used as a hint to get a unique list name. +# If not set, then define sender name from $from. + +unique_from = "" + +sender_field = "" +sender_addr = "" +sender_addr2 = "" +sender_site = "" +sender_domain = "" +sender_sub1 = "" +sender_account = "" + +:0 +*$ $SUPREME^0 ^(Sender:|$from1)\/.* +*$ $SUPREME^0 ^From \/.* +{ + sender_field = $MATCH + + # Call subroutine + + save=$VERBOSE + + VERBOSE = "off" + INPUT = $MATCH + INCLUDERC = $rc_email + + VERBOSE=$save + + sender_addr = $ADDRESS # foo@a.b.com + sender_addr2 = $ACCOUNT@$DOMAIN # foo@b.com + + sender_account = $ACCOUNT # foo + sender_domain = $DOMAIN # b.com + sender_site = $SITE # a.b.com + sender_sub1 = $SUB1 + + unique_from = $sender_field +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::::::: #TO" + +to_field = "" +to_addr = "" +to_addr2 = "" +to_site = "" +to_account = "" +to_domain = "" +to_sub1 = "" + +:0 +* ^To:\/.* +{ + to_field = $MATCH + + saved = $VERBOSE + + VERBOSE = "off" + INPUT = $to_field + INCLUDERC = $rc_email + + VERBOSE = "$saved" + + to_addr = $ADDRESS + to_addr2 = $ACCOUNT@$DOMAIN + + to_account = $ACCOUNT + to_domain = $DOMAIN + to_site = $SITE + to_sub1 = $SUB1 +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::::: #REPLY" + +reply_field = "" +reply_addr = "" +reply_addr2 = "" +reply_account = "" +reply_site = "" +reply_domain = "" +reply_sub1 = "" + +:0 +* ^Reply-To:\/.* +{ + reply_field = $MATCH + + saved = $VERBOSE + + VERBOSE = "off" + INPUT = $reply_field + INCLUDERC = $rc_email + + VERBOSE = "$saved" + + reply_addr = $ADDRESS + reply_addr2 = $ACCOUNT@$DOMAIN + + reply_account = $ACCOUNT + reply_domain = $DOMAIN + reply_site = $SITE + reply_sub1 = $SUB1 +} + +cc_field = "" +cc_addr = "" +cc_addr2 = "" +cc_account = "" +cc_site = "" +cc_domain = "" +cc_sub1 = "" + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::::: #CC" + +:0 +* ^CC: \/[^,]+ +{ + cc_field = $MATCH + + saved = $VERBOSE + + VERBOSE = "off" + INPUT = $cc_field + INCLUDERC = $rc_email + + VERBOSE = "$saved" + + cc_addr = $ADDRESS + cc_addr2 = $ACCOUNT@$DOMAIN + + cc_account = $ACCOUNT + cc_domain = $DOMAIN + cc_site = $SITE + cc_sub1 = $SUB1 +} + +# ....................................................... &microsoft ... + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: #MICROSOFT" + +# Microsoft mailing lists +# +# From BackOfficeEditor_004060@news.newswire.microsoft.com +# From: "Microsoft TechNet" <MicrosoftTechNet_004@news.newswire.microsoft.com> + +:0* LIST ?? ^^^^ +*$ ^$from.*@news.*.microsoft +{ + :0 + *$ ^$from.*$pfx+\/$abc+_$d+@ + *$ MATCH ?? ()\/$a+ + { + LIST = $MATCH + } +} + +# ................................................. &targetted-catch ... + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: #LSV" + +# X-LSV-ListID: SPAM-L + +:0 +* LIST ?? ^^^^ +*$ ^X-LSV-ListID:$s+\/$abc+ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: #List-Id" + +# -- The first supreme matches both these cases +# +# List-Id: A user list for the exim MTA <exim-users.exim.org> +# List-ID: <java.mysql.com> + +# -- The second supreme mathes this +# +# List-ID: <mailto:java-subscribe@lists.mysql.com> +# List-Id: gnome-print-list.gnome.org + + +dummy = "pm-jalist.rc: List-ID" + +:0 +* LIST ?? ^^^^ +*$ $SUPREME^0 ^List-ID:.*<\/$abc+ +*$ $SUPREME^0 ^List-ID:.*$pfx\/$abc+> +*$ $SUPREME^0 ^List-ID:$s*\/$abc+ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: #List-* " + +# More similar headers that can be used ... +# +# Precedence: bulk +# List-Help: <mailto:java-help@lists.mysql.com> +# List-Unsubscribe: <mailto:java-unsubscribe-posting-list=mailandnews.com@lists.mysql.com> +# List-Post: <mailto:java@lists.mysql.com> +# List-Subscribe: <mailto:java-subscribe@lists.mysql.com> +# +# Precedence: list +# List-Help: <mailto:sympa@mandrivalinux.org?subject=help> +# List-Subscribe: <mailto:sympa@mandrivalinux.org?subject=subscribe% +# 20cooker> +# List-Unsubscribe: +# <mailto:sympa@mandrivalinux.org?subject=unsubscribe%20cooker> +# List-Post: <mailto:cooker@mandrivalinux.org> +# List-Owner: <mailto:cooker-request@mandrivalinux.org> + +dummy = "pm-jalist.rc: Other List-* headers" + +:0 +* LIST ?? ^^^^ +*$ $SUPREME^0 ^List-Post:.*<\/$abc+ +*$ $SUPREME^0 ^List-Post:.*$pfx\/$abc+> +*$ $SUPREME^0 ^List-(Un)?Subscribe:.*$pfx\/$abc+> +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: Mailman" + +# X-Mailman-Version: 1.0 +# Precedence: bulk +# List-Id: LeoCAD Development List <leocad-devel.gerf.org> +# X-Loop: docwhat@gerf.org + +:0 +* ! +* LIST ?? ^^^^ +* ^X-Mailman-Version: +* ^List-Id:[^<]+<\/[^>]+ +{ + dummy = "pm-jalist.rc: Mailman MATCH is $MATCH" + LIST = `echo $MATCH | sed 's/\./@/'` + dummy = "$is: Mailman LIST is $LIST" +} + +# ..................................................... mailing-list ... +# X-Mailing-List: <procmail@informatik.rwth-aachen.de> archive/latest/17987 +# X-Mailing-List: <info-bbdb@xemacs.org> archive/latest/954 +# X-Mailing-List: <efs-help@cuckoo.hpl.hp.com> archive/latest/119 +# X-Mailing-List: <xemacs-beta@xemacs.org> +# Mailing-List: contact jde-help@sunsite.auc.dk; run by ezmlm +# Mailing-List: contact pgp-users-help@joshua.rivertown.net; run by ezmlm +# X-Mailing-List: <procmail@informatik.rwth-aachen.de> archive/latest/22876 + + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: X-Mailing-List1" + +dummy = "pm-jalist.rc: X-Mailing-List AGENT-" + +:0 +* LIST ?? ^^^^ +*$ ^(X-)?Mailing-List:$pfx$agent-\/$abc+@ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: X-Mailing-List non-greedy match" + +:0 +* LIST ?? ^^^^ +*$ ^(X-)?Mailing-List:${pfx}\/$abc+@ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: X-Mailing-List greedy match" + +:0 +* LIST ?? ^^^^ +*$ ^(X-)?Mailing-list:.*${pfx}\/$abc+@ +{ + LIST = $MATCH +} + +# .................................................... &list-headers ... + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::: list-* [$LIST]" + +# A great of good set of headers to pick list name from +# +# List-Software: Lyris Server version 2.54, <http://www.lyris.net> +# List-Subscribe: <mailto:subscribe-perl-win32-users@lyris.activestate.com> +# List-Owner: <mailto:owner-perl-win32-users@lyris.activestate.com> +# List-Help: <mailto:help@lyris.activestate.com> +# X-List-Host: ActiveState Tool Corp. <http://www.activestate.com> +# Reply-To: "Christopher Maujean (Volt Computer)" <a-chrism@microsoft.com> +# Sender: perl-win32-users-admin@lyris.activestate.com +# Precedence: bulk +# X-Lyris-To: [foo@example.com] +# X-Lyris-MemberID: 45971 +# X-Lyris-MessageID: 32936 +# X-listname: perl-win32-users +# X-ListMember: [foo@example.com] + +:0 +* LIST ?? ^^^^ +*$ ^X-Listname:$s+\/$abc+ +{ + LIST = $MATCH +} + +:0 +* LIST ?? ^^^^ +*$ ^List-Owner:$pfx$agent-\/$abc+@ +{ + LIST = $MATCH +} + +# List-Unsubscribe: <mailto:leave-jscript-146465L@ls.activeserverpages.com> +# List-Unsubscribe: unsubscribe network-computing-newsletter + +:0 +* LIST ?? ^^^^ +*$ $SUPREME^0 ^List-Unsubscribe: +unsubscribe$pfx\/$abc+ +*$ $SUPREME^0 ^List-Unsubscribe:$pfx\/$abc+ +{ + + LIST = $MATCH + + :0 + * ^List-Unsubscribe:\/.* + { + unique_from = $MATCH + } + + # Check if there is Reply-To and narrow "leave-jscript-146465L" to + # "jscript" by searching common match. + + :0 + *$ $SUPREME^0 ^Reply-To:.*[<]\/$abc+ + *$ $SUPREME^0 ^Reply-To:.*$pfx\/$abc+ + { + replyToListName = $MATCH + + dummy = "pm-jalist.rc: is replyToListName included in List-Unsubscribe?" + + :0 + *$ LIST ?? $replyToListName + { + LIST = $replyToListName + } + } +} + +# ........................................................ &triggers ... + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: TO #TRIGGER" + +# Just impossible to know that this is list....without -discuss keyword + +# From list-relay@mlist.ucsd.edu Fri Jan 22 20:13:07 1999 +# Sender: foo@bar.com +# From: foo@bar.com +# To: <fhs-discuss@ucsd.edu> + +:0 +* LIST ?? ^^^^ +*$ ^To:$pfx\/$abc+-$trigger@ +{ + LIST = $MATCH + unique_from = $to_field +} + +# ...................................................... envelope-to ... +# X-Envelope-to: tango-L@mitvma.mit.edu + +dummy = "pm-jalist.rc: TRY X-Envelope-to" + +:0 +* LIST ?? ^^^^ +*$ ^X-Envelope-to:${pfx}\/$abc+ +{ + LIST = $MATCH +} + +# ........................................................... sender ... +# Sender: Discussion of Any Aspect of the Argentine Tango +# <TANGO-L@MITVMA.MIT.EDU> +# Sender: Open discussion of TI Graphing Calculators +# <CALC-TI@LISTS.PPP.TI.COM> +# Sender: owner-ding@hpc.uh.edu +# Sender: Flamenco discussion group <FLAMENCO@LISTSERV.TEMPLE.EDU> +# Sender: owner-ntemacs-users@cs.washington.edu + +# ((((( NOTE ))))) +# This would match +# +# Sender: owner-announce@perl.org --> LIST = "announce" +# +# Which is prevented with JA_LIST_KILL_POSTFIX test +# +# The SUPREME will match first Sender field, then any field that has +# agent properties like owner- ... + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: Sender" + +:0 +* LIST ?? ^^^^ +*$ $SUPREME^0 ^Sender:$pfx$agent-\/$abc+ +*$ $SUPREME^0 ^[-a-z]+:$pfx$agent-\/$abc+ +*$ ! MATCH ?? ^^$JA_LIST_KILL_POSTFIX^^ +{ + LIST = $MATCH + + :0 + *$ ^Sender:\/.* + { + unique_from = $MATCH + } +} + +dummy = "pm-jalist.rc: TRY sender1a" + +:0 +* LIST ?? ^^^^ +*$ ^Sender:.*${pfx}\/$abc+-L\> +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: TRY sender1b" + +:0 +* LIST ?? ^^^^ +*$ ^Sender:.*${pfx}\/$abc+@listserv +{ + LIST = $MATCH +} + +# Sender: semi-gnus-en-owner@meadow.scphys.kyoto-u.ac.jp + +dummy = "pm-jalist.rc: sender postfix words in list name" + +:0 +* LIST ?? ^^^^ +*$ ^Sender:${pfx}\/$abc+-$agent +{ + LIST = $MATCH +} + +# Reply-To: "AIP Public" <public@lists.association.org> +# Sender: public-admin@lists.association.org + +dummy = "pm-jalist.rc: sender lists.domain" + +:0 +* LIST ?? ^^^^ +*$ ^Sender:.*\/${abc}+@lists\. +{ + LIST = $MATCH +} + +# ............................................................. From ... + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: From-Owner 1" + +:0 +* LIST ?? ^^^^ +*$ ^$from.*${pfx}\/$abc+-$agent +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: From-Owner 2" + +:0 +* LIST ?? ^^^^ +*$ ^$from.*$pfx\/$agent-$abc+@ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: From-Owner 3 TRIGGER" + +# To: Planet IT Members:; +# Subject: Join Planet IT's New Systems-Management Technology Center +# From: Planet IT Announcements <cmpnet-announcements@lists.cmpnet.com> +# Errors-To: anchovy+cmp-planetit010899-1@mx.lodo.infobeat.com + +:0 +* LIST ?? ^^^^ +*$ $SUPREME^0 ^$from.*$pfx.*\/${abc}+-$trigger@ +*$ $SUPREME^0 ^$from.*$pfx.*\/${trigger}-$abc+@ +{ + LIST = $MATCH +} + +# We can't do anything automatic to detect this list. User must +# set JA_LIST_HEADER_REGEXP to match @motleyfool.com, then the +# FoolWatch: from Subject line it taken. + +# From: foolexpress@motleyfool.com +# Received: (qmail 1528 invoked by uid 536); 17 Dec 1998 02:31:49 -0000 +# Message-ID: <19981217023149.1527.qmail@mail3.motleyfool.com> +# Date: 16 Dec 1998 21:31:49 -0500 +# Subject: FoolWatch: Downsizing Tidal Wave? and Rule Breaker on Amazing Amazon +# Subject: Fool Watch: +# To: foo@bar.com + +dummy = "pm-jalist.rc: TRY FromLogin 2" + +:0 +* LIST ?? ^^^^ +*$ $SUPREME^0 ^Subject: +\/$abc$abc$abc$abc+: +*$ $SUPREME^0 ^Subject: $abc$abc$abc$abc+ +\/$abc$abc$abc$abc+: +*$ MATCH ?? ()\/[^:]+ +*$ $JA_LIST_HEADER_REGEXP +{ + LIST = $MATCH +} + +# This is tough. We pick the host names from the From address and try to +# see if those exist in the Subject line. SIDEWALK can be found +# +# The regexp ^Subject:.* +\/$abc$abc$abc$abc+: makes sure there is +# some list name with colon. Simple "re:" won't do, but "Alert:" does. + +# From: talktous@sandiego.sidewalk.com +# To: <foo@bar.com> +# Subject: Sidewalk Ticket Alert: Handel's "Messiah," Jingle Ball + +dummy = "pm-jalist.rc: TRY From-Subject 1" + +:0 # host 1 after @ +* LIST ?? ^^^^ +*$ ^Subject:.* +\/$abc$abc$abc$abc+: +*$ ^$from.*@\/$abc+ +*$ ^Subject:.*$\MATCH +{ + tmp = $MATCH + + :0 + *$ ^$from.*\/$S+@.*$tmp + *$ MATCH ?? ()\/[^@]+ + { + LIST = $MATCH + + :0 + *$ ^()\/$from.*@.*$tmp + { + unique_from = $MATCH + } + } +} + +dummy = "pm-jalist.rc: TRY From-Subject 2" + +:0 # host 2 after @ +* LIST ?? ^^^^ +*$ ^Subject:.* +\/$a$a$a$a+: +*$ ^$from.*@$a+\.\/$a+\.$a+ +*$ MATCH ?? ()\/$a+ +*$ ^Subject:.*$\MATCH +{ + + # We can use this "sidewalk", because it's sub-domain and UNIQUE + # would pick. We want something outside... + + tmp = $MATCH + + # Get the login. find the correct FROM that contains TMP, then extract + # the login + + :0 + *$ ^$from.*\/$S+@.*$tmp + *$ MATCH ?? ()\/[^@]+ + { + LIST = $MATCH + + :0 + *$ ^()\/$from.*@.*$tmp + { + unique_from = $MATCH + } + } +} + +dummy = "pm-jalist.rc: TRY From-Subject 3 words" + +# Try to match three same words from both SUBJECT and FROM: +# +# To: foo@bar.com +# Subject: Silicon Alley Daily for Monday, January 4, 1999 +# From: Silicon Alley Daily <daily@sar.infobeat.com> +# Errors-To: daily-errors+1.0.92574.foo#bar.com@bounce.sar.infobeat.com +# +# Notice that here are 2 common words +# +# Subject: Silicon Alley Reporter Net TV Show @ 4 p.m. +# From: Silicon Alley Daily <daily@sar.infobeat.com> +# +# Ignore messages that come from daemon, like +# +# From: Mail Delivery System <Mailer-Daemon@example.org> +# Subject: Mail delivery failed: returning message to sender + +:0 +* LIST ?? ^^^^ +*$ ! $JA_FROM_DAEMON +*$ ! $JA_FROM_MAILER +*$ ^Subject: +\/$S+ +$S+ +*$ ^$from1\/$s*$\MATCH.* +*$ ^Subject: +\/$S+ +$S+ .* +{ + tmp = $MATCH # save "Silicon alley Daily" + status = "read-more" + + :0 # Record the correct FROM line + *$ ^()\/$from.*$tmp.* + { + unique_from = $MATCH + } + + # Now make list name. Note that first "]" character must end reading + # words + # + # Subject: [this list] + + dummy = " *** WORD 1" + + :0 + *$ tmp ?? ^^()\/$S+ + { + part = $MATCH + + :0 + * part ?? ()\/[a-zA-Z0-9_-]+ + { + LIST = $MATCH + } + + :0 + *$ part ?? \]^^ + { + status = "stop" + } + } + + dummy = " *** WORD 2" + + :0 + * status ?? read-more + *$ tmp ?? ^^$S+ +\/$S+ + { + part = $MATCH + + :0 + * part ?? ()\/[a-zA-Z0-9_-]+ + { + LIST = $LIST-$MATCH + } + + :0 + *$ part ?? \]^^ + { + status = "stop" + } + } + + dummy = " *** WORD 3" + + :0 + * status ?? read-more + *$ tmp ?? ^^$S+ +$S+ +\/$S+ + { + part = $MATCH + + :0 + * part ?? ()\/[a-zA-Z0-9_-]+ + { + LIST = $LIST-$MATCH + } + } +} + +# ................................................ FromLogin-Subject ... + +# Check if LOGIN is found from SUBJECT +# +# From: newsletter@x10.com +# To: <login@some.com> +# Subject: X-10 Newsletter: FREE Sticka Switches + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: From-Login" + +:0 +* LIST ?? ^^^^ +*$ ^$from.*${pfx}\/$abc+ +*$ ^Subject:.*$MATCH: +{ + LIST = $MATCH +} + +# ....................................................... subscriber ... + +# To: "internet-subscribers" <foo@bar.com> +# From: <internet-editor@amazon.com> +# Subject: Amazon.com Delivers Internet + +:0 +* LIST ?? ^^^^ +*$ ^To:.*\/($abc.*subscriber|subscriber.*$abc) +*$ $JA_LIST_HEADER_REGEXP +{ + LIST = $MATCH +} + +# ........................................................... X-list ... +# X-Listserver: ListSTAR v1.1 by StarNine Technologies, a Quarterdeck Company +# X-List-Subscribe: <mailto:FAQ-Maintainers@consensus.com?subject=subscribe> +# X-List-Help: <mailto:FAQ-Maintainers@consensus.com?subject=help> +# List-Subscribe: <mailto:updatemail-on@lists.funnytown.com> + +# The list name can't be deternined by $trigger, but we can +# estimate that if +# +# Sender = To, then it's list +# OR +# Reply-To = To +# +# Reply-To: Alpha K9s <ALPHAK9S@APPLE.EASE.LSOFT.COM> +# Sender: Alpha K9s <ALPHAK9S@APPLE.EASE.LSOFT.COM> +# From: "Mark A. Winters" <wintdavi@PANIX.COM> +# To: ALPHAK9S@APPLE.EASE.LSOFT.COM + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: Using heuristics" + +# ....................................................... sender ... + +dummy = "pm-jalist.rc: ****** Checking Sender" + +:0 +* LIST ?? ^^^^ +* sender_addr ?? [a-z] +* to_addr ?? [a-z] +{ + dummy = "pm-jalist.rc: to_addr $to_addr ?? sender_addr $sender_addr" + + # We try first with exact matches, then with only the top level domain + # + # addr = site.this.com + # addr2 = this.com + + :0 + *$ $SUPREME^0 to_addr ?? ()\/$\sender_addr + *$ $SUPREME^0 to_addr ?? ()\/$\sender_addr2 + *$ $SUPREME^0 to_addr2 ?? ()\/$\sender_addr + *$ $SUPREME^0 to_addr2 ?? ()\/$\sender_addr2 + *$ MATCH ?? ()\/$abc+@ + { + :0 + *$ ! sender_addr ?? $JA_LIST_FROM_TO_IGNORE + { + dummy = "pm-jalist.rc: Sender is identical to To." + unique_from = $to_addr2 + LIST = $MATCH + } + } + + # To: humor@NewHumor.com + # Sender: ListManager@NewHumor.com + # + # But, it must not be person-to-person message, that's why + # JA_LIST_HEADER_REGEXP addition. + + dummy = "pm-jalist.rc: sender_addr [$sender_addr] ?? to_site [$to_site] [$to_addr]" + + :0 E + *$ $JA_LIST_HEADER_REGEXP + *$ sender_addr ?? $\to_site + *$ to_addr ?? ()\/$abc+ + { + dummy = "pm-jalist.rc: Sender address matched To domain." + LIST = $MATCH + } +} + +# ..................................................... reply-to ... + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: Reply-to" + +:0 +* LIST ?? ^^^^ +* ^Reply-To:\/.* +*$ to_addr ?? ()\/$abc+ +{ + + # ................................. Reply-To identical to To ... + # To: web-consultants@just4u.com + # Reply-To: web-consultants@just4u.com + + dummy = "pm-jalist.rc: Check if Reply-To identical to To." + dummy = "pm-jalist.rc: [$to_addr] ?? [$reply_addr]" + + :0 + *$ $SUPREME^0 to_addr ?? ()\/$\reply_addr + *$ $SUPREME^0 to_addr ?? ()\/$\reply_addr2 + *$ $SUPREME^0 to_addr2 ?? ()\/$\reply_addr + *$ $SUPREME^0 to_addr3 ?? ()\/$\reply_addr2 + *$ MATCH ?? ()\/$abc+@ + { + unique_from = $to_addr2 + LIST = $MATCH + } + + # ............................... Reply-To identical to From ... + + dummy = "pm-jalist.rc: Check if Reply-To identical to From." + dummy = "pm-jalist.rc: [$sender_addr] ?? [$reply_addr]" + + :0 E + *$ sender_addr ?? $\reply_addr + *$ MATCH ?? ()\/$abc+@ + *$ $JA_LIST_HEADER_REGEXP + { + dummy = "pm-jalist.rc: MAYBE LIST, Reply-To is identical to From address." + LIST = $MATCH + } + + # Hm, not identical addresses; but partially. + # + # Reply-To: dispatch-faq@cnet.com + # From: CNET Digital Dispatch <dispatch@cnet.com> + + dummy = "pm-jalist.rc: SENDER/REPLY acc [$sender_account] ?? [$reply_account]" + :0 E + *$ $SUPREME^0 sender_account ?? ()\/$reply_account + *$ $SUPREME^0 reply_account ?? ()\/$sender_account + *$ $JA_LIST_HEADER_REGEXP + { + LIST = $MATCH + } + + # Well: howabout site names then? + # + # From: TripMiles <sender@que.thetrip.com> + # Reply-to: feedback@thetrip.com + + dummy = "pm-jalist.rc: SENDER/REPLY domain [$sender_domain] ?? [$reply_adomain]" + + :0 E + *$ $SUPREME^0 sender_domain ?? ()\/$\reply_domain + *$ $JA_LIST_HEADER_REGEXP + { + LIST = $reply_sub1-$reply_account + } +} + +# ...................................................... Error-To ... + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: Errors-to" + +:0 +* LIST ?? ^^^^ +*$ ^Errors-To:.*\/$email +* MATCH ?? @()\/.* +{ + errors_domain = $MATCH + + # Hmmm The address is not identical, but maybe there is Errors-To + # Header that we could use for tracking a list context ? + # + # To: list-member@foo.com + # Reply-To: news@fusion.nww.com + # Errors-To: bounced@fusion.nww.com + + dummy = "pm-jalist.rc: Errors-To [$errors_domain] reply_addr [$reply_addr]" + + :0 + * ! reply_addr ?? ^^^^ + *$ reply_addr ?? $\errors_domain + { + unique_from = $reply_addr + + :0 + *$ reply_addr ?? ()\/$abc+ + { + LIST = $MATCH + } + } + + dummy = "pm-jalist.rc: Errors-To [$errors_domain] reply_addr [$sender_addr]" + + :0 E + * ! sender_addr ?? ^^^^ + *$ sender_addr ?? $\errors_domain + { + unique_from = $sender_addr + + :0 + *$ sender_addr ?? ()\/$abc+ + { + LIST = $MATCH + } + } + + dummy = "pm-jalist.rc: Errors-To [$errors_domain] to_addr [$to_addr]" + + :0 E + * ! to_addr ?? ^^^^ + *$ to_addr ?? $\errors_domain + { + unique_from = $to_addr + + :0 + *$ to_addr ?? ()\/$abc+ + { + LIST = $MATCH + } + } +} + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: From-newsletter" + +# From: newsletter@x10.com +# Subject: X-10 Buyer's Alert: Super-Saver Weekend Deals - up to 60% OFF! + +:0 E +*$ ^$from:.*newsletter@ +{ + LIST = "newsletter" + + :0 + *$ ^()\/$from:.*newsletter@.* + { + unique_from = $MATCH + } +} + +# ................................................. named LIST in CC ... + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: TO-CC mailing List" + +# Somebody is replying direct, but also sending to list with CC: +# +# To: Foo Bar <foo@bar.com> +# Cc: procmail mailing list <procmail@informatik.rwth-aachen.de> +# +# Also find +# +# JAVAL-L <foo@bar.com> + +:0 +* LIST ?? ^^^^ +*$ ^(To|CC):\//*(.*mailing$s+list|\<$S+-L\>).* +*$ MATCH ?? ()\/[^$WSPC<]+@ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: TO-CC postfix match" + +# Try to find POSTFIX address somewhere in header +# To:foo@example.com +# Cc: winNT Emacs list <foo-users@cs.washington.edu> + +:0 +* LIST ?? ^^^^ +*$ ()[<, ]\/$abc+-$trigger@ +{ + LIST = $MATCH +} + +# ..................................................... X-ListMember ... +# some lists are announce only and they contain "null". Pick name from +# X-ListMember field +# +# To: ora-news@list.ora.com +# From: Ora-News <null@list.ora.com> +# Reply-To: <null@list.ora.com> +# X-ListMember: me@here.com [ora-news@list.ora.com] + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: X-ListMember" + +dummy = "pm-jalist.rc: check SENDER ?? TO_FIELD [$sender] ?? [$to_field] " + +# See if DOMAIN if same in both From and To +# See if ACCOUNT is found from FROM field + +:0 +* LIST ?? ^^^^ +* X-ListMember +*$ ^To:.*@\/$abc+ +*$ ^$from.*$MATCH +*$ ^To:.*$pfx\/$abc+ +*$ ^$from.*$MATCH +{ + LIST = $MATCH +} + +# ...................................................... &ListServer ... +# From: ListServer@wrox.com +# Message-Id: <199812301439.IAA13867@neuman.interaccess.com> +# Date: 30 Dec 1998 08:37:27 -0600 +# Subject: Wrox Press Newsletter, 12/29/98 +# To: foo@bar.com + +:0 +* LIST ?? ^^^^ +*$ ^$from1.*ListServer@\/[^.]+ +{ + LIST = $MATCH # grab server + + :0 # Grab fist word too + *$ ^Subject: $LIST +\/$S+ + { + LIST = $LIST-$MATCH + } +} + +# .......................................................... &digest ... + +# From foo@bar.com +# From: sans@clark.net +# To: foo@bar.com +# Subject: SANS Digest Vol 2, No. 11 + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: DIGEST" + +# The \/$from.* is just for logging purposes + +:0 +* LIST ?? ^^^^ +* ! ^Subject:.*re: +* ^()\/$from.* +* ^Subject: +\/.*digest () +*$ MATCH ?? ()\/$abc+ +digest +*$ MATCH ?? ()\/$abc+ +*$ ^$from.*$MATCH@ +{ + LIST = $MATCH + + # The $from can match multiple from fields, like + # + # From foo@bar.com + # From: sans@clark.net + # + # And we want to force reading UNIQUE from "From:", otherwise the + # $from would take the "From ". See Unique recipe and SUPREME. + + :0 + *$ ^()\/$from.*$MATCH.* + { + unique_from = $MATCH + } +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: #NEWS" + +# From: sender@thetrip.com +# Reply-to: feedback@thetrip.com +# Subject: TheTrip.com Newsletter +# +# Sender: SERVERWATCH <SERVERWATCH@listserv.internet.com> +# From: SERVERWATCH <Serverwatchnews@internet.com> +# Subject: Serverwatch News - January 22, 1999 + +:0 +* LIST ?? ^^^^ +* ! ^Subject:.*(Re:|fwd) +*$ ^Subject:$s+\/$S+$s+news(letter)?.* +*$ ^Subject:$s+\/$S+ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: #[LIST]" + +# This must be last, because relying on the [] syntax is last resort. +# Many users indicate the nature of message in the first word, like +# +# [off topic] +# [bug] +# +# And those are not list names. But then again this is: +# +# Message-Id: <199903031849.NAA19835@defender.perl.org> +# From: TPI News Pumpking <pudge@perl.org> +# To: TPI News List <daily-news@perl.org> +# Subject: [TPI News] March 03, 1999 +# Sender: owner-announce@perl.org +# Precedence: bulk +# Reply-To: news@perl.org +# X-Debug: List=(announce@perl.org) + +x = $abc +word = "($x$x$x$x?$x?$x?$x?$x?$x?$x?)" # maximum size of the word + +:0 +* LIST ?? ^^^^ +*$ ^Subject: +\[\/$word($s+$word)?\] +*$ $JA_LIST_HEADER_REGEXP +{ + tmp = $MATCH + + :0 + *$ tmp ?? ()\/$x+ + { + LIST = $MATCH + } + + :0 # second word + *$ tmp ?? $x$s+\/$x+ + { + LIST = "$LIST-$MATCH" + } +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: @LIST.COM" + +# To: <webprog@list.cgibook.com> + +:0 +* LIST ?? ^^^^ +*$ ()\/$abc+@list\.* +* MATCH ?? ()\/[^@]+ +{ + LIST = $MATCH +} + +dummy = "pm-jalist.rc: ::::::::::::::::::::::::::::::::: FOR list-name" + +# Suggestion by Tony Lam <Tony.Lam@Eng.Sun.COM> +# +# To: nm-interest@foo.com, nm-consulting@foo.com +# +# 1. if header matches the following, extract the full email +# address from the match: +# +# for <[a-z0-9]+-[a-z0-9]+.*>; +# +# 2. if the extracted email address is also found in any of the +# To/Cc, extract the portion before @ as the name of alias +# +# (3. BTW, if step 2 fails, the mesage is very likely an ube) +# + +:0 +* LIST ?? ^^^^ +*$ for($SPCL)+[<]()\/[a-z0-9]+-[a-z0-9]$S+@ +{ + tmp = $MATCH + + :0 + *$ (To|CC):\/.*$MATCH + { + unique_from = $MATCH + LIST = $tmp + } +} + +# ...................................................... experiments ... +# Many times domain name has server "list" if it's running mailing list +# Try to catch some of them if previous ones failed. + +dummy = "pm-jalist.rc: :::::::::::::::::::::::: Last try [$LIST]" + +:0 +* LIST ?? ^^^^ +{ + :0 + * ()\/list server.* + { + dummy = "pm-jalist.rc: ==== potential list ==== $MATCH" + } + + :0 E + *$ ()\/(From|X-From-Line|Sender:|CC:|To:).*\.lists?.*\ + |(From|X-From-Line|Sender:|CC:|To:).* list$S*@.* + { + dummy = "pm-jalist.rc: ==== potential list ==== $NL $MATCH" + } + + :0 E + * ()\/(From|Sender:|CC:).*(Majordomo|listserv).* + { + dummy = "pm-jalist.rc: ==== potential list ==== $NL $MATCH" + } + + :0 E + * ()\/Errors-To:.* + { + dummy = "pm-jalist.rc: ==== potential list ==== $MATCH" + } + + :0 E + *$ ()\/^Reply-To:(.*\<list|@$abc+list).* + { + dummy = "pm-jalist.rc: ==== potential list ==== $MATCH" + + + # We can safely conver this to list name + # Reply-To: "The Radicati Group, Inc." <list@radicati.com> + + :0 + *$ ^Reply-To.*list@\/$a+ + { + LIST = list-$MATCH + } + } + + :0 E + * ()\/^Subject.*\<digest\> + { + dummy = "pm-jalist.rc: ==== potential list ==== $MATCH" + } + + :0 E + * ()\/Mailing-list:.* + { + dummy = "pm-jalist.rc: ==== potential list ==== $MATCH" + } +} + +# ............................................................ clean ... + +dummy = "pm-jalist.rc: Cleaning matched list: ($LIST)" + +:0 +* ! LIST ?? ^^^^ +{ + + :0 # delete "@" from the end of string + * LIST ?? @ + * LIST ?? ^^\/[^@]+ + { + LIST = $MATCH + } + + :0 # delete "mailto:" from the beginning of string + * LIST ?? mailto:\/.* + { + LIST = $MATCH + } + + # Remove numbers + # mailto:leave-jscript-146465L --> mailto:leave-jscript + # 1. Check if it has numbers at the end + # 2. Match everything until last - + # 3. Remove last - + + :0 + * LIST ?? ().*[-][0-9]+.^^ + * LIST ?? ()\/.*[-] + * MATCH ?? ()\/.*[^-] + { + LIST = $MATCH + } + + # ................................................. postfix deletion ... + + # The regexp says: + # 1) see if these keywords are there + # 2) Read everything up till last dash and store it to MATCH + # 3) Match up till not including final dash + + :0 + *$ LIST ?? ()-${JA_LIST_KILL_POSTFIX}^^ + * LIST ?? ^^\/.*- + * MATCH ?? ^^\/.*[^-] + { + LIST = $MATCH + } + + # .............................................. prefix deletion ... + + dummy = "pm-jalist.rc: prefix deletion" + + :0 + *$ LIST ?? ^^${JA_LIST_KILL_PREFIX}-\/.* + { + LIST = $MATCH + } + + # ....................................................... unique ... + + dummy = "pm-jalist.rc: make unique list name: $NL$NL $unique_from" + + :0 + *$ LIST ?? $JA_LIST_MAKE_UNIQUE + *$ $SUPREME^0 unique_from ?? ()\/$abc+@$abc+ + *$ $SUPREME^0 ^()\/$from.*${pfx}$abc+@$abc+ + { + host = $MATCH + save = $VERBOSE + VERBOSE = "off" + + INPUT = $host + INCLUDERC = $rc_email + + VERBOSE = "$save" + + # list.shopguidenews.com, we can't accept "list" as match, so we + # use "shopguidenews" + + :0 + * SUB1 ?? [a-z] + { + LIST = $SUB1-$LIST + } + + :0 E + { + LIST = $host-$LIST + } + } + + # ............................................. converting list name ... + + dummy = "pm-jalist.rc: :::::::::::::::::::::::: List conversion" + + LIST_DETECTED = $LIST + + dummy = "pm-jalist.rc: Searching for conversion in array JA_LIST_CONVERSION" + dummy = $JA_LIST_CONVERSION + + :0 + *$ JA_LIST_CONVERSION ?? $LIST$s+\/[^$WSPC,]+ + { + LIST = $MATCH + } + + :0 + * JA_LIST_SAVE ?? yes + { + :0 fhw + | ${FORMAIL:-formail} \ + -I "X-List-Detected: $LIST_DETECTED mapped to $LIST" + } +} + +dummy = "pm-jalist.rc: end: grabbed list ($LIST)" + +# end of file pm-jalist.rc diff --git a/share/procmail/pm-jamime-decode.rc b/share/procmail/pm-jamime-decode.rc @@ -0,0 +1,290 @@ +# pm-jamime-decode.rc -- decode MIME body contents; quoted-printable, base64 +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Documentation +# +# The original father of the decoding scheme used here was +# presented by Peter Galbraith <galbraith@mixing.qc.dfo.ca> in +# procmail mailing list somewhere at the end of 1997. +# +# This subroutine supposes that the header has MIME header +# Content-Type: text/plain and performs quoted-printable or +# base64 decoding on the whole message. Note, that if you +# receive messages that have many mime attachments, then this +# recipe is not suitable for it. +# +# Procmail is *not* designed to handle mime attachments and this +# recipe only applies to whole _body_. +# +# The `pm-jamime-*.rc' is really stretching the limits and any +# serious work should be delegated to other tools. Alternatives: +# +# o A Perl MIME module which will allow you to manipulate MIME +# body parts rather elegantly. See +# http://www.perl.com/CPAN-local/authors/Eryq/ for MIME-tools. +# o mimedecode at ftp://ftp.dde.dk/pub/mimedecode.c +# +# Notes +# +# Perl or Python is not used, because both are CPU intensive. It +# would be too expansive for accounts or environments receiving +# hundreds of mails per day (like from several mailing lists). +# +# RFC 2047 gives possiblity to use MIME iso-8859-1 extensions +# for mail headers. +# +# Subject: Re: [PIC]: RSA =?iso-8859-1?Q?encryption=B7=B7?= +# Subject: =?iso-8859-1?Q?=5BEE=5D:TV_&_video_IC=B4s_!!?= +# +# There is also base64 possibility (although rare): +# +# Subject: =?iso-8859-1?B?zvLi5fI6ICAgICAgTVBMQUIzLjQw?= +# +# In worst possible case there is even multiple ISO encoded +# strings in subject. Yes, this is valid, the continued line +# includes spaces at front to keep it with original just like +# in `Received:' headers. This subroutine will not touch headers +# that have multiple ISO tags - procmail is too limited for that. +# +# Subject: AW: Re: AW: neue =3D?ISO-8859-1?Q?M=3DF6glichkeiten_=3D28was_=3D=C4hn?=3D +# =3D?ISO-8859-1?Q?lichkeiten_von_=3DDCbungen=3D29?=3D +# +# Required settings +# +# Variable `PMSRC' must point to source directory of procmail code. +# This subroutine will include +# +# o pm-javar.rc, pm-jamime.rc +# o Programs `$MIME_BIN', `$MIME_BIN_QP' and `$MIME_BIN_64' +# must have been installed (see pm-javar.rc). +# +# Call arguments (variables to set before calling) +# +# o `JA_MIME_DECODE_TREAT_SUBJECT', default "yes". Decode +# Subject header by removing mime. +# o `JA_MIME_DECODE_TREAT_FROM', default "no". Decode +# From header by removing mime. +# o `JA_MIME_DECODE_TREAT_BODY', default "no". Decode +# body of message by removing quoted-printable from a +# message that contains only one part. Messages with multiple +# parts are not handled. +# +# Return values +# +# o `PM_JAMIME_COMPLEX_SUBJECT' is set to "yes". +# This flag is set to indicate that some other program +# should handle the message. If Subject header contains ISO +# encoding several times, it cannot be handled by this module. +# +# Examples +# +# Instead of testing the existence of text/plain in the body, +# you can force decoding by settings JA_MIME_DECODE_REGEXP to +# ".*". +# +# RC_MIME_DECODE = $PMSRC/pm-jamime-decode.rc +# +# :0 +# * condition +# { +# JA_MIME_DECODE_REGEXP = ".*" +# } +# +# INCLUDERC = $RC_MIME_DECODE # call subroutine. +# +# +# Change Log (none) + + +dummy = " +======================================================================== +pm-jamime-decode.rc: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +:0 +* ! MIME_VER ?? [0-9] +{ + INCLUDERC = $PMSRC/pm-jamime.rc +} + +# .......................................................... &public ... +# User configurable sections + +JA_MIME_DECODE_TREAT_SUBJECT = "yes" # Set to "no" to disable +JA_MIME_DECODE_TREAT_FROM = "no" # Set to "yes" to enable +JA_MIME_DECODE_TREAT_BODY = "no" # Set to "yes" to enable + +JA_MIME_DECODE_REGEXP = ${JA_MIME_DECODE_REGEXP:-\ +"^Content-Type: *text/plain"} + +# ........................................................... &do-it ... +# Run conversion if it was quoted printable. +# Also reflect correct MIME header + +JA_MIME_DECODE_HEADER = ${JA_MIME_DECODE_HEADER:-\ +"X-Mime-Header-Decoded"} + +dummy = "pm-jamime-decode.rc: handle quoted printable" + +PM_JAMIME_COMPLEX_SUBJECT # Return value if too complex subject + +jamimeHandledSubject = "no" + +# Kill variables +jamimeSubject +jamimeSubjectRest + +:0 +* JA_MIME_DECODE_TREAT_SUBJECT ?? yes +* ^Subject: \/.* +{ + jamimeSubject = $MATCH + jamimeISO = "\?iso-8859-[1-9]\?[QB]\?.+\?=" + + :0 + *$ jamimeSubject ?? $jamimeISO()\/.* + { + # ".*" is actually minimum match. See pm-doc.sf.net + jamimeSubjectRest = $MATCH + } + + :0 + *$ jamimeSubjectRest ?? $jamimeISO() + { + # This Subejct line contains ISO encoding several times. + # This is out of our league. Can't hanle it, so quit. + + jamimeSubject + JAMIME_COMPLEX_SUBJECT = "yes" + } +} + +:0 +* ! jamimeSubject ?? ^^^^ +{ + str = $jamimeSubject + decoder = $MIME_BIN_QP + type = "quoted-printable" + + :0 + * ^Subject:.*\?B\? + { + type = "base64" + decoder = $MIME_BIN_64 + } + + # NOTE "?" is not wildcard "as is" in sed. + + clean = \ + ` echo "$str" \ + | $SED \ + -e 's/^\(.*\)?\(iso\|ISO\)-\{0,1\}8859-[1-9]?[QB]?\(.*[^?]\)?=/\1\2/g' \ + -e 's/=0D//g' \ + -e 's/=0A//g' \ + -e 's/=B7//g' \ + -e 's/_/ /g' \ + | $decoder + ` + + handledSubject = "yes" + + :0 fhw + * ! clean ?? ^^^^ + | $FORMAIL \ + -i "Subject: $clean" \ + -I "${JA_MIME_DECODE_HEADER}-Subject: $type" +} + +# Too bad Procmail does not have subroutines. This recipe is +# identical to "Subject" check above. +# +# Note, that 'From' header is different from the 'Subject' header +# in respect to the ISO encoding. Look closely where '?=' ends: +# +# Subject: =?ISO-8859-1?Q?=C4hnlichkeiten_von_=DCbungen?= +# From: =?ISO-8859-1?Q?Holger_Hoffst=E4tte?= <holger@example.com> + +jamimeHandledFrom = "no" + +:0 +* JA_MIME_DECODE_TREAT_FROM ?? yes +*$ ^From: +()\/=\?iso-8859-[1-9]\?[QB]\?.+\?=.* +*$ ^From: +()\/.*=\?.+[>] +{ + str = $MATCH + decoder = $MIME_BIN_QP + type = "quoted-printable" + + :0 + * ^Subject:.*\?B\? + { + type = "base64" + decoder = $MIME_BIN_64 + } + + clean = \ + ` echo "$str" \ + | $SED \ + -e 's/=?\(iso\|ISO\)-\{0,1\}8859-[1-9]?[QB]?\(.*[^?]\)?=/\2/g' \ + -e 's/=0D//g' \ + -e 's/=0A//g' \ + -e 's/=B7//g' \ + | $decoder + ` + + jamimeHandledFrom = "yes" + + # Make sure there is <send@example.com> before replacing anything + + :0 fhw + * clean ?? [>] + | $FORMAIL \ + -i "From: $clean" \ + -i "${JA_MIME_DECODE_HEADER}-From: $type" +} + +# Touch only real mime messages and text/plain +# $MIME_BIN_QP does not handle separate MIME sections + +:0 +* JA_MIME_DECODE_TREAT_BODY ?? yes +*$ $JA_MIME_DECODE_REGEXP +{ + :0 fbw + * ^Content-Transfer-Encoding: *quoted-printable + | $MIME_BIN_QP + + :0 A fhw + | $FORMAIL -I "Content-Transfer-Encoding: 8bit" + + :0 fbw + * ^Content-Transfer-Encoding: *base64 + | $MIME_BIN_64 + + :0 A fhw + | $FORMAIL -I "Content-Transfer-Encoding: 8bit" +} + +dummy = "pm-jamime-decode.rc: end:" + +# End of file pm-jamime-decode.rc diff --git a/share/procmail/pm-jamime-kill.rc b/share/procmail/pm-jamime-kill.rc @@ -0,0 +1,712 @@ +# pm-jamime-kill.rc -- General MIME attachment killer (vcards, html) +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# Note: If you think this module can do miracles, it cannot. +# MIME messages are very complex in structure and all this module +# can do is to detect *simple* attachements. It cannot be used +# as - all purpose - all detecting - MIME attachement killer. +# But the part it can do, is done efficiently, because most of the +# things are accomplished using procmail and resource friendly +# `awk'. +# +# There are meny programs that add additional information to the +# messages. Microsoft's mail program is one which may include +# a 7k application/ms-tnef attachment to the end of +# message. Many other programs may do the same. This was the idea +# in 1997 when this module was written; to get rid of the extra +# cruft which should not land in the mailbox. +# +# This recipe works like this: If email's structure is +# +# --boundary +# message-text (maybe quoted-printable) +# --boundary +# some-unwanted-mime-attachment +# --boundary +# +# then the attachment is killed from the body. The message-text part +# is also decoded if it was quoted printable. This leaves clean text +# with no MIME anywhere. MIME headers have will be modified as needed +# due to conversion from multi part and possibly quoted printable to +# plain text and the final message looks like: +# +# message +# +# But if email's structure is anything else, like if there were 3 +# mime sections: +# +# --boundary +# message-text (maybe quoted-printable) +# --boundary +# some-attachment +# --boundary +# some-unwanted-mime-attachment +# --boundary +# +# then the "unwanted" part is emptyed by replacing with one empty +# line. The message structure stays the same, but the killed +# "some-unwanted-mime-attachment" part is labelled as text/plain +# so that the MUA (Mail User Agent; the email reader program) +# can decode the MIME message correctly. +# +# Applications for other mime attachments +# +# The following cases are ncluded on in this module. You need to +# separately the behavior before this module will start working. +# +# o Lotus Notes attachment. +# o Microsoft Express attachement. It sends a copy of message in HTML +# format. +# o Mozilla's Netscape attachement. It sends a copy of message in HTML. +# o `Vcard' attachments. +# o Openmail attachment. It sends 10-20 line base64 attachments +# WINMAIL.DAT. +# +# Example of lotus notes attachment +# +# Subject: message +# From: foo@bar.com +# X-Lotus-FromDomain: XXX COMPANIES +# Mime-Version: 1.0 +# Boundary="0__=cieg4oHxUNf2h3evyOXIsHTGDpFfaZilTDCFhpZSgsw" +# Content-Type: multipart/mixed; +# Boundary="0__=cieg4oHxUNf2h3evyOXIsHTGDpFfaZilTDCFhpZSgsw" +# +# --0__=cieg4oHxUNf2h3evyOXIsHTGDpFfaZilTDCFhpZSgsw +# Content-type: application/octet-stream; +# name="PIC10898.PCX" +# Content-transfer-encoding: base64 +# +# eJ8+IjsQAQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAEIgAcA +# b3NvZnQgTWFpbC5Ob3RlADEIAQ2ABAACAAAAAgACAAEEkAYAyAEAAAEAAAAQ +# +# <AND-THE-REST-OF-BASE64> +# +# --0__=cieg4oHxUNf2h3evyOXIsHTGDpFfaZilTDCFhpZSgsw-- +# +# Example of MS Explorer's ms-tnef message +# +# Subject: message +# From: foo@bar.com +# MIME-Version: 1.0 +# Content-Type: multipart/mixed; +# boundary="---- =_NextPart_000_01BD04D4.A5AC6B00" +# Lines: 158 +# +# ------ =_NextPart_000_01BD04D4.A5AC6B00 +# Content-Type: text/plain; charset="iso-8859-1" +# Content-Transfer-Encoding: quoted-printable +# +# <MESSAGE ITSELF IS HERE> +# +# ------ =_NextPart_000_01BD04D4.A5AC6B00 +# Content-Type: application/ms-tnef +# Content-Transfer-Encoding: base64 +# +# eJ8+IjsQAQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAEIgAcA +# b3NvZnQgTWFpbC5Ob3RlADEIAQ2ABAACAAAAAgACAAEEkAYAyAEAAAEAAAAQ +# +# <AND-THE-REST-OF-BASE64> +# +# ------ =_NextPart_000_01BD04D4.A5AC6B00-- +# +# Example of MS Express's HTML message +# +# MIME-Version: 1.0 +# Content-Type: multipart/alternative; +# boundary="----=_NextPart_000_003A_01BD16E2.C97E27B0" +# X-Mailer: Microsoft Outlook Express 4.72.2106.4 +# X-MimeOLE: Produced By Microsoft MimeOLE V4.72.2106.4 +# +# This is a multi-part message in MIME format. +# +# ------=_NextPart_000_003A_01BD16E2.C97E27B0 +# Content-Type: text/plain; +# charset="iso-8859-1" +# Content-Transfer-Encoding: quoted-printable +# +# <ACTUAL TEXT> +# +# ------=_NextPart_000_003A_01BD16E2.C97E27B0 +# Content-Type: text/html; +# charset="iso-8859-1" +# Content-Transfer-Encoding: quoted-printable +# +# <SAME IN HTML> +# ------=_NextPart_000_003A_01BD16E2.C97E27B0-- +# +# Example of Netscape's HTML attachment +# +# X-Mailer: Mozilla 4.04 [en] (X11; U; Linux 2.0.33 i686) +# MIME-Version: 1.0 +# Content-Type: multipart/alternative; +# boundary="------------69D9D579CF587DC8BB26C49C" +# +# +# --------------69D9D579CF587DC8BB26C49C +# Content-Type: text/plain; charset=us-ascii +# Content-Transfer-Encoding: 7bit +# +# <ACTUAL TEXT> +# +# --------------69D9D579CF587DC8BB26C49C +# Content-Type: text/html; charset=us-ascii +# Content-Transfer-Encoding: 7bit +# +# <SAME IN HTML> +# --------------69D9D579CF587DC8BB26C49C-- +# +# Example of Netscape's vcard attachment. +# +# Content-Type: text/x-vcard; charset=us-ascii; name="vcard.vcf" +# Content-Transfer-Encoding: 7bit +# Content-Description: Card for Laird Nelson +# Content-Disposition: attachment; filename="vcard.vcf" +# +# begin: vcard +# fn: Laird Nelson +# n: Nelson;Laird +# org: Perot Systems Corporation +# adr: 101 Main Street;;;Cambridge;MA;02142;USA +# email;internet: ljnelson@unix.amherst.edu +# title: Software Engineer +# tel;work: (617) 303-5059 +# tel;fax: (617) 303-5293 +# tel;home: (978) 741-3126 +# note;quoted-printable:Information is for reference only;=0D=0A= +# please do not abuse it. +# x-mozilla-cpt: ;0 +# x-mozilla-html: TRUE +# version: 2.1 +# end: vcard +# +# Required settings +# +# To handle base64 encoded messages, package called `metamail' must +# have been installed to system. It provides program `mimencode' +# which is used through variable $MIME_BIN (see pm-javar.rc). +# +# Variable $PMSRC must point to source directory of procmail code. +# This subroutine will include +# +# o pm-javar.rc +# o pm-jamime.rc +# +# Call arguments (variables to set before calling) +# +# First of all, this is primarily a framework recipe to kill any kind +# of attachment. If you do not set `JA_MIME_TYPE' before calling +# this recipe, recipe will try to determine the right value by itself. +# If the automatic detection fails you _need_ to preset the value +# of `JA_MIME_TYPE' beforehand. +# +# o `JA_MIME_TYPE' is a case sensitive AWK *REGEXP*. Always use +# *lowercase* letters in this regexp because the line is lowercased +# before match is made. This regexp determines if the kill +# recipe is applied to the message or not. Suggested default +# value: "text/html". If empty (not set), the heuristics +# tries to set it for MS explorer, MS express, Netscape, +# Lotus Notes etc. +# o `JA_MIME_KILL_RE', additional *REGEXP* to kill lines from the +# message. Value is case sensitive awk regexp and by default matches +# Lotus notes tag: name="XXX.PCX". +# o `JA_MIME_EXTRA_HEADER', name of header added to the message +# if the MIME portion was killed. Default value is +# "X-Mime-Type-Killed". +# +# It may be possible that some messages are malformed and that +# they do not contain proper "boundary" definition string in the +# header. There have been messages that have text/html +# attachments, but no proper Mime headers. For those cases there +# is additional variable that will kill all text up till +# matching line regardless of message content. +# +# o `JA_MIME_KILL2_RE' is set to "text/html|application/ms-tnef". +# Update this to match attchements you receive. Set variable to +# "" if you don't want to change the body of non-compliant MIME +# message. +# +# That variable is the last resort if the standard MIME detection +# failed. There must have been some problem in the sender's MUA that +# composed message. It's dangerous, so make sure you don't set it +# lightly. +# +# Possible conflict with the awk +# +# If you see an error message in the log file saying that awk failed: +# +# procmail: Executing awk, +# ... +# procmail: Error while writing to "awk" +# procmail: Rescue of unfiltered data succeeded +# +# it means that the system's standard `awk' doesn't support the +# variable passing syntax. Do the following test: +# +# % awk '{print VAR; exit}' VAR="value" /etc/passwd +# +# It should print "value". If not, then see if you have `gawk' or +# `mawk' in the system. Try whcih awk understands the variable passing +# syntax. The only change needed is to define variable AWK +# somewhere at the top of `~/.procmailrc'. +# +# AWK = "gawk" # Better than standard "awk" +# +# WARNING: In some systems the `gawk' is not real GNU awk, but a +# symlink to somewhere alse. E.g. in SunOs/Solaris you may find this +# setup, which is unsufficient. For Solaris, the GNU awk is available +# at http://www.blastwave.org +# +# $ which gawk +# $ gawk --version +# <syntax error> +# $ ls -l /usr/local/bin/gawk +# /usr/local/bin/gawk -> /usr/bin/nawk +# +# Warnings +# +# You should know that the variable `JA_MIME_KILL_RE' is used to wipe +# any lines that match that regexp. This is due to MIME structure +# where continuing header lines exist in the body: +# +# ------=_NextPart_000_003A_01BD16E2.C97E27B0 +# Content-Type: text/plain; +# charset="iso-8859-1" << kill this line too +# +# If you want to be absolutely sure that anything valuable won't be +# accidentally killed (like a code line in programming language scripts), +# you should set this variable to nonsense value that newer matches: +# +# JA_MIME_KILL_RE = "match_it_never_I_hope" +# +# Usage example: Customizing the attachment killing +# +# Suppose you receive new `application/ms' type attachment that the +# default settings doesn't cover. This is a new mime type and you +# have to instruct this module to kill it. Add this and similar +# tests for other mime types: +# +# myCustomMimeType = "application/ms" # must be all lowercase +# +# :0 +# *$ $myCustomMimeType +# { +# PM_JA_MIME_TYPE = $myCustomMimeType +# } +# +# INCLUDERC = $PMSRC/pm-jamime-kill.rc +# +# Usage example +# +# To kill text/html or pdf, postscript and others add something +# like this to `~/.procmailrc'. It demonstrates how the correct +# MIME types are detected: +# +# # ..................................................... +# # 1) Uncomment following line if your standard "awk" is broken +# +# # AWK = "gawk" +# +# # ..................................................... +# # 2) Set correct value for attachment killing +# +# :0 +# * ^X-Lotus-FromDomain: +# { +# # Kill Lotus notes .pcx attachments +# JA_MIME_TYPE = "application/octet-stream" +# } +# +# :0 +# * H ?? ^From:.*foo@example.com +# * B ?? ^Content-Type:.*text/html +# { +# # Kill html attachments +# JA_MIME_TYPE = "text/html" +# } +# +# # ..................................................... +# # 3) Call module +# +# INCLUDERC = $PMSRC/pm-jamime-kill.rc +# +# Change Log (none) + +# .................................................... &initialising ... + + +id = "pm-jamime-kill.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +:0 +* ! MIME_VER ?? [0-9] +{ + INCLUDERC = $PMSRC/pm-jamime.rc +} + +# .......................................................... &public ... +# User configurable sections + +# If linebuf is too small, then AWK scripts can't be called +JA_MIME_KILL_LINEBUF = ${JA_MIME_KILL_LINEBUF:-524280} + +JA_MIME_KILL_RE = ${JA_MIME_KILL_RE:-"\ +name=.*(pcx|PCX)|charset=|This is.*MIME"} + +JA_MIME_KILL2_RE = ${JA_MIME_KILL2_RE:-"\ +Content-Type: +(text/html|application/ms-tnef|x-vcard)"} + +# If set, this header will contain the MIME type ("text/html" etc.) +# which was killed +JA_MIME_EXTRA_HEADER = ${JA_MIME_EXTRA_HEADER:-"X-Mime-Type-Killed"} + +# .................................................... &set-defaults ... +# Set default value, unless user has set this previously. + +:0 +* JA_MIME_TYPE ?? ^^^^ +{ + dummy = "$id: automatic JA_MIME_TYPE detection" + + # The (safe) default value. Will be changed below + + JA_MIME_TYPE = "application/ms-tnef" + + :0 + * ^Content-Type:.*image/()\/(jpeg|tiff|png|gif|bmp) + { + JA_MIME_TYPE = "image/$MATCH" + } + + :0 E + * ^X-Lotus-FromDomain: + { + JA_MIME_TYPE = "application/octet-stream" + dummy = "$id: Type: Lotus Notes" + } + + :0 E + * ^X-Mailer: (Microsoft.*Express|mozilla) + { + JA_MIME_TYPE = "text/html" + dummy = "$id: Type: MS Express,Netscape" + } + + :0 E + * ^X-Mailer:.*mozilla + * B ?? begin:.*vcard + { + JA_MIME_TYPE = "text/x-vcard" + dummy = "$id: Type: Netscape vcard" + } + + :0 E + * B ?? application/x-openmail + { + JA_MIME_TYPE = "application/x-openmail" + dummy = "$id: Openmail attachment found" + } + + # Remove executables + + :0 E + * B ?? application/x-msdownload + * MIME_B_ATTACHMENT ?? \.(hqx|com|exe|pif) + { + JA_MIME_TYPE = "application/x-msdownload" + dummy = "$id: MS *.exe attachment found" + } +} + +# - If user set JA_MIME_KILL_RE, make sure that value is not empty, +# because awk doesn't like empty regexps +# - Subtitute the value with something that doesn't match. + +:0 +*$ JA_MIME_KILL_RE ?? ^^^^ +{ + JA_MIME_KILL_RE = "_do_not___match_" +} + +:0 # This must have value +*! LINEBUF ?? [0-9] +{ + LINEBUF = 8192 +} + +jaMimeKillLINEBUF = $LINEBUF # save old value + +# ........................................................... &do-it ... + +# Prevent calling sh -c here. This speeds up procmail + +jaMimeKillSHELLMETAS = $SHELLMETAS # save original value +jaMimeKillModified = "no" # Flag +jaMimeKillMsg # Kill variable +SHELLMETAS # kill variable + +dummy = "JA_MIME_TYPE [$JA_MIME_TYPE]" +dummy = "MIME_BOUNDARY [$MIME_BOUNDARY]" +dummy = "Check if running the kill recipe, SHELL= $SHELL" + +:0 +* ! JA_MIME_TYPE ?? ^^^^ +* ! MIME_BOUNDARY ?? ^^^^ +* H ?? ^Content-Type:.*multipart +*$ B ?? ^Content-Type:$s+$JA_MIME_TYPE +{ + # If there were only 3 mime tags, then then message is in format + # + # boundary-tag + # message + # boundary-tag + # unwanted-mime-part + # boundary-tag + # + # a) make sure count is 3 + # b) make sure we have the boundary string + + LINEBUF = $JA_MIME_KILL_LINEBUF + + :0 + * MIME_BOUNDARY_COUNT ?? ^^3^^ + { + dummy = "$NL$NL$id: exactly 3 boundary strings" + + # - AWK removes the mime boundary strings, so we must remember + # if the message had quoted printable. The variable MIME_B_QP + # contain the qp information. + # + # Program logic (effectively a state machine) + # - First blank line is header end. Print header verbatim. + # - Keep track of seen boundaries: 1, 2, 3 + # - When EAT (text/html) portion is found, kill text up + # till next boundary marker + # + # We need the "i" flag because awk quits before it has read + # all the input + + :0 fbw i + | $AWK \ + ' \ + /^[ \t]*$/ { \ + print; \ + header = 0; \ + } \ + \ + header { \ + print; \ + next; \ + } \ + \ + $0 ~ RE { \ + boundary++; \ + } \ + \ + { \ + if ( killUntil ) \ + { \ + if ( boundary < killUntil ) \ + { \ + next; \ + } \ + killUntil = 0; \ + } \ + \ + line = tolower($0); \ + \ + if ( ! found && match($0, EAT) > 0 ) \ + { \ + found++; \ + killUntil = boundary + 1; \ + } \ + \ + if ( match($0, RE) > 0 ) {next} \ + if ( match($0, KILL) > 0 ) {next} \ + if ( match($0, "^Content-") > 0 ) {next} \ + \ + print; \ + } \ + ' RE="$MIME_BOUNDARY" \ + EAT="^Content-Type:.*$JA_MIME_TYPE" \ + KILL="$JA_MIME_KILL_RE" + + # -- If AWK succeeded -- + # The body is no more multipart/mixed. Correct headers or + # the MUA may get confused + + :0 a + { + # Why Rewrite Mime-Version: + # + # Lotus notes adds the boundary string to this header, but + # because we have already removed all boundary strings from the + # body, we must clear this header. + # + # Call to replace Mime-Version header wipes the `boundary=` tag + + :0 fhw + | $FORMAIL \ + -I "Content-Type: text/plain" \ + -I "Mime-Version: $MIME_VER" + + jaMimeKillMsg = "$JA_MIME_TYPE" + jaMimeKillModified = "yes" # Yes, we changed body + + } + } + + # Note: 1997-12-30 + # + # - This works fine for ms-tnef, but it may be dangerous with + # Lotus notes, because it's attachment is a general + # "application/octec-stream". + # - Report me the problems if you encounter them with Lotus Notes. + # + + # There was more than 2 mime parts: just remove the base64 block. + # + # - raise suppress flag if we find mime. Also change the mime type. + # - set flag back to 0 when the ending tag is found + # - print the lines when flag is 0 + # + # The ms-tnef is now converted to: + # + # ------ NextPart_000_01BD04D4.A5AC6B00 + # Content-Type: text/plain; + # + # ------ NextPart_000_01BD04D4.A5AC6B00-- + # + + dummy = "$NL$NL$id: _not_ exactly 3 boundary strings" + + :0 fbw + * ! MIME_BOUNDARY_COUNT ?? ^^3^^ + | $AWK \ + ' { \ + line = tolower($0); \ + \ + if ( match(line, HDR) > 0 ) \ + { \ + flag = 1; \ + print "Content-Type: text/plain;"; \ + } \ + \ + if ( match($0, RE) ) \ + { \ + flag = 0; \ + } \ + \ + if ( flag == 0 ) \ + { \ + print; \ + } \ + } \ + ' RE="$MIME_BOUNDARY" HDR="$JA_MIME_TYPE" + + LINEBUF = $jaMimeKillLINEBUF +} + +# ..................................................... &invalid-mime ... +# This is last resort, if message looks like MIME, but it isn't +# because it doesn't have headers: +# +# MIME-Version: 1.0 +# Content-Type: multipart/alternative; boundary="...." + +dummy = "$NL$NL$id: last resort, kill up till regexp" + +# Non-mime compliant messages +# +# The only way to kill attachment is to use approximation. +# If we do not have the boundary string (i.e. this not mime), +# then apply this recipe. + +dummy = "$id: MIME_BOUNDARY $MIME_BOUNDARY" + +:0 +* MIME_BOUNDARY ?? ^^^^ +* JA_MIME_KILL2_RE ?? [a-z] +*$ B ?? $JA_MIME_KILL2_RE +{ + LINEBUF = $JA_MIME_KILL_LINEBUF + + # Well we could use SED here, but then there is a problem with + # "/" delimiter in sed. The awk solution accepts REGEXP as is + # as you don't have to play with funny quoting + # + # sed -e "'"/$regexp/q"'" + # + # or something like that... (the above is untested) + + :0 fbw + | $AWK \ + ' { \ + if ( match($0,RE) > 0 ) {exit} \ + print \ + } \ + ' RE="$JA_MIME_KILL2_RE" + + :0 A + { + jaMimeKillMsg = "Forced kill by JA_MIME_KILL2_RE" + jaMimeKillModified = "yes" + } + + LINEBUF = $jaMimeKillLINEBUF +} + +# ............................................................... &qp ... +# Run conversion if it was quoted printable. +# Also reflect correct MIME header + +dummy = "$id: handle quoted printable" + +:0 fhw +* jaMimeKillModified ?? yes +* ! jaMimeKillMsg ?? ^^^^ +* ! JA_MIME_EXTRA_HEADER ?? ^^^^ +| $FORMAIL -I "$JA_MIME_EXTRA_HEADER: $jaMimeKillMsg" + +:0 fbw +* jaMimeKillModified ?? yes +* MIME_B_QP ?? yes +* MIME_BIN_QP ?? [a-z] +| $MIME_BIN_QP + + # If the previous recipe succeeded, then fix the headers to indicate + # decoding. + + :0 A fhw + | $FORMAIL -I "Content-Transfer-Encoding: 8bit" + +SHELLMETAS = $jaMimeKillSHELLMETAS # Restore original value + +dummy = "$id: end:" + +# end of file pm-jamime-kill.rc diff --git a/share/procmail/pm-jamime-recode.rc b/share/procmail/pm-jamime-recode.rc @@ -0,0 +1,185 @@ +# pm-jamime-recode.rc -- re-encode MIME Header: Subject, From as quoted-printable +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Documentation +# +# This subroutine supposes that message has been handled by +# 'pm-jamime-decode.rc'. The purpose is to restore *Subject* and +# *From* headers back to quoted printable format so that +# messages can be savely saved through IMAP system which may not +# handle 8-bit messages. If message is stored directly to +# mailbox and the used Mail user Agent has no problems with +# dealing 8-bit characters, this module is not needed. +# +# An example where this subroutine could be applied: +# +# o Feed message to `pm-jamime-decode.rc' +# o Feed message `pm-jasubject.rc' (to clean multiple Re: Re: Fwd ..) +# o Restore From/Subject encodings with `pm-jamime-recode.rc' +# o Save message to mailbox +# +# Notes +# +# Perl or python is not used, because both are CPU intensive. +# It would be too expansive for accounts or environments +# receiving hundreds of mails per day (like from several mailing +# lists). +# +# Required settings +# +# Variable `PMSRC' must point to source directory of procmail code. +# This subroutine will include +# +# o pm-javar.rc +# o pm-jamime.rc +# o Program `$MIME_BIN_QP_E' +# must have been installed (see pm-javar.rc). +# o pm-jamine-decode.rc must have been called and message must +# contain headers `X-Mime-Header-Decoded-*' +# +# Call arguments (variables to set before calling) +# +# o `JA_MIME_RECODE_TREAT_SUBJECT', default "yes". Decode +# Subject header by removing mime. +# o `JA_MIME_RECODE_TREAT_FROM', default "no". Decode +# From header by removing mime. +# +# Return values +# +# (none) +# +# Examples +# +# To fix Subject header and then make it 7bit clean again. Note, +# this may not be exactly what you want. The pm-jamime-decode.rc +# file does a little more than From/Header handling (also modifies +# message body). Read documentation of each file before using +# following example +# +# INCLUDERC = $PMSRC/pm-jasubject.rc +# INCLUDERC = $PMSRC/pm-jamime-decode.rc +# INCLUDERC = $PMSRC/pm-jamime-recode.rc +# +# Change Log (none) + +dummy = " +======================================================================== +pm-jamime-recode.rc: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +:0 +* ! MIME_VER ?? [0-9] +{ + INCLUDERC = $PMSRC/pm-jamime.rc +} +# .......................................................... &public ... +# User configurable sections + +JA_MIME_RECODE_REGEXP = ${JA_MIME_RECODE_REGEXP:-\ +"^Content-Type: *text/plain"} + +JA_MIME_RECODE_TREAT_SUBJECT = "yes" # Set to "no" to disable +JA_MIME_RECODE_TREAT_FROM = "no" # Set to "yes" to enable + +# ........................................................... &do-it ... +# Run conversion if it was quoted printable. +# Also reflect correct MIME header + +# Must be same header than in pm-jamime-decode.rc +JA_MIME_RECODE_HEADER = "X-Mime-Header-Decoded" +JA_MIME_RECODE_HEADER_SUBJECT = ${JA_MIME_RECODE_HEADER}-Subject +JA_MIME_RECODE_HEADER_FROM = ${JA_MIME_RECODE_HEADER}-From + +# Hard coded, do not change. We DO not know what chacters are in there, +# so we just use this encoding stanza and hope for the best. + +JA_MIME_RECODE_CHARSET_BEG = "=?iso-8859-1-?Q?" +JA_MIME_RECODE_CHARSET_END = "?=" + +dummy = "pm-jamime-recode.rc: handle quoted printable" + +handledSubject = "no" + +:0 +* JA_MIME_RECODE_TREAT_SUBJECT ?? yes +*$ ^$JA_MIME_RECODE_HEADER_SUBJECT +* ^Subject: +\/.* +{ + str = $MATCH + bin = $MIME_BIN_QP_E + beg = $JA_MIME_RECODE_CHARSET_BEG + end = $JA_MIME_RECODE_CHARSET_END + + # NOTE: not all sed (SunOS) know \t shortcuts. + + new = \ + ` echo "$str" \ + | $bin \ + | ${SED:-sed} \ + -e "s/^\(.*\)$/$beg\\1$end/" \ + -e 's/ /_/g' \ + ` + + handledSubject = "yes" + + :0 fhw + * ! new ?? ^^^^ + | $FORMAIL \ + -I "Subject: $new" \ + -I "$JA_MIME_RECODE_HEADER_SUBJECT:" +} + +# This part is identical to above (Procmail does not have subroutines) + +handledFrom = "yes" + +:0 +* JA_MIME_RECODE_TREAT_FROM ?? yes +*$ ^$JA_MIME_RECODE_HEADER_FROM +* ^From: +\/.* +{ + str = $MATCH + bin = $MIME_BIN_QP_E + beg = $JA_MIME_RECODE_CHARSET_BEG + end = $JA_MIME_RECODE_CHARSET_END + + new = \ + ` echo "$str" \ + | $bin \ + | ${SED:-sed} \ + -e "s/^\(.*\)$/$beg\\1$end/" \ + -e 's/ /_/g' \ + ` + + handledFrom = "yes" + + :0 fhw + * ! new ?? ^^^^ + | $FORMAIL \ + -I "From: $new" \ + -I "$JA_MIME_RECODE_HEADER_FROM:" +} + +dummy = "pm-jamime-recode.rc: end:" + +# End of file pm-jamime-recode.rc diff --git a/share/procmail/pm-jamime-save.rc b/share/procmail/pm-jamime-save.rc @@ -0,0 +1,486 @@ +# pm-jamime-save.rc -- save message's MIME attachement (one file) to a file +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Documentation +# +# This module saves _one_ simple file attachment (MIME) from he +# message. The message must define following MIME headers. If +# "filename=" does not exists, then the message is ignored. +# +# Mime-Version: <version> +# Content-Type: <type> +# Content-Disposition: attachment; filename="file.txt" +# +# The last line can also be in separate line, provided that it +# is indented according to standard rules: +# +# Mime-Version: <version> +# Content-Type: <type> +# Content-Disposition: attachment; +# filename="file.txt" +# +# Procmail is not very suitable for saving MIME attachments and +# you should not think that this the right tool for you. +# If you receive anything more than 1 attachment, this recipe +# does nothing, because that's out of our league and you need some +# more heavy weight mime tools. E.g. Perl CPAN has MIME libraries. +# +# _Note_: when the attachment is in the body, it is simply written +# to a disk and the location in message is replaced with test: +# +# Extracted to file:/users/foo/junk/<YYYY-MM-DD-hhmm>.file.txt. +# +# The existing mime headers that surround the attachment are +# lect untouched, so don't try to press your Mail Agent's MIME buttons +# at that point. There is no such file in that spot +# if you set `JA_MIME_SAVE_DEL' to `yes'. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This +# subroutine includes library: +# +# o pm-javar.rc +# o pm-jamime.rc +# o pm-jamime-decode.rc +# o pm-jadate.rc (which will call other pm-jadate*.rc files) +# +# Call arguments (variables to set before calling) +# +# o `JA_MIME_SAVE_DIR', point this to directory where you +# want to store attachments. +# o `JA_MIME_SAVE_DECODE', set this to "yes", if you want that +# attachment is decoded before written to disk. This usually +# opens quoted printable or base64 encoding. +# o `JA_MIME_SAVE_DEL', set this to "yes", if you want to remove +# the attachment from the body of the message after it has +# been filed. Be vary careful if you use this option. If you +# keep backup cache of incoming mail, then you might try "yes". +# o `JA_MIME_SAVE_OVERWRITE', set this to "yes" if it's okay to +# overwrite to an existing filename found from attachment. +# If you get periodic attachments always with same name, then +# you would want to set this to yes. +# +# Core dump note +# +# Because procmail uses LINEBUF when filtering messages, a core +# dump may happen if the attachment being filtered is bigger than +# the LINEBUF. The current setting accepts 524K attachments, but if +# you expect to get bigger than that, you want to increase +# `JA_MIME_SAVE_LINEBUF'. +# +# Possible conflict with your awk +# +# Awk is used because it is much more system load friendly than perl. +# If you see an error message in the log file saying that awk failed: +# +# procmail: Executing awk, +# ... +# procmail: Error while writing to "awk" +# procmail: Rescue of unfiltered data succeeded +# +# it means that the system's standard awk doesn't support the +# variable passing syntax. To verify that this is the case, run +# following test: +# +# % awk '{print VAR; exit}' VAR="value" /etc/passwd +# +# The proper awk should print "value". If not, then see if you have +# `nawk' or `gawk' in your system, which should understand the +# variable passing syntax. To change the AWK, you need to set +# following variable somewhere at the top of your *.procmailrc* +# +# AWK = "gawk" # if that works better than standard "awk" +# +# Return values (none) +# +# Change Log (none) + +dummy = " +======================================================================== +pm-jamime-save.rc: init:" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +:0 +* ! MIME_VER ?? [0-9] +{ + INCLUDERC = $RC_MIME +} + +:0 +* ! YYYY ?? [0-9] +{ + INCLUDERC = $RC_DATE +} + +:0 # if has no value, set it +*$ ! LINEBUF ?? $d +{ + LINEBUF = 1024 +} + +jaMimeSaveLinebuf = $LINEBUF + +# .......................................................... &public ... +# User configurable sections + +JA_MIME_SAVE_DIR = ${JA_MIME_SAVE_DIR:-"$HOME"} +JA_MIME_SAVE_DECODE = ${JA_MIME_SAVE_DECODE:-"no"} +JA_MIME_SAVE_DEL = ${JA_MIME_SAVE_DEL:-"no"} +JA_MIME_SAVE_LINEBUF = ${JA_MIME_SAVE_LINEBUF:-524280} +JA_MIME_SAVE_OVERWRITE = ${JA_MIME_SAVE_OVERWRITE:-"no"} + +# ........................................................... &do-it ... + +dummy = "pm-jamime-save.rc: HEADER; $MIME_H_ATTACHMENT" + +:0 +* MIME_H_ATTACHMENT ?? [a-z] +{ + jaMimeSaveFile = $MIME_H_ATTACHMENT + + :0 + * JA_MIME_SAVE_DECODE ?? yes + { + # decode regardless of body content + JA_MIME_DECODE_REGEXP = ".*" + + INCLUDERC = $RC_MIME_DECODE + } + + # ..................................................... filename ... + + :0 + * JA_MIME_SAVE_OVERWRITE ?? no + *$ ? $IS_EXIST $JA_MIME_SAVE_DIR/$jaMimeSaveFile + { + # Kill variable + jaMimeSaveDate + + :0 + *$ YYYY ?? $d + { + jaMimeSaveDate = "$YYYY-$MM-$DD" + + :0 + *$ hh ?? $d + { + jaMimeSaveDate = "$jaMimeSaveDate-$hh$mm" + } + + jaMimeSaveFile = "$jaMimeSaveDate.$jaMimeSaveFile" + + # Still not unique? + + :0 + *$ ? $IS_EXIST $JA_MIME_SAVE_DIR/$jaMimeSaveFile + { + :0 fhw + | $FORMAIL -I "X-jaMimeSave-Error: (file exists) $jaMimeSaveFile" + + # kill variable to prevent next recipe from running + jaMimeSaveFile + } + } + } + + # .................................................... write out ... + + :0 + * jaMimeSaveFile ?? [a-z] + { + :0 bwc: # do not modify body + * JA_MIME_SAVE_DEL ?? no + | $CAT > $JA_MIME_SAVE_DIR/$jaMimeSaveFile + + # Write out the attachment and replace body + # with reference to the file. + + :0 E + { + :0 + *$ LINEBUF ?? ^^([5-9]$d$d$d$d$d|$d$d$d$d$d$d$d)^^ + { + # User has set bigger linebuf than our default + } + :0 E + { + LINEBUF = $JA_MIME_SAVE_LINEBUF + } + + :0 fbw: + | ( $CAT > $JA_MIME_SAVE_DIR/$jaMimeSaveFile; echo "Saved to $JA_MIME_SAVE_DIR/$jaMimeSaveFile" ) + + LINEBUF = $jaMimeSaveLinebuf + } + } +} + +dummy = "pm-jamime-save.rc: BODY check" + +:0 E +* MIME_B_ATTACHMENT ?? [a-z] +* MIME_B_ATTACHMENT_FILE_COUNT ?? ^^1^^ +{ + dummy = "pm-jamime-save.rc: BODY ENTERED: only some limited operations." + jaMimeSaveFile = $MIME_B_ATTACHMENT + + # Try to locate the header where the content type is defined for + # file attachment. Note: there is no typo in the regexp, the + # caret(^) matches newline. + # + # Content-Type: application/octet-stream + # Content-Disposition: attachment; filename="file.txt" + # Content-Transfer-Encoding: 7bit + + dummy = "pm-jamime-save.rc: Check contentType BODY 1" + + :0 + *$ B ?? ^Content-Type:$s+\/.*\ + ^Content-Disposition:.*($MIME_B_ATTACHMENT\ + |^$s+.*$MIME_B_ATTACHMENT) + * MATCH ?? \/.* + { + contentType = $MATCH + } + + dummy = "pm-jamime-save.rc: Check contentType BODY 2" + + :0 E + *$ B ?? ^Content-Type:$s+\/.*\ + ^Content-Transfer-Encoding:.*\ + ^Content-Disposition:.*($MIME_B_ATTACHMENT\ + |^$s+.*$MIME_B_ATTACHMENT) + * MATCH ?? \/.* + { + contentType = $MATCH + + # The last "Content-Disposition" match allows two cases + # + # 1. Content-Disposition: attachment; filename="file.txt" + # + # 2. Content-Disposition: attachment; + # filename="file.txt" + + :0 + *$ B ?? ^Content-Type:.*\ + ^Content-Transfer-Encoding:$s\/.*\ + ^Content-Disposition:.*($MIME_B_ATTACHMENT\ + |^$s+.*$MIME_B_ATTACHMENT) + * MATCH ?? \/.* + { + contentEncoding = $MATCH + } + } + + # We expect that the headers come in this order. + # If they don't, then we can't know the encoding. + # We don't even try anything else: Procmail is not the right tool + # for complete MIME handling. + + dummy = "pm-jamime-save.rc: Check contentEncoding BODY" + + :0 + * contentEncoding ?? ^^^^ + *$ B ?? ^Content-Type:.*\ + ^Content-Disposition:.*\ + ^Content-Transfer-Encoding:$s+\/.* + { + contentEncoding = $MATCH + } + + :0 E + * contentEncoding ?? ^^^^ + *$ B ?? ^Content-Type:.*\ + ^Content-Transfer-Encoding:$s+\/.* + { + contentEncoding = $MATCH + } + + :0 + * contentEncoding ?? ^^^^ + *$ B ?? ^Content-Type:.*\ + ^Content-Transfer-Encoding:$s+\/.* + { + contentEncoding = $MATCH + } + + # ............................................... fix mixed-part ... + # In most typical message, sender "says" something in text/plain and + # then adds an atatchement + # + # But, due to order of the MIME headers we may have picked the + # text/plain. Change it to application/octet-stream if found. + # + # Mime-Version: 1.0 + # Content-Type: multipart/mixed; boundary="----------118D218634724256" + # + # ------------118D218634724256 + # Content-Type: text/plain; charset=us-ascii + # Content-Transfer-Encoding: 7bit + # + # + # ------------118D218634724256 + # Content-Type: application/octet-stream; name="Ass_rake.dbf" + # Content-Transfer-Encoding: base64 + # Content-Disposition: attachment; filename="Ass_rake.dbf" + + dummy = "pm-jamime-save.rc: Check contentType ($contentType) text/plain => application" + + :0 + * contentType ?? text/ + *$ B ?? ^Content-Type:$s+\/application.* + { + contentType = $MATCH + + dummy = "pm-jamime-save.rc: finding Transfer-Encoding for application/*" + + :0 + *$ B ?? ^Content-Type:$s+application.*\ + ^Content-Transfer-Encoding:$s\/.* + { + contentEncoding = $MATCH + } + } + + # ............................................... check filename ... + # Change filename if there is already that file + + dummy = "pm-jamime-save.rc: check filename" + + # Kill variable + jaMimeSaveDate + + :0 + *$ YYYY ?? $d + { + jaMimeSaveDate = "$YYYY-$MM-$DD" + + :0 + *$ hh ?? $d + { + jaMimeSaveDate = "$jaMimeSaveDate-$hh$mm" + } + + jaMimeSaveFile = "$jaMimeSaveDate.$jaMimeSaveFile" + + # Still not unique? + + :0 + *$ ? $IS_EXIST $JA_MIME_SAVE_DIR/$jaMimeSaveFile + { + :0 fhw + | $FORMAIL -I "X-jaMimeSave-Error: (file exists) $jaMimeSaveFile" + + # kill variable to prevent next recipe from running + jaMimeSaveFile + } + } + + # ........................................................ &save ... + + # 1) Locate the positions where the attachment starts + # 2) When found, start looking for empty line which ends the mime + # headers. GO is set to 1, when attachment starts + # 3) Attachment ends when mime boundary is hit. Actually + # it ended one line before that, which was a empty line. + + jaMimeSaveShellmetas = $SHELLMETAS + LINEBUF = $JA_MIME_SAVE_LINEBUF + SHELLMETAS + + :0 fbw + * MIME_BOUNDARY_COUNT ?? [1-9] + * jaMimeSaveFile ?? [a-z] + | $AWK \ + ' BEGIN { found = 0; go = 0 } \ + { \ + if ( match($0, MATCH) > 0 ) \ + { \ + found++; \ + } \ + if ( found && match($0, "^[ \t]*$") ) \ + { \ + go = 1; \ + next; \ + } \ + if ( match($0, MIME) > 0 ) \ + { \ + go = 0; \ + } \ + if ( go ) \ + { \ + if ( DELETE == "yes") \ + { \ + if ( urlFlag == 0 ) \ + { \ + urlFlag = 1; \ + printf "\nextracted to file:%s\n\n", FILE; \ + } \ + } \ + else \ + { \ + print; \ + } \ + print $0 >> FILE; \ + next; \ + } \ + print; \ + } \ + ' DELETE="$JA_MIME_SAVE_DEL" \ + MIME="$MIME_BOUNDARY" \ + COUNT="$MIME_BOUNDARY_COUNT" \ + MATCH="Disposition:.*$MIME_B_ATTACHMENT" \ + FILE="$JA_MIME_SAVE_DIR/$jaMimeSaveFile" + + LINEBUF = $jaMimeSaveLinebuf + SHELLMETAS = $jaMimeSaveShellmetas + + # ....................................................... decode ... + dummy = "pm-jamime-save.rc: Encoding($contentEncoding) of $jaMimeSaveFile" + + :0 + *$ jaMimeSaveFile ?? $a + *$ contentEncoding ?? $a + { + jaMimeSaveFile2 = "$jaMimeSaveFile.raw"; + + :0 wc + * contentEncoding ?? base64 + | $CAT $JA_MIME_SAVE_DIR/$jaMimeSaveFile \ + | $MIME_BIN_64 > $JA_MIME_SAVE_DIR/$jaMimeSaveFile2 \ + && $MV $JA_MIME_SAVE_DIR/$jaMimeSaveFile2 \ + $JA_MIME_SAVE_DIR/$jaMimeSaveFile + + :0 Ewc + * contentEncoding ?? quoted-printable + | $CAT $JA_MIME_SAVE_DIR/$jaMimeSaveFile \ + | $MIME_BIN_QP > $JA_MIME_SAVE_DIR/$jaMimeSaveFile2 \ + && $MV $JA_MIME_SAVE_DIR/$jaMimeSaveFile2 \ + $JA_MIME_SAVE_DIR/$jaMimeSaveFile + + } +} + +dummy = "pm-jamime-save.rc: end:" + +# End of file pm-jamime-save.rc diff --git a/share/procmail/pm-jamime.rc b/share/procmail/pm-jamime.rc @@ -0,0 +1,245 @@ +# pm-jamime.rc -- subroutine to read mime boundary etc. variables +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Documentation +# +# This includerc reads MIME boundary string from the message +# if it exists. The boundary string is typically found from +# Content-Type header. +# +# Mime-Version: 1.0 +# Content-Type: multipart/mixed; boundary=9i9nmIyA2yEADZbW +# +# In addition it will define few other mime variables. See the +# returned values. You use these variables later in your MIME +# message processing. +# +# Mime Notes +# +# 1998-07-28 Brett Glass <brett@lariat.org> reported in PM-L that +# there was security exploit in long attachment filenames: +# http://www.xray.mpe.mpg.de/mailing-lists/procmail/1998-07/msg00248.html +# +# And here is the url to the matter: +# +# http://www.sjmercury.com/business/microsoft/docs/security0728.htm +# +# +# When you use this module to detect mime messages, you can check the +# filename length with recipe: +# +# # Recipe after calling $RC_MIME, this module, +# +# re = ".........." # regexp with 10 matches +# too_long = "$re$re$re$re" # allow 40 characters maximum +# +# :0 +# *$ $SUPREME^0 MIME_H_ATTACHMENT ?? $re +# *$ $SUPREME^0 MIME_B_ATTACHMENT ?? $re +# { +# dummy = "** Dangerously long mime attachment filename" +# dummy = "** $MIME_H_ATTACHMENT $MIME_B_ATTACHMENT" +# +# :0 : +# /var/spool/mail/MimeDanger +# } +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# +# Call arguments (variables to set before calling) +# +# (none) +# +# Return values +# +# o Variable MIME is set to "yes" or "no" if messages has mime version +# string +# o MIME_VER contains the mime version string from the header. +# o MIME_TYPE contains the Content-Type from the header. +# o MIME_CTE contains Content-Transfer-Encoding from the header. +# o MIME_H_QP is "yes" if Content-Transfer-Encoding: quoted-printable +# is in the header. +# o MIME_B_QP is "yes" if Content-Transfer-Encoding: quoted-printable +# is found from the body. +# o MIME_BOUNDARY contains the boundary string, which is used to +# differentiate mime sections in the body. +# o MIME_BOUNDARY_COUNT is the number of boundary strings found +# from the body. The value is 3 if there is two mime sections, +# and 4 if 3 etc. MIME_BOUNDARY_COUNT -1 = count of sections. +# o MIME_H_ATTACHMENT, contains the filename if there was attachement +# filename in the header. Content-Disposition: attachment; +# filename="..." +# o MIME_B_ATTACHMENT. `body' file attachment. Note however that +# this is the match of first string in the body. There may be +# several attachments. MIME_B_ATTACHMENT_FILE_COUNT tells you +# how many filenames are in the body. +# +# Usage example +# +# INCLUDERC = $PMSRC/pm-jamime.rc +# +# Change Log (none) + +# ............................................................ &code ... + + +dummy = " +======================================================================== +pm-jamime.rc: init:" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables + +MIME = "no" # set default value +MIME_H_QP = "no" +MIME_B_QP = "no" + +MIME_VER +MIME_CTE +MIME_TYPE +MIME_BOUNDARY +MIME_BOUNDARY_COUNT + +# ........................................................... &do-it ... +# The WSPC ?? ( ) is there just double checking that we REALLY read +# the pm-javar.rc. We must not set any MIME variables if that wasn't +# read. + +:0 +* ^Mime-Version: *\/[0-9.]+ +* WSPC ?? [ ] +{ + MIME = "yes" + MIME_VER = $MATCH + + :0 + * ^Content-Type: +\/.* + { + MIME_TYPE = $MATCH + } + + :0 + *$ ^Content-Transfer-Encoding:$s+\/.* + { + MIME_CTE = $MATCH + + :0 + * MIME_CTE ?? quoted-printable + { + MIME_H_QP = "yes" + } + } + + :0 + *$ B ?? ^Content-Transfer-Encoding:$s+quoted-printable + { + MIME_B_QP = "yes" + } + + # What is the MIME tag in this message? + # + # Content-Type: multipart/mixed; + # boundary="---- =_NextPart_000_01BD04D4.A5AC6B00" + # + # Note that in the text, this string may not be excatly like this, + # Eg. in my messages there was "--" prepended to the tag. + # + + :0 + * boundary *= *\"\/[^\";]+ + { + MIME_BOUNDARY = $MATCH + } + + # Hm, the boundary string was not surrounded by double quotes. + # Search this kind of boundary string then: + # + # Content-Type: multipart/mixed; boundary=9i9nmIyA2yEADZbW + + :0 E + * boundary *= *\/[^\";]+ + { + # " Don't mind this, a dummy double quote to help Emacs + # to end starting quote below. Otherwise syntax colour + # highlighting would go beserk. + + MIME_BOUNDARY = $MATCH + } + + dummy = "pm-jamime.rc: Do we have the boundary string?" + + :0 + *! MIME_BOUNDARY ?? ^^^^ + { + # Count how many mime sections there are in the message. + # MIME_BOUNDARY_COUNT -1 = count of mime sections. + + :0 + *$ B ?? 1^1 $\MIME_BOUNDARY + { } + + MIME_BOUNDARY_COUNT = $= + } + + # Mime-Version: 1.0 (generated by tm-edit 7.106) + # Content-Type: application/octet-stream + # Content-Disposition: attachment; filename="file.txt" + # Content-Transfer-Encoding: 7bit + # + # Note: the second regexp assumes "filename=file.txt" + + mimeAttachementRegexp1 = "filename$s*=$s*[\"']\/[^\"\']+" + mimeAttachementRegexp2 = "filename$s*=$s*\/.*" + + :0 + *$ H ?? ^Content-Disposition:.*attachment$s*;$s*\/.* + *$ $SUPREME^0 MATCH ?? $mimeAttachementRegexp1 + *$ $SUPREME^0 MATCH ?? $mimeAttachementRegexp2 + { + MIME_H_ATTACHMENT = $MATCH + } + + :0 E + *$ B ?? ^Content-Disposition:.*attachment$s*;$s*\/.* + *$ $SUPREME^0 MATCH ?? $mimeAttachementRegexp1 + *$ $SUPREME^0 MATCH ?? $mimeAttachementRegexp2 + { + MIME_B_ATTACHMENT = $MATCH + + :0 + *$ B ?? 1^1 ^Content-Disposition:.*attachment.*filename + { } + + MIME_B_ATTACHMENT_FILE_COUNT = $= + + } +} + +dummy = "pm-jamime.rc: end:" + +# pm-jamime-tag.rc ends here diff --git a/share/procmail/pm-janetmind.rc b/share/procmail/pm-janetmind.rc @@ -0,0 +1,214 @@ +# pm-janetmind.rc -- handle http://minder.netmind.com/ messages +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# ** THIS MODULE IS OBSOLETE. THE NETMIND SERVICE NO LONGER EXISTS ** +# +# http://minder.netmind.com/ +# +# ...Netmind, or The URL-minder is a free, automatic Web-surfing robot +# that keeps track of changes to Web pages that are important to you. +# When the URL-minder detects changes in any of the Web pages you +# have registered, it sends you e-mail. an effective way to test if +# the address is known to Internet. You could use this information to +# see if some automated reply to a address can be sent. +# +# +# In another words, if you're interested in some URL; say an FAQ page +# and any updates to them, you can tell Netmind to monitor the page +# changes for you and it send a message back every time page changes. +# +# This recipe "pretty formats" the announcement sent by Netmind +# by stripping the message to bare minimum. You usually aren't interested +# in 4k message which includes "Note from our sponsors", "Try the free +# online demo" etc. The things saved from the announcement message are: +# +# o The changed url, which is moved to subject +# o Cancellation url pointer +# o url to the lists of your monitored urls +# o your id number +# +# [Note] +# +# Please let Netmind send you one "pure" message first so that you +# have a huch what it originally looks like. Then plug int his module +# and see how the original message is reduced. +# +# [Thank you] +# +# The Doctor What <docwhat@holtje-christian-isdn.mis.tandem.com> +# 1998-03-12 send me a patch, where a)body message is more informative +# b) URL is now included in the body for auto-click browsers c) +# mime headers were removed. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o If you se variable JA_NETMIND_SUBJECT to "yes", then the changed +# url http pointer is put to subject line. +# +# Usage example +# +# INCLUDERC = $PMSRC/pm-janetmind.rc # reformat the message +# +# :0: # drop to folder +# * netmind +# url.mbox +# +# Change Log (none) + +# .................................................... &initialising ... + + + +id = "pm-janetmind.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + + +# Are we allowed to change the Subject? + +JA_NETMIND_SUBJECT = ${JA_NETMIND_SUBJECT:-"no"} + +# ........................................................... &do-it ... +# catch both "From" and "From:" header lines + +:0 +* ^From.*netmind\. +{ + # ............................................... change subject ... + # Get the changed page and put it into subject line: you see immediate + # what page has changed when you browse your mailbox summary. + + subject = "" + + :0 + *$ ^Subject:\/.* + *$ MATCH ?? ()\/$a.* + { + subject = $MATCH + } + + + :0 + *$ 1^1 B ?? new changes in:$SPCL+\/.* + *$ 1^1 B ?? changed page, +visit:($)\/.* + *$ MATCH ?? ()\/$a.* + { + + TheUrl = $MATCH + + :0 fhw + * JA_NETMIND_SUBJECT ?? yes + | $FORMAIL -I "Subject: $MATCH" + + } + + # .................................................. change body ... + # The message from URL-minder is roughly 4k and lot of the information + # is useless. There is "note from out sponsor", how to stop requesting + # messages etc. + + # To retrieve the password + + pass = "" + + :0 + * B ?? ()\/http.*netmind.*responder.* + { + pass = $MATCH + } + + # To update your account visit + + update = "" + + :0 + *$ B ?? ().*update.*account.*($)\/.* + { + update = $MATCH + } + + + # Save the cancel information + + cancel = "" + + :0 + *$ B ?? ^To$s+cancel.*this.*($)\/.* + { + cancel = $MATCH + } + + # Save "NetMind List" pointer: list of monitored urls + + cancelAll = "" + + :0 + *$ B ?? ^To$s+cancel.*all.*($)\/.* + { + cancelAll = $MATCH + } + + # .......................................................... body ... + # modify the body only if we got enough matches + + dummy = "$id: changing message contents" + + :0 + * update ?? [a-z] + * cancel ?? [a-z] + * cancelAll ?? [a-z] + { + + # Remove the mime headers, the message is no longer MIME. + + :0 fhw + | $FORMAIL -I "Content-Type:" -I "Mime-Version:" + + # Avoid multiple echo commands and put message into one string + + msg = "Subject : $subject${NL}Changed : $TheUrl${NL}Update : $update" + msg = "$msg${NL}${NL}Cancel this: $cancel${NL}Cancel all : $cancelAll" + + :0 fbw + | echo "$msg$NL" + + } + :0 E #else statement + { + dummy = "$id: $JA_MSG_ERROR the message format has changed" + dummy = "$id: $JA_MSG_ERROR send copy to maintainer of the module" + } + +} + +dummy = "$id: end:" + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-janslookup.rc b/share/procmail/pm-janslookup.rc @@ -0,0 +1,395 @@ +# pm-janslookup.rc -- run nslookup on variable INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine runs `nslookup' on given INPUT address. This may be +# an effective way to test if the address is known to Internet. You +# could use this information to determine if some automated reply to +# a address can be sent. The know truth is that you can't validate +# whole email address +# +# to_someone@foo.com +# +# but you can validate "foo.com"; that's the closest you get. +# +# [Warning: If you don't use cache feature...] +# +# Do not however use this module to regularly check _all_ incoming +# from addresses with this subroutine for possible bogus UBE +# addresses, because calling nslookup +# +# o may be slow, building to connection and querying the results +# may take several seconds. (some times, usually it's quote fast) +# o consumes quite a lot resources. +# +# You can however check _some_ messages that are likely UBE to verify +# your doubts. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jaaddr.rc +# +# Call arguments (variables to set before calling) +# +# o INPUT, the address (only strict domain part) which is checked. +# Eg. "this.domain.com". See examples for more. +# If this string contains "@" character, then additional +# subroutine pm-jaaddr.rc is called to extraxt the domain name +# INPUT = "John Doe <foo@site.com>" --> INPUT = "site.com" +# o JA_NSLOOKUP_CACHE, filename. If exists, cache is used and updated. +# o JA_NSLOOKUP_FORCE, if "yes", then cache is not used but a forced +# nslookup is performed. +# o JA_NSLOOKUP_OPT, is currently empty, but you could see if you +# you want to use "-querytype=MX". However this option may give +# you response: "No mail exchanger (MX) records available", +# which is flagged as nslookup failure. +# o JA_NSLOOKUP_SERVER, optional, the server to user for nslookup +# +# If the cache file can be read: +# +# o Each entry has format "address.com ns-error". The error +# indication is added to the line if the nslookup failed when +# address was checked. Otherwise line contains "address.com". +# o The cache is always checked first. If there is no entry matching +# the current address, only then is nslookup called and new entry +# added to cache. +# +# Return values +# +# o Variable ERROR will be set to "yes" if nslookup failed or +# to "no" if nslookup succeeded. It can also contain "maybe" if +# nslookup returned "No address (A) records available" +# o ERROR_MATCH contains one line lookup failure reason. +# +# Following conditions trigger "maybe" and no "ns-error" is written +# into the cache. +# +# o "No address (A) records available for xxx" +# +# Usage example +# +# If you are going to check some header field, like From:, please +# explode the content with pm-jaaddr.rc first. Suppose you have +# string: +# +# "From: foo@ingrid.sps.mot.com (Yoshiaki foo)" +# +# You have to derive the address from string and pass the site name: +# Read From: field and address from it. +# +# PMSRC = $HOME/pm +# RC_NSLOOKUP = $PMSRC/pm-janslookup.rc # name the subroutine +# +# :0 +# * MAYBE_UBE ?? yes +# * ^From:\/.* +# { +# INPUT = $MATCH +# INCLUDERC = $RC_NSLOOKUP # to nslookup +# +# :0 +# * ERROR ?? yes +# { +# # Hm, nslookup failed, can't send anything back to this +# # address +# } +# } +# +# Second example, check if the address is reachable before sending reply +# +# INPUT = `$FORMAIL -rt -x To:` +# INCLUDERC = $RC_NSLOOKUP +# +# :0 +# * ERROR ?? no +# { +# # okay, at least site address seems to be reachable +# } +# +# +# Change Log (none) + +# .................................................... &initialising ... + + +dummy = " +======================================================================== +pm-janslookup.rc: init: INPUT = $INPUT" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# If user gave string that had Email, explode it automatically +# INPUT = "John doe <foo@site.com>" --> "site.com" + +:0 +* INPUT ?? @ +{ + INCLUDERC = $PMSRC/pm-jaaddr.rc # - explode INPUT string + INPUT = $SITE # - the address is only fed +} + +# ...................................................... &input-vars ... +# o INPUT contains the address to check +# o JA_NSLOOKUP_CACHE is optional + +# Set to empty "" if you don't wan't to use cache in some particular +# cases + +JA_NSLOOKUP_CACHE = ${JA_NSLOOKUP_CACHE:-"$HOME/.nslookup.cache"} + +# other options + +JA_NSLOOKUP_FORCE = ${JA_NSLOOKUP_FORCE:-"no"} +JA_NSLOOKUP_OPT = ${JA_NSLOOKUP_OPT:-"-querytype=MX"} +JA_NSLOOKUP_SERVER = ${JA_NSLOOKUP_SERVER:-""} + +NSLOOKUP = ${NSLOOKUP:-"nslookup"} # Add `-silent' in Linux +TOUCH = ${TOUCH:-"touch"} # binary to create cache file + +# ..................................................... &output-vars ... +# output variables + +ERROR = "yes" +ERROR_MATCH + +# ........................................................... &do-it ... +# ErrorWord is not really ment for user configurable, but +# as you can see, it is coded that way in case you would like to +# use some other error word. + +ErrorWord = ${ErrorWord:-"nlookup-error"} +dummy = "pm-janslookup.rc: do the work" + +# The string must have one dot somewhere, otherwise it is not a domain + +:0 +*$ INPUT ?? $NSPC+\.$NSPC+ +{ + topDomain = "xxx-dummy-regexp" + cache = "no" + entry = "no" + + :0 + * INPUT ?? ()\/[^.]+\.[^.]+^^ + { + topDomain = $MATCH # xxx.foo.com --> foo.com + } + + # If variable is not empty, suppose that user wants to use cache + + :0 + * ! JA_NSLOOKUP_CACHE ?? ^^^^ + * JA_NSLOOKUP_FORCE ?? no + { + cache = "yes" + + :0 hwic # Create file if it doesn't exist. + * ! ? $IS_EXIST $JA_NSLOOKUP_CACHE + | $TOUCH $JA_NSLOOKUP_CACHE + } + + dummy = "pm-janslookup.rc: Test if cache is in use" + + :0 + * cache ?? yes + *$ ? $IS_READABLE $JA_NSLOOKUP_CACHE + { + # Convert regexp to "safe" format, escapeping regexp + # metacharacters. See pm-tips.txt + + regexp = "$\INPUT" + + :0 # kill leading "()" + * regexp ?? ^^\(\)\/.* + { + regexp = "$MATCH" + } + + # b) search hostname and SPACE like in: "this.site.com nlookup-error" + # a) or "this.site.com" + + line = `$EGREP "^$regexp( | *$)" $JA_NSLOOKUP_CACHE` + + :0 # was this address in cache? + *$ line ?? $INPUT + { + entry = "yes" + } + + dummy = "pm-janslookup.rc: Test if cache line does _not_ include $ErrorWord" + + :0 + * entry ?? yes + *$ ! line ?? $ErrorWord + { + ERROR = "no" + } + } + + # Cache is not used OR there was no line in the cache + + dummy = "pm-janslookup.rc: Test if we call nslookup" + + :0 + * entry ?? no + { + stat = `$NSLOOKUP $JA_NSLOOKUP_OPT "$INPUT" $JA_NSLOOKUP_SERVER` + + # If nslookup succeeds, at least HP-UX 9/10, ULTRIX and SUN + # return some of these choices upon success: + # + # Non-authoritative answer: + # Name: uta.fi + # + # Or + # + # Non-authoritative answer: + # geocities.com preference = 0, mail exchanger = ... + # + # Or + # + # Name: foo.com + # Address: 209.54.94.60 + # + # Or + # + # Authoritative answers can be found from: + # foo.com + # origin = xx.foo.com + # + # Or + # Non-authoritative answer: + # foo.com mail exchanger = 0 mx1.foo.com. + # + # Or ^($)$topDomain + # + # This needs some explaining. When procmail captures + # the `nslookup' command it does it wrong for some unknown reason + # for some mail hosts. The captured output is: + # + # procmail: Assigning "stat=Name Server: zeus.tele.nokia.fi + # Address: 131.228.134.50 + # + # umd.umich.edu + # origin = tiamat.umd.umich.edu + # mail addr = hostmaster.tiamat.umd.umich.edu + # serial = 970727 + # refresh = 28800 (8 hours) + # retry = 14400 (4 hours) + # expire = 2419200 (28 days) + # minimum ttl = 14400 (4 hours)" + # + # notice? The line "Authoritative answers can be found from:" + # is not there while it is if I run the same command is + # run from command line. + + # |Authoritative answers can be found from:($).* + + :0 + * stat ?? ()\/No +address.*available.* + { + # *** No address information is available for ... + ERROR_MATCH = $MATCH + ERROR = "yes" + } + + :0 E + *$ stat ?? ()\/answer:($)(Name:)? *$INPUT\ + |(Name: *$INPUT)|from:($) +$topDomain\ + |($) *$topDomain + { + ERROR = "no" + } + + # ............................................. Linux/Cygwin ... + # Win32/Cygwin nslookup returns this answer + + # prompt> nslookup -querytype=MX cs2.tpu.fi + # + # Non-authoritative answer: + # Server: nsX.koti.tpo.fi + # Address: 212.63.10.250 + # + # cs2.tpu.fi MX preference = 0, mail exchanger = xxx.tpu.fi + # cs2.tpu.fi MX preference = 10, mail exchanger = yyy.tpu.fi + # cs2.tpu.fi MX preference = 20, mail exchanger = zzz.funet.fi + # + # fi nameserver = HYDRA.HELSINKI.fi + # fi nameserver = NS-SE.ELISA.NET + # fi nameserver = PRIFI.FICORA.fi + # fi nameserver = NS1-FIN.GLOBAL.SONERA.fi + # fi nameserver = T.NS.VERIO.NET + # fi nameserver = NS.UU.NET + # xxx.tpu.fi internet address = 193.167.70.45 + # yyy.tpu.fi internet address = 193.167.70.20 + # mail.funet.fi internet address = 193.166.0.98 + # mail.funet.fi internet address = 193.166.0.97 + # HYDRA.HELSINKI.fi internet address = 128.214.4.29 + # PRIFI.FICORA.fi internet address = 193.229.4.44 + + dummy="Win32/Cygwin nslookup check" + + :0 + *$ stat ?? internet address = .*$topDomain + { + ERROR = "no" + } + + # .................................................. message ... + + msg = "" + + :0 + * ERROR ?? yes + { + msg = $ErrorWord + } + + :0 + * ERROR ?? maybe + { + msg = "maybe" + } + + # .............................................. write cache ... + + dummy = "pm-janslookup.rc: Test if '$INPUT' should be added to cache" + + :0 hwic: + * cache ?? yes + | echo "$INPUT $msg" >> $JA_NSLOOKUP_CACHE + + } +} + +:0 E +{ + dummy = "pm-janslookup.rc: $JA_MSG_ERROR invalid INPUT" +} + +dummy = "pm-janslookup.rc: end: input: $INPUT error: $ERROR" + +# end of file pm-janslokup.rc diff --git a/share/procmail/pm-jaorig.rc b/share/procmail/pm-jaorig.rc @@ -0,0 +1,273 @@ +# pm-jaorig.rc -- Extract embedded original message (simple recipe) +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Documentation +# +# This subroutine digs embedded message from the body and replaces +# current message with it. Copy the message to folder before calling +# this subroutine if you need original. +# +# NOTE: This is _simple_ tool and the sole purpose is to derive +# simple embedded messages. Write full fledged perl script if you +# want better extracting features. The used AWK inside this procmail +# recipe will fail to find 30% of the cases, mostly due to non-standard +# way of including the message. The recognized formats are as follows. +# Anything that differs from these are ignored or incorrectly parsed. +# +# o Message is embedded left flushed "as is". With full headers or +# Minimum of `From:' `Subject' `Received' +# o The embedded message is quoted with `>' with optional _one_ +# space. +# +# Where you would use this module +# +# If you're subscribed to mailing lists that regularly sent copies of +# original message to the list, like forwarding spam to SPAM-L +# mailing list at http://bounce.to/dmuth, then you'd like to +# extract the original embedded message which you can then feed to +# your UBE filter to test if the shield holds. +# +# <spam-l-request@peach.ease.lsoft.com> +# subscribe SPAM-L <First name> <Last name> +# +# This recipe takes simplistic approach and tries it's best to +# extract embedded message. Idea for this recipe comes from Era +# Eriksson's posting "recipe to turn list postings back into original +# spam" 1998-06-25 in Procmail mailing list. +# +# o Body must contain headers +# o Remove all `>' quotations. +# o extract everything to the end of message. (There are no means +# to get rid of the attached signatures that ot forwarding poster +# or list server may have attached. +# +# How the message is extracted +# +# When this recipe ends, the current message has been modified so that +# it _is_ _the_ _original_ _message_. Like if you would receive: +# +# HEADER-1 # The poster +# body-1 # his comments +# HEADER-2 # The original embedded message +# body-2 +# body-1 # And poster's signature or mailing list footer +# +# The message now looks like +# +# HEADER-2 +# body-2 +# body-1 +# +# And you can save this as original message or feed it to your +# UBE filter and test if it detects it. +# +# Code note: procmail or awk core dump +# +# For some reason procmail kept dumping core I write the code in +# more nicer format like below, but if I made it compact, then it +# didn't dump core. Go figure. I'm not pleased that I had to sacrafice +# clarity, but there was no other way. +# +# [The good style] [The forced compact style] +# if () if () { statement } +# { +# statement +# } +# +# I have no explanation why this +# happens, the same AWK code would work just fine most of the cases and +# then came this message `x' and caused dumping the code, if I feed +# some other message, I didn't get core dump. Total mystery to me. +# Don't let the log message fool you, this had nothing to do +# regexp "^[> ]*From:.*[a-zA-Z]". If I deletd one line from AWK +# script, it worked ok, if I added it back the core dump happened with +# that message `x' +# +# procmail: Assigning "pfx=[> ]*" +# procmail: No match on "^[> ]*From:.*[a-zA-Z]" +# Segmentation fault (core dumped) +# +# Required settings +# +# PMSRC must point to source directory of procmail includerc code. +# This subroutine needs module(s): +# +# o pm-javar.rc +# +# Call arguments (variables to set before calling) +# +# (none) +# +# Usage Example +# +# Let's assume that you want to feed all forwarded UBE that is +# posted to spam-l mailing list to your filter and see if it needs +# improving by checking the logs later. The forwarded UBE to the list +# is labelled "SPAM:" in the subject line. +# +# $RC_LIST = $PMSRC/pm-jalist.rc # mailing list detector +# $RC_ORIG = $PMSRC/pm-jaorig.rc # extract original +# $RC_UBE = $PMSRC/pm-jaube.rc # UBE filter +# +# ... +# +# INCLUDERC = $RC_LIST # defines variable `LIST' +# +# :0 +# * ! LIST ^^^^ +# { +# :0 # spam-l mailing list +# * LIST ?? spam +# * Subject: +SPAM: +# { +# INCLUDERC = $RC_ORIG # Change it to UBE message +# +# # Ok, next feed it to filter, set some variables first +# # Log = Short log; What filters were applied to message +# # mbx = If message was trapped, save it here +# +# JA_UBE_LOG = "$PMSRC/pm-ube.log" +# JA_UBE_MBOX = "junk.ube.ok.mbox" +# +# INCLUDERC = $RC_UBE +# +# :0 : # If comes here, filter failed +# junk.ube.nok.mbx +# } +# +# :0 : # save normal list messages +# list.$LIST +# } +# +# +# +# Change Log (none) + + +# ............................................................ &init ... + + +id = "pm-jaorig.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# .......................................................... &detect ... + +pfx = "[> ]*" + +:0 +*$ B ?? ^${pfx}From:.*$a +*$ B ?? ^${pfx}Subject:.*$a +*$ B ?? ^${pfx}Received: +from +{ + + # Remove all original headers from the message, + # AWK will shift up the headers in the body + + :0 fhw + | echo "" + + + :0 # make sure LINEBUF has value or procmail dumps core + *$ ! LINEBUF ?? $d + { + LINEBUF = 8192 + } + + # Set bigger LINEBUF. Otherwise procmail/awk may dump core when + # a big message is handled. + + savedLinebuf = $LINEBUF + LINEBUF = 524280 + + savedShell = $SHELLMETAS + SHELLMETAS + + # How it works: + # + # *) Because AWK can't do multi line matches, we have to use two flags: + # `prevHead' is set to 1 as soon as header line is detected. + # _BUT_ in order to start header, it must follow with next + # header immediately. The `head' is set to 1 only if previous + # line was header. + # + # --> when `head' is raised, then main starts printing the message + # + # *) do case insensitive match and filter out certain lines. + # + # *) `Received:' Header is immediate indication of message. + # + # *) Remove `>' quotation + # + # *) Print embedded message + # + # variable `end' is set as soon as there is end of headers. + # we fix continued non-header start lines by preceding them + # with two spaces. (Forwarded message to spam-l was all left + # flushed, thus breaking the proper RFC header continuation) + # Var `end' tells when we must not fix lines any more. + # + + :0 fhbw + | $AWK \ + ' \ + /^[>]* ?([A-Z][-a-zA-Z]+:|^From )/ \ + { if( prevHead && !head) {print prev; head=1} } \ + \ + { \ + str = tolower($0); \ + if ( match(str, "forwarded message") > 0) { next } \ + if ( match(str, "received: +from|return-path:")>0) { head = 1 } \ + \ + if ( head == 1 ) \ + { \ + sub("^[>]",""); \ + if ( match($0,"^[ ]*$") ) { end = 1 } \ + if ( !end ) { sub("^ +","")} \ + if ( !end && match($0,"[A-Z][-a-zA-Z]+:|^From ") < 1) \ + { $0 = " " $0; } \ + print; \ + } \ + \ + prevHead = 0; \ + if ( match($0, "^[>]* ?([A-Z][-a-zA-Z]+:|^From )") > 0 ) \ + { prevHead = 1; prev = $0; } \ + } \ + ' + + LINEBUF = $savedLinebuf + SHELLMETAS = $savedShell + + # Add a From_ line if it doesn't have one. + + :0 fhw + *$ ! ^^From$s+ + | $FORMAIL + +} + +dummy = "$id: end:" + +# End of file pm-jaorig.rc diff --git a/share/procmail/pm-japing.rc b/share/procmail/pm-japing.rc @@ -0,0 +1,125 @@ +# pm-japing.rc -- reply shortly to message "Subject: ping"; account ok +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# When I'm on remote site and I don't seem to get throught +# with telnet or even with Unix ping(1), I want to know if the +# at least the mail server is up. I can send a ping message and the +# auto responder will reply immediately. +# +# Sometimes, when you send a message to a person, it would be nice, +# if you could test that the destination address is valid, before +# sending a message to a black hole. If the receiver had ping +# service running; like this, then you would know that you spelled the +# the right address. (after wondering two weeks; why you don't get +# response). Nowadays `finger(1)' command seems to be blocked many times. +# +# This recipe answers to simple ping message like this: +# +# To: you@site.com +# Subject: ping +# +# Recipe sends a short message back to the sender. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jastore.rc +# +# Call arguments (variables to set before calling) +# +# (see Usage) +# +# Usage example +# +# JA_PING_MBOX = $HOME/Mail/spool/ping.spool +# INCLUDERC = $PMSRC/pm-japing.rc +# +# Change Log (none) + + +# .................................................... &initializing ... + + +id = "pm-japing.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ........................................................... &input ... + +JA_PING_MBOX = ${JA_PING_MBOX:-"junk.ping"} +JA_PING_XLOOP = ${JA_PING_XLOOP:-"$LOGNAME ping"} + +# ............................................................ &code ... + +dummy = "$id: start:" + +:0 +*$ ^Subject:$s*ping$s*$ +*$ ! ^X-Loop: $JA_PING_XLOOP +*$ ! $JA_FROM_DAEMON +{ + :0 fhw + | $FORMAIL -rt -A "X-Loop: $JA_PING_XLOOP" + + # Remember, Don't send back anything that would be vital to attacker. + # It doesn't matter if the `uptime` or other scripts fail, the reply + # is sent anyway. + # + # Record this ping request + # + # 'a' Makes sure Formail succeeded and could create reply address. + # HOST is your Mail delively host; the same where your programs + # will run. + + :0 ahwc + | ( $CAT -; \ + uptime; \ + echo "[$HOST] User count: "; who | wc -l; \ + echo "Unread mail count:"; $GREP '^From ' $DEFAULT |wc -l; \ + ) | $SENDMAIL + + MBOX = $JA_PING_MBOX + INCLUDERC = $PMSRC/pm-jastore.rc +} + + +# When pinging yourself +# the reply message comes back to you as "Re: ping" + +:0 +*$ ^Subject:.*\<ping\>$s*$ +{ + MBOX = $JA_PING_MBOX + INCLUDERC = $PMSRC/pm-jastore.rc +} + +dummy = "$id: end:" + +# end of pm-japing.rc diff --git a/share/procmail/pm-japop3.rc b/share/procmail/pm-japop3.rc @@ -0,0 +1,415 @@ +# pm-japop3.rc -- Remotedly download messages by mail command request +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# Ahem, that `pop3' is just to draw your attention. This module has +# nothing to do with pop3. The idea may resemble it though. This +# module listens pop3 requests, and when it gets one, it sends +# the whole mailbox content as separate forwarded messages to the +# account from where you sent the request. +# +# This is kinda "empty my mailbox in account X and send the messages +# to account Y" +# +# You might have permanent forwarding on in account X, but if that +# is your secondary account, you can ask what messages has been arrived +# there with this recipe. +# +# After you have configured your magic pop3 command, which is your +# password, simply send a message to account X, and this module +# initiates emptying the mailbox. Here is an example: +# +# Subject: pOp3-send [mailbox] [kill] +# +# o `mailbox', is optional folder name which you want to process. +# it is $DEFAULT if not given in subject. Use *absolute* path if +# you specify one. +# o if word `kill' is found, the mailbox will be emptied after +# forwarding. If the word is not found, messages are preserved. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-japop3.rc # Phew! We include ourself, we are recursive. +# +# Call arguments (variables to set before calling) +# +# o `JA_POP3_SUBJECT_CMD' is your personal access command string. +# If this is the first word in the subject line, forwarding starts. +# This string is case sensitive. +# o `JA_POP3_TMP' is the file where mailbox is moved before starting +# to forward the messages. Do not put to point to your $HOME, +# becaus that may exceed the quota. +# o `JA_POP3_TO_MUST_MATCH' must contain regexp that match the email +# addresses where the pop3 messages are allowed to send. BE SURE +# TO DEFINE this. If you have account X,Y,Z where you want to receive +# pop3 messages, set this regexp to match those site's email addresses. +# o `JA_POP3_LOGFILE' is the log where you can see how the forked +# procmail processes send each pop3 mail. You may want to set this +# to different location than your default `$LOGFILE'. +# +# Return value +# +# `STATUS' will contain mailbox name if valid pop3 request was received. +# You may wish to save the pop3 requests to separate folder. See example +# below. +# +# Example usage +# +# You install this same setup for each site where you have account. This +# is the account X, from where you want to empty the mailboxes. +# +# RC_POP3 = $PMSRC/pm-japop3.rc +# +# .. somewhere in your .procmailrc .. +# +# JA_POP3_SUBJECT_CMD = myPoPcmd +# INCLUDERC = $RC_POP3 +# +# # Save all pop3 requests to folder +# +# :0 : +# * STATUS ?? [a-z] +# mail.pop3-req.mbox +# +# +# In account Y, from where you send the pop3 requests. Following code stores +# the received messages to separate folder +# +# # The MATCH will contain the host name from where the messages +# # were moved +# +# :0 : +# *$ X-Loop-Fwd:.*\.rc +\/$NSPC+ +# mail.fwd.$MATCH.mbox +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-japop3.rc" +dummy = " +======================================================================== +$id: init: +" + +dummy = "$id: FORKED PROCESS: $JA_POP3_CHILD $JA_POP3_FWD_TO +DEFAULT [$DEFAULT] $NL$NL" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# .......................................................... &public ... + +JA_POP3_TMP = ${JA_POP3_TMP:-"$TMPDIR/$LOGNAME.pop3"} +JA_POP3_SUBJECT_CMD = ${JA_POP3_SUBJECT_CMD:-"XyZ-yourPop3-cmd"} +JA_POP3_TO_MUST_MATCH = ${JA_POP3_TO_MUST_MATCH:-"Allowed-address-regexp"} +JA_POP3_LOGFILE = ${JA_POP3_LOGFILE:-"$LOGFILE"} + + +# Do not set this to "sendmail -oi -t" + +JA_POP3_SENDMAIL = ${JA_POP3_SENDMAIL:-"sendmail"} # /usr/lib/ + +# Script to call to handle each piece of forwarded mail. + +JA_POP3_RC = ${JA_POP3_RC:-"$PMSRC/pm-japop3.rc"} # don't touch + +# ......................................................... &private ... + +# Don't change or define these variables anywhere! These are passed +# to child process from this module when forking new procmail copy. + +JA_POP3_CHILD = ${JA_POP3_CHILD:-"not-child"} +JA_POP3_FWD_TO = ${JA_POP3_FWD_TO:-""} + +# ..................................................... &output-vars ... + +STATUS + +# .............................................. start-pop3-transfer ... + +:0 D +* JA_POP3_CHILD ?? not-child +*$ ^Subject: $JA_POP3_SUBJECT_CMD\/.* +{ + subject = $MATCH + + + # Set default values + + error = "" + kill = "" + mbox = "" + + mailbox = $DEFAULT + keyword = "forwarded to" + address = `$FORMAIL -rt -x To:` + + # - mark each message forwardable by adding X-Loop header. + + xloop = "X-Loop: $keyword $address from $HOST" + + # ................................................... &kill-flag ... + + :0 + * ^Subject:.* kill\> + { + kill = "yes" + } + + # ............................................... &other-mailbox ... + + dummy = "$id: Check /mailbox/ keyword in subject line" + + :0 + *$ subject ?? ()\/$NSPC+ + { + mailbox = $MATCH + } + + # ................................................. check-access ... + + :0 + *$ ! address ?? $JA_POP3_TO_MUST_MATCH + { + error = "Invalid destination [$address]" + } + + + # ............................................... &check-mailbox ... + + :0 + * error ?? ^^^^ + * mailbox ?? [a-z] + *$ ? $IS_READABLE $mailbox + { + mbox = $mailbox + } + + :0 e + { + error = "mailbox is not readable" + } + + # ............................................... &check-formail ... + + :0 fh w # Just check that formail is working ok + * error ?? ^^^^ + | $FORMAIL -I"X-Dummy-Test: xyz" + + :0 e + { + error = "formail [$FORMAIL] not working right" + } + + # ................................................. &check-child ... + + :0 + * error ?? ^^^^ + *$ ! ? $IS_EXIST $JA_POP3_RC + { + error = "child module does not exist" + } + + # ............................................. &prepare-mailbox ... + + japop3LOCKFILE = $LOCKFILE + lockFile = $JA_POP3_TMP$LOCKEXT + + + # ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~ &protect .~. + # We must not allow another request to arirve during this period + # for this same mailbox. Any new try must be ignored + + :0 + *$ ! $IS_EXIST $lockFile + { + + # Activate regional lockfile. no other file locks are needed + # from now on. + + LOCKFILE = $lockFile + + + :0 hwic # copy to temporary place + * error ?? ^^^^ + * mbox ?? [a-z] + | $CP $mbox $JA_POP3_TMP + + :0 e + { + error = "cp [$CP] failure" + } + + + :0 hwic # protect mailbox + * error ?? ^^^^ + | $CHMOD 600 $JA_POP3_TMP + + :0 e + { + error = "chmod [$CHMOD] protection failure" + } + + # ....................................................... &do-it ... + + dummy = "$id: Check if pop3 should be initiated." + + :0 + * error ?? ^^^^ + * CP ?? [a-z] + * CAT ?? [a-z] + *$ ! ^$xloop + { + STATUS = $mbox + + :0 + *$ ? $IS_READABLE $mbox + { + + dummy = "$id: child: $TIMEOUT $HOST $JA_POP3_RC" + dummy = "$id: SH [$SHELL]" + dummy = "$id: SENDMAIL [$SENDMAIL]" + dummy = "$id: FORMAIL [$FORMAIL]" + dummy = "$id: PROCMAIL [$PROCMAIL]" + dummy = "$id: HOME [$HOME]" + dummy = "$id: PATH [$PATH]" + + + # This may take some time, give enough rope + # 16 minutes maximum to process the mailbox + + japop3TIMEOUT = $TIMEOUT + TIMEOUT = 960 + + # - we're calling ourself, so we must pass the envinronment + # variables too so that called JA_POP3_RC script inherits + # the environment. + # + # - DEFAULT is set to /dev/null so that any failure in + # child won't put messages back to our mailbox. + # + # - FORMAIL options are: (-n 5), maximum 5 parallel processes + # (-d), ignore Content-Length header, (-s), split + # mailbox -- must be the last option. + # + + :0 a hwic + | $CAT $JA_POP3_TMP | \ + $FORMAIL \ + -A"$xloop" \ + -n5 \ + -d \ + -s \ + $PROCMAIL \ + VERBOSE="on" \ + LOGABSTRACT="all" \ + LOGFILE="$JA_POP3_LOGFILE" \ + DEFAULT="/dev/null" \ + SHELL="$SHELL" \ + HOME="$HOME" \ + PATH="$PATH" \ + PMSRC="$PMSRC" \ + FORMAIL="$FORMAIL" \ + SENDMAIL="$SENDMAIL" \ + JA_POP3_CHILD="child" \ + JA_POP3_FWD_TO="$address" \ + JA_POP3_TO_MUST_MATCH="$JA_POP3_TO_MUST_MATCH" \ + $JA_POP3_RC + + TIMEOUT = $japop3TIMEOUT + + :0 e # failed; cancel killing the mailbox + { + kill = "" + + :0 hwc + | ( $FORMAIL \ + -rt \ + -A "X-Loop: Error" \ + | echo "Sorry, $FORMAIL -s failed" \ + ) | $SENDMAIL + + } + + + :0 hwic: # Truncate the file + * kill ?? yes + | $CAT /dev/null > $mbox + + } + :0 E # ***************** else invalid request + { + :0 hwc + | ( $FORMAIL \ + -rt \ + -A "X-Loop: Error" \ + | echo "[$mbox] does not exist" \ + ) | $SENDMAIL + + } + } + + dummy = "$id: POP3 request handled." + + LOCKFILE = $japop3LOCKFILE + } + # ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~ &protect .~. + + +} + +# ........................................................ the-child ... + +# The individual messages are mailed back to this script, this +# is the "receiver" and handles forwarding, unless message is +# already forwarded. + + +dummy = "$id: Check if we're forwarding (pop3) messages: $JA_POP3_CHILD" +dummy = "$id: $JA_POP3_FWD_TO ?? $JA_POP3_TO_MUST_MATCH" + +:0 +* JA_POP3_CHILD ?? ^^child^^ +*$ JA_POP3_FWD_TO ?? $JA_POP3_TO_MUST_MATCH +{ + + :0 fhw # mark this message "forwarded" + | $FORMAIL -A "X-Loop-Fwd: pm-japop3.rc $HOST" + + # You can also only test the recipe if you set + # + # SENDMAIL = "tee -a $HOME/tmp/sent.mail" + + :0 + ! $JA_POP3_FWD_TO + +} + + + +dummy = "$id: end: STATUS = $STATUS" + +# End of pm-japop3.rc diff --git a/share/procmail/pm-jarandf.rc b/share/procmail/pm-jarandf.rc @@ -0,0 +1,128 @@ +# pm-jarandf.rc -- pick (rand)om line from (f)ile +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# Return random line or a line from a file. This subroutine uses +# shell command `awk' and possibly `wc' to be as small burden to the +# system as possible. +# +# Required settings +# +# You must have awk that supports VAR=value assignment syntax outside +# the code block: that is, in the input line. I know no awk that +# would not have this feature, but at least you know now what it takes. +# +# % awk '{print VAR; exit;}' VAR=1 /etc/passwd +# +# Try using GNU awk, if your standard awk didn't print 1 in above +# test. (Put this line to the top of your .procmailrc) +# +# AWK = "gawk" +# +# Call arguments (variables to set before calling) +# +# If intend to call this subroutine many times, then please calculate +# the number of lines beforehand and pass it to this subroutine. If +# the MAX is not set, then `wc' is called every time to find your the +# line count. +# +# o FILE, from what file to select. Make sure this exists; existence +# is not checked here. +# o [MAX] optional, number of lines in the FILE. +# +# Returned value +# +# variable LINE +# +# Example usage +# +# # Select random line from a file +# +# $RC_RANDF = $PMSRC/pm-jarand.rc +# $COOKIE = $HOME/txt/cookie.lst +# +# ...somewhere.. +# MAX=20 FILE=$COOKIE INCLUDERC=$RC_RANDF +# +# # LINE contains randomly read line +# +# Change Log: (none) + +# ............................................................ &init ... + +id = "pm-jarandf.rc" +dummy = " +======================================================================== +$id: init: +" + + +# ........................................................... &input ... + +# FILE; MAX; defined by user + +# ..................................................... &output-vars ... +# output variables + +LINE + +# ........................................................... &do-it ... +# Prevent calling sh -c here. Speeds up procmail. + +jarandfShellmetas = $SHELLMETAS +SHELLMETAS + +:0 +* FILE ?? [a-z] +{ + + # If max is not set beforehand + + :0 + * ! MAX ?? ^^[0-9]+^^ + { + # Awk can't know how many lines are in the file in advance, + # we must find it out. + + MAX = `wc -l $FILE` + } + + # It works like this: + # - When line number(NR) is 1, calculate random line + # - calculated line is same as current line number, print and exit. + + LINE = `$AWK \ + ' \ + function GetRand(i, j) \ + { \ + srand(); \ + return (i + int ( rand()*j )); \ + } \ + { \ + if ( NR == 1 ) { line = GetRand(1, max); } \ + if ( NR == line ) { print; exit; } \ + } \ + ' max=$MAX $FILE ` + +} + +SHELLMETAS = $jarandfShellmetas + +dummy = "$id: end:" + +# pm-store.rc ends here diff --git a/share/procmail/pm-jasrv-check.rc b/share/procmail/pm-jasrv-check.rc @@ -0,0 +1,84 @@ +# pm-jasrv-check.rc -- check FILE validity, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of the TPFS or MPFS file server. +# Check FILE for nonvalid filenames or other access problems. +# +# Input +# +# o JA_SRV_F_FILE_CASE_SENSITIVE, flag +# o FILE, filename to check. possibly converted to lowercase. +# +# Output +# +# o stat, set to "ok" if filename is acceptable. Otherwise contains +# brief error reason; +# +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv-check.rc" +dummy = " +======================================================================== +$id: init: +" + + +stat = "ok" + + +# .................................................. &conversion ... +# Should we ignore spelling mistakes? File.txt --> file.txt + +:0 D +* JA_SRV_F_FILE_CASE_SENSITIVE ?? no +* FILE ?? [A-Z] +{ + FILE = `echo "$FILE" | $TR A-Z a-z` +} + +# ........................................................... &check ... +# Do not accept wildcard names, because +# +# % test -r file*txt +# +# would succeed, but there is no no such individual file + +:0 +* FILE ?? [][*?{}()<>&!'$;] +{ + stat = "invalid-characters" +} + + +# Check that filename does not have "../" security risk. +# Or dos styled "..\" -- perhaps for NT? + +:0 +* FILE ?? \.\.[/\] +{ + stat = "invalid-directory-access" +} + + +dummy = "$id: end: STAT = $stat" + +# Enf of pm-jasrv-check.rc diff --git a/share/procmail/pm-jasrv-daemon.rc b/share/procmail/pm-jasrv-daemon.rc @@ -0,0 +1,118 @@ +# pm-jasrv-daemon.rc -- server request check, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of the MPFS file server. +# Handle BOUNCES to mail server messages, eg if delivery failed +# due to maximum byte limit. +# +# 552 <foo@site.com>... Message is too large; 100000 bytes max +# +# Input +# +# (none) This recipe examines headers and body to see if it's daemon +# bounce. +# +# Output +# +# o stat, set to "daemon" if message was handled. +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv-daemon.rc" +dummy = " +======================================================================== +$id: init: Check if this is bounced server message. +" + +stat = "" +msg = "" +subject = "" +to = "" + + +# Hm, We wouldn't even need the FROM_DAEMON test, because +# X-Loop is supposed to be unique. Because we expect to see bounce +# message the original message is included in the body, that's by "B ??" +# search. +# +# Handle only some daemon messages, notify the recipient about an error. + +dummy = "$id: The pm-javar.rc daemon status is: $JA_FROM_DAEMON" + +:0 +*$ $JA_FROM_DAEMON +*$ B ?? ^X-Loop: $JA_SRV_XLOOP +{ + :0 + * B ?? ^Subject:\/.* + { + subject = $MATCH; + } + + :0 + * B ?? ^To:\/.* + { + to = $MATCH + } + + :0 + *$ B ?? ()\/^$d+ .*Message is too large.* + { + msg = $MATCH + } + + :0 + * msg ?? [a-z] + { + stat = "daemon"; + + # Add new header telling that this bouce was auto-notified back + # to original reqeastor. + + :0 fhw + | $FORMAIL -I "X-Mpfs-daemon: [notified $to] $msg" + + + # make sure To has "@" character, otherwise picking of + # "To" from the body failed. + + :0 wc + * to ?? @ + | ( $FORMAIL \ + -rtk -p " >" \ + -I "To: $to" \ + -I "X-Loop: $JA_SRV_XLOOP " \ + -I "Subject: $msg" \ + ; \ +echo "Your account didn't accept the requested file. " ; \ +echo "Get server help file with 'send help' and see conversion types etc."; \ +echo "Or notify the File Server admin"; \ + ) | $SENDMAIL; \ + echo " [ja-srv; daemon $to; $msg;]" >> $JA_SRV_LOG; + + } + +} + +dummy = "$id: end: STATUS = $stat" + + +# End of pm-jasrv-daemon.rc diff --git a/share/procmail/pm-jasrv-err.rc b/share/procmail/pm-jasrv-err.rc @@ -0,0 +1,101 @@ +# pm-jasrv-err.rc -- send message, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This module is part of the MPFS file server. +# Ssnd error notice: file didn't exist. +# +# Input +# +# o FILE, file or command that did ot exist. +# +# Output +# +# o fld, additional field to be added to the saved mbox log message +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv-err.rc" +dummy = " +======================================================================== +$id: init: +" + +# File didn't exist, send notice. + +stat = "error-NotExist $FILE" + + +# ....................................................... record-log ... +# Theese are no-op. We just want to leave trace to the log file TO whom +# the message was sent. + +:0 +* ^To:\/.* +{ } + +:0 +* ^From\/.* +{ } + +# ................................................... Subject-notify ... + +header + +:0 +* JA_SRV_F_SUBJ_NOTIFY ?? yes +{ + header = "-ISubject: Re: $JA_SRV_SUBJECT [$stat]" +} + + +# ............................................................. send ... +# We use "c" to copy this request to out log mbox + + +dummy = "$id: HEADER: $header" + +:0 fbw +* header ?? [a-z] +| $FORMAIL ${header+"$header"} + + +:0 hwic: +| ( \ + $CAT - | $FORMAIL -I "From "; \ + echo "[srv-err] file `$FILE' does not exist."; \ + echo "The file may have been renamed or removed."; \ + echo "Please use 'send help'"; \ + ) | \ + $SENDMAIL ; \ + echo " [ja-srv; $stat; $to;]" \ + >> $JA_SRV_LOG; + +# ....................................................... extra-info ... +# We don't want user to see this because here is directory info +# This information is for ourself only. + +fld = "-A$JA_SRV_X_HEADER: $stat; $file; $JA_SRV_FROM" + + +dummy = "$id: end:" + + +# Enf of pm-jasrv-err.rc diff --git a/share/procmail/pm-jasrv-from.rc b/share/procmail/pm-jasrv-from.rc @@ -0,0 +1,103 @@ +# pm-jasrv-from.rc -- compose reply, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of the MPFS file server. +# Compose headers for reply message using `formail' -rt. +# +# Here is dry run example to test this module +# +# % procmail DEFAULT=/dev/null VERBOSE=on LOGABSTRACT=all \ +# FORMAIL=/opt/local/bin/formail \ +# JA_SRV_FORMAIL_FROM=me@here \ +# JA_SRV_CONTENT_TYPE=content-type \ +# JA_SRV_XLOOP=xloop \ +# $HOME/pm/pm-jasrv-from.rc \ +# < $HOME/any-sample.email +# +# Input +# +# o JA_SRV_FORMAIL_FROM, JA_SRV_XLOOP +# o JA_SRV_CONTENT_TYPE +# +# Output +# +# (none) +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv-from.rc" +dummy = " +======================================================================== +$id: init: +" + + +# add initial headers. The MIME headers may +# very well change later on + +dummy = "$id: Preparing reply." + +# This a bit special. When we construct reply to user with formail +# -rt, the From address would include the address where your +# server is. That't usually fine. +# +# But if you have some virtual or `contact' address that you want +# poeple to use instead of the current address where are, then you +# want to rewrite the `From' field. Hm. You could also add Reply-To, +# but suppose you don't want to show the real address at all. +# +# If you set JA_SRV_FORMAIL_FROM variable, then the email address +# appears in From field. If you don't define the variable, a normal +# formail -rt is used. +# +# Adding "From:" automatically adds From_, get rid of it too +# +# NOTE: We must put something into `header'; because the above formail +# fails if the header contains only "". In here we duplicate the +# harmless call to "-aMessage-ID:" + +header = "-aMessage-ID:" + +:0 +* JA_SRV_FORMAIL_FROM ?? [a-z] +{ + header = "-AFrom: $JA_SRV_FORMAIL_FROM" +} + + +:0 fhw +| $FORMAIL -rt \ + -a Message-ID: \ + -A "Mime-Version: 1.0" \ + -A "Content-Type: $JA_SRV_CONTENT_TYPE" \ + -A "Content-Transfer-Encoding: 7bit" \ + -A "Precedence: bulk" \ + -A "X-Loop: $JA_SRV_XLOOP" \ + -I "From " \ + ${header+"$header"} + + +# test = `$CAT - >> $HOME/tmp/srv.tst` + + +dummy = "$id: end:" + +# Enf of pm-jasrv-from.rc diff --git a/share/procmail/pm-jasrv-msg.rc b/share/procmail/pm-jasrv-msg.rc @@ -0,0 +1,77 @@ +# pm-jasrv-msg.rc -- send message, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of the TPFS or MPFS file server. Run $CODE +# and return resutls to to user. Subroutine is meant to be used for +# informational messages. +# +# Input +# +# o code, code to run in shell +# o stat, status message for user +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv-msg.rc" +dummy = " +======================================================================== +$id: init: +" + + + +head = "" + + +dummy = "$id: Check if subject notify is on " + +:0 +* JA_SRV_F_SUBJ_NOTIFY ?? yes +{ + header = "-ISubject: Re: $JA_SRV_SUBJECT [$stat]" +} + +:0 fhw +| $FORMAIL \ + ${header+"$header"} \ + -A "$JA_SRV_X_HEADER: $stat $FILE" -I "From " + + +:0 # Just for logging purposes, record TO in MATCH +* ^To:\/.* +{ } + +dummy = "$id: Running code [$code] and sending to [$MATCH]" + +:0 hwc: +| ( $CAT -; $code ) | \ + $SENDMAIL ; \ + echo " [ja-srv; $stat $FILE; $JA_SRV_FROM;]" \ + >> $JA_SRV_LOG; + +MBOX = $JA_SRV_MSG_MBOX +INCLUDERC = $JA_SRV_RC_MBOX + + +dummy = "$id: end:" + + +# Enf of pm-jasrv-msg.rc diff --git a/share/procmail/pm-jasrv-multi.rc b/share/procmail/pm-jasrv-multi.rc @@ -0,0 +1,136 @@ +# pm-jasrv-multi.rc -- send multipart MIME message, subroutine for FileSrv +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of MPFS file server. Send out FILE as +# multipart MIME message. The message will always be base64 +# encoded before sending. +# +# Input +# +# o JA_SRV_MIME_MULTI_SEND, command to feed the composed and message +# which will handle sending it as multipart MIME. +# o JA_SRV_MULTIPART_THRESHOLD is the hunk size for slitting mail. +# o FILE, only filename part. Included in MIME headers. +# o file, absolute path to send +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv-multi.rc" +dummy = " +======================================================================== +$id: init: +" + +fld = "" +ok = "no" +to = `$FORMAIL -rtzxTo:` # LOGFILE: To whom we're sending message + +# ........................................................ read file ... +# Read file and base64 encode it to BODY. Flag "yes" is everything is ok + +:0 fbw +| $CAT $file + +dummy = "$NL$id: Base64 encoding... $NL" + +:0 fbw +| $MIME_BIN_64_E + + :0 a + { + ok = "yes" + } + +# ............................................... error while base64 ... + + +:0 +* ok ?? no +{ + # Combine this message to previous field. See pm-tips.txt + + msg = "-AX-Error: $MIME_BIN_64_E failed. Notify server admin." + nl nl=${fld+"$NL"} fld="$fld${nl}$msg" + + # We might as well kill the body, because user + # doesn't want to receive binary (gzip) + + :0 fbw + | echo + + + :0 wc: $JA_SRV_LOG.$LOCKEXT + | $FORMAIL -I From ${fld+"$fld"} | $SENDMAIL; \ + echo " [ja-srv; $file; $JA_SRV_FROM;]" \ + >> $JA_SRV_LOG; + +} + +# ................................. base64 succeeded, send multipart ... + +:0 +* ! ok ?? no +{ + dummy = "$NL$NL$id: Sending multipart message:$NL $to$NL $file$NL" + + + type = "application/octet-stream" + coding = "base64" + comment = "This is MIME multipart. You must assemble every part$NL\ + together in sequential order. Then decode, cat BODY| mmencode -u > $FILE$NL" + + :0 fhw + | $FORMAIL \ + -I From \ + -I "Content-Type: $type" \ + -I "Content-Transfer-Encoding: $coding" \ + -I "Content-Disposition: attachment; filename=\"$FILE\"" \ + -I "Content-Description: $comment" + + :0 wc + | $JA_SRV_MIME_MULTI_SEND + + :0 a hwic: + | echo " [ja-srv; $type $file; $JA_SRV_FROM;]" \ + >> $JA_SRV_LOG; + + :0 E + { + dummy = "$NL$NL$id: $JA_MSG_ERROR ERROR While calling $JA_SRV_MIME_MULTI_SEND $NL" + + :0 hwic: + | echo " [ja-srv; SENDMAIL FAIL $type $file; $JA_SRV_FROM;]" \ + >> $JA_SRV_LOG; + } + +} + + + +# kill body contents before saving to log + +:0 fbwi +| echo + + +dummy = "$id: end:" + +# Enf of pm-jasrv-multi.rc diff --git a/share/procmail/pm-jasrv-req.rc b/share/procmail/pm-jasrv-req.rc @@ -0,0 +1,85 @@ +# pm-jasrv-req.rc -- server request check, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of the MPFS file server. +# Check if file server request is on the JA_SRV_SUBJECT and +# do case or incasensitive check. +# +# To Dry run this module use following skeleton. Substitute keywods +# as needed to reflect your system setup: +# +# % procmail DEFAULT=/dev/null VERBOSE=on LOGABSTRACT=all \ +# PMSRC=$HOME/txt JA_SRV_CMD_STRING=send \ +# JA_SRV_SUBJECT="send newbie_article.rtf noconv" \ +# txt/pm-jasrv-req.rc < ~/test.mail +# +# Input +# +# o JA_SRV_F_CMD_CASE_SENSITIVE; if "yes" then server request +# is case sensitive. +# o JA_SRV_FORMAIL_FROM. the email From field +# +# Output +# +# o stat, set to "ok" if request is accepted +# +# Change Log (none) + +# ............................................................ &init ... +# - no leading periods(.) are accepted in the filename +# - Invalid filename access "../" is tested later + +id = "pm-jasrv-req.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + + +regexp = "^^$s*$JA_SRV_CMD_STRING$s+$NSPC+" +subj = $JA_SRV_SUBJECT +stat = "" + + +dummy = "$NL$id: do we use case sensitive request keyword?$NL" + +:0 +* JA_SRV_F_CMD_CASE_SENSITIVE ?? yes +{ + flags = "D" +} + +dummy = "$NL$is: check if this is request $NL" + +:0 $flags +*$ subj ?? $regexp +{ + stat = "ok" +} + +dummy = "$id: end:" + + +# Enf of pm-jasrv-req.rc diff --git a/share/procmail/pm-jasrv-send.rc b/share/procmail/pm-jasrv-send.rc @@ -0,0 +1,333 @@ +# pm-jasrv-send.rc -- server request check, subroutine for File Server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine is part of the MPFS file server. +# Send the requested file. You can dry-run test this module with +# following command: a) make sure that $HOME/test conatins any simple +# email message b) define FORMAIL if it isnot found from path. +# +# % procmail DEFAULT=/dev/null VERBOSE=on LOGABSTRACT=all \ +# PMSRC=$HOME/txt JA_SRV_LOG=/dev/null \ +# FORMAIL=/opt/local/bin/formail \ +# file=$HOME/test FILE=test WORD=WORD JA_SRV_FROM=foo@bar \ +# SENDMAIL="tee -a $HOME/test.send" txt/pm-jasrv-send.rc < ~/test +# +# Note: +# +# The MIME headers here selected previously were: +# +# Content-type: application/octet-stream +# Content-transfer-encoding: x-gzip64 +# +# But Defining own CTE such as x-gzip64 is strongly discouraged by +# the MIME RFC's. Most e-mail clients would be at a loss on how to +# handle these. Many would just bomb out and not even give you the +# opportunity to save it to a file. A more correct MIME type is this, +# which is now used: +# +# Content-type: application/x-gzip +# Content-transfer-encoding: base64 +# +# Input +# +# o `FILE' is the filename(chdir to directory is already done) +# `file' is _absolute_ filename +# `WORD' is next word from subject line after FILE word. +# o JA_SRV_CMD_STRING is flag +# o JA_SRV_F_SUBJ_NOTIFY is flag +# +# Output +# +# o FILE_ERROR is set to "yes" if file is not found. +# +# Change Log (none) + +# ............................................................ &init ... + + +id = "pm-jasrv-send.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* IS_READABLE ?? ^^^^ +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + + +stat = "" +FILE_ERROR = "" + +:0 +* FILE ?? [a-z0-9] +* file ?? [a-z0-9] +*$ ? $IS_READABLE $file +{ + stat = "$JA_SRV_CMD_STRING" + + # no header notify here, because this is ok situation, + # Some MUA's thread the sending according to Subject, + # so keep subject clean. (it already has Re:) + # + # In error situations, it's desirable to Subject line + # to tell the condition right away. + +# :0 fh +# * JA_SRV_F_SUBJ_NOTIFY ?? yes +# | $FORMAIL -I"Subject: Re: $JA_SRV_SUBJECT [$stat]" + + # ...................................................... gzip ... + # How should we send the file? + # - If FILE matches list of files in JA_SRV_XGZIP_REGXP + # then it is send in compresses base64 gzip format, because + # it's too big. + # + # There must be no "noconv" word request from the user + # + # - For other files, send it without conversions. + + dummy = "$NL$NL$id: Setting defaults and clearing variables $NL" + + comment = "regular file" + type = "$JA_SRV_CONTENT_TYPE" + coding = "$JA_SRV_CONTENT_ENCODING" + convert = "" + xgzip = "" + + # ........................................................ xgzip ... + + dummy = "$NL$NL$id: check that there is no noconv $NL" + + :0 + * JA_SRV_XGZIP_REGEXP ?? [a-z] + *$ FILE ?? $JA_SRV_XGZIP_REGEXP + * ! WORD ?? noconv + { + xgzip = "yes" + } + + dummy = "$NL$NL$id: Has user requested gzip: $WORD $NL" + + :0 + * WORD ?? ^^(gz|gzip)^^ + { + xgzip = "yes" + } + + dummy = "$NL$NL$id: Was xgzip YES? $NL" + + + :0 + * xgzip ?? yes + { + convert = "gzip-base64" + comment = "To decode, cat BODY| mmencode -u| gzip -d > $FILE$NL\ +If you don't have MIME capable MUA (Email agent) or if you don't have$NL\ +mmencode, you can request file without conversion with subject:$NL\ +'send $FILE noconv'" + type = "application/x-gzip" + stat = "$stat gzip" + coding = "base64" + } + + # But, do always "gzip" for these files, even if "noconv" + # was requested. + + dummy = "$NL$NL$id: Decide if we convert to base64 -- $FILE $NL" + + :0 + * JA_SRV_BASE64_ALWAYS ?? [a-z] + *$ FILE ?? $JA_SRV_BASE64_ALWAYS + { + xgzip # kill variable + convert = "base64" + comment = "To decode, cat BODY| mmencode -u > $FILE$NL" + type = "application/octet-stream" + stat = "$stat gzip" + coding = "base64" + + } + + # .................................................... MIME-TYPE ... + + :0 + * FILE ?? \.(doc|rtf)^^ + { + type = "application/winword" + } + + :0 + * FILE ?? \.zip^^ + { + type = "application/zip" + } + + :0 + * FILE ?? \.gz^^ + { + type = "application/gzip" + } + + + # ...................................................... headers ... + # Prevent calling shell layer (because there is ; in the command) + # This speeds up procmail + + saved = $SHELLMETAS + SHELLMETAS + + # Complete the MIME headers: user can download the file if he + # has mime aware MUA + + :0 fhw + | $FORMAIL \ + -I "Content-Type: $type" \ + -I "Content-Transfer-Encoding: $coding" \ + -I "Content-Disposition: attachment; filename=\"$FILE\"" \ + -I "Content-Description: $comment" + + SHELLMETAS = $saved + + + # ................................................. &sending ... + # pick the right sending method + + dummy = "$NL$NL$id: Sending $file $convert $NL" + + # See procmail tips page. We stack all headers to variable *f* + # and avoid calling multiple `formail' processes. + + fld # kill variable + + :0 + * convert ?? [a-z] + { + ok = "yes" + error = "no" + + :0 # insert file "as is" + * ! convert ?? gzip + { + :0 fbw + | $CAT $file + + :0 e + { + error = "yes" + } + } + + :0 + * convert ?? gzip + { + :0 fbw # gzip while insert + | $GZIP -9c $file + + :0 e + { + error = "yes" + } + } + + + :0 + * error ?? yes + { + # If previous command failed + # Add error message to separate header + + ok = "no" + fld = "-AX-Error: $GZIP failed, try with noconv." + } + + # ............................................... base64 ... + + :0 fbw + * convert ?? base64 + * ok ?? yes + | $MIME_BIN_64_E + + :0 E + * ok ?? yes + { + # Combine this message to previous field. See pm-tips.txt + + msg = "-AX-Error: $MIME_BIN_64_E failed. Try with noconv." + + nl + nl = ${fld+"$NL"} + + fld = "$fld${nl}$msg" + + comment = "" + + # We might as well kill the body, because user + # doesn't want to receive binary (gzip) + + :0 fbw + | echo + } + } + :0 E fb wi + | $CAT $file + + + # This is no-op as far as this recipe is concerned. + # If you need to examine logs, you will see the TO address + # where the message was sent in MATCH. + + :0 + * ^To:\/.* + { } + + dummy = "$id: programs: $FORMAIL $SENDMAIL" + dummy = "$NL$NL$id: Extra fields: $fld $NL" + + :0 fbw + * fld ?? [a-z] + | $FORMAIL ${fld+"$fld"} + + + :0 wc: $JA_SRV_LOG$LOCKEXT + | $FORMAIL -I "From " | $SENDMAIL; \ + echo " [ja-srv; $convert $FILE; $JA_SRV_FROM;]" \ + >> $JA_SRV_LOG; + + # kill body contents before saving to log + + :0 fb wi + | echo + + # Continue to the end + + fld = "-A$JA_SRV_X_HEADER: $stat; $JA_SRV_FILE_DIR/$FILE" + +} + +:0 E +{ + FILE_ERROR = "yes" +} + +dummy = "$id: end:" + +# Enf of pm-jasrv-send.rc diff --git a/share/procmail/pm-jasrv.rc b/share/procmail/pm-jasrv.rc @@ -0,0 +1,704 @@ +# pm-jasrv.rc -- MIME capable Procmail File server +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This is the MPFS (Mime Procmail File Server) and it can send MIME +# compliant messages with command +# +# "send <ITEM> [WORD1] [WORD2]" +# +# Usually only the ITEM arg is used, and the rest of the words are for +# special uses like password and preventing file encoding. A typical +# request looks like: +# +# Subject: send help # ask for file named 'help' +# +# Overview of features +# +# o MIME types gzip and text/plain are supported. +# o .gz .zip etc. files are sent out as base64 attachments +# o .gz .tar.gz files that exceed 100K are sent out as MIME multiparts +# o requires procmail 3.11+ and MATCH operator \/ +# o requires `mmencode' and `gzip' executables to be present in PATH. +# +# Install: server file directory +# +# You have to create a directory for the server where the files are kept. +# Usually I don't put the files there, but whenever I want to make a +# file available, I draw a hard or softlink to the real file. +# +# % mkdir $HOME/pm-server +# +# # Repeat this as needed for files you want to put available +# +# % cd $HOME/pm-server +# % ln -s $HOME/txt/interesting-file.txt interesting-file.txt +# +# You define the server directory by setting +# +# JA_SRV_FILE_DIR = $HOME/pm-server +# +# The short server log is written to file pointed by this variable: +# +# JA_SRV_LOG = $HOME/pm-server.log +# +# The incoming "send" requests are stored to mailbox pointed by +# following variable. The default value is /dev/null, but +# you may want to set it to ~/Mail/spool/log.srv.spool which can be +# used read as a newsgroup by Emacs Gnus [In Gnus create newsgroup with +# `G` `m' `nnml' `log.srv'] +# +# JA_SRV_MSG_MBOX +# +# Install: special files +# +# Tweak this variable to commands you want to allow shell to execute +# in server's directory. This tells when <ITEM> "ls" means command +# instead of file +# +# JA_SRV_SH_COMMAND = "^(ls|what)$" +# +# That means that request like this: +# +# Subject: send ls # run "ls" command and return results +# +# Be sure that the commands exist in your system. See man pages for +# more if you want to know what these commands do. Commands cannot +# take switches currently for security reasons. E.g. if you want to +# give access to "ls -la" listing, put a file "ls-la.txt" available +# in the directory, user can get it with "send ls-la.txt" +# +# ls -- list directory +# file -- print file type information. +# what -- prints all @(#) tags from files +# ident -- print all $ $ tags from files +# +# Install: file `help' +# +# Users want to get a help file with message "send help" and the +# `help' is just a file in your server directory. Be sure to supply it +# prior to any other files. You can always draw a link to a file if you +# don't want to name it that way (e.g. if you keep several server help +# files in a RCS tree) +# +# # draw symlink to `help' +# +# % ln -s $HOME/txt/srv-public-hlp.txt $HOME/server/help +# +# Basic usage in details +# +# The server accepts command in format +# +# "send <ITEM> [CMD|PASSWORD]" +# +# Where ITEM can be any name as long as it starts with [^ .]. The +# regexp says: Anything goes as long as FILE does _not_ start with +# space or period. This gives you quite a much freedom to construct +# filenames. if you want to hand out file: +# +# .procmailrc +# +# You can't. Instead make a link to point to plain "procmailrc" +# without the leading period. There is also additional checks +# against possible security threat "../" like below; user can't +# request such file. +# +# ../../../gotcha or dir/../../gotcha +# +# The filename cannot contain special characters like [*?<>{}()]. +# +# Advanced usage +# +# [conversions] +# +# If some of your files are big, it makes sense to send them in +# compressed base64 format; which in MIME world is called content-type +# gzip. You can set a regexp to enforce encoding for your big +# files before they are sent to user. The following setting will send +# all text files in compressed format to user. +# +# JA_SRV_XGZIP_REGEXP = "\.txt" +# +# When the message is composed a header is inserted into the message +# telling how the message is to be decoded, in case user doesn't have +# decent MUA that can handle the MIME type: +# +# X-comment: To decode, cat msg| mmencode -u| gzip -d > test.txt +# +# [noconv and gz] +# +# The `WORD1' parameter after the `FILE' is optional and user can +# override base64 encoding and request plain file if he uses word +# "noconv". +# +# Subject: send <FILE> [noconv|gzip] +# +# However, there are files where `noconv' must not be obeyed, like +# the compressed packages that you have put available in .zip, .gz, +# .tar.gz or .tgz (GNU tar) format. Following variable controls +# when file is always sent as base64: +# +# JA_SRV_BASE64_ALWAYS +# +# If the `WORD1' is "gz" or "gzip", then the gzip is explicitly +# requested, This may be desirable, because some of the text files in +# the server directory may be big and some accounts don't accept big +# messages. A typical bounce looks like: +# +# 552 <foo@site.com>... Message is too large; 100000 bytes max +# 554 <foo@site.com> Service unavailable +# +# These kind of file server bounce messages are handled in separate +# module which notifies the user that his account didn't accept the +# sent file. +# +# [case sensitivity] +# +# By default the request word ("send") and ITEM (filename) are not +# case sensitive, unless you set these flags: +# +# JA_SRV_F_CMD_CASE_SENSITIVE = "yes" +# JA_SRV_F_FILE_CASE_SENSITIVE = "yes" +# +# If values are "no", then these are identical commands: +# +# Subject: Send Help +# Subject SEND HELP +# +# Multi part mime messages +# +# If you want to deliver big files, you better be sure not to send +# them as a big file. That blocks the connection between every host +# along the path that the big file is transferred. The +# solution is to use MIME multi parts that can be assembled back in +# the receiving MUA. (In case you don't have multi part assembler +# receive Perl script to do it). +# +# MIME multiparts are sent out if +# +# o Filename matches JA_SRV_BASE64_ALWAYS, typically tar.gz, zip +# o Filesize is bigger than JA_SRV_MULTIPART_THRESHOLD, where +# default chunk size is 100K. +# +# When a file meets these criteria, it is read to the `BODY' of message +# and base64 encoded. This all happens in memory, so watch +# procmail logs to see if any problems with very big files. (>30Meg). +# Next, if the base64 conversion succeeded, the composed is handed +# to +# +# JA_SRV_MIME_MULTI_SEND +# +# Which does the actual delivery and splitting. The default program +# used is `splitmail'. Make sure you have it or substitute the +# program with some equivalent one. +# +# Stopping server +# +# Sometimes you're making rearrangements in you file directory or +# doing some other maintenance and you are unable to respond to `send' +# requests. You can stop the server by setting +# +# JA_SRV_IN_USE = "no" +# +# And when you want to enable the server again; just comment out the +# statement or assign `yes'. [The default is `yes']. When this +# variable is set to `no', the server sends a message from following +# variable as a response to any "send" request. +# +# JA_SRV_IN_USE_NO_MSG +# +# Using password to validate file requests +# +# You should be aware that this file server's implementation is public +# in nature. Anyone who asks for a file is allowed to get it. But it +# would be good if you could limit the access to documents with some +# simple way, like if you set up two file servers (see next chapter) +# where one is public and the other is interesting only to group of +# people. You can define a string that must be found in Subject field +# by setting the following variable +# +# JA_SRV_PASSWORD = ".*" # default +# +# The default value will match anything in the subject, thus making the +# server public. But if you set it like this +# +# JA_SRV_PASSWORD ".*123" +# +# Then string "123" must be there somewhere in the line, like here +# +# Subject: send <FILE> 123 +# +# Yes, "123" is actually a CMD definition, but it doesn't matter +# because there is no CMD 123. Subject now matches password and the +# server can be accessed. Of course the following is valid too. +# +# Subject: send <FILE> noconv 123 +# +# If the password was wrong, server won't tell it. The message just +# lands to your mailbox in that case and you can investigate who +# tried to access the restricted server. +# +# Changing server's command string (multiple servers) +# +# The default command string is "send", but you can change it and thus +# create multiple services. Here is one example, where you have set up +# two file servers where each has its own directory. +# +# # The public server +# +# JA_SRV_CMD_STRING = "send" +# JA_SRV_FILE_DIR = $HOME/server/public +# INCLUDERC = $HOME/procmail/pm-jasrv.rc +# +# # Company server, only interests fellow workers. +# # Here "xyz-send" is just magic server request string. +# # Notice case sensitivity settings. +# +# JA_SRV_F_CMD_CASE_SENSITIVE = "yes" +# JA_SRV_CMD_STRING = "xyz-send" +# JA_SRV_PASSWORD = ".*12qw" +# JA_SRV_FILE_DIR = $HOME/server/public/xyz-dir +# INCLUDERC = $HOME/procmail/pm-jasrv.rc +# +# Notes from the author +# +# [basic Mime type note] +# +# All basic files that you send must be US-ASCII, 7bit. At least that +# is the default MIME type used. See `JA_SRV_CONTENT_TYPE'. I once +# received following message back +# +# ----- Transcript of session follows ----- +# 554 <foo@bar>... Cannot send 8-bit data to 7-bit destination +# 501 <foo@bar>... Data format error +# +# because in the previous releases, the MIME type headers were not +# in the message saying that the content really was plain 7bit ascii. +# +# [Sending the file as is] +# +# Note, that the file is included "as is" without any extra +# *start-of-file* or *end-of-file* tags. This is possible, because +# the file is sent in MIME format. +# +# [Using one line log entry] +# +# It may look very spartan to print a single line log entry. You see +# messages like above in the file server log. Using one line entry +# instead of multi line announcements makes it possible to write a small +# perl tool to parse information from a single line. If you get many +# file server messages per day, it quicker to look at the single line +# entries too. +# +# [ja-srv1; sh file; Foo Bar <foo@site.com>;] +# [ja-srv1; send xxx-file.txt; Foo Bar <foo@site.com>;] +# | +# Server's request keywords (you may have multiple servers) +# +# [wish list] +# +# (*) MIME multipart message's mime headers may need some adjustments. +# +# (*) I rely on simple regexp to send out base64 or gzip files. +# The natural extension would be to use file size threshold: if file +# is bigger than N bytes, send it out with gzip. And further: if +# file is more than NN bytes, send it out as multi part MIME. +# +# (*) In fact there is a slight mime type errors: .zip files +# should be send as application/zip. If you have experience with the +# mime types, please contact me and help me to sort out proper +# mime headers. +# +# Required settings +# +# PMSRC must point to the source directory of procmail code. This +# subroutine will include many pm-jasrv-*.rc modules and other files +# from there. +# +# Please test the File Server in your environment before you start +# using it for every day. For example I had some weird local problem +# where PATH had /usr/contrib/bin/ where gzip was supposed to be, but +# in spite of my tries procmail didn't find it along the path. Don't +# ask why. I now use absolute binary name: +# +# GZIP = /usr/contrib/bin/gzip +# +# In addition, if your messages are not sent to recipient, but you +# get daemon message: +# +# ... Recipient names must be specified +# +# That's because you have setting SENDMAIL="sendmail"; which is not +# enough. It must be +# +# SENDMAIL = "sendmail -oi -t" +# +# Usage example +# +# This is my .procmailrc installation. Notice that the file server +# code is used only if you get "send" request. On the other hand, this +# double wrapping is not all necessary, you could as well rely on the +# File server's capability to detect SEND request. +# +# +# PMSRC = $HOME/pm # directory where the procmail rc files are +# RC_FSRV = $PMSRC/pm-jasrv.rc +# +# mySavedLOGFILE = $LOGFILE # record file server actions elsewhere +# LOGFILE = $PMSRC/pm-jasrv.log +# +# # Listen "send" requests. +# :0 +# * ^Subject: +send\> +# { +# JA_SRV_FILE_DIR = $HOME/fsrv # Where to get the files +# JA_SRV_LOG = $HOME/fsrv.log # Write log here +# INCLUDERC = $RC_FSRV # Use file server now +# } +# +# LOGFILE = $mySavedLOGFILE +# +# Change Log (none) + +# ............................................................ &init ... + +id = "pm-jasrv.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# Too many people forget that SENDMAIL definition must include flags -oi -t + +:0 +* ! SENDMAIL ?? (-) +{ + LOG = "(jasrv) ** ERROR: please make sure SENDMAIL contains flags -oi -t" + LOG = "(jasrv) ** ERROR: please see pm-javar.rc for SENDMAIL definition" + HOST # Quit immediately +} + +# .......................................................... &public ... +# Public variables. User configurable section. +# +# ** DO NOT MAKE MODIFICATIONS TO THIS FILE ** +# Copy variables to your ~/.procmailrc and make changes there. +# Recall the 'Installation example' + +# ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... . flags ... + +# Notify errors on returned Subject line? +# - Always adds message to the body too. + +JA_SRV_F_SUBJ_NOTIFY = ${JA_SRV_F_SUBJ_NOTIFY:-"yes"} + +# Should Command be case sensitive? How about file names? + +JA_SRV_F_CMD_CASE_SENSITIVE = ${JA_SRV_F_CMD_CASE_SENSITIVE:-"no"} +JA_SRV_F_FILE_CASE_SENSITIVE = ${JA_SRV_F_FILE_CASE_SENSITIVE:-"no"} + +# Should the initial "send" request be copied to folder "as is" + +JA_SRV_F_MBOX_REQUEST = ${JA_SRV_F_MBOX_REQUEST:-"yes"} + +# And how about our answer to the request? + +JA_SRV_F_MBOX_REQUEST_SENT = ${JA_SRV_F_MBOX_REQUEST_SENT:-"no"} + +# ... ... ... ... ... ... ... ... ... ... ... ... ... ... files-dirs ... + +JA_SRV_TMP_DIR = ${JA_SRV_TMP_DIR:-$TMPDIR} +JA_SRV_FILE_DIR = ${JA_SRV_FILE_DIR:-"$HOME/pm-server"} +JA_SRV_LOG = ${JA_SRV_LOG:-"$HOME/pm-srv.log"} +JA_SRV_MSG_MBOX = ${JA_SRV_MSG_MBOX:-"/dev/null"} + +# ... ... ... ... ... ... ... ... ... ... ... ... ... .. basic-config ... + +JA_SRV_CMD_STRING = ${JA_SRV_CMD_STRING:-"send"} +JA_SRV_PASSWORD = ${JA_SRV_PASSWORD:-".*"} + + +# From: header in OUTGOING MAIL +# +# - This is the "From:" header that is set when you send a reply +# - You may want to set this to different address than your regular +# login address. + +JA_SRV_FORMAIL_FROM = ${JA_SRV_FORMAIL_FROM:-""} + +JA_SRV_XGZIP_REGEXP = ${JA_SRV_XGZIP_REGEXP:-"dummy-regexp"} +JA_SRV_BASE64_ALWAYS = ${JA_SRV_BASE64_ALWAYS:-"\.(zip|tar|tgz|gz)$"} + +JA_SRV_X_HEADER = ${JA_SRV_X_HEADER:-"X-Mpfs-Info"} +JA_SRV_SH_COMMANDS = ${JA_SRV_SH_COMMANDS:-"^(ls|what|ident|file)$"} + +# ... ... ... ... ... ... ... ... ... ... ... ... ... ... .. headers .. + +# Headers read from INCOMING MAIL +# +# We could do ${JA_SRV_FROM:-`$FORMAIL -xFrom:`} here, but +# this way we prevent calling extra formail processes. + +JA_SRV_SUBJECT = ${JA_SRV_SUBJECT:-""} +JA_SRV_FROM = ${JA_SRV_FROM:-""} + +:0 +* JA_SRV_SUBJECT ?? ^^^^ +* ^Subject:\/.* +{ + JA_SRV_SUBJECT = $MATCH +} + + +:0 +* JA_SRV_FROM ?? ^^^^ +* ^From:\/.* +{ + JA_SRV_FROM = $MATCH +} + +# ... ... ... ... ... ... ... ... ... ... ... ... ... .. maintenance .. + +JA_SRV_IN_USE = ${JA_SRV_IN_USE:-"yes"} +JA_SRV_IN_USE_NO_MSG = ${JA_SRV_IN_USE_NO_MSG:-\ +"File server is not functional at the moment due to maintenance."} + +# Could also be application/octet-stream for plain files + +JA_SRV_CONTENT_TYPE = ${JA_SRV_CONTENT_TYPE:-"text/plain; charset=US-ASCII"} +JA_SRV_CONTENT_ENCODING= ${JA_SRV_CONTENT_ENCODING:-"7bit"} + +# ................................................... multipart mime ... + +# If file is bigger than 100K, it is better that it is sent as mime multipart +# to save network connections. +# +# This applies to only files that match regexp JA_SRV_BASE64_ALWAYS + +JA_SRV_MULTIPART_THRESHOLD = ${JA_SRV_MULTIPART_THRESHOLD:-100000} + +# When the message has been composed, (file is in the body), it is +# handed to this program to do the actual mail split and sending. +# make sure you have this in your system. + +JA_SRV_MIME_MULTI_SEND = ${JA_SRV_MIME_MULTI_SEND:-"\ +splitmail -d -s $JA_SRV_MULTIPART_THRESHOLD"} + +# ..................................................... &subroutines ... +# You could replace any of these modules. +# if you change them and think the change would be useful for others too, +# send me an update or improvement. + +JA_SRV_RC_REQUEST = ${JA_SRV_RC_REQUEST:-$PMSRC/pm-jasrv-req.rc} +JA_SRV_RC_FROM = ${JA_SRV_RC_FROM:-$PMSRC/pm-jasrv-from.rc} +JA_SRV_RC_REPLY = ${JA_SRV_RC_REPLY:-$PMSRC/pm-jasrv-msg.rc} +JA_SRV_RC_CHECK = ${JA_SRV_RC_CHECK:-$PMSRC/pm-jasrv-check.rc} +JA_SRV_RC_SEND = ${JA_SRV_RC_SEND:-$PMSRC/pm-jasrv-send.rc} +JA_SRV_RC_SEND2 = ${JA_SRV_RC_SEND2:-$PMSRC/pm-jasrv-multi.rc} +JA_SRV_RC_SEND_ERR = ${JA_SRV_RC_SEND_ERR:-$PMSRC/pm-jasrv-err.rc} +JA_SRV_RC_DAEMON = ${JA_SRV_RC_DAEMON:-$PMSRC/pm-jasrv-daemon.rc} +JA_SRV_RC_MBOX = ${JA_SRV_RC_MBOX:-$PMSRC/pm-jastore.rc} + +# Please do _not_ change this variable; it is important the revision +# Number is shown there. And when you upgrade tp a new version, the +# variable has again the right version number. + +JA_SRV_XLOOP = ${JA_SRV_XLOOP:-\ +"Mime Procmail file server (MPFS $Revision: 2.9 $)\ +$JA_SRV_FORMAIL_FROM"} + +# .......................................................... &daemon ... + +INCLUDERC = $JA_SRV_RC_DAEMON # Is this bounce to FileServer msg? + +:0 # is stat is empty, everything is ok. +* stat ?? ^^^^ +{ + INCLUDERC = $JA_SRV_RC_REQUEST # Determine if we got request. +} + + +# ......................................................... &service ... + +:0 +* stat ?? ok +*$ ^Subject:.*$JA_SRV_PASSWORD +*$ ! ^X-Loop: $JA_SRV_XLOOP +{ + + # The nice thing is that the dummies show up in the VERBOSE log + # so you have a better clue where program is executing. + + dummy = "$NL$NL$id: copying original request to $JA_SRV_MSG_MBOX $NL" + + :0 c # Copy the original request + * JA_SRV_F_MBOX_REQUEST ?? yes + { + MBOX = $JA_SRV_MSG_MBOX + INCLUDERC = $JA_SRV_RC_MBOX + } + + INCLUDERC = $JA_SRV_RC_FROM # compose initial -rt reply + + # ......................................... &server-in-use-check ... + # Is the server up or down currently: If not; send message and quit. + + dummy = "$NL$NL$id: Is server down currently? $NL" + + :0 + * JA_SRV_IN_USE ?? no + { + stat = "NotInUse" + code = "echo \"$JA_SRV_IN_USE_NO_MSG\"" + INCLUDERC = $JA_SRV_RC_REPLY + } + + # "send THISFILE noconv" + # | | + # <FILE> WORD + # + + dummy = "$NL$NL$id: Subject: $JA_SRV_SUBJECT [reading the file] $NL" + FILE = "" + WORD = "" + + :0 + *$ JA_SRV_SUBJECT ?? $NSPC+$s+\/$NSPC+ + { + FILE = $MATCH + } + + :0 + *$ JA_SRV_SUBJECT ?? $NSPC+$s+$NSPC+$s+\/$NSPC+ + { + WORD = $MATCH + } + + # ....................................................... &check ... + + INCLUDERC = $JA_SRV_RC_CHECK + dummy = "$NL$NL$id: was $FILE a legal name $NL" + + :0 + * ! stat ?? ok + { + code = "echo \"$FILE is not acceptable\"" + INCLUDERC = $JA_SRV_RC_REPLY + } + + # ....................................................... &shell ... + + dummy = "$NL$NL$id: Check if FILE [$FILE] is allowed SHELL command $NL" + + :0 + * FILE ?? [a-z0-9] + *$ FILE ?? $JA_SRV_SH_COMMANDS + { + dummy = "$NL$NL$id: PATH used for shell command is [$PATH] $NL" + stat = "sh" + code = "$FILE * " + INCLUDERC = $JA_SRV_RC_REPLY + } + + # ........................................................ &send ... + + dummy = "$NL$NL$id: Test if file exists in server dir $NL" + + MAILDIR = $JA_SRV_FILE_DIR # chdir to the fileserver directory + file = $MAILDIR/$FILE # absolute filename + + :0 + * FILE ?? [a-z0-9] + *$ ? test -r $file + { + + dummy = "$NL$NL$id: Checking mime multipart $NL" + size = "" + + # only binary files are send out as multiparts. + # We call Perl only if we need the file size information + + :0 + * JA_SRV_BASE64_ALWAYS ?? [a-z] + *$ FILE ?? $JA_SRV_BASE64_ALWAYS + { + size = `$PERL -e 'print "", (stat shift @ARGV)[7]; exit' $file` + } + + # If we got the file size, (perl succeeded), and if the size is + # more than the threshold, send the file as MIME multipart. + # ELSE then send the file conventionally. + + :0 + * size ?? [0-9] + * JA_SRV_MULTIPART_THRESHOLD ?? [0-9] + *$ $size ^0 + *$ -$JA_SRV_MULTIPART_THRESHOLD ^0 + { + INCLUDERC = $JA_SRV_RC_SEND2 + } + + :0 E + { + INCLUDERC = $JA_SRV_RC_SEND + } + + } + :0 E + { + INCLUDERC = $JA_SRV_RC_SEND_ERR + } + + # ........................................................ &mbox ... + # Sink the "send FILE" msg + + dummy = "$NL$NL$id: Sinking request to $JA_SRV_MSG_MBOX $NL" + + :0 + * JA_SRV_F_MBOX_REQUEST_SENT ?? yes + { + # Do we have anything to report before sinking to folder? + # Add possible new fields ($fld) in one call. + + dummy = "$NL$NL$id: Anything to report in headers? $NL" + + :0 fhw + * ! fld ?? ^^^^ + | $FORMAIL ${fld+"$fld"} + + MBOX = $JA_SRV_MSG_MBOX + INCLUDERC = $JA_SRV_RC_MBOX + } + + # IF the answer was not filed (JA_SRV_F_MBOX_REQUEST_SENT == no) + # Then kill the message. + + :0 h + /dev/null +} + + +dummy = "$id: end:" + +# Enf of pm-jasrv1.rc diff --git a/share/procmail/pm-jastore.rc b/share/procmail/pm-jastore.rc @@ -0,0 +1,139 @@ +# pm-jastore.rc -- Store messagee to inbox or gzip inbox +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This subroutine stores the message to file pointed by `MBOX'. This +# subroutine is meant to be used with the the other general purpose +# includerc files. This makes it possible to have a centralized file +# storage handling for all your rc files. +# +# Regular user doesn't get much out of this rc unless he mixes both +# .gz and regular files in his .procmailrc +# +# R e p e a t: This module is basis for general purpose procmail +# rc plug-ins to strre message to mailbox pointed by some rc +# configuration variable. Normal user can simply say in his .procmailrc: +# +# :0: +# mail.private +# +# Required settings +# +# (none) +# +# Call arguments (variables to set before calling) +# +# `MBOX' must have been set to point to message storage. +# `MBOX_SUFFIX' is extension added to MBOX. Default is none. +# `MBOX_MH' if "yes" then deliver to MH mailbox with +# `MBOX_MH_CMD' which is "rcvstore" by default. +# +# o message is delivered to MH mailbox using `MBOX_MH_CMD' +# +# otherwise +# +# o If MBOX is `some.mbox' the message is stored as is. +# o If MBOX is `some.mbox.gz' the message is gzipped to folder. +# o If MBOX is `some-dir/.' then deliver as individual files +# +# Example usage +# +# $RC_MBOX = $PMSRC/pm-jastore.rc +# +# :0 +# * condition +# { +# MBOX = $HOME/Mail/spool/junk.mbox INCLUDERC = $RC_MBOX +# } +# +# Change Log: (none) + +# ............................................................ &init ... + +id = "pm-jastore.rc" +dummy = " +======================================================================== +$id: init: +" + + +# ........................................................... &do-it ... +# make sure you define MBOX before calling this module. + +:0 h +* MBOX ?? /dev/null +/dev/null + +:0 E +* MBOX ?? [a-z] +{ + + MBOX_SUFFIX = ${MBOX_SUFFIX:-""} + MBOX_MH = ${MBOX_MH:-"no"} + MBOX_MH_CMD = ${MBOX_MH_CMD:-"rcvstore"} + lock = "$MBOX$LOCKEXT" + + :0 fhw # Add possibly missing From_ line + * ! ^From + + | $FORMAIL + + dummy = "pm-jastore.rc: testing MH mbox" + + :0 + * MBOX_MH ?? yes + { + # Do we need lock for MH ? + + :0 w: $lock + | $MBOX_MH_CMD $MBOX + } + :0 E + { + + dummy = "pm-jastore.rc: testing compressed mbox" + + :0 w: $lock + * MBOX ?? \.gz + | $GZIP -9fc >> $MBOX + + # Whether it is regular mbox or directory, this + # will deliver the message to it + + :0 E + { + + dummy = "pm-jastore.rc: if empty MBOX_SUFFIX (ordinary mbox)" + + :0 : + * MBOX_SUFFIX ?? ^^^^ + $MBOX + + :0 E: + $MBOX$MBOX_SUFFIX + } + +} + +:0 E +{ + dummy = "pm-jastore.rc: ***** WARNING - MBOX variable is empty ******" +} + +dummy = "$id: end:" + +# pm-store.rc ends here diff --git a/share/procmail/pm-jasubject.rc b/share/procmail/pm-jasubject.rc @@ -0,0 +1,573 @@ +# pm-jasubject.rc -- Subject field cleaner and canonicalizer (Re:) +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# _NOTE:_ If you receive RFC 2047 encoded Subject headers like +# "Subject: =?ISO-8859-1?Q?=C4hnlichkeiten_von_=DCbungen?=", you +# must first decode it before using this subroutine. Feed the +# message to `pm-jamime-decode.rc' first. +# +# There are many different Email programs out there that add their +# own `reply' characters to the subject field. The most sad programs +# come usually from PC platform. Eg. Microsoft has gained a lot of +# bad reputation due to it's own standards. +# +# o MS Explorer can use localized reply strings, +# Eg `Vs:' or `vast:' seems to be Finnish `Vastaus'. +# o MS product Outlook (??) can be configured similarly. +# I have received swedish `Sv:' `-Svar' for `Svaring' (eng: reply) +# o MS mail uses `FW:' in forwarded mails. +# o Intelligent MUAs try to keep count of replies with +# `Re2:' or `Re[2]' +# o Japanese MUA Denshin 8 Go V321.1b7 has sent Re^2: +# o Some mua uses `Re>' +# o Lotus notes (in French version) uses `Ref:' +# o Some MS product sends `UQ:' +# o XXX uses `-reply' +# o Forwarding schemes: (fwd) [fwd] <fwd> fw: [FWD: [FWD:]] +# o Subject references: -subj subj- subj: +# +# There already is a de facto standard where message should contain +# only single `Re:' if message has been replied to (no matter how +# many times). This makes it possible to do efficient message +# threading by only using Subject and date fields. And grepping same +# subjects is lot easier than from this horrible mess. Note that +# all text is on one line, the subject has been broken only +# for visual reasons: +# +# Subject: re- Re^2: Re[32]: FW: Re: Re(15) Sv: Re[9]: -reply +# (fwd) [fwd] <fwd> fw: [FWD: [FWD:]] +# -subj subj: subj: subj- +# test +# +# This recipe standardizes any subject (like above) that has been +# replied to, to de facto format below. That is: "Any number of 'Re:' +# will be converted to *single* 'Re:' and any number of 'Fwd:' will be +# converted to *single* 'Fwd:'" +# +# Subject: Re: test (fwd) +# +# About In-Reply-To header +# +# If there is `In-Reply-to' header in the message, but there is +# not *Re:* in the subject line, one is added automatically. +# Some broken Mailers forget to add the *Re:* to the Subject +# line. +# +# Variable JA_SUBJECT_SAVE +# +# This is by default `yes' which causes the original subject to +# be saved under header field `X-Old-Subject'. If you don't want +# that extra header generated, set this variable to `no' +# +# Variable JA_SUBJECT_FWD_KILL +# +# This is by default `yes', which will kill extra forwarding +# indication words like (fwd) [fwd] <fwd> <f>. If you set this +# to `no', then all the forwarding words are preserved. The de +# facto forward format is: +# +# Subject: This subject (fwd) +# +# Code note +# +# This subroutine's intention is to make Subject more expressive +# by deleting redundant information. A simplistic approach has +# been taken where Subject consists of list of *words* whose +# each attribute can be either `ok' or `delete'. No attempt has +# been made to determine the structure of the Subject. You can +# see the algorithm better +# from an example: +# +# Re: New subject (was Re: Old subject) +# +# That should be treated syntactically like "New subject" and +# forgetting anything between parenthesis. This is however not +# respected and not even tried. The rule applied here is "One +# Re: is tolerated", so the subject won't change. It doesn't +# matter where "Re:" is. +# +# But here the subject is changed. The rule applied is: Delete +# all unwanted _words_ and then add one Re: to the beginning if OLD +# content had any Reply indications +# +# Re: New subject (was Re: Old subject) +# --> Re: New subject (was Old subject) +# +# IMPORTANT notice +# +# Please check that your `SHELL' variable setting in `~/procmailrc' +# is `sh' derivate, /bin/sh or /bin/bash. This module won't work with +# other shells. +# +# Awk usage note +# +# `awk' is a small, effective and much smaller than perl for little +# tasks. See the verbose log and make sure your awk understands +# VAR="value" passing syntax. Change it to `nawk' or `gawk' if they +# work better than your standard awk. +# +# AWK = "gawk" # you may need this, try also gawk +# +# Customizations +# +# Let's say Polish M$Outlook uses `ODP:' instead of +# standard `re:' and you want to handle that too: Then set: +# +# JA_SUBJECT_KILL = "odp:" # NOTE: all lowercase +# JA_SUBJECT_SAVE = "no" +# INCLUDERC = $PMSRC/pm-jasubject.rc +# +# You ca use `JA_SUBJECT_KILL' to delete any additional words from the +# subject line. E.g. if you have good news-reader, you don't need the +# mailing list prefixes that some mailing lists add to the beginning +# +# Subject: [LIST-xxx] the subject here +# +# to remove that list prefix, you simply match it +# +# JA_SUBJECT_KILL = "(list-xxx|list-yyy)" +# +# Important: The regexp must be _all_ lowercase, because when match +# happens, the words have been converted to lowercase. +# +# Example usage +# +# You need nothing special, just include this recipe +# before you save message to folder. +# +# INCLUDERC = $PMSRC/pm-jasubject.rc +# +# Debugging +# +# You can dry-run test this module with following command and watching +# output. Substitute variables as they are in your system. You feed +# the content of entire example mail where the Subject that needs +# correction is found. +# +# % procmail SHELL=/bin/sh AWK=gawk VERBOSE=on LOGABSTRACT=all \ +# DEFAULT=/dev/null LOGFILE=$(tty) \ +# JA_SUBJECT_KILL="(ace-users)" \ +# PMSRC=/path/to/install/dir \ +# /path/to/pm-jasubject.rc \ +# < ~/test.mail +# +# Thank you +# +# Thanks to <Tony.Lam@Eng.Sun.Com> for his creative +# improvement suggestions and sending code that this +# recipe didn't catch at first. +# +# Change Log (none) + +dummy = " +======================================================================== +pm-jasubject.rc: init: +" + +:0 +* ! WSPC ?? ( ) +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# .......................................................... &public ... + +# -- Put your own reply customization here: regexp is merged to +# default values. +# -- The regexp must be _all_ lowercase, because the matched +# word in the line is converted to lowercase before +# matching takes place. + +JA_SUBJECT_KILL = ${JA_SUBJECT_KILL:-""} + +# Set to "no" if you don't want to see `X-Old-Subject:' + +JA_SUBJECT_SAVE = ${JA_SUBJECT_SAVE:-"yes"} +JA_SUBJECT_FWD_KILL = ${JA_SUBJECT_FWD_KILL:-"yes"} + +# ........................................................... &check ... +# If the pm-javar.rc module was not loaded, then it would be +# disaster to call awk block. Make sure the $a and $AWK variables +# exist before doing anything. + +error = "no" + +:0 +* a ?? [a-z] +* AWK ?? [a-z] +{ } +:0 E # Else +{ + dummy = "pm-jasubject.rc: $JA_MSG_ERROR CONFIGURATION IS NOT CORRECT" + error = "yes" +} + +# .......................................................... &private ... + +subject = # Kill variable + +:0 +* ^Subject: *\/.* +{ + originalSubject = $MATCH + subject = $MATCH +} + +# These variables are not all caps, because they are not intended to be +# user configurable. Please email the author if this module if they are +# not enough for you. +# +# All characters in the regexp must be lowercase, because regexp is +# used in awk. Remember: -- Always parenthesize -- +# +# Notes: +# o Using regexp "re^[0-9]+:" to kill Re^2: doesn't work. We use +# regexp "re.[0-9]+:" +# o re(2) is matched by re[(][0-9]+[)]. Notice that there is not colon(:) +# o [[(<]fwd?[])>] matches things like (fwd) [fwd] <fwd> + +fwd = "" +fwdKill = 0 # AWK needs numeric True/False +fwdCount = "" +forwarded = "no" +savedLINEBUF = $LINEBUF +LINEBUF = 8192 # Need bigger value than default + +# All letters MUST BE LOWERCASE (for awk). No spaces anywhere in regexp + +fwdRegexp = ${fwdRegexp:-"(fwd?):|[[(<]fw?d?[])>]"} + +:0 +* JA_SUBJECT_FWD_KILL ?? yes +{ + fwd = $fwdRegexp + fwdKill = 1 + + :0 + *$ $fwdRegexp + { + forwarded = "yes" + } +} + +# All letters MUST BE LOWERCASE (for awk). No spaces anywhere in regexp + +replyTypes = ${replyTypes:-"\ +(re([0-9]+|.[0-9]+.|.[0-9]+):\ +|re[(][0-9]+[)]\ +|re-|re>|-reply|-svar\ +|(vs|vl|aw|fs|vast|sv|rv|ref|uq):\ +|-subj|subj-|subj:\ +)"} + +SubjectDoIt = "no" +UserRegexp = "" +wordKillRegexp = "$replyTypes" +dummy = "pm-jasubject.rc: Possibly adding JA_SUBJECT_KILL" + +# Has user given any additional keywords to kill? +# The variable must contains a-z + +dummy = "pm-jasubject.rc: :::::::::::::::::::::::::::::: #JA_SUBJECT_KILL" + +:0 +* ! subject ?? ^^^^ +*$ JA_SUBJECT_KILL ?? $a +{ + wordKillRegexp = "$replyTypes|$JA_SUBJECT_KILL" + + # Always remove words that user has defined + + :0 + *$ subject ?? $JA_SUBJECT_KILL + { + SubjectDoIt = "yes" + UserRegexp = "yes" + } +} + +# ....................................................... &forwarded ... + +dummy = "pm-jasubject.rc: :::::::::::::::::::::::::::::: #FWD" + +:0 +*$ fwdRegexp ?? [a-z] +{ + wordKillRegexp = "$wordKillRegexp|$fwdRegexp" + + :0 + * SubjectDoIt ?? no + *$ subject ?? ($fwdRegexp)\/.* + { + subject = $MATCH + fwdCount = "1" + + SubjectDoIt = "yes" + + :0 + *$ subject ?? ()\/($fwdRegexp).* + { + fwdCount = "2" + } + } +} + +# must parenthise, so that ".*" can be added to it + +wordKillRegexp = "($wordKillRegexp)|re:" + +# ........................................................ &de-facto ... +# We count because we want to know if we need to call awk or not. +# If there is only 1, then there is no point running external shell process, +# if there is at least two, then we need awk. +# +# In any case we need AWK if user has set mailing list kill words, like +# [this-list] + + +# *) grab first match. REPLY word count is then 1. In this case there is +# nothing more to kill +# *) Search second match, REPLY word count is 2 + + +dummy = "pm-jasubject.rc: :::::::::::::::::::::::::::::: #DE-FACTO" +replyCount = 0 + +:0 +*$ subject ?? re:\/.* +{ + subject = $MATCH + replyCount = 1 + + :0 + *$ subject ?? ()\/re:.* + { + replyCount = 2 + SubjectDoIt = "yes" + } +} + +# .................................................... &non-standard ... + +# Note: The "Re[0-9]+ " is special case. We can't pass it to AWK, because +# it doesn't see spaces, it couns only words, which are delimited by +# ^...$ + +dummy = "pm-jasubject.rc: :::::::::::::::::::::::::::::: #REPLY-TYPES " + +:0 +* SubjectDoIt ?? no +* subject ?? ()\/.* +*$ $SUPREME^0 subject ?? ($replyTypes)\/.* +*$ $SUPREME^0 subject ?? Re[0-9]+ \/.* +{ + subject = $MATCH + replyCount = 1 + + SubjectDoIt = "yes" + + :0 + *$ subject ?? ()\/($replyTypes).* + { + replyCount = 2 + } +} + +dummy = "pm-jasubject.rc: ::::::::::::::::::::::::::::: #DO-IT $SubjectDoIt" + +# Many foreign language is usually presented in encoded format +# (iso-8859-1). Furthermore, if pm-jamime-decode.rc was used to +# "open" the Subject line it will set a flag +# `PM_JAMIME_COMPLEX_SUBJECT' for messages that should not be +# touched (too complex). In those cases it the procmail's +# capabilities were reaached and the Subject line should be left +# as is. + +:0 +*$ $SUPREME ?? ^Subject:.*\?iso-8859-.\? +*$ $SUPREME ?? ! PM_JAMIME_COMPLEX_SUBJECT ?? ^^^^ +{ + SubjectDoIt = "no" +} + +:0 +* SubjectDoIt ?? no +{ + # Remove excess spaces between the "Subject" keyword and subject itself + + :0 fh w + *$ subject ?? $s$s+\/$NSPC.* + | $FORMAIL -I "Subject: $MATCH" + + # Some Emacs VM users reply emails without + # adding "Re: " in front of the subject (as VM default setting). + # Add one if needed. + + :0 fh w + * replyCount ?? 0 + * ^(In-Reply-To|References): + *$ subject ?? $s+\/.* + | $FORMAIL -I "Subject: Re: $MATCH" + + # Some users (of dtmail) forward emails without + # adding "fwd " in front of the subject + # Add one if needed. + + :0 E + * ^Message-ID: \<libSDtMail\..*\> + * fwdCount ?? 0 + * replyCount ?? 0 + * B ?? ^ ---[\-]+ Begin Forwarded Message --- + { + :0 fh w + *$ subject ?? $s+\/.* + | $FORMAIL -I "Subject: $MATCH (fwd)" + } +} + +:0 +* subject ?? ()\/.+ +* error ?? no +* SubjectDoIt ?? yes +{ + subject = $MATCH + + # Print log entry to show what regexp we're using. + # Grab the regexp from there for external testing or development. + + dummy = "pm-jasubject.rc: $SHELL $AWK is called with regexp: $NL\ + $wordKillRegexp $NL $fwdRegexp" + + # ......................................................... clean ... + + # The awk works this way: + # - split subject to individual words --> array LIST + # - convert every word to lowercase(str) before doing match + # because AWK is case sensitive + # - Add only valid words to "s" (string) and return "clean" subject. + # + # There is a special check in this program. Notice the 'lastpos'. + # It's purpose is to detect cases like this: + # + # [Fwd: Re: [jp] J-Pilot 0.99.8-pre2] Real subject here + # | + # lastpos + # + # The above subject is too complex to be treated like words, + # because it contains inner bracket which ends to lastpos. All + # of them must be removed. The word based match would treat it like: + # + # [Fwd: Re: [jp] J-Pilot 0.99.8-pre2] + # 1 2 3 4 5 + # + # 1. Looks like forwarding word. Removed + # 2. Looks like forwarding word. Removed + # 3. Looks good word + # 4. Looks good word; the ']' is not special + # + # And the result would be: + # + # J-Pilot 0.99.8-pre2] + + clean = `echo "$subject" | $AWK \ + ' { \ + max = split( $0, list, "[ \t]+" ); \ + lastpos = 0; \ + s = ""; \ + for( i = 1; i <= max; i++) \ + { \ + word = list[i]; \ + str = tolower( word ); \ + if ( FWD_KILL && match(str,FWD_RE) > 0 ) \ + { \ + fwd = 1; \ + } \ + if ( match(str,RE) < 1 && match(str, "^re[0-9]+$") < 1 ) \ + { \ + if ( s == "" ) \ + { \ + s = word; \ + } \ + else \ + { \ + s = s " " word; \ + } \ + } \ + if ( match(str,"^[^][]+[]]") > 0 ) \ + { \ + lastpos = i; \ + } \ + } \ + if ( lastpos ) \ + { \ + s = ""; \ + for( i = lastpos + 1; i <= max; i++) \ + { \ + s = s " " list[i]; \ + } \ + } \ + if ( match(s, "^ *$") ) \ + { \ + s = "(none)"; \ + } \ + if ( fwd ) \ + { \ + printf "%s (fwd)", s; \ + } \ + else \ + { \ + print s; \ + } \ + } \ + ' RE="$wordKillRegexp" FWD_RE="$fwdRegexp" FWD_KILL=$fwdKill ` + + # ................................................ update subject ... + + dummy = "pm-jasubject.rc: :::::::::::::::::::::::::::: #RESULT" + word = "" + + :0 + *$ replyCount ?? [1-9] + { + word = "Re: " + } + + # it makes sense replacing the Subject only if the word + # contains something + + :0 + * clean ?? [a-z] + { + + # Coording to RFs, all user defined additional fields + # must start with X- + + :0 fh w + * JA_SUBJECT_SAVE ?? yes + | $FORMAIL -I "X-Old-Subject: $originalSubject" + + :0 fh w + | $FORMAIL -I "Subject: $word$clean" + } +} + +LINEBUF = $savedLINEBUF +dummy = "pm-jasubject.rc: end: $word$clean" + +# End of pm-jasubject.rc diff --git a/share/procmail/pm-jatime.rc b/share/procmail/pm-jatime.rc @@ -0,0 +1,127 @@ +# pm-jatime.rc -- "hh:mm:ss" time parser from variable INPUT +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This includerc parses date from variable INPUT which has string +# +# "hh:mm:ss" +# +# Example input +# +# "Thu, 13 Nov 1997 11:43:23 +0200" +# +# Returned values +# +# hh = 2 digits +# mm = 2 digits +# ss = 2 digits +# +# Variable ERROR is set to "yes" if it couldn't recognize the INPUT +# and couldn't parse all hh, mm, ss variables. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include pm-javar.rc from there. +# +# Call arguments (variables to set before calling) +# +# INPUT = string-to-parse +# +# The INPUT can be anything as long as it contains NN:NN:NN +# +# Usage example +# +# Get the time of received message. The From_ header will always +# have the standard time stamp. +# +# PMSRC = $HOME/pm +# RC_DATE_TIME = $PMSRC/pm-jatime.rc +# +# :0 c +# * ^From +\/.* +# { +# INPUT = $MATCH +# # Turn off the logging while executing this part +# +# VERBOSE=off INCLUDERC = $RC_DATE_TIME VERBOSE=on +# +# :0 +# * ERROR ?? yes +# { +# # Should not ever happen, you have broken From_ +# } +# } +# +# Change Log (none) + +# .................................................... &initializing ... + +id = "pm-jatime.rc" +dummy = " +======================================================================== +$id: init: +" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# ..................................................... &output-vars ... +# output variables +# +hh mm ss +ERROR = "yes" # set default value + +# ........................................................... &do-it ... +# Check that input is something like: Thu, 13 Nov 1997 +# +dummy = "$id: Parse date like [Tue, 31 Dec 1997}" +dummy = "$id: INPUT = $INPUT" + +:0 +*$ INPUT ?? $s*\/$d$d:$d$d:$d$d +{ + + INPUT = $MATCH + + *$ INPUT ?? ^\/$d$d + { + hh = $MATCH + } + + :0 + *$ INPUT ?? ^$d$d:\/$d$d + { + mm = $MATCH + } + + + :0 + *$ INPUT ?? ^$d$d:$d$d:\/$d$d + { + ss = $MATCH + ERROR = "no" + } +} + +dummy = "$id: end:" + +# end of file pm-jadate.rc diff --git a/share/procmail/pm-jaube-keywords.rc b/share/procmail/pm-jaube-keywords.rc @@ -0,0 +1,785 @@ +# pm-jaube-keywords.rc -- Bare bones word list based UBE filter +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your UBE (aka spam) filters towards the _end_ of your +# ~/.procmailrc. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked. +# +# Now, if 50-70 % hit rate is good enough for your starting point, +# go ahead and read more. This file is supposed to be the last resort, +# if you really do not have any better tool to analyze messages. +# +# Overview of features +# +# o Word and phrase based matching +# o 50-70 % success rate. 90 % never achieved. That's a guarantee. +# o Extremely fast and a dream to CPU resources. Implemented in pure +# procmail and you can almost hear the humming sound of its +# regular expression engine shredding UBE messages to pieces. +# +# Description +# +# Are you sure you want use this word list based checking? +# +# Think twice before you use this subroutine. It knows nothing about +# the content your mail. "It's all UBE unless proven otherwise" is the +# motto. The brutal search tracks words and phrases to find an indication +# of mass posting and traces of Unsolicited Bulk Email (UBE aka spam). +# _Repeat:_ Read the first paragraph again before you consider putting +# this file into action. This filter WILL PASS through unwanted mail +# and it WILL catch good mail. This is rule based matching, so I suppose +# you know where you're putting your head with this. Ahem. Alerted? Good. +# +# The Story +# +# There was a man and mail account. The account had limited space, +# couldn't install any other programs because disk quota would have +# exceeded. System administrators weren't' interested in installing +# anything. The Mail server ran behind firewall and had OS that was +# never heard of - it couldn't run other programs. Or if it could, +# the Bad system administrator was too scared to install extra +# programs to the host MTA ran. No joy -- no means to stop incoming +# UBE -- Right? +# +# Wrong. There was procmail. The Bad system adminitrator didn't mention +# that `~/.procmailrc' was honored - just the the external programs +# we a no-no-no (Technical: the MDA host mounted user disks; the +# server ran on separate host and couldn't use any of the user +# compiled programs. Statically linked ones filled up the man's disk +# space). +# +# First line of defense, any defense would do. So, this rule based +# file was born. Nothing else was installed in that account and the +# happy word list based matching routine kept chewing mail, mail, +# mail. And the system administrator was happy - he nurtured the MTA +# host's CPU resources and noticed nothing alarming. All ticked like +# clockwork. +# +# Life began again. After 1000 mail bombards a day, the account was +# usable again. +# +# Motivation +# +# If you can, use the Bayesian filters and forget all rule based +# ones, word and phrase matching based ones; all static filters. On +# the other hand, if you want quick solution, even imperfect, until +# you have time to learn and setup other tools, this subroutine may +# be of interest. +# +# The best part. You can carry this single file anywhere where procmail +# lives. No other files are needed. Setup couldn't be simpler. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address is usually forged. Do not +# increase the network traffic. Instead save the messages to folders +# and periodically check their contents. It's not nice to be forced to +# apologize about bounces to a wrong destination. +# +# Code Note +# +# Procmail is picky about the whitespace in continuing lines, make sure +# there is _not_ a single spaces left after the continuation backslash. +# Use good editors or external programs to get rid of the white spaces. In +# Emacs you would add this line to your `~/.emacs' startup file: +# "(add-hook 'write-file-hooks 'delete-trailing-whitespace)" +# +# :0 +# * ^Subject:.*(regexp\ +# |and-more\ +# |and-more\ +# ) +# { +# # Process it +# } +# +# Why are the regexps put into this file and not to a separate regexp +# file? Good question. It is possible to check message's content with +# external process, like `grep', to see if any matches are found. +# This kind of methodology is covered in Procmail Tips section +# "Using grep with file lists to mach messages" at +# <http://pm-tips.sf.net>. The reason why all the regexp are maintained +# inside this file is: +# +# o Simplicity. One file - no extra configuration files or regexp +# databases. +# o Self standing. Does not call external processes, so it's a little +# faster than possible `grep' and `fgrep' solution. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o JA_UBE_KEYWORD_HEADER, if set, then the results are put to +# messages headers. By default this variable is not defined +# to save from external `formail' process call. +# Suggestion: "X-Spam-JaubeKwd"; without trailing colon. +# +# Return values +# +# o `ERROR_STATUS' is set to word "Bad" otherwise empty. +# o `ERROR' is set to short descriptive word that indicate which +# rule was matched. Values: *Header-FromKeywords*, +# *Header-SubjectKeywords* and *Body-Keywords* +# o `ERROR_MATCH' is set to some words that happened to trigger +# UBE catch rule. +# +# Usage example +# +# PMSRC = "/path/to/procmail/lib" +# # Exclude these addresses from tests +# VALID_FROM = "(my@address.example.com|word@here.example.com)" +# +# :0 +# *$ ! ^From:.*$VALID_FROM +# * ! FROM_DAEMON +# { +# INCLUDERC = $PMSRC/pm-jaube-keywords.rc +# +# # Variable "ERROR" is set if message was UBE +# +# :0 : +# * ! ERROR ?? ^^^^ +# junk.ube.spool +# } +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmal.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None. + +dummy = " +======================================================================== +pm-jaube-keywords.rc: init:" + + +####################################################################### +# +# User configurable variables. Set these, before calling this +# module/subroutine. +# +####################################################################### + +# Set to a empty to suppress external shell call to `formail'. + +JA_UBE_KEYWORD_HEADER = ${JA_UBE_KEYWORD_HEADER:-"X-Spam-JaubeKwd"} + +####################################################################### +# +# Private variables. Do not touch +# +####################################################################### + +# Kill variables or set default values + +ERROR +ERROR_MATCH +ERROR_STATUS + +NL = " +" +LF = $NL # synonym, linefeed +CR = " " # Carriage return +TAB = " " # \t character, you won't see it. +WSPC = " $TAB" # whitespace in procmail: space + tab + +# These are the variables that you're likely to use in +# condition lines. Notice that there is Perl styles `s' variable +# for shorter name for most used SPC. + +SPC = "[$WSPC]" # Regexp space/tab +NSPC = "[^$WSPC]" # Negation, non-whitespace +CHAR = "[^ $TAB$NL$CR]" # A character + +# Whitespace with linefeed +# Note that in regexps, the character class is faster that OR. +# Refer to O'Reilly book "Mastering Regular Expressions" +# +# space + tab + dollar +# +# ( | |$) is slower than ([ ]|$) + +SPCL = "($SPC|$|$CR)" # space or tab; linefeed; Carriage return + +jaubeKwdLinebufOld = $LINEBUF +LINEBUF = 65535 # Increase + +jaubeKwdVerboseOld = $VERBOSE # don't write log for these variables +VERBOSE = off + +# German, Spanish and other languages + +jaubeLanguage="(\ +[a-z] (con|m[ae]s|para) [a-z]\ +|\<aloha\ +|\<bitte\>\ +|\<arbeitet\ +|\<bail[ae]\ +|\<damen\ +|\<ganz\ +|\<herren\ +|\<bestaetigung\ +|\<contenidos\ +|\<fabricamos\ +|\<freundlichen\ +|\<kontakte\ +|\<seguridad\ +|<\ihre\ +|\<jetzt\ +|\<keine?\>\ +|\<kontakt\ +|\<telefono\ +|\<tenga\ +|\<totalmente\ +|\<trabaj\ +|\<vacantes\ +)" + +# English words. These keywords must be strict, because they are used +# BOTH in header and body. + +jaubeKeywords="(\ +[0-9][0-9.]* +per +(month|year)\ +|\<18th\>\ +|\<accessor(y|ies)\ +|\<acne\>\ +|\<adult\>\ +|\<advertis\ +|\<adorn\ +|\<a+n+a+l\ +|\<aphrodi\ +|\<affordable\ +|\<at + no +charge\ +|\<babe\>\ +|bachelor\ +|\<be\>.*\<(again|strong)\ +|bedroom\ +|bewitch\ +|\<bitch(es)?\>\ +|\<biz\>\ +|\<blonde\>\ +|\<bodyguard\ +|\<bondage>\ +|\<boob([sy]|ed)?\>\ +|boyfriend\ +|\<breast\ +|\<brunette\ +|\<bucks\>\ +|business +on our\>.*\<site\>\ +|\<call +[+]?[0-9][0-9]\ +|\<call +(me|us)\>\ +|\<cash\>\ +|\<cable +tv\ +|calsium\ +|cartoon\ +|cartridge\ +|casino\ +|celebrit\ +|\<censor(ed)?\>\ +|\<cheap(er|est)?\>\ +|cholesterol\ +|C[|i]+a[|]*1is\ +|\<clinic\ +|\<click +here\ +|\<clits?\>\ +|\<cocaine\ +|\<cock\>\ +|\<congrat\ +|confiden(c|tial)\ +|confrontation\ +|consultation\ +|\<cutie\ +|\<credits?\>\ +|\<cum(shots?)?\>\ +|\<daughter\ +|\<(dating|escort) +service\ +|\<deal.*to.*\<you\ +|\<dear.*(user|owner)\ +|\<defensa\ +|\<delight\ +|\<dental\ +|depressant\ +|detective\ +|\<diabet\ +|\<dick\>\ +|\<dildo\>\ +|diploma\ +|discreet\ +|\<do +you +like\ +|\<doctor\ +|domestic\ +|download.*today\ +|dramatic\ +|drugs\ +|earnings\ +|\<eighteen\ +|erection\ +|eroti[ck]\ +|fair +exchange\ +|exchange +rate\ +|exquisite\ +|\<fags\>\ +|farmac[yo]\ +|fashion\ +|female\ +|financ(e|ial)\ +|filing.*quotes\ +|\<films?\>\ +|filthy\ +|fitness\ +|\<for .*your.*Needs\ +|\<f+u+c+k\ +|\<funds?\>\ +|\<g+a+y+\>\ +|get it for (just)?.*[$]\ +|get +perfect.*your\ +|get +(lucky|fucked)\ +|Get +the +best\ +|girls?\>\ +|get +(a|for)? *free\ +|\<granny\ +|greetings\ +|gouranga\ +|h+a+r+d+c+o+r+e\ +|herbalife\ +|(hi|hello|hey)[.!?]* +(people|lucky)\ +|\<hot\>\ +|\<honey\>\ +|horoscope\ +|hurry +(now|fast)\ +|\<job +offer\ +|\<husband\ +|\<illnes\ +|\<income\ +|\<in +bed\ +|\<invest(ment)?\>\ +|\<interest +rates\>?\ +|\<iraq\ +|just .*$d+.*days\ +|\<jude\>\ +|\<kenedy\ +|laboratory\ +|\<laden\>\ +|\<lad(y|ies)\>\ +|legislation\ +|lesbian\ +|\<libido\ +|lifestyle\ +|(limited|special|future)\>.*\<offer\ +|\<li+m+i+t+e+d.*time\ +|lingerie\ +|\<lo+l+i+t+a+\ +|\<lose +(some)? *(weight|pounds)\ +|losing +it +all\ +|\<low.*rate\ +|\<loan\ +|\<lott(o|ery)\>\ +|madam\ +|mafia\ +|manhood\ +|\<marine\<\ +|masturbat\ +|medic(a[lt]|in)\ +|mexican\ +|money\ +|mortgage\ +|movie\ +|\<new.*<(video|dvd|cd)s?\>\ +|nigeria\ +|nipple\ +|offer.*valid\ +|offshore\ +|<\oil\>\ +|oppurtun\ +|\<orgy\>\ +|\<our +(company|product)\ +|order +(soon|now|fast)\ +|pain killer\ +|paycheck\ +|paying\ +|\<partner\ +|\<pence\ +|\<penis\>\ +|\<pharmae?c\ +|\<poker\ +|\<prank\ +|\<pregnan\ +|\<p[0o]+rn\ +|\<polls?\>\ +|\<profit\>\ +|promotion\ +|prostitute\ +|\<puss(y|ies)\>\ +|\<rape\>\ +|\<rates +starting +at\ +|\<realestate\ +|refinance\ +|regalis\ +|(restaurant|food) +recipe\ +|\<rich\>\ +|robbery\ +|\<rolex\ +|\<sadd?am\ +|sadomasokism\ +|satellite.*\<(tv|dish)\>\ +|\<(sav(ing|e)|buy|see|web).*\<(pills|meds|m +e +d +s)\>\ +|\<scent\>\ +|screensaver\ +|\<sex\>\ +|\<sin\>\ +|since we've chatted\ +|\<silver\ +|\<singles\ +|\<sir\>\ +|\<s[i|]ze +(real[a-z|]+ +)*matters?\>\ +|\<sluts?\>\ +|sperm\ +|stamina\ +|stocks?\ +|sydney\ +|\<save .*[0-9]+ *%\ +|\<(secretary|wom[ea]n|girl|nude|teen).*\<strip\ +|sweetheart\ +|\<tax\>\ +|\<teeny?(ie)?s?\>\ +|terrorist\ +|\<trad(e|ing)\ +|tobacco\ +|\<try .* our\>\ +|\<USD? *[$]\ +|\<[$][0-9][0-9.,]*[0-9]\>\ +|\<uncle\>\ +|Unauthorized access.*paypal\ +|u+n+d+e+r+a+g+e\ +|update.*your.*(bank)\ +|\<vegas\ +|\<venture\>\ +|\<v[1i@.,!:;?]a+[:]*g+[:]*r+[:]*a\ +|\<v[^ ]+gra\>\ +|v[i|]+aggar\ +|\<vip\>.*visitor\ +|view +my +profile\ +|wanted you to hear about.*\<new\ +|\<wanna\ +|\<we +specialize\ +|\<weight[ -]+loss\ +|welcome +to +our\ +|\<h[0o]usew[1i]f\ +|\<webcam\ +|\<women acting\ +|\<wom[ae]n.*your.*area\ +|\<your?\>.*\<(benefit|w[io]n|satisf|payment|pri[zc]e|need|loan)\ +|\<your on\ +|\<you're on\ +|\<you search for something\ +|\<your cr[a-z.]* (rating|record)\ +|\<you can be\>.*\<(safe|secure)\ +|\<youth\ +|$jaubeLanguage\ +)" + +# Some regexps cannot be used, because they would easily match legimite mail: +# +# - "your.*address" would match +# Please confirm your XXX Forwarding Address +# - "charm" would match +# works like a charm... +# +# Notes: +# - Regalis, Cialis are viagra drugs + +jaubeSubjectKeywordsOnly="(\ +[?][?]\ +|!!\ +|(\$|USD) *[0-9][0-9.,]\ +|\<(down|king).*size\ +|\<(try|do).*<(it|now|today)\ +|\<(offer|receive).* you\ +|\<(china|korea|usa|europe|australia|r+u+s+i+a|ira[qn]|beijing|iraq)\ +|\<(bush|clinton)\>\ +|\<(tv|she|us|hi|heya?|hiya|hello|win|ink|pics?|yo)\>\ +|\<action\ +|\<advisor\ +|\<aging\>\ +|anytime\ +|anywhere\ +|attractive\ +|\<are you\>\ +|\<ass\>\ +|\<award(ing)?\>\ +|\<back +to\ +|\<be +successful\ +|\<believ\ +|\<belowed\ +|\<bid\ +|\<[bm]illion\ +|\<blowjob\ +|\<bonus\>\ +|\<breath\ +|\<bringing\ +|bulk_mailer\ +|\<busines\ +|\<buy\ +|\<camera\ +|\<candle\ +|\<cds?\>\ +|\<charge\ +|\<che+a+[pt]\>\ +|\<check.*\<out\>\ +|\<child\>\ +|\<ciao\ +|\<cigar\ +|\<cold\ +|\<contact.*\<(bank)\ +|\<coral\ +|\<cost\ +|\<coupon\ +|\<dance\ +|\<dear\>\ +|\<(debt|debs)\>\ +|\<density\ +|\<deserve\ +|\<diet\ +|\<digital\ +|\<discount\ +|\<d[0o]llar\ +|\<don't +be\ +|doesn't.*\<(hurt)\ +|\<dudes?\>\ +|\<dvds?\>\ +|\<dying\ +|\<earn\ +|effortless\ +|eliminate\ +|\<employ\ +|\<enjoy\ +|\<enlarge\ +|\<expedition\ +|find +out\ +|fingering\ +|\<free\>.*(website|download)\ +|\<for\>.*\<you.*(order|self)\ +|\<fortune\ +|\<fountain\ +|\<friend\ +|\<fun\>\ +|\<g[eo]t +some\ +|\<gain\ +|\<g[eo0]t\>.*\<(smart)\ +|\<go.* for\ +|\<gold\ +|good +day\ +|governor\ +|\<got +it\ +|\<gratis\ +|\<guarant\ +|\<health\ +|\<hold +of\ +|\<hope\ +|\<h[0o]use\ +|\<hussy\ +|\<humble\ +|\<instant\ +|\<is your\>\ +|\<judical\ +|\<large\ +|\<life\ +|\<love\ +|\<luck\ +|\<make\>.*\<(her)\ +|\<master\>\ +|\<market\ +|\<mastercard\ +|\<mobile\ +|\<more[!?]\ +|\<movie\ +|\<mp3\ +|\<muscle\ +|\<music\ +|newsletter\ +|\<now!? \ +|\<nurtur\ +|\<oil\>\ +|\<online.*web\ +|\<our\>\ +|\<overnight\ +|\<paid\>\ +|\<pay\>\ +|\<passi[o0]\ +|\<pda\>\ +|\<personal\ +|\<phone\ +|\<photo\ +|\<picture\ +|\<pills?\>\ +|\<premier\ +|\<prescri[pb]\ +|\<pound\ +|president\ +|\<pretty\>\ +|\<prices?\ +|\<propagand\ +|\<reciprocal\ +|\<representative\ +|\<refill\ +|\<sales?\>\ +|\<screensaver\ +|\<see\>.*\<this\>.*(www|web|site|page)\ +|\<sell\>\ +|\<sensati\ +|\<sense\ +|\<she\>.*(happy|try|tried)\ +|\<shop\ +|\<sincer\ +|\<sisters?\>\ +|\<smok(e|ing)?\>\ +|\<solicit\ +|\<spend\>\ +|\<spirit\ +|\<stress\ +|\<stock\ +|\<summer\>\ +|\<super\ +|\<swallow\ +|\<seeking.*assistance\ +|\<target\ +|\<thank +you\ +|\<the +time\ +|\<thin\ +|thousand\ +|\<time +to\ +|\<today\ +|\<toner\ +|\<tons\>\ +|\<travel\ +|\<try\>\ +|\<typing\ +|\<ultimate\ +|\<(university|college) .*(degree|diploma)\ +|\<up +to\ +|\<urgent\ +|\<utmost\ +|\<video\ +|\<visitor\ +|\<wash\ +|\<watch\ +|\<we +ship\ +|\<we need your\ +|\<weather\ +|\<welcome\ +|\<wife\ +|\<wines?\>\ +|\<wish\ +|\<w[oi]n\>\ +|\<wom[ae]n\ +|\<work.*\<for\>\ +|XXX\ +|yellow +page\ +|\<young\ +|$jaubeKeywords\ +)" + +# Restore saved values + +VERBOSE = $jaubeKwdVerboseOld + +dummy="pm-jaube-keywords.rc: TEST Subject keywords" + +:0 +*$ ^Subject:.*\/$jaubeSubjectKeywordsOnly$CHAR* +{ + ERROR = "Header-SubjectKeywords" + ERROR_MATCH = "$MATCH" +} + +dummy = "pm-jaube-keywords.rc: TEST Header From keywords" + +:0 +*$ ^From.*()\/$jaubeKeywords$CHAR* +{ + ERROR_MATCH = "$MATCH" + + :0 + * ERROR ?? ^^^^ + { + ERROR = "Header-FromKeywords" + } + :0 E + { + ERROR = "$ERROR:Header-FromKeywords" + } +} + +dummy = "pm-jaube-keywords.rc: TEST body keywords" + +:0 +*$ B ?? ()\/$jaubeKeywords$CHAR* +{ + ERROR_MATCH = "$MATCH" + + :0 + * ERROR ?? ^^^^ + { + ERROR = "Body-Keywords" + } + :0 E + { + ERROR = "$ERROR:Body-Keywords" + } +} + +:0 +* ! ERROR ?? ^^^^ +{ + ERROR_STATUS = "Bad" + + # strip leading and trailing whitespace. + + :0 + * ERROR_MATCH ?? ^^[$WSPC] + * ERROR_MATCH ?? ()\/[^$WSPC].*[^$WSPC] + { + ERROR_MATCH = "$MATCH" + } + + :0 + * ! JA_UBE_KEYWORD_HEADER ?? ^^^^ + { + jaubeKwdInfo = "$ERROR $ERROR_MATCH" + jaubeKwdHeader = "$ERROR_STATUS $jaubeKwdInfo" + + :0 fw + | ${FORMAIL:-"formail"} \ + -I "$JA_UBE_KEYWORD_HEADER: $jaubeKwdHeader" + } +} + +LINEBUF = $jaubeKwdLinebufOld +dummy = "pm-jaube-keywords.rc: end: $ERROR_STATUS $ERROR" + +# pm-jaube.rc ends here diff --git a/share/procmail/pm-jaube-prg-annoyance-filter.rc b/share/procmail/pm-jaube-prg-annoyance-filter.rc @@ -0,0 +1,218 @@ +# pm-jaube-prg-spamprobe.rc -- Interface to Annoyance Filter program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ mkdir $HOME/.annoyance +# $ DB=$HOME/.annoyance/dict.bin; DB2=$HOME/.annoyance/fdict.bin +# $ annoyance-filter --mail single.msg --prune --write $DB +# $ annoyance-filter --phrasemax 2 \ +# --read $DB \ + --mail dir/to/good/messages \ +# --junk dir/to/bad/messages \ +# --prune --write $DB +# $ annoyance-filter -v --read $DB --prune --fwrite $DB2 +# +# To check message: +# +# $ annoyance-filter --read $DB --test mail.msg +# $ annoyance-filter --fread $DB2 -v --class mail.msg +# +# Overview of features +# +# o Implements interface to +# http://sourceforge.net/projects/annoyancefilter/ project. +# See article "Training Annoyance Filter to combat spam" by +# Corrado Cau at +# http://www.newsforge.com/software/03/10/24/2046238.shtml?tid=74 +# o variable `ERROR' is set if the message was UBE. +# o Results are available by default in header +# `X-Spam-Annoyance-Status'. +# +# Description +# +# There are several Bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# This procmail subroutine implements call interface to program +# `annoyance-filter', which must already have been installed. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `annoyance-filter' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_ANNOYANCE_PRG = /usr/bin/spamprobe +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o `JA_UBE_ANNOYANCE_PRG', path to the program [required]. +# o `JA_UBE_ANNOYANCE_SPAM_DB', path to the dictionary database +# [required]. E.g. `$HOME/.annoyance/dict.db'. +# o `JA_UBE_ANNOYANCE_SPAM_DB_OPT', type of dictionary to read. +# Default is "--read", but this could be fast dictionary option +# "--fread". +# o `JA_UBE_ANNOYANCE_HEADER', the header name where the results +# are put. If not defined, no header is added. +# Defaults to *X-Spam-Annoyance-Status* +# o `JA_UBE_ANNOYANCE_FORCE', if set to _yes_ then call program no matter +# what. Normally if there already is *X-Spam-Annoyance-Status* header, +# it is assumed that the message has already been checked +# and no new checking is needed. +# +# Return values +# +# o ERROR, is set to the return value of the program. +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_ANNOYANCE_PRG = "/usr/bin/nice -n 5 /usr/bin/annoyance-filter" +# JA_UBE_ANNOYANCE_SPAM_DB = $HOME/.annoyance/dict.db +# INCLUDERC = $PMSRC/pm-jaube-prg-spamprobe.rc +# +# # The ERROR will contains word "yes" if message was spam +# +# :0 : +# * ERROR ?? yes +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-annoyance-filter.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_ANNOYANCE_PRG = ${JA_UBE_ANNOYANCE_PRG:-""} + +# There is no default location for the dictionaly file, so these +# variables *must* be set in order to activate this module. + +JA_UBE_ANNOYANCE_SPAM_DB_OPT = ${JA_UBE_ANNOYANCE_SPAM_DB_OPT:-"--read"} +JA_UBE_ANNOYANCE_SPAM_DB = ${JA_UBE_ANNOYANCE_SPAM_DB:-""} + +# The header name with no colon at the end. If this variable +# is empty, then external formail call is saved - results can still +# be checked from variable ERROR. There is no trailing colon in this +# variable. + +JA_UBE_ANNOYANCE_HEADER = ${JA_UBE_ANNOYANCE_HEADER:-"\ +X-Spam-Annoyance-"} + +# Should we check even if there already was header +# JA_UBE_ANNOYANCE_HEADER + +JA_UBE_ANNOYANCE_FORCE = ${JA_UBE_ANNOYANCE_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variable + +:0 +* JA_UBE_ANNOYANCE_PRG ?? [a-z] +* JA_UBE_ANNOYANCE_SPAM_DB ?? [a-z] +*$ ! 9876543210^0 ^$JA_UBE_ANNOYANCE_HEADER +* 9876543210^0 JA_UBE_ANNOYANCE_FORCE ?? yes +{ + # Will return headers like: + # + # X-Annoyance-Filter-Junk-Probability: 0 + # X-Annoyance-Filter-Classification: Mail + + :0 w : spamannoyance$LOCKEXT + jaubeAnnoyanceData=|$JA_UBE_ANNOYANCE_PRG \ + $JA_UBE_ANNOYANCE_SPAM_DB_OPT \ + $JA_UBE_ANNOYANCE_SPAM_DB \ + --transcript - --test - + + :0 + * jaubeAnnoyanceData ?? ^X-Annoyance-Filter-Junk-Probability: \/.+ + { + jaubeAnnoyanceScore = $MATCH + + :0 + * jaubeAnnoyanceData ?? ^X-Annoyance-Filter-Classification: \/.+ + { + jaubeAnnoyanceType = $MATCH + + :0 + * jaubeAnnoyanceType ?? Junk + { + ERROR = "yes" + } + } + + :0 fw + * ! JA_UBE_ANNOYANCE_HEADER ?? ^^^^ + | ${FORMAIL:-formail} \ + -I "${JA_UBE_ANNOYANCE_HEADER}Status: ${ERROR:-no}" \ + -I "${JA_UBE_ANNOYANCE_HEADER}Classification: $jaubeAnnoyanceType" \ + -I "${JA_UBE_ANNOYANCE_HEADER}Probability: $jaubeAnnoyanceScore" + } +} + +dummy = "pm-jaube-prg-annoyance-filter.rc: end: $ERROR" + +# End of file diff --git a/share/procmail/pm-jaube-prg-bmf.rc b/share/procmail/pm-jaube-prg-bmf.rc @@ -0,0 +1,283 @@ +# pm-jaube-prg-bmf.rc -- Interface to Bayesian Mail Filter program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages +# are filed first (mailing lists, your work and private mail, +# bounces) and only the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ ls spam/*.mail | xargs -n 1 bmf -s # feed individual messages +# $ ls good/*.mail | xargs -n 1 bmf -n # feed individual messages +# +# To test +# +# $ bmf -p < test.mail | less +# +# Overview of features +# +# o Implements interface to http://www.sf.net/projects/bmf +# "Bayesian Mail Filter" project. The called binary is "bmf" +# hence the name of this subroutine. Bmf program uses well +# know statistical analysis which is much more reliable than +# any hand made procmail scripts could ever achieve. +# o Variable `ERROR' is set if the message was UBE. +# o Results are available in headers `X-Spam-bmf-Status' and +# `X-Spam-bmf-Flag' for further analysis. +# +# Description +# +# There are several bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the +# UBE detection. +# +# For serious discussion of strenghts of the different programs, +# refer to a very good article "Spam Filters" by Sam Holden at +# 2004-08-16 <http://freshmeat.net/articles/view/964>. The +# article evaluated throughly following programs: +# +# o Bayesian Mail Filter (bayesian) +# o Bogofilter (bayesian) +# o dbacl (bayesian; multiple wordlists) +# o Quick Spam Filter (bayesian) +# o SpamAssassin (perl matching + bayesian) +# o SpamProbe (bayesian) +# o SPASTIC (procmail recipes) +# +# This subroutine implements call interface to `bmf' program. Why +# whould you need it? Because unfortunately `bmf' by default +# use exactly the same headers as spamasassin and the two cannot +# co-operate together: bmf would overwrite existing +# spamassasin headers. This subroutine takes care of saving +# previous headers and move `bmf' results to their own +# `X-Spam-bmf-*' headers. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. +# The UBE sender is not there, because the address forged. Do +# not increase the network traffic; you will not do any good to +# anybody by bouncing messgas -- you just increase mail traffic +# even more. Instead save the messages to folders and +# periodically periodically check their contents. +# +# Required settings +# +# If `bmf' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_BMF_PRG = "/usr/bin/bmf" +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o JA_UBE_BMF_PRG, path to program +# o JA_UBE_BMF_HEADER_PREFIX, the header name where the results +# are put. If not defined, no headers are added. Default +# value is `X-Spam-bmf'. +# o JA_UBE_BMF_FORCE, if set to _yes_ then call program no matter +# what. Normally if there already are `X-Spam-bmf-*' headers, +# it is assumed that the message has already been checked +# and no new checking is needed. +# +# Return values +# +# o ERROR, is set to short ube trigger recipe reason. Contains +# content of `X-Spam-bmf-Status' header which you can check +# for values +# o ERROR_MATCH contains detailed content of +# `X-Spam-bmf-Status' header. +# +# If headers were enabled, they will contain: +# +# X-Spam-bmf-Status: Yes, hits=1.000000 required=0.900000, tests=bmf +# X-Spam-bmf-Flag: YES +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_BMF_PRG = "/usr/bin/nice -n 5 /usr/bin/bmf" +# INCLUDERC = $PMSRC/pm-jaube-prg-bmf.rc +# +# # The ERROR will contains word "yes" if it program classified +# # the message into "bad" category. +# +# :0 : +# * ERROR ?? yes +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-bmf.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_BMF_PRG = ${JA_UBE_BMF_PRG:-""} +JA_UBE_BMF_PRG_OPT = ${JA_UBE_BMF_PRG_OPT:-"-p"} + +# The header name prefix with no colon at the end. If this variable +# is empty, then `formail' is not called and no headers are added to +# the message. This saves a shell call and will make this repice a +# bit faster. The return status can still be checked from variable +# ERROR + +JA_UBE_BMF_HEADER_PREFIX = ${JA_UBE_BMF_HEADER_PREFIX:-"X-Spam-Bmf-"} + +# Should we run the check even if there aready were header +# JA_UBE_BMF_HEADER_PREFIX? Setting to 'yes' might mean: +# +# o We suspect that someone else had added the header, so don't +# trust it but generate our own +# o We don't trust the local MDA's result (if it had invoked +# bmf for us), because we want' to run the message +# through our own trained database +# o Or, we're simply testing and have several INCLUDERC=$RC_UBE_BMF +# calls in our ~/.procmailrc to find out what location would be the +# best (beginning, middle, last) by examining the procmail LOGFILE. + +JA_UBE_BMF_FORCE = ${JA_UBE_BMF_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variable + +# The condition below reads: +# - Require that variable is defined (contains path to 'bmf' program) +# - Run immediately: if there is no X-spambmf header +# - OR Run immediately: (even if there were headers) forced evaluation + +:0 +* JA_UBE_BMF_PRG ?? [a-z] +*$ 9876543210^0 ! ^$JA_UBE_BMF_HEADER_PREFIX +* 9876543210^0 ! JA_UBE_BMF_FORCE ?? yes +{ + + # Unfortunately bmf inserts same headers as Spamassassin (SA), so + # we must first save previous SA values. Kill variables first + # + # Note: the initial value is set here to header name, so that if + # there is no previous SA headers, they will be left empty. This + # works fine, because e.g. "formail -I X-Name:" does nothing when + # message does not include "X-Name:" header. + + dummy = "pm-jaube-prg-bmf.rc: saving previous X-Spam-* headers" + + jaubeBmfSaStatus = "X-Spam-Status:" + jaubeBmfSaFlag = "X-Spam-Flag:" + + :0 + * ^\/X-Spam-Status:.* + * ! ^\/X-Spam-Status:.*tests=bmf + { + jaubeBmfSaStatus = $MATCH + + :0 + * ^\/X-Spam-Flag:.* + { + jaubeBmfSaFlag = $MATCH + } + } + + # Now run the filter with -p "pass through". + + jaubeBmfStatus + jaubeBmfFlag + + :0 fw : bmf$LOCKEXT + | $JA_UBE_BMF_PRG ${JA_UBE_BMF_PRG_OPT} + + # After previous call, there should be these headers. It is unfortunate, + # that "tests=bmf" is not included with "No" case + # + # X-Spam-Status: No, hits=0.000000 required=0.900000 + # X-Spam-Status: Yes, hits=1.000000 required=0.900000, tests=bmf + # X-Spam-Flag: YES + + :0 a + * ^X-Spam-Status: \/.+ + { + + :0 + * ^X-Spam-Status: \/.+tests=bmf + { + ERROR = $MATCH + } + + jaubeBmfStatus = "${JA_UBE_BMF_HEADER_PREFIX}Status: $MATCH" + jaubeBmfFlag = "${JA_UBE_BMF_HEADER_PREFIX}Flag:" # Initial value + + :0 + * ^X-Spam-Flag: \/.* + { + jaubeBmfFlag = "$jaubeBmfFlag $MATCH" + } + + dummy = "pm-jaube-prg-bmf.rc: restore X-Spam-* / add X-Spam-Bmf headers" + + # Rearrange headers nicely and put back all Spamassassin values + + :0 fhw + * ! jaubeBmfSaStatus ?? ^^^^ + * ! jaubeBmfSaFlag ?? ^^^^ + * ! jaubeBmfStatus ?? ^^^^ + * ! jaubeBmfFlag ?? ^^^^ + | ${FORMAIL:-formail} \ + -I "$jaubeBmfSaStatus" \ + -I "$jaubeBmfSaFlag" \ + -I "$jaubeBmfStatus" \ + -I "$jaubeBmfFlag" + } +} + +dummy = "pm-jaube-prg-bmf.rc: end: $ERROR" + +# pm-jaube-prg-bmf.rc ends here diff --git a/share/procmail/pm-jaube-prg-bogofilter.rc b/share/procmail/pm-jaube-prg-bogofilter.rc @@ -0,0 +1,219 @@ +# pm-jaube-prg-bogofilter -- Interface to bogofilter program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ rm -f ~/.bogofilter/*.db # delete database +# $ bogofilter -B -n good.msg ... +# $ bogofilter -B -s spam.msg ... +# +# Overview of features +# +# o Implements interface to http://www.sf.net/projects/bogofilter +# project. +# o variable `ERROR' is set if message was likely spam. +# o Results are available by default in header +# `X-Spam-Bogofilter-Status'. +# +# Description +# +# There are several Bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# This procmail subroutine implements call interface to program +# `bogofilter', which must already have been installed. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `bogofilter' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_BOGOFILTER_PRG = /usr/bin/bogofilter +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o JA_UBE_BOGOFILTER_PRG, path to the program +# o JA_UBE_BOGOFILTER_HEADER_NEW, the header name where the results +# are put. If not defined, no header is added. +# Defaults to `X-Spam-Bogofilter-Status' +# o JA_UBE_BOGOFILTER_FORCE, if set to _yes_ then call program no matter +# what. Normally if there already is `X-Spam-*' header, +# it is assumed that the message has already been checked +# and no new checking is needed. +# +# Return values +# +# o ERROR, is set to the return value of program if message was spam. +# o ERROR_INFO, is set if case is "unsure". +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_BOGOFILTER_PRG = "/usr/bin/nice -n 5 /usr/bin/bogogilter" +# INCLUDERC = $PMSRC/pm-jaube-prg-bogofilter.rc +# +# # The ERROR will contains reason if program classified +# # the message into "bad" category. +# +# :0 : +# * ! ERROR ?? ^^^^ +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-bogofilter.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_BOGOFILTER_PRG = ${JA_UBE_BOGOFILTER_PRG:-""} +JA_UBE_BOGOFILTER_OPT = ${$JA_UBE_BOGOFILTER_OPT:-""} + +# No user options cannot be passed, because the output would +# change. This variable is not used. +# JA_UBE_BOGOFILTER_PRG_OPT = ${JA_UBE_BOGOFILTER_PRG_OPT:-""} + +# The original header name. + +JA_UBE_BOGOFILTER_HEADER_ORIGINAL = ${JA_UBE_BOGOFILTER_HEADER_ORIGINAL:-"\ +X-Bogosity"} + +# The header name with no colon at the end. If this variable +# is empty, then external formail call is saved - results can still +# be checked from variable ERROR. + +JA_UBE_BOGOFILTER_HEADER_NEW = ${JA_UBE_BOGOFILTER_HEADER:-\ +"X-Spam-bogofilter-Status"} + +# Should we check even if there already was already header +# 'JA_UBE_BOGOFILTER_HEADER' ? + +JA_UBE_BOGOFILTER_FORCE = ${JA_UBE_BOGOFILTER_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variables +ERROR_INFO + +:0 +* JA_UBE_BOGOFILTER_PRG ?? [a-z] +*$ ! 9876543210^0 ^$JA_UBE_BOGOFILTER_HEADER_NEW +* 9876543210^0 JA_UBE_BOGOFILTER_FORCE ?? yes +{ + # This call will add header. Notice that newer version output + # "Ham" instead of "No" + # + # X-Bogosity: No, tests=bogofilter, spamicity=0.000111, version=0.92.5 + # X-Bogosity: Ham, tests=bogofilter, spamicity=0.004063, version=0.93.2 + # X-Bogosity: Unsure, tests=bogofilter, spamicity=0.499327, version=0.92.5 + # X-Bogosity: Yes, tests=bogofilter, spamicity=1.000000, version=0.92.5 + + jaubeBogoHdr # Kill variable + + :0 + * ! JA_UBE_BOGOFILTER_HEADER_NEW ?? ^^^^ + { + jaubeBogoHdr = $JA_UBE_BOGOFILTER_HEADER_NEW + + # -e = Exit with code 0 if message is ham/unsure. + # -p = Pass through + + :0 fhbw # : bogofilter$LOCKEXT + | $JA_UBE_BOGOFILTER_PRG \ + -e \ + -p \ + --spam-header-name="$JA_UBE_BOGOFILTER_HEADER_NEW" \ + $JA_UBE_BOGOFILTER_OPT + } + :0 E + { + jaubeBogoHdr = $JA_UBE_BOGOFILTER_HEADER_ORIGINAL + + :0 fhbw : bogofilter$LOCKEXT + | $JA_UBE_BOGOFILTER_PRG -e -p $JA_UBE_BOGOFILTER_OPT + } + + # Bogofilter returns three status messages: Yes, Unsure, No|Ham + # Save the value for user to check + + :0 + *$ ^$jaubeBogoHdr: \/yes.* + { + ERROR = "bogofilter; $MATCH" + } + :0 E + *$ ^$jaubeBogoHdr: \/unsure.* + { + ERROR_INFO = "bogofilter; $MATCH" + } + :0 E + *$ ^$jaubeBogoHdr: \/.+ + { + # Do nothing. Just record bogofilter response to log file + } +} + +dummy = "pm-jaube-prg-bogofilter.rc: end: $ERROR" + +# End of file diff --git a/share/procmail/pm-jaube-prg-bsfilter.rc b/share/procmail/pm-jaube-prg-bsfilter.rc @@ -0,0 +1,214 @@ +# pm-jaube-prg-bsfilter.rc -- Interface to Bsfilter program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ bsfilter --add-clean good.msg ... +# $ bsfilter --add-spam spam.msg ... +# +# Overview of features +# +# o Implements interface to project +# http://packages.debian.org/testing/mail/bsfilter +# o variable `ERROR' is set if the message was UBE. +# o Results are available by default in header +# `X-Spam-Bsfilter-Status'. +# +# Description +# +# There are several Bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# This procmail subroutine implements call interface to program +# `bsfilter', which must already have been installed. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `bsfilter' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_BSFILTER_PRG = /usr/bin/bsfilter +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o `JA_UBE_BSFILTER_PRG', path to the program. +# o `JA_UBE_BSFILTER_HEADER', the header prefix name where the results +# are put. If not defined, no header is added. +# Defaults to *X-Spam-Bsfilter-* +# o `JA_UBE_BSFILTER_FORCE', if set to _yes_ then call program no matter +# what. Normally if there already is *X-Spam-Bsfilter-* header, +# it is assumed that the message has already been checked +# and no new checking is needed. +# +# Return values +# +# o `ERROR', is set to the return value of `bsfilter' program. +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_BSFILTER_PRG = "/usr/bin/nice -n 5 /usr/bin/bsfilter" +# INCLUDERC = $PMSRC/pm-jaube-prg-bsfilter.rc +# +# # The ERROR will contains word "yes" if message was spam +# +# :0 : +# * ERROR ?? yes +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-bsfilter.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_BSFILTER_PRG = ${JA_UBE_BSFILTER_PRG:-""} + +# You could use "--update" if database is well trained. + +JA_UBE_BSFILTER_PRG_OPT = ${JA_UBE_BSFILTER_PRG_OPT:-""} + +# The header prefix name. If this variable is empty, then external +# formail call is saved - results can still be checked from variable +# ERROR. + +JA_UBE_BSFILTER_HEADER = ${JA_UBE_BSFILTER_HEADER:-"\ +X-Spam-Bsfilter-"} + +# Should we check even if there already was header +# JA_UBE_BSFILTER_HEADER + +JA_UBE_BSFILTER_FORCE = ${JA_UBE_BSFILTER_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variable + +:0 +* JA_UBE_BSFILTER_PRG ?? [a-z] +*$ ! 9876543210^0 ^$JA_UBE_BSFILTER_HEADER +* 9876543210^0 JA_UBE_BSFILTER_FORCE ?? yes +{ + # bsfilter uses same headers as spamassassin, so we must + # read the results separately. + + :0 w : bsfilter$LOCKEXT + jaubeBsfilterData=|$JA_UBE_BSFILTER_PRG \ + --pipe \ + --insert-revision \ + --insert-flag \ + --insert-probability \ + $BSFILTER_OPT + + # X-Spam-Revision: bsfilter release 1.0.4 revision 1.63 + # X-Spam-Flag: No + # X-Spam-Probability: 0.906504 + + jaubeBsfilterVer # Kill variables + jaubeBsfilterFlag + jaubeBsfilterStatus + + :0 + * jaubeBsfilterData ?? X-Spam-Revision: \/.*bsfilter + { + jaubeBsfilterVer = $MATCH + + :0 + * jaubeBsfilterData ?? X-Spam-Flag: \/.+ + { + jaubeBsfilterFlag = $MATCH + } + + :0 + * jaubeBsfilterData ?? X-Spam-Probability: \/.+ + { + jaubeBsfilterStatus = $MATCH + } + + :0 + * jaubeBsfilterFlag ?? yes + { + ERROR = "yes" + + :0 + * ! jaubeBsfilterStatus ?? ^^^^ + { + ERROR = "$ERROR $jaubeBsfilterStatus" + } + } + } + + :0 fw + * ! JA_UBE_BSFILTER_HEADER ?? ^^^^ + * ! jaubeBsfilterFlag ?? ^^^^ + | ${FORMAIL:-formail} \ + -I "${JA_UBE_BSFILTER_HEADER}Flag: $jaubeBsfilterFlag" \ + -I "${JA_UBE_BSFILTER_HEADER}Status: $jaubeBsfilterStatus" \ + -I "${JA_UBE_BSFILTER_HEADER}Version: $jaubeBsfilterVer" +} + +dummy = "pm-jaube-prg-bsfilter.rc: end: $ERROR" + +# End of file diff --git a/share/procmail/pm-jaube-prg-ifile.rc b/share/procmail/pm-jaube-prg-ifile.rc @@ -0,0 +1,183 @@ +# pm-jaube-prg-ifile -- Interface to ifile program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ rm ~/.idata # delete database +# $ echo herbalife | ifile -i spam # initialize database +# $ ifile -h -i good good.msg ... +# $ ifile -h -i spam spam.msg ... +# +# Overview of features +# +# o Implements interface to http://freshmeat.net/projects/ifile +# project. +# o variable `ERROR' is set to the result of ifile check. This +# usually holds the "folder" name the ifile was trained at the +# time. E.g. if the folder used for training Unsolicited Bulk +# Email was "ifile -i spam", then the return value is "spam". +# o Results are available by default in header `X-Spamifile'. +# +# Description +# +# There are several Bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# This procmail subroutine implements call interface to program +# `ifile', which must already have been installed. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `ifile' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_IFILE_PRG = /usr/bin/ifile +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o JA_UBE_IFILE_PRG, path to the program +# o JA_UBE_IFILE_HEADER, the header name where the results +# are put. If not defined, no header is added. +# Defaults to `X-Spam-Ifile-Status' +# o JA_UBE_IFILE_FORCE, if set to _yes_ then call program no matter +# what. Normally if there already is header, +# it is assumed that the message has already been checked +# and no new checking is needed. +# +# Return values +# +# o ERROR, is set to the return value of `ifile' program. +# +# If header output is enabled, it will contain the folder name +# `ifile' thinks the message belongs to. Assuming that trained +# folders used for messages were *spam* and *good*, then the headers +# read: +# +# X-Spam-Ifile-Status: spam +# X-Spam-Ifile-Status: good +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_IFILE_PRG = "/usr/bin/nice -n 5 /usr/bin/ifile" +# INCLUDERC = $PMSRC/pm-jaube-prg-ifile.rc +# +# # The ERROR will contains reason if program classified +# # the message into "bad" category. +# +# :0 : +# * ! ERROR ?? ^^^^ +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-ifile.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_IFILE_PRG = ${JA_UBE_IFILE_PRG:-""} + +# No user options cannot be passed to ifile, because the output would +# change. This variable is not used. +# JA_UBE_IFILE_PRG_OPT = ${JA_UBE_IFILE_PRG_OPT:-""} + +# The header name with no colon at the end. If this variable +# is empty, then external formail call is saved - results can still +# be checked from variable ERROR. + +JA_UBE_IFILE_HEADER = ${JA_UBE_IFILE_HEADER:-\ +"X-Spam-Ifile-Status"} + +# Should we check even if there already was header +# JA_UBE_IFILE_HEADER ? + +JA_UBE_IFILE_FORCE = ${JA_UBE_IFILE_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variable + +:0 +* JA_UBE_IFILE_PRG ?? [a-z] +*$ ! 9876543210^0 ^$JA_UBE_IFILE_HEADER +* 9876543210^0 JA_UBE_IFILE_FORCE ?? yes +{ + :0 w : ifile$LOCKEXT + jaubeIfileFolder=|$JA_UBE_IFILE_PRG --strip-header --query --concise + + :0 + * ! jaubeIfileFolder ?? ^^^^ + { + ERROR = $jaubeIfileFolder + + :0 fhw + * ! JA_UBE_IFILE_HEADER ?? ^^^^ + | ${FORMAIL:-formail} -I "$JA_UBE_IFILE_HEADER: $jaubeIfileFolder" + } +} + +dummy = "pm-jaube-prg-ifile.rc: end: $ERROR" + +# End of file diff --git a/share/procmail/pm-jaube-prg-runall.rc b/share/procmail/pm-jaube-prg-runall.rc @@ -0,0 +1,280 @@ +# pm-jaube-prg-runall.rc -- Interface to all Bayesian filter programs +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Overview of features +# +# o To detect spam reliably, run all Bayesian programs one by one +# to see if any of them classifies the message as spam. +# o Programs supported: bogofilter, spamprobe, Bayesian Mail +# Filter, Annoyance Filter, Bsfilter, Spamoracle and Spamassassin. +# +# Description +# +# There are several bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. This module is a +# _meta_ _package_ which will call all other individual modules +# that interface to these Bayesian programs. The use is simple: define +# programs that are available in your system and which you have +# trained (Bayesian programs need to be trained before use), and this +# this module will query how those programs would classify the message. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# o pm-jaube-prg-spamprobe.rc +# o pm-jaube-prg-spamoracle.rc +# o pm-jaube-prg-annoyance-filter.rc +# o pm-jaube-prg-bsfilter.rc +# o pm-jaube-prg-bmf.rc +# +# Call arguments (variables to set before calling) +# +# To activate Bayesian program(s), define path to them. Default +# value for all these variables is "" i.e. is is supposed that +# no programs have been installed or trained. +# +# o `JA_UBE_BOGOFILTER_PRG', path to *bogofilter* program. +# o `JA_UBE_SPAMPROBE_PRG', Path to *spamprobe* program +# o `JA_UBE_BMF_PRG', Path to Bayesian Mail Filter *bmf* program. +# o `JA_UBE_SPAMASSASSIN_PRG', path to *spamassassin* program. +# If daemon version is available, set this to *spamc* program. +# o `JA_UBE_SPAMORACLE_PRG', path to *spamoracle* program. +# o `JA_UBE_ANNOYANCE_PRG', path to *annoyance-filter* program. +# You must also set `JA_UBE_ANNOYANCE_SPAM_DB' to fast +# dictionary database location. +# o `JA_UBE_BSFILTER_PRG', path to *bsfilter* program. +# +# Optional variables to set: +# +# o `JA_UBE_BOGOFILTER_OPT'. Default is "-p" passthrough. +# Option "-e" will report exit code to procmail. +# o `JA_UBE_SPAMASSASSIN_OPT'. Default is "". +# o `JA_UBE_SPAMASSASSIN_MAX_SIZE'. Default is 256000 (256k). +# Spamassassin is a Perl program, which is slow at startup, +# so checking e.g. long attachements consumes lot of resources. +# Keep this value relatively small. +# +# Important notes +# +# All headers are canonicalized to *X-Spam-<PROGRAM>-* so e.g. +# in bogofilter's case, the default *X-Bogocity* header is +# changed to value *X-Spam-Bogofilter-Status* and so on. +# Summaries like below can then be generated: +# +# $ egrep -i '(Subject|From|^X-Spam.*Status)' *.mbox +# +# Return values +# +# o `ERROR' variable's first word is set to program that classified +# the spam: *bogofilter*, *bmf* (Bayesian Mail Filter), +# *spamassassin* etc. It is followed by semicolon ";" and +# detailed return status from the program. +# o `ERROR_INFO' is set only in bogofilter's case if it thinks +# the message is neither spam nor ham ("Unsure"). +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# # ... other checks, mailing lists, work mail etc. +# +# # bogofilter and Bayesian Mail Filter available and trained. Use them. +# +# JA_UBE_BOGOFILTER_PRG = "/bin/nice -n 5 /bin/bogofilter" +# JA_UBE_BMF_PRG = "/bin/nice -n 5 /bin/bmf" +# +# # Call the "umbrella" module, which will take care of +# # all the details. +# +# INCLUDERC = $PMSRC/pm-jaube-prg-runall.rc +# +# # ERROR is set if message was spam. The "()\/" logs reason. +# +# :0 : +# * ERROR ?? ^()\/.+ +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-runall.rc: init:" + +# Kill variables + +ERROR +ERROR_INFO + +dummy = "pm-jaube-prg-runall: Run Bogofilter" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_BOGOFILTER_PRG ?? [a-z] +{ + INCLUDERC = $RC_UBE_BOGOFILTER + + :0 + * ERROR ?? ^()\/spam.* + { + ERROR = "bogofilter; $MATCH" + } + + :0 E + { + ERROR # Kill variable + } +} + +dummy = "pm-jaube-prg-runall: Run Spamprobe" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_SPAMPROBE_PRG ?? [a-z] +{ + INCLUDERC = $RC_UBE_SPAMPROBE + + :0 + * ERROR ?? ^()\/spam.* + { + ERROR = "spamprobe; $MATCH" + } + + :0 E + { + ERROR + } +} + +dummy = "pm-jaube-prg-runall: Run Annoyance filter" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_ANNOYANCE_PRG ?? [a-z] +{ + INCLUDERC = $RC_UBE_ANNOYANCE + + :0 + * ERROR ?? yes + { + ERROR = "annoyance-filter; $MATCH" + } + + :0 E + { + ERROR + } +} + +dummy = "pm-jaube-prg-runall: Run Bayesian Mail Filter" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_BMF_PRG ?? [a-z] +{ + INCLUDERC = $RC_UBE_BMF + + :0 + * ERROR ?? ^()\/yes.* + { + ERROR = "bmf; $MATCH" + } + + :0 E + { + ERROR + } +} + +dummy = "pm-jaube-prg-runall: Run Spamassassin" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_SPAMASSASSIN_PRG ?? [a-z] +{ + INCLUDERC = $RC_UBE_SPAMASSASSIN + + :0 + * ERROR ?? yes + { + ERROR = "spamassassin; $MATCH" + } + + :0 E + { + ERROR + } +} + +dummy = "pm-jaube-prg-runall: Run Bsfilter" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_BSFILTER_PRG ?? [a-z] +{ + INCLUDERC = $RC_UBE_BSFILTER + + :0 + * ERROR ?? yes + { + ERROR = "bsfilter; $MATCH" + } + + :0 E + { + ERROR + } +} + +dummy = "pm-jaube-prg-runall: Run Spamoracle" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_SPAMORACLE_PRG ?? [a-z] +{ + # We must run spamoracle last, because it lacks the ability + # to read message from stdin. Due to this many shell calls + # are needed. See the RC file for more information. + + INCLUDERC = $RC_UBE_SPAMORACLE + + :0 + * ERROR ?? yes + { + ERROR = "spamoracle; $MATCH" + } + + :0 E + { + ERROR + } +} + +dummy = "pm-jaube-prg-runall.rc: end: $ERROR" + +# pm-jaube-prg-bmf.rc ends here diff --git a/share/procmail/pm-jaube-prg-spamassassin.rc b/share/procmail/pm-jaube-prg-spamassassin.rc @@ -0,0 +1,236 @@ +# pm-jaube-prg-spamassassin -- Interface to spamassassin program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ rm -f ~/.spamassassin/bayes* +# $ sa-learn $opt --local --no-rebuild --ham good.msg ... +# $ sa-learn $opt --local --no-rebuild --spam spam.msg ... +# $ sa-learn --rebuild +# +# Overview of features +# +# o Implements interface to http://www.spamassassin.org/ +# project. +# o variable `ERROR' is set if message was spam. +# o Results are available in default headers (X-Spam-*) +# +# Description +# +# There are several Bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# This procmail subroutine implements call interface to program +# `spamassassin', which must already have been installed. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `spamassassin' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_SPAMASSASSIN_PRG = /usr/bin/spamassassin +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o JA_UBE_SPAMASSASSIN_PRG, path to the program +# o JA_UBE_SPAMASSASSIN_MIN_SIZE, minumum message size. Default is +# 100 bytes. +# o JA_UBE_SPAMASSASSIN_MAX_SIZE, maximum message size. Default is +# 256 000 bytes (about 256k). +# o JA_UBE_SPAMASSASSIN_FORCE, if set to _yes_ then call program no +# matter what. Normally if there already is `X-Spam-*' header, +# it is assumed that the message has already been checked +# and no new checking is needed. +# +# Return values +# +# o ERROR, is set to the return value of program if message was spam. +# o ERROR_INFO, is set if case is "unsure". +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_SPAMASSASSIN_PRG = "/usr/bin/nice -n 5 /usr/bin/bogofilter" +# INCLUDERC = $PMSRC/pm-jaube-prg-spamassassin.rc +# +# # The ERROR will contains reason if program classified +# # the message into "bad" category. +# +# :0 : +# * ! ERROR ?? ^^^^ +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-spamassassin.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_SPAMASSASSIN_PRG = ${JA_UBE_SPAMASSASSIN_PRG:-""} + +# No user options cannot be passed, because the output would +# change. This variable is not used. +# JA_UBE_SPAMASSASSIN_PRG_OPT = ${JA_UBE_SPAMASSASSIN_PRG_OPT:-""} + +# Theshold values when to run spamassassin for a message. + +JA_UBE_SPAMASSASSIN_MIN_SIZE = ${JA_UBE_SPAMASSASSIN_MIN_SIZE:-100} +JA_UBE_SPAMASSASSIN_MAX_SIZE = ${JA_UBE_SPAMASSASSIN_MAX_SIZE:-256000} + +# Headers of earlier run of the program. No trailing colon. + +JA_UBE_SPAMASSASSIN_HEADER_FLAG = ${JA_UBE_SPAMASSASSIN_HEADER_FLAG:-\ +"X-Spam-Flag"} + +JA_UBE_SPAMASSASSIN_HEADER_STATUS = ${JA_UBE_SPAMASSASSIN_HEADER_STATUS:-\ +"X-Spam-Status"} + +# Should we check even if there already was header +# JA_UBE_SPAMASSASSIN_HEADER ? + +JA_UBE_SPAMASSASSIN_FORCE = ${JA_UBE_SPAMASSASSIN_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variables +ERROR_INFO + +:0 +* JA_UBE_SPAMASSASSIN_PRG ?? [a-z] +*$ ! 9876543210^0 ^$JA_UBE_SPAMASSASSIN_HEADER_FLAG +* 9876543210^0 JA_UBE_SPAMASSASSIN_FORCE ?? yes +{ + # Last, run spamassassin if it has not already been run + # system wide at MTA level. NOTE: run spamassassin + # absolutely _last_ and only _if_ message was still not + # detected as Unsolicited Bulk Email by previous recipes. + # + # A lock is used so that only one program is run at a time. + # X-Spam-Flag just tests if systemwide SA has already + # been run => Headers are there already and we should save CPU + # and not call SA again. Skip too long messages (256K) + + :0 + *$ > $JA_UBE_SPAMASSASSIN_MIN_SIZE + *$ < $JA_UBE_SPAMASSASSIN_MAX_SIZE + { + jaubeSaved = $LINEBUF + LINEBUF = $JA_UBE_SPAMASSASSIN_MAX_SIZE + + # This is Procmail's global variable. Kill it for now. + + PROCMAIL_OVERFLOW + + # The message must be saved, because if there is + # a problem with SA call, it will trash the whole message. + + :0 + * HB ?? ^^\/(.*$)+$ + { + jaubeSavedMsg = $MATCH + } + + # Procmail will set PROCMAIL_OVERFLOW if 'jaubeSavedMsg' + # cannot hold the content + # + # procmail: Exceeded LINEBUF + # procmail: Assigning "PROCMAIL_OVERFLOW=yes" + + :0 fhbw : spamassassin$LOCKEXT + * PROCMAIL_OVERFLOW ?? ^^^^ + | ${JA_UBE_SPAMASSASSIN_PRG} ${JA_UBE_SPAMASSASSIN_OPT:-""} + + # Check if SA trashed the message. This is usually due + # to errors in environment. + # + # procmail: Executing "/usr/bin/spamassassin," + # Use of uninitialized value in pattern match (m//) at /usr/share/perl5/Mail/SpamAssassin/ArchiveIterator.pm line 571. + # ... + # Unable to open : No such file or directory + + :0 + * HB ?? 1^1 ^.+ + { } + + # If no lines were found, then message was trashed. Restore + + :0 E fhbw + * jaubeSavedMsg ?? [a-z] + | echo -e "$jaubeSavedMsg" + + LINEBUF = $jaubeSaved + } + + :0 + *$ ^$JA_UBE_SPAMASSASSIN_HEADER_FLAG: yes + *$ ^$JA_UBE_SPAMASSASSIN_HEADER_STATUS: \/.* + { + ERROR = "spamassassin; $MATCH" + } +} + +dummy = "pm-jaube-prg-spamassassin.rc: end: $ERROR" + +# End of file diff --git a/share/procmail/pm-jaube-prg-spamoracle.rc b/share/procmail/pm-jaube-prg-spamoracle.rc @@ -0,0 +1,281 @@ +# pm-jaube-prg-spamoracle.rc -- Interface to Spamoracle program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ spamoracle add -v -spam good.msg ... # feed individual messages +# $ spamoracle add -v -good good.msg ... # feed individual messages +# +# To test +# +# $ spamoracle test mail.msg | less +# +# Overview of features +# +# o Implements interface to http://freshmeat.net/projects/spamoracle +# OCaml language based Bayesian Mail program. +# o Variable `ERROR' is set to "yes" if the message was UBE. +# o Results are available in headers `X-Spam-Spamoracle-Status', +# `X-Spam-Spamoracle-Score', `X-Spam-Spamoracle-Details' and +# `X-Spam-Spamoracle-Attachment' for further analysis. +# +# Description +# +# There are several bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# +# Using Spamoracle as sole spam protection is inefficient, because +# version version 1.4 (2004-09-29) does not accept messages from +# stdin. Becaus of this message has to be written to a temporary file +# before calling Spamoracle. Later the temporary file must be removed +# with `rm'. All these three shell calls are needed for each message. +# If you have other detection programs, call them first to identify +# unsolicited Bulk Email. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `spamoracle' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_SPAMORACLE_PRG = /usr/bin/spamoracle +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o `JA_UBE_SPAMORACLE_PRG', path to program +# o `JA_UBE_SPAMORACLE_HEADER_PREFIX', the header name where the results +# are put. If not defined, no headers are added. Default +# value is *X-Spam-Spamoracle'*. +# o `JA_UBE_SPAMORACLE_FORCE', if set to _yes_ then call program no matter +# what. Normally if there already are *X-Spam-Spamoracle-* headers, +# it is assumed that the message has already been checked +# and no new checking is needed. +# o `JA_UBE_SPAMORACLE_REGEXP', regexp to match for spam probability. +# Defaul value will match probabbility of 0.8 with 5 interesting words. +# The match is tried agains *X-Spam-Spamoracle-Score* header. +# +# Return values +# +# o `ERROR', value "yes" if `JA_UBE_SPAMORACLE_REGEXP' matched. +# o `ERROR_MATCH' contains detailed content of +# `X-Spam-Spamoracle-Score' header. +# +# If headers were enabled, they will contain these values. The +# score's values are spam probability 0.0 - 1.0 and the degree of +# similarity 0-15 of the message with the spam messages in the +# corpus. +# +# X-Spam-Spamoracle-Status: yes +# X-Spam-Spamoracle-Score: 1.00 -- 15 +# X-Spam-Spamoracle-Details: refid:98 $$$$:98 surfing:98 asp:95 click:93 +# cable:92 instantly:90 https:88 internet:87 www:86 U4:85 isn't:14 month:81 +# com:75 surf:75 +# X-Spam-Spamoracle-Attachments: cset="GB2312" type="application/octet-stream" +# name="Guangwen4.zip" +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_SPAMORACLE_PRG = "/usr/bin/nice -n 5 /usr/bin/bmf" +# INCLUDERC = $PMSRC/pm-jaube-prg-spamoracle.rc +# +# # The ERROR will contains word "yes" if it program classified +# # the message into "bad" category. +# +# :0 : +# * ERROR ?? yes +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-spamoracle.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_SPAMORACLE_PRG = ${JA_UBE_SPAMORACLE_PRG:-""} + +# The header name prefix with no colon at the end. If this variable +# is empty, then `formail' is not called and no headers are added to +# the message. This saves a shell call and will make this repice a +# bit faster. The return status can still be checked from variable +# ERROR + +JA_UBE_SPAMORACLE_HEADER_PREFIX = ${JA_UBE_SPAMORACLE_HEADER_PREFIX:-"\ +X-Spam-Spamoracle-"} + +# Should we run the check even if there aready were header +# JA_UBE_SPAMORACLE_HEADER_PREFIX? Setting to 'yes' might mean: +# +# o We suspect that someone else had added the header, so don't +# trust it but generate our own +# o We don't trust the local MDA's result (if it had invoked +# bmf for us), because we want' to run the message +# through our own trained database +# o Or, we're simply testing and have several INCLUDERC=$RC_UBE_SPAMORACLE calls +# in our ~/.procmailrc to find out what location would be the +# best (beginning, middle, last) by examining the procmail LOGFILE. + +JA_UBE_SPAMORACLE_FORCE = ${JA_UBE_SPAMORACLE_FORCE:-"no"} + +# This regexp is matched against header like below. If found, the ERROR +# is set to "yes" to flag the spam. Range 0.8 - 1.00 and at least 5 +# or more interesting words. +# +# X-Spam--Spamoracle-Score: 0.81 -- 5 + +JA_UBE_SPAMORACLE_REGEXP = "\ +(\.[8-9]|1\.).* *-- *([5-9]|[0-9][0-9])" + +# Program cannot read message from STDIN, so we must write it to a file + +JA_UBE_SPAMORACLE_TMP_FILE = ${JA_UBE_SPAMORACLE_TMP_FILE:-\ +$HOME/spamoracle-${USER:-${LOGNAME:-foo}}.tmp} + +# ............................................................ do it ... +# Kill variables + +ERROR +ERROR_MATCH + +:0 +* JA_UBE_SPAMORACLE_PRG ?? [a-z] +*$ 9876543210^0 ! ^$JA_UBE_SPAMORACLE_HEADER_PREFIX +* 9876543210^0 ! JA_UBE_SPAMORACLE_FORCE ?? yes +{ + jaubeSpamoracleData = "" + jaubeSpamoracleDetails = "" + jaubeSpamoracleAttach = "" + + # This area must be locked, so that no other process + # is writing at the same time. + + LOCKFILE = spamoracle$LOCKEXT + + savedMetas = $SHELLMETAS + savedShell = $SHELL + SHELLMETAS = ">" + SHELL = /bin/sh + + :0 wc + | ${CAT:-/bin/cat} > $JA_UBE_SPAMORACLE_TMP_FILE + + :0 w + jaubeSpamoracleData=| $JA_UBE_SPAMORACLE_PRG \ + test \ + $JA_UBE_SPAMORACLE_TMP_FILE + + dummy = `${RM:-/bin/rm} -f $JA_UBE_SPAMORACLE_TMP_FILE` + + SHELLMETAS = $savedMetas + SHELL = $savedShell + + LOCKFILE + + # An empty message looks like this + # + # From: + # Subject: + # Score: 0.50 -- 0 + # Details: + + :0 + * jaubeSpamoracleData ?? ^From: .+ + * jaubeSpamoracleData ?? ^(X-)?(Spam-)?Score: \/.+ + { + dummy = $jaubeSpamoracleData + ERROR_MATCH = $MATCH + + :0 + * jaubeSpamoracleData ?? ^(X-)?(Spam-)?Details:\/.+ + { + jaubeSpamoracleDetails = $MATCH + } + + :0 + * jaubeSpamoracleData ?? ^(X-)?(Spam-)?Attachments:\/.+ + { + jaubeSpamoracleAttach = $MATCH + } + + dummy = "pm-jaube-prg-spamoracle.rc: Does score match?" + + :0 + *$ ERROR_MATCH ?? $JA_UBE_SPAMORACLE_REGEXP + { + ERROR = "yes" + } + + :0 fhw + | ${FORMAIL:-formail} \ + -I "${JA_UBE_SPAMORACLE_HEADER_PREFIX}Status: ${ERROR:-no}" \ + -I "${JA_UBE_SPAMORACLE_HEADER_PREFIX}Score: $ERROR_MATCH" \ + -I "${JA_UBE_SPAMORACLE_HEADER_PREFIX}Details:$jaubeSpamoracleDetails" \ + -I "${JA_UBE_SPAMORACLE_HEADER_PREFIX}Attachments:$jaubeSpamoracleAttach" + } +} + +dummy = "pm-jaube-prg-spamoracle.rc: end: $ERROR" + +# pm-jaube-prg-spamoracle.rc ends here diff --git a/share/procmail/pm-jaube-prg-spamprobe.rc b/share/procmail/pm-jaube-prg-spamprobe.rc @@ -0,0 +1,192 @@ +# pm-jaube-prg-spamprobe.rc -- Interface to Spamprobe program +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your Unsolicited Bulk Emacil (aka spam) filters towards the +# end of your `~/.procmailrc'. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked last. +# +# YOU CANNOT USE THIS PROCMAIL SUBROUTINE UNLESS YOU HAVE TRAINED THE +# BAYESIAN PROGRAM FIRST! +# +# To train: +# +# $ spamprobe -8 good good.msg ... +# $ spamprobe -8 spam spam.msg ... +# +# Make sure there are no stale lock files, or the spamprobe and this +# subroutine will hang infinitely: +# +# $ rm -f ~/.spamprobe/lock +# +# Overview of features +# +# o Implements interface to http://freshmeat.net/projects/spamprobe/ +# project. +# o variable `ERROR' is set if the message was UBE. +# o Results are available by default in header +# `X-Spam-Spamprobe-Status'. +# +# Description +# +# There are several Bayesian based statistical analysis programs that +# study the message's tokens and then classify it into two categories: +# good or bad, or if you like, ham and spam. All the Bayesian programs +# are not the same, so if you want to achive magic 99.99% probability +# the only methodology to do that is to chain several programs in +# serially. There is no single program that can solve the UBE detection. +# This procmail subroutine implements call interface to program +# `spamprobe', which must already have been installed. +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address forged. Do not increase +# the network traffic; you will not do any good to anybody by +# bouncing messgas -- you just increase mail traffic even more. +# Instead save the messages to folders and periodically periodically +# check their contents. +# +# Required settings +# +# If `spamprobe' program is available, define this variable in your +# `~/.procmailrc'. Use absolute path to make the external shell +# quick; it'll save server load considerably. +# +# JA_UBE_SPAMPROBE_PRG = /usr/bin/spamprobe +# +# If you _do_ _not_ have program installed, do not leave the +# variable lying aroung, because it will keep this subroutine active. +# Calling a non existing program is not a good idea, so it better to +# empty the variable if the program is not available. +# +# Required settings +# +# None. No dependencies to other procmail modules. +# +# Call arguments (variables to set before calling) +# +# o `JA_UBE_SPAMPROBE_PRG', path to the program. +# o `JA_UBE_SPAMPROBE_HEADER', the header name where the results +# are put. If not defined, no header is added. +# Defaults to *X-Spam-Spamprobe-Status* +# o `JA_UBE_SPAMPROBE_FORCE', if set to _yes_ then call program +# no matter what. Normally if there already is +# *X-Spam-Spamprobe-Status* header, it is assumed that the +# message has already been checked and no new checking is +# needed. +# +# Return values +# +# o `ERROR', is set to the return value of `spamprobe' program. +# +# Usage example +# +# PMSRC = $HOME/procmail # procmail recipe dir +# +# <other checks, mailing lists, work mail etc.> +# +# JA_UBE_SPAMPROBE_PRG = "/usr/bin/nice -n 5 /usr/bin/spamprobe" +# INCLUDERC = $PMSRC/pm-jaube-prg-spamprobe.rc +# +# # The ERROR will contains word "yes" if message was spam +# +# :0 : +# * ERROR ?? yes +# junk.mbox +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmail.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# None + +dummy = " +======================================================================== +pm-jaube-prg-spamprobe.rc: init:" + +# ................................................... User variables ... + +# You must define program path, because we don't know +# if it has been installed in this system or not + +JA_UBE_SPAMPROBE_PRG = ${JA_UBE_SPAMPROBE_PRG:-""} + +# Command "score" examines the message +# You could use command "train" is you have good database. + +JA_UBE_SPAMPROBE_PRG_OPT = ${JA_UBE_SPAMPROBE_PRG_OPT:-"score"} + +# The header name with no colon at the end. If this variable +# is empty, then external formail call is saved - results can still +# be checked from variable ERROR. There is no trailing colon in this +# variable. + +JA_UBE_SPAMPROBE_HEADER = ${JA_UBE_SPAMPROBE_HEADER:-"\ +X-Spam-Spamprobe-Status"} + +# Should we check even if there already was header +# JA_UBE_SPAMPROBE_HEADER + +JA_UBE_SPAMPROBE_FORCE = ${JA_UBE_SPAMPROBE_FORCE:-"no"} + +# ............................................................ do it ... + +ERROR # Kill variable + +:0 +* JA_UBE_SPAMPROBE_PRG ?? [a-z] +*$ ! 9876543210^0 ^$JA_UBE_SPAMPROBE_HEADER +* 9876543210^0 JA_UBE_SPAMPROBE_FORCE ?? yes +{ + jaubeSpamprobeScore # Kill variable + + :0 w # : spamprobe$LOCKEXT + jaubeSpamprobeScore=|$JA_UBE_SPAMPROBE_PRG ${SPAMPROBE_OPT:-"score"} + + # Check for failures; require (A)and condition + # + # procmail: Executing "/usr/bin/spamprobe,score" + # error: unable to open database ....spamprobe/sp_words: + # Cannot allocate memory + # warning: berkeley db reported error: env close: Invalid argument (22) + # caught runtime exception: unable to open words database + # caught signal 11: cleaning up + + :0 A + * jaubeSpamprobeScore ?? [a-z] + { + ERROR = $jaubeSpamprobeScore + + # X-Spam-Spamprobe-Status: GOOD 0.0000273 e5af974acad8028bea8a10f1f08b966e + # X-Spam-Spamprobe-Status: SPAM 0.9742932 07a3b71c9c96968641bbfa497a458d8e + :0 fw + * ! JA_UBE_SPAMPROBE_HEADER ?? ^^^^ + | ${FORMAIL:-formail} \ + -I "$JA_UBE_SPAMPROBE_HEADER: $jaubeSpamprobeScore" + } +} + +dummy = "pm-jaube-prg-spamprobe.rc: end: $ERROR" + +# End of file diff --git a/share/procmail/pm-jaube.rc b/share/procmail/pm-jaube.rc @@ -0,0 +1,1575 @@ +# pm-jaube.rc -- Unsolicited Bulk Email (UBE) filter. +# +# {{{ Documentation +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Warning +# +# Put all your UBE (aka spam) filters towards the _end_ of your +# ~/.procmailrc. The idea is that valid messages are filed +# first (mailing lists, your work and private mail, bounces) and only +# the uncategorized messages are checked. +# +# Are you sure you want to use procmail for UBE? +# +# If you think you can put this recipe as a first line of defence to +# your mail, you will disappoint. Checking UBE with procmail's +# rule based means does not work that way. The good messages +# must be sorted first (like your mailing lists and your +# important work or friend message) and only then what's left to +# process can be scanned by static rule based tools, like this +# procmail module. There are much more better tools that are +# based on statistical analysis of messages. You really should +# consider using one or combination of Bayesian tools: +# *Spamassassin*, *bogofilter*, *spamprobe*, *Bayesian* *Mail* +# *Filter*, *ifile* etc. +# +# _Repeat:_ procmail rules are not the tool to UBE control. The +# pattern matching rules can never keep up with the spammers. That +# said, if you: +# +# o Can bare a 70-80 % UBE detection rate. +# o Can bare 10 % false hits; you need to check you UBE folder +# regularly for messaged that did not belong there. +# o Have an account that does not get large number of UBE messages. +# o Or if procmail is all you have in the system. +# +# only then consider this module or any other procmail based +# spam filters in that respect. So, please don't set your +# expectations high. Spend good time with the configuration +# variables and check there returned result in variable `ERROR' +# carefully. Good luck. +# +# Overview of features +# +# o Requires procmail 3.11pre7+ +# o You don't need external files: site block lists, the +# heuristics nail most of the UBE messages. Just plug in this +# module and you have UBE shield active. +# o Header based filtering: Minimum headers, Pegasus bulk mail, +# X-uidl validity check, bogus From-To combination, +# o Address based filtering: Numeric address, Invalid address (eg. +# me@myMarketing.global), UBE-like(friend,remove request.) +# o Text filtering: no html accepted, common advertising slogans, +# unnecessary many capitalized words, HTML message body detection, +# o And many more check that just not were listed here. +# +# Remember: this is not 100% and there will always be some mishits, so +# don't just junk messages to `/dev/null'. +# +# Description +# +# Originally Daniel Smith posted his spam.rc, where he had gathered +# many tips and heuristics to filter UBE email. This filter here +# expresses work of many procmail users. Original filters were +# modified, some rules were left out that catched false email +# messages and made the package look a bit more general so that it +# could be included via `INCLUDERC' in the standard way. +# +# Thanks to Daniel and others, the UBE bomb days can be reduced, +# when this filter is active. Some UBE messages may still lurk +# into the mailbox, but that's the problem with all static rule +# based tools. +# +# Logging the events +# +# A good strategy to follow incoming mail is to log the vital parts +# like Date, From, Subect to some log file and then a reason what +# happened to a message. The `~/Mail/mail.log' might look like: +# +# 1997-12-08 work@example.com Extra Holiday $$$$$ +# [jaube; Marketing-Big-ExitCode; LEGAL, MONEY-MAKING PHENOMENON] +# 1997-12-09 Denizen <logger@example.com> [RePol] hiding +# 1997-12-09 david X <dx@example.com> Re: Send list to incoming folder +# 1997-12-09 david X <dx@example.com> Re: Send list to incoming folder +# 1997-12-09 OMC manager <omcman@example.fi> "Environments updated" +# [my; work-localenv] +# 1997-12-09 doodle@example.org Re: Gnus (Emacs Newsreader) FAQ +# [my; emacs; Re: Gnus (Emacs Newsreader) FAQ ] +# +# First a UBE message that was identified and saved +# to folder. Next 3 messages were filed to mailing-list folders and +# there was no [] action displayed for them (left out due to high +# volume of these messages). Second Last was internal work +# message. Lastly someone asked somthign about Emacs. +# +# The basic incoming message log recipe could be like this. +# Variable `TODAY' is `$YYYY-$MM-$DD' whose values are set after +# calling `pm-jadate.rc'. The `LISTS' is user set variable to exclude +# mailing lists whose activity is not important. Variables `FROM' and +# `SUBJECT' are fields read the message's headers. +# +# BIFF = $HOME/Mail/mail.log +# INCLUDERC = $PMSRC/pm-jadate.rc +# ... +# +# :0 hwic: +# *$ ! $LISTS +# |echo "$TODAY $FROM $FSUBJECT" >> $BIFF +# +# Here is small perl script to print summary of trapped UBE +# messages from a log like above. It gives nice overview which recipes +# catch most of the UBE messages. +# +# perl -ne '/jaube; (\S+)/; $s{$1}++; \ +# END { $s = (map{$x += $_; $_= $x} values %s)[-1]; \ +# $i = int $s{$_}/$s *100; \ +# for (keys %s) { printf "$s{$_} $i $_\n" } \ +# }' \ +# mail.log | \ +# sort -nr +# +# Here is sample results during two month period There are total of +# 3248 UBE messages catched. +# +# count % type +# ------------------------------------------ +# 554 17 Marketing-CountBigLetterWords +# 457 14 Marketing +# 422 12 Marketing-SelectedBigLetterWords +# 349 10 AddrBogus-ToFrom +# 263 8 FromReceived-Mismatch +# 223 6 NoDirectAddress-ToCc +# 216 6 HdrForgedPegasus +# 164 5 AddrBogus-To +# 151 4 MessageId +# 102 3 BodyHtml +# 73 2 Received-IPError +# 63 1 Identical-FromTo +# 53 1 AddrInvalid +# 15 0 From-nslookup +# 9 0 HdrReceivedTime +# 7 0 HdrX-UIDL +# 4 0 Marketing-headers +# +# About bouncing message back +# +# The general consensus is, that you should not send bounces. The UBE +# sender is not there, because the address is usually forged. Do not +# increase the network traffic. Instead save the messages to folders +# and periodically check their contents. It's not nice to be forced to +# apologize if you bounced message to a wrong destination. DON'T +# BOUNCE. Forget all recipe examples that use HOST and EXITCODE and +# be a good Net citizen. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This +# recipe file will include +# +# o pm-javar.rc +# o pm-janslookup.rc +# o pm-jaaddr.rc +# +# Call arguments (variables to set before calling) +# +# Only handful of the most important variables are described here. +# You really should read all the comments placed in the "user configured +# section" in this procmail module's code. Most of the defaults +# should work out of the box. +# +# o `JA_UBE_VALID_ADDR', your email addresses or other +# valid from addresses that will say "this is mail addressed +# directly to you". +# o `JA_UBE_HDR', If non-empty, a new header is added which tells which +# recipe was triggered. The header is not added to message, if +# there is nothing to report; i.e. message passed all tests. +# o Various flags: Some of the ube detecting recipes give more +# false hits than nail real ube. Experiment with yourself and turn +# on or off the recipes that work for the kind of ube messages +# you receive. +# o `JA_UBE_MAX_BIG_WORDS', the maximum count of big letter words in the +# message that is tolerated. The current count 5 is rather +# conservative and it is suggested you to increase it to prevent +# trapping too many false hits. Alternatively update JA_UBE_CAPS_OK +# to include accepted words. +# o `JA_UBE_APPARENTLY_TO_MAX', how many Apparently-To headers are +# tolerated. Default is 3. +# o `JA_UBE_MAX_HTML_TAGS', maximum count of html tags allowed in the +# body. +# o `JA_UBE_ATTACHMENT_ILLEGAL_KILL', if set to "yes" (default), then +# illegal attachment from body is ripped off. This is brute way +# to truncate the message abruptly to save mailbox space. You still +# see the headers for tracking, but the body is gone. The regexp +# to test is set in `JA_UBE_ATTACHMENT_ILLEGAL_REGEXP'. +# o `JA_UBE_ATTACHMENT_SUSPECT_KILL', if set to "yes" (default "no"), +# kill suspectible characters in attachement filename. The regexp +# to test is set in `JA_UBE_ATTACHMENT_SUSPECT_NAME_REGEXP'. +# o JA_UBE_CHARSET_LEGAL, if set, accept only these character. The +# default value detect messages with 7bit only (english speaking. +# For foreign language you may want to set this something like +# `$CHAR_7BIT_SET$CHAR_LIST_FINLAD' +# for Finnish. See `pm-javar.rc' for available character sets. +# +# Return values +# +# o `ERROR_STATUS', status word of checks. Value "Good" or "Bad" +# o `ERROR,' is set to short ube trigger recipe reason +# o `ERROR_MATCH', is set to some MATCH that happened while triggering +# UBE message. +# +# Alternatively you check content of header `JA_UBE_HDR' which contains +# results of the above variables. Possible values for `ERROR' are: +# +# AddrAOLinvalid +# AddrBogus-From +# AddrInvalid-From +# AddrInvalid-To +# AddrNumeric +# AddrNumericDomain +# AddrUbeLike +# BodyAttachment-FileIllegalAdditional +# BodyAttachment-FileIllegalMatch +# BodyAttachment-FileIllegalOther +# BodyAttachment-FileSuspect +# BodyCharacters-Illegal +# BodyHtml-NonMime +# BodyHtml-script +# BodyHtmlBase64 +# BodyHtmlImage +# BodyHtmlTags +# BodyMimeCharset-Illegal +# EnvelopeFrom-Invalid +# From-nslookup +# FromReceived-Mismatch +# HdrForgedPegasus +# HdrReceived +# HdrReceivedTime +# HdrX-Distribution +# HdrX-UIDL +# Header-ApparentlyTo +# HeaderCharacters-Illegal +# HeaderMimeCharset-Illegal +# Html-base64 +# Identical-FromTo +# Marketing-Body +# Marketing-CountBigLetterWords +# Marketing-SelectedBigLetterWords +# Marketing-Subject +# Marketing-SubjectGreeting +# MegaSpammer +# MessageId-Invalid +# MessageId-Empty +# NoDirectAddress-ToCc +# NotEnoughHeaders +# Received-IPError +# VirusBody +# VirusHeader +# +# Usage example +# +# # - All legimate messages should already been handled and +# saved before this recipe. +# # - Activate the filter only for messages that are not from +# # daemon and not from valid senders: like from "my" domain +# # and mailing lists and from somewhere else. +# +# VALID_FROM = "(my@address.example.com|word@here.example.com)" +# +# :0 +# *$ ! ^From:.*$VALID_FROM +# *$ ! FROM_DAEMON +# { +# +# # Do not add extra headers. This saves external shell call +# # (formail). Also do not try to kill the message content, +# # again saving one external call (awk). With these, the +# # recipe is faster and more CPU friendly. +# +# PM_JA_UBE_HDR = "" +# JA_UBE_ATTACHMENT_ILLEGAL_KILL = "no" +# +# INCLUDERC = $PMSRC/pm-jaube.rc +# +# # Variable "ERROR" is set if message was UBE, record error +# # to log file with "()\/" +# +# :0 : +# * ERROR ?? ()\/[a-z].* +# { +# # Don't save those *.exe, *.zip UBE attachements +# :0 +# * ERROR ?? attacment.*file +# /dev/null +# +# :0 : +# spam.mbox +# } +# } +# +# There may be UBE messages that fool `FROM_DAEMON' test, so +# you could also use something more finer check. The standard daemon +# error message almost always has sentence "Transcript of session +# follows" in the body. This recipe says: "Unless proven otherwise, +# I don't believe this is daemon message even if it looked like that". +# Add More "2^1" checks to raise score for other valid daemon cases. +# +# * -1^0 ^FROM_DAEMON +# * ! 2^1 B ?? Transcript of session follows +# { +# # ... Now call UBE checker +# } +# +# File layout +# +# The layout of this file is managed by Emacs packages tinyprocmal.el +# and tinytab.el for the 4 tab text placement. +# See project http://freshmeat.net/projects/emacs-tiny-tools/ +# +# Change Log +# +# 2004-09-10 Restructural changes and many improvements with added +# checks. This module no longer saves messages - it only checks if +# message is UBE or not. +# +# 1998-08-24 Gregory Sutter sent update to his recipe. +# +# 1998-02-27 <bochmann@TUDURZ.urz.tu-dresden.de> (Henryk Bochmann) +# reported that the ReceivedFrom test triggered all htmail messages. +# Now Fixed. +# +# }}} +# {{{ Variables + +# ............................................................ &init ... + +dummy = " +======================================================================== +pm-jaube.rc: init:" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc + + :0 # This is extremely critical, so flag error + * ! WSPC ?? [ ] + { + LOG = "(pm-jaube.rc) *** FATAL ERROR: couldn't include pm-javar.rc" + } +} + +####################################################################### +# +# User configurable variables. Set these, before calling this +# module/subroutine. +# +####################################################################### + +# ............................................... &enabling-features ... + +# Recipe enable flags. Turn off if you think they +# give too many false hits. Set to 'yes' or 'no' + +JA_UBE_FLAG_IP = ${JA_UBE_FLAG_IP:-"yes"} +JA_UBE_FLAG_MID = ${JA_UBE_FLAG_MID:-"yes"} +JA_UBE_FLAG_NUM_ADDR = ${JA_UBE_FLAG_NUM_ADDR:-"yes"} +JA_UBE_FLAG_TEXT_MARKET = ${JA_UBE_FLAG_TEXT_MARKET:-"yes"} +JA_UBE_FLAG_TEXT_VIRUS = ${JA_UBE_FLAG_TEXT_VIRUS:-"yes"} +JA_UBE_FLAG_IDENTICAL_FROM_TO = ${JA_UBE_FLAG_IDENTICAL_FROM_TO:-"yes"} +JA_UBE_FLAG_TO_CC = ${JA_UBE_FLAG_TO_CC:-"yes"} +JA_UBE_FLAG_BIG_LETTER_WORDS = ${JA_UBE_FLAG_BIG_LETTER_WORDS:-"yes"} + +# Is there is an attachment (*.exe ...), setting this option to 'yes' +# will brutally remove file attached in base64 data thus reducing the +# size of the saved message considerably. Warning: the MIME headers +# WILL BE INVALID after this brutal operation, so some Mail User +# Agents (MUAs) may not be able to read the message properly. +# +# If you have plenty of disk space OR if you plan to send the +# message to /dev/null after checking the ERROR variables for +# indication of "attachment.*file", please turn this option "off". +# Then no external awk process is called and your procmal +# process is faster. + +JA_UBE_ATTACHMENT_ILLEGAL_KILL = $JA_UBE_ATTACHMENT_ILLEGAL_KILL:-"yes"} +JA_UBE_ATTACHMENT_SUSPECT_KILL = $JA_UBE_ATTACHMENT_SUSPECT_KILL:-"no"} + +# Should the From: addresses domain be validated with nslookup? +# Turning this option on may slow down UBE filter for first 200 +# mails. After that the nslookup cache starts playing well. + +JA_UBE_FLAG_FROM_NSLOOKUP = ${JA_UBE_FLAG_FROM_NSLOOKUP:-"yes"} + +# ....................................................... &variables ... + +JA_UBE_HDR = ${JA_UBE_HDR:-"X-Spam-Jaube"} # No trailing colon! + +# Define this variable to match _all_ valid From and To addresses that +# are yours. Put your regexp inside prenthesis. +# +# This defualts to "(logname|email@foo.com)" or "(logname|xyzabc)" +# if EMAIL is not defined. + +JA_UBE_VALID_ADDR = ${JA_UBE_VALID_ADDR:-\ +(${LOGNAME:-$USERNAME}|${EMAIL:-xyzabc})} + +# A Macro + +JA_UBE_FROM = ${JA_UBE_FROM:-\ +"(^(Apparently-|Resent-)*(From|Reply-To|Sender):|^From$NSPC+)"} + +# If message comes from these address, check that From addresses domain +# is found from Received header. If not, then it's forged. +# +# This regexps must not include @ character because the matched string +# is used later "as is" and included @ will confuse the algorithm. +# +# 1998-10-05 Jacques Gauthier <jacques_g@yahoo.com> informed that +# rocketmail was merged with lycosmail, but that rocketmail still exists. + + +JA_UBE_FROM_QUESTIONABLE = ${JA_UBE_FROM_QUESTIONABLE:-"\ +@.*(compuserve\ +|aol\.\ +|microsoft\ +|yahoo +|juno\.\ +|netcom\ +|earthlink\ +|prodigy\ +|freeyellow\ +|hotmail\ +|rocketmail\ +|lycosmail\ +|wowmail\ +)"} + + +# This list is _not_ meant to be comprehensive. Just some words that are +# likely to be used in Computer related communication. +# +# ootb = out of the box oob = out of box +# fyi = for your information +# fwiw = +# itp = intent to package +# eof = end of file +# esmtp = If message headers have been attached thre will be ESMTP Mail server +# Received: lines +# dst,cest = timezone values + +JA_UBE_CAPS_OK_DEFAULT = ${JA_UBE_CAPS_OK:-\ +"\<(\ +\<AM\>\ +|ASAP\ +|API\ +|BEGIN\ +|BLOCK\ +|\<CEST\>\ +|CVS\ +|CYGWIN\ +|DHCP\ +|\<DIR\ +|\<DSA\>\ +|\<DST\>\ +|\<IP\>\ +|\<EET\>\ +|EMACS\ +|ENCRYPTED\ +|\<END\>\ +|E?SMTP\ +|EXIT\ +|\<EOF\>\ +|FAQ\ +|\<FSF\>\ +|FWIW\ +|GNOME\ +|\<GCC\ +|\<GNU\>\ +|GPG\ +|GPL\ +|\<FYI\>\ +|GIF\ +|GSM\ +|HOME\ +|HP-?UX\ +|HTTP\ +|\<ITP\>\ +|JPG\ +|\<KB\>\ +|KDE\ +|\<KEY\ +|LANG\ +|LC_ALL\ +|LC_CTYPE\ +|MESSAGE\ +|MIME\ +|NOTE\ +|OOB\ +|OOTB\ +|\<PART\>\ +|PATH\ +|\<PID\>\ +|PCX\ +|PGP\ +|<\ORACLE\>\ +|POSIX\ +|PUBLIC\ +|PXE\ +|README\ +|RSA\ +|\<SIGN(ED)?\>\ +|SSH\ +|TEXT/PLAIN\ +|\<UID\>\ +|\<URL\>\ +|US-ASCII\ +|\<UTC\>\ +|WWW\ +|XEMACS\ +)\>"} + +# Allowed words that are all caps. +# If message contains too many capitalized words, it's certainly UBE. +# +# If you want caps checking, set +# +# JA_UBE_CAPS_OK = $JA_UBE_CAPS_OK_DEFAULT + +JA_UBE_CAPS_OK = "" # Disabled by default + +# If you'tr english speankin and to not want any messages that +# contains exotic character, this default is fine. If you speak +# some other language, you should define this variable to list +# of characters allowed. It will be later converted into [ ... ] +# class regexp. + +JA_UBE_CHARSET_LEGAL = ${JA_UBE_CHARSET_LEGAL:-\ +"$CHAR_7BIT_SET$CHAR_7BIT_CONTROL"} + +# Check for header of body for these MIME content types + +JA_UBE_MIME_CHARSET_ILLEGAL = ${JA_UBE_MIME_CHARSET_ILLEGAL:-\ +"\<(ks_\ +|euc-kr\ +|ISO-.*2022\ +|big-?5\ +|gb[0-9]\ +|koi[0-9]\ +|kr\>\ +|cs\>\ +|jis\>\ +|jp\>\ +|Windows-1251\ +)"} + + +# Any regexp than can match the full attachment file name. +# *.scr is audio/x-wav + +JA_UBE_ATTACHMENT_ILLEGAL_REGEXP = ${JA_UBE_ATTACHMENT_ILLEGAL_REGEXP:-\ +"\.(\ +ba[st]\ +|bin\ +|chm\ +|cmd\ +|com\ +|cpl\ +|dll\ +|exe\ +|hta\ +|inf\ +|jar\ +|ms[cit]\ +|mp3\ +|pcd\ +|pif\ +|ram\ +|reg\ +|sc[rt]\ +|swf\ +|vb[es]?\ +|wav\ +|ws[cfh]\ +)"} + +# In addition to JA_UBE_ATTACHMENT_ILLEGAL_REGEXP, this regexp is tried. +# So, if you want to retain the default (*.exe) checks, do not touch +# JA_UBE_ATTACHMENT_ILLEGAL_REGEXP, but set +# JA_UBE_ATTACHMENT_ILLEGAL_REGEXP_ADDITIONAL +# +# You could include \.(bmp|jpe?g|gif|png) + +JA_UBE_ATTACHMENT_ILLEGAL_REGEXP_ADDITIONAL = \ +${JA_UBE_ATTACHMENT_ILLEGAL_REGEXP_ADDITIONAL:-""} + +# If this regexp matches the attachement filename, then it is +# suspect. Some spammers send files named after the email address, +# so this regexp catches those. An example: +# +# name="j.doe@example.net" +# +# Set this variable to an empty string "" to disable checking. + +JA_UBE_ATTACHMENT_SUSPECT_NAME_REGEXP = \ +${JA_UBE_ATTACHMENT_SUSPECT_NAME_REGEXP:-\ +"[@&%!?#|;:<>{}\[\]\'$]"} + +# Subject field words to classify as "Greeting" + +JA_UBE_SUBJECT_GREETING = ${JA_UBE_SUBJECT_GREETING:-\ +"\<(hi|hey|greeting|hello|help)\>"} + +# ...................................................... &thresholds ... + +JA_UBE_MAX_APPRENTLY_TO = ${JA_UBE_MAX_APPRENTLY_TO:-3} +JA_UBE_MAX_BIG_WORDS = ${JA_UBE_MAX_BIG_WORDS:-5} +JA_UBE_MAX_HTML_TAGS = ${JA_UBE_MAX_HTML_TAGS:-4} + +# ........................................................... &other ... +# Define DEGUG = "yes" to get the headers into the LOGFILE + +:0 +* DEBUG ?? on +{ + LOG = "$NL$NL ######## head-begin $NL" + HEADER = `sed /^$/q` + LOG = "$NL ######## head-end $NL" +} + +####################################################################### +# +# Private variables. Do not touch +# +####################################################################### + +jaubePGPmessage = "no" # set initial value for flag + +:0 +* B ?? BEGIN PGP (SIGNED )?MESSAGE +{ + jaubePGPmessage = "yes" +} + +jaubeHTML = "no" # set initial value for flag + +:0 +*$ HB ?? ^Content-Type:.*html +{ + jaubeHTML = "yes" +} + +# .......................................................... &output ... + +# The status of this message. Changed to "Bad" if ERROR is set here. + +ERROR_STATUS = "Good" + +# - Kill these variables. +# - The UBE catch reason is stored into ERROR. +# - If something was matched while detecting UBE, te second +# will hold the match. + +ERROR +ERROR_MATCH + +# }}} + +# ............................................................ &misc ... + +money1="[0-9]+([,.][0-9]+)*$WSPC+(dollars?|euros?)" + +money = "(\ +\$[0-9]\ +|[0-9]$WSPC*%\ +|$money1 +)" + + +# {{{ Body: Attachments + +# ............................................................ &text ... + +dummy="pm-jaube.rc: Check attachements" + +# These are some clever attachement names like: +# name="this.doc .pif" +# name="this.doc +# .pif" + +:0 +* ERROR ?? ^^^^ +* HB ?? Content-Type:.*(application|octet-stream|multipart|alternative) +*$ B ?? name=\/.+$SPCL+[^\"']+ +{ + jaubeFile = $MATCH + + # Remove leading quote mark + + :0 + *$ jaubeFile ?? ^^[\"']+\/.+$SPCL+[^\"']+ + { + jaubeFile = $MATCH + } + + :0 + * ! JA_UBE_ATTACHMENT_ILLEGAL_REGEXP ?? ^^^^ + *$ $SUPREME^0 jaubeFile ?? ()\/$JA_UBE_ATTACHMENT_ILLEGAL_REGEXP + { + ERROR = "BodyAttachment-FileIllegalMatch" + ERROR_MATCH = "$jaubeFile ($MATCH)" + } + + :0 + * ! JA_UBE_ATTACHMENT_ILLEGAL_REGEXP_ADDITIONAL ?? ^^^^ + *$ $SUPREME^0 jaubeFile ?? ()\/$JA_UBE_ATTACHMENT_ILLEGAL_REGEXP_ADDITIONAL + { + ERROR = "BodyAttachment-FileIllegalAdditional" + ERROR_MATCH = "$jaubeFile ($MATCH)" + } +} + +:0 +* ERROR ?? ^^^^ +* HB ?? Content-Type:\/.*(audio|video) +{ + ERROR = "BodyAttachment-FileIllegalOther" + ERROR_MATCH = "$MATCH" +} + +:0 +* ERROR ?? ^^^^ +* ! JA_UBE_ATTACHMENT_SUSPECT_NAME_REGEXP ?? ^^^^ +* B ?? base64 +* B ?? name=\/.* +* MATCH ?? ()\/[^\"\' ]+ +{ + jaubeFile = $MATCH + + :0 + *$ jaubeFile ?? $JA_UBE_ATTACHMENT_SUSPECT_NAME_REGEXP + { + ERROR = "BodyAttachment-FileSuspect" + ERROR_MATCH = "$jaubeFile" + } +} + +# }}} +# {{{ Invalid IP and domains, or From_ + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_IP ?? yes +*$ ^Received.*()\/\[[0-9\.]*([03-9]$d$d|2[6-9]$d|25[6-9]) +{ + ERROR = "Received-IPError" + ERROR_MATCH = $MATCH +} + +# 1998-05-26 By <dattier@wwa.com> (David W. Tamkin) in +# procmail mailing list. Message-ID: <m0ye6in-001HOsC@tekka.wwa.com> +# +# Valid envelope From_ address looks like and anything different from +# that is probably spam. +# +# From foo@bar.com Tue May 26 02:46:33 1998 + +:0 +* ERROR ?? ^^^^ +*$ ! ^From$WSPC+$NSPC+$WSCPC+.*$weekdays +*$ From+s+\/.* +{ + ERROR = "EnvelopeFrom-Invalid" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Invalid message id + +# By era eriksson <era@iki.fi> +# +# Invalid Message-Id:s are likely UBE +# Careful, this seems to give false hits sometimes(and one is enough!) +# You may want to disable this permanently. +# +# There is software out there that breaks +# RFC822 in that they don't include an "@" in the Message-Id. I don't +# care too much since I see them in my spam tank but if you send stuff +# to /dev/null, you'll probably want to take out the @ part. +# +# RFC822 says (4.1): +# +# msg-id = "<" addr-spec ">" +# addr-spec = local-part "@" domain ; global address +# local-part = word *("." word) +# domain = sub-domain *("." sub-domain) +# => +# Message-Id: word *("." word) "@" sub-domain *("." sub-domain), +# +# where (3.3): +# +# word = atom / quoted-string +# atom = 1*<any CHAR except specials, SPACE and CTLs>; efectively ascii 33-127. +# +# Example invalid: <winATT-3.01-userid-999> +# Example valid : <v03130307b0b2fc185d0b@[206.109.113.133]> +# +# Below, it is required that domain is like "this.com", and not just "localhost". + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_MID ?? yes +* ^Message-Id:\/.* +*$ ! ^Message-Id:[$WSPC]+<[^$WSPC<>@]+@([a-zA-Z0-9-]+\.)+[a-zA-Z]+> +{ + ERROR = "MessageId-Invalid" + ERROR_MATCH = $MATCH +} + +# Empty Message-ID should never be generated by a real mail program + +:0 +* ERROR ?? ^^^^ +*$ ^Message-Id:.*<$WSPC*> +{ + ERROR = "MessageId-Empty" + # ERROR_MATCH = $MATCH +} + +# }}} + +# .......................................................... &header ... + +# {{{ Header: Required minimum + +:0 +* ^From: +* ^(Apparently-|Delivered-|Envelope-)?To: +* ^Date: +{ } +:0 E +* ERROR ?? ^^^^ +{ + ERROR = "NotEnoughHeaders" + # ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Header: X-distribution + +# Pegasus mail uses this + +:0 +* ERROR ?? ^^^^ +*$ ^X-Distribution:$WSPC*\/(moderate|bulk|mass) +{ + ERROR = "HdrX-Distribution" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Header: Illegal character sets + +# This section is special. We always run the character test set, +# No matter if the previous check would have found another +# error (and ERROR is set) + +dummy = "pm-jaube.rc: Check illegal character sets" +charset = $JA_UBE_MIME_CHARSET_ILLEGAL + +:0 +* ! JA_UBE_CHARSET_LEGAL ?? ^^^^ +{ + dummy = "Charset test: $JA_UBE_CHARSET_LEGAL" + + :0 + *$ ^(Subject|From|To):.*()\/[^$JA_UBE_CHARSET_LEGAL] + { + ERROR = "${ERROR}${ERROR+:}HeaderCharacters-Illegal" + ERROR_MATCH = $MATCH + } + + :0 E + *$ B ?? ()\/[^$JA_UBE_CHARSET_LEGAL] + { + ERROR = "${ERROR}${ERROR+:}BodyCharacters-Illegal" + ERROR_MATCH = $MATCH + } +} + +:0 +*$ $SUPREME^0 ^Content-Type:.*\/$charset[^ \"'<>]* +*$ $SUPREME^0 ^Subject:.*=[?]\/$charset[^ '\"<>]* +{ + ERROR = "${ERROR}${ERROR+:}HeaderMimeCharset-Illegal" + ERROR_MATCH = "$MATCH" +} + +:0 +*$ B ?? charset=.*\/$charset[^ '\"<>]* +{ + ERROR = "${ERROR}${ERROR+:}BodyMimeCharset-Illegal" + ERROR_MATCH = "$MATCH" +} + +# }}} +# {{{ Header: Apparently-To + +# One typical UBE is where there is multiple apparently-to headers +# +# Apparently-To: +# Apparently-To: +# Apparently-To: +# Apparently-To: +# Apparently-To: + +:0 +* ERROR ?? ^^^^ +*$ -$JA_UBE_MAX_APPRENTLY_TO^0 +* 1^1 ^Apparently-To: +{ + ERROR = "Header-ApparentlyTo" + ERROR_MATCH = "$= too many" +} + +# }}} +# {{{ Header: X-uidl + +# Headers that shouldn't exist in "real" mail +# +# Might need to be a little more particular here; +# Philip Guenther <guenther@gac.edu>: If a message comes into your +# mailbox that has the X-UIDL: header, and doesn't have your address in +# the header, then I would have strong doubts about it's legitimacy. +# +# Edward J. Sabol <sabol@alderaan.gsfc.nasa.gov>: E-mails with +# X-UIDL: headers are almost definitely spam unless they've been +# Resent-To: me by someone. Also, valid X-UIDL: headers have 32 hexadecimal +# digits exactly. + +hex8 = "$h$h$h$h$h$h$h$h" + +:0 +* ERROR ?? ^^^^ +* ^X-UIDL: +*$ ! ^X-UIDL:$WSPC*\/$hex8$hex8$hex8$hex8$WSPC*$ +* ! ^Resent-To: +{ + ERROR = "HdrX-UIDL" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Header: bogus Pegasus + +# 1998-08-24 Gregory kindly sent update to this filter. Thank you. +# +# Pegasus mailer is the only mailer which legitimately generates +# "Comments: Authenticated sender is ..." so kill anything else. +# --Gregory S. Sutter <foo@xample.com> +# +# Pegasus mailer is the only mailer which legitimately generates +# "Comments: Authenticated sender is ..." so kill anything else. +# This works for Pegasus versions 2.54 and below only, 2.55 and +# above don't generate the Authenticated Sender header. + +:0 +* ERROR ?? ^^^^ +* ^Comments:.*Authenticated sender +* ! ^X-Mailer:.*Pegasus Mail +* ! ^Resent-To: +* ! ^Return-Path:.*owner- +{ + ERROR = "HdrForgedPegasus" + # ERROR_MATCH = $MATCH # what should be saved here? +} + +# }}} +# {{{ Header: Received + +# ........................................................ &received ... + +# Spamford's "Cyber-Bomber" generates "CLOAKED!" headers. +# The following also catches bogus IP addresses + +:0 +* ERROR ?? ^^^^ +* ^Received: \/.*(CLOAKED|\[(0)+\.(0)+\.(0)+\.(0)+\]).* +{ + ERROR = "HdrReceived $MATCH" + ERROR_MATCH = $MATCH +} + +# Stealth Mailer bogus timestamp + +:0 +* ERROR ?? ^^^^ +* ^Received: \/.*-0[67]00 \(E[SD]T\) +{ + ERROR = "HdrReceivedTime" + ERROR_MATCH = $MATCH +} + +# by wwgrol@sparc01.fw.hac.com (W. Wesley Groleau x4923) +# Check that suspicious From site is mentioned in the Received headers + +:0 +* ERROR ?? ^^^^ +*$ ! ^(From|To|Cc):.*$JA_UBE_VALID_ADDR +* ^Received: +*$ ^From:.*\/$JA_UBE_FROM_QUESTIONABLE +*$ ! ^Received:.*\/$MATCH +{ + ERROR = "FromReceived-Mismatch" + ERROR_MATCH = $MATCH +} + +# }}} + +# ......................................................... &Address ... + +# {{{ Address: Numeric + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_NUM_ADDR ?? yes +*$ ^From:\/$WSPC*$d+@.* +{ + ERROR = "AddrNumeric" + ERROR_MATCH = $MATCH +} + +# Bogus, all-numeric domain names: + +:0 +* ERROR ?? ^^^^ +* ^(From|To|Reply-To): \/.*@[0-9]+\..* +{ + ERROR = "AddrNumericDomain" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Address: Invalid AOL + +# By John Gianni <jjg@cadence.com> +# +# From Postmaster@aol.com: Valid AOL address can not: +# +# - be shorter than 3 or longer than 10 characters +# - begin with numerals +# - contain periods, underscores, dashes or other punctuation +# +# Valid AOL mail will have a short, verifiable Received path directly +# from a resolvable host within AOL.COM to your mail host. Valid AOL +# address are 10 characters or less and also has to begin with a +# letter and not a number also. +# +# If AOL address starts with anything else but A-Z; then it must be bogus. + +:0 +* ERROR ?? ^^^^ +* ^From: \/.*@aol\.com +* ! ^From: *([^a-z]|.+[^0-9a-z]|............).*@ +{ + ERROR = "AddrAOLinvalid" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Address: Bogus + +:0 +* ERROR ?? ^^^^ +{ + + # Originally by Daniel Smith + + word = "[a-z0-9][-a-z0-9_.+]*" + word2 = "[-a-z0-9]" + + # See "Top Level Domains (gTLDs)" http://www.icann.org/tlds/ + + tld = "(\ +aero\ +|arpa\ +|biz\ +|com\ +|coop\ +|edu\ +|gov\ +|info\ +|int\ +|mil\ +|museum\ +|name\ +|net\ +|org\ +|pro\ +|[a-z][a-z]\ +)" + +} + +:0 +* ERROR ?? ^^^^ +*$ ! ^From:\/.*$word@($word2+\.)+$tld +{ + ERROR = "AddrBogus-From" + ERROR_MATCH = $MATCH +} + +:0 +* ERROR ?? ^^^^ +*$ ! $SUPREME^0 (To|Cc):.*$JA_UBE_VALID_ADDR +*$ ! $SUPREME^0 (To|Cc):.*$word@($word2+\.)+$tld +{ + :0 + * (To|Cc):\/.* + *$ MATCH ?? $NSPC.+$NSPC + { } + + ERROR = "AddrInvalid-To" + ERROR_MATCH = $MATCH +} + +# If the From: line contains a @ but no . after it, it's suspect +# By Era eriksson + +:0 +* ERROR ?? ^^^^ +* ^From:\/.*@[^ >]+>? +*$ ! ^From:.*@[^.]+\. +{ + ERROR = "AddrInvalid-From" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Address: UBE-like + +:0 +* ERROR ?? ^^^^ +*$ ()\/(${JA_UBE_FROM}|^TO)(remove|delete|\<free\>|friend@) +{ + ERROR = "AddrUbeLike" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Header: From-To, To-Cc + +# By Era Eriksson, Sun, 08 Feb 1998 in procmail mailing list +# The lone "To" is purely for logging purposes to record MATCH + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_IDENTICAL_FROM_TO ?? yes +*$ ! ^(From|To|Cc):.*$JA_UBE_VALID_ADDR +* ^To: \/.* +* $ ^\/(From|Reply-To): $\MATCH +{ + ERROR = "Identical-FromTo" + ERROR_MATCH = $MATCH +} + +# If the message is not directly addressed to ME, then It's suspect. +# Be sure to handle mailing lists before you call this file !! + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TO_CC ?? yes +* ! FROM_DAEMON +* ^(To|Cc):\/.* +*$ ! ^(To|Cc):.*$JA_UBE_VALID_ADDR +{ + ERROR = "NoDirectAddress-ToCc" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ Text: Marketing slogans + +# ....................................................... &marketing ... +# Notice that the MATCH is set to text line that triggered the UBE + +dummy = "pm-jaube.rc: Marketing-CaseSensitive" + +# Case sensitive tests + +:0 D +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TEXT_MARKET ?? yes +* HB ?? ()\/\<(\ + GUARANTEED|OFFER|BONUS|CREDIT\ + |LEGAL(LY)?|SECRET|\<CLICK\>\ + |NO RISK|MAKE.*MONEY\ + |MILLION|THOUSEND\ + ).* +{ + ERROR = "Marketing-SelectedBigLetterWords" + ERROR_MATCH = $MATCH +} + +dummy = "pm-jaube.rc: Marketing-Headers" + +# If there is a dollar in header(subject), this is ube. + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TEXT_MARKET ?? yes +*$ ^Subject:.*()\/(\$[0-9]|[0-9]$WSPC*%|\<Free\>|!!+) +* ! SUBJECT ?? Returned mail +{ + ERROR = "Marketing-Subject" + ERROR_MATCH = $MATCH +} + +dummy = "pm-jaube.rc: Simple headers, dollar body" + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TEXT_MARKET ?? yes +*$ ^Subject:$WSPC*((fwd|re):)*$WSPC*$JA_UBE_SUBJECT_GREETING +*$ ^Subject:()\/.* +*$ B ?? $money +{ + ERROR = "Marketing-SubjectGreeting" + ERROR_MATCH = $MATCH +} + +dummy = "pm-jaube.rc: Marketing body" + +# "Earn" must not match "learn" +# Some marketing people try to be clever, they send +# +# for just $19.95, for incredible $19.95, for the sum 19.195 +# for 19.95 +# +# So we match anything that has "for" and NN+.N+. There must not be +# dollar in from, because the marketing could also use English pounds +# or some other currency. +# +# \<for\>.*\<[0-9][0-9.]*\> + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TEXT_MARKET ?? yes +*$ B ?? ()\/\ + \<(naked|women|girls|nude)\>\ + |\<(babe|chick|blonde|brunette|cash|sex|hardcore|viagra)\>\ + |\<(promote|earn|porn|drug\ + |make.*money\ + |Money making\ + |Make \$[0-9]\ + |(Low|fair|these) +price\ + |price.*\<range\ + |want to buy\ + |bulk email\ + |No Credit Check\ + |this is your chance\ + |The most incredible stuff\ + |You have nothing to lo*se\ + |weight control\ + |lifetime membership\ + |Internet Business\ + |order(ing)? (now|form)\ + |are.*you.*looking for\ + |global.*Advertis\ + |marketing resource\ + |Don't waste.*(dollars|money)\ + |bring to your attention\ + |limited.*(trial|time)\ + |our.*offerings\ + |We.*(guarantee|seek)\ + |\<(for|cost)\>.*$[0-9][0-9.]\ + |This offer\ + |FREE.*(offer|bonus|sample)\ + |as low as.*$[0-9]\ + |$money1\ + |send \$.* to\ + |save up.*to.*%\ + |save as much as.*[$%]\ + |sav(e|ing).*money\ + |Delete if not interested\ + |wish to be (excluded|removed)\ + |to our remove list\ + |Remov(al|e) instruction\ + |to be removed from.*list\ + |to reply to remov\ + |you were.*selected\ + |life style\ + |phone card\ + |long distance\ + |Life Insurance\ + |forgive the intrusion\ + |Your.*(bonus|marker)\ + |(visit|Welcome).*our.*Web ?site\ + |(CALL|visit).*\<(us|today)\>\ + |webcam\ + |Response +needed\ + )$S*$WSPC*$S* +*$ MATCH ?? $NSPC +{ + ERROR = "Marketing-Body" + ERROR_MATCH = $MATCH +} + +dummy = "pm-jaube.rc: Virus message" + +:0 +* ERROR ?? ^^^^ +{ + regexpBody = "\ +Attenzione Virus\ +|Returned due to virus\ +|[]{<(]virus[]})>]\ +|InterScan NT Alert\ +|Message quarantined\ +|Filter incident\ +|Symantec AVF detected\ +|banned filename .*in mail from you\ +|File blocked - ScanMail for Lotus\ +|MDaemon Notification -- Attachment Removed\ +|SAV detected a violation in a document\ +|MailMarshal has detected a suspect attachment\ +|Security Alert - ScanMail for Lotus Notes\ +|Skynet Mail Protection scan results\ +|Vexira ALERT\ +|You sent potentially unsafe content\ +" + + # These are too general to appear in Body. + + regexpHeader = "\ +virus(es|ii)?.*\<(alert|warn|detect|remov|found|infect|notif|scan|mail)\ +|\<(alert|warn|detect|remov|found|infect|notif|scan|mail|sen[dt]).*virus\ +|\<(contained).*virus\ +|\<anti-?vir(us)?\>\ +|virus.*(gefunden|encontrado|enviado|correo)\ +|$regexpBody\ +" + +} + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TEXT_VIRUS ?? yes +*$ ()\/($regexpHeader)$S*$WSPC*$S* +{ + ERROR = "VirusHeader" + ERROR_MATCH = $MATCH +} + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_TEXT_VIRUS ?? yes +*$ B ?? ()\/($regexpBody)$S*$WSPC*$S* +{ + ERROR = "VirusBody" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ score: big letters + +# Count full words whose all letters have been capitalized +# - If must not be uuencoded message, +# - Ignore some commond words like: IP AM SMTP +# - Word must have at least 3 big letters + +dummy = "pm-jaube.rc: CHECK BigLetterWords" + +:0 D +* ERROR ?? ^^^^ +* jaubeHTML ?? no +* jaubePGPmessage ?? no +*$ ! JA_UBE_CAPS_OK ?? ^^^^ +*$ -$JA_UBE_MAX_BIG_WORDS^0 +*$ B ?? -1^1 ()$JA_UBE_CAPS_OK +* B ?? 1^1 ()\/\<[A-Z][A-Z][A-Z]+\> +{ + ERROR = "Marketing-CountBigLetterWords" + ERROR_MATCH = "$= too many" +} + +# }}} +# {{{ text: html + +# Raw HTML, but missing MIME definition headers. +# Or you could match B ?? ()<(body[^<>]*|html)> + +:0 +* ERROR ?? ^^^^ +*$ B ?? ^^$SPCL*<html> +* ! H ?? ^(Mime-Version\\|Content-Type): +{ + ERROR = "BodyHtml-NonMime" + ERROR_MATCH = $MATCH +} + +:0 +* ERROR ?? ^^^^ +* HB ?? ^Content-Type:.*/html +* HB ?? ^Content-Transfer-Encoding:.*base64 +* HB ?? ^\/Subject:.* +{ + ERROR = "Html-base64" +} + +# The Javascript, VBscript + +:0 +* ERROR ?? ^^^^ +* B ?? ()<html> +* B ?? ()\/<$SPC*script$SPC*(lang.+)?> +* B ?? </$SPC*script$SPC*> +{ + ERROR = "BodyHtml-script" + ERROR_MATCH = $MATCH +} + +:0 +* ERROR ?? ^^^^ +*$ -$JA_UBE_MAX_HTML_TAGS^0 +* B ?? 1^1 ()\/</?(body|html|ul|ol|dl|dd|dt|li|br|p|pre|font\ + |h[123456]|table|tr|td)> +{ + ERROR = "BodyHtmlTags" + ERROR_MATCH = "$= too many" +} + +:0 +* ERROR ?? ^^^^ +* B ?? ^Content-Type:.*text/html +* B ?? ^Content-Transfer-Encoding:.*base64 +{ + ERROR = "BodyHtmlBase64" + # ERROR_MATCH = $MATCH +} + +:0 +* ERROR ?? ^^^^ +*$ B ?? ()<img$WSPC+src$WSPC*=.*http +{ + ERROR = "BodyHtmlImage" + # ERROR_MATCH = $MATCH +} + +# Known MEGA Spammers +# +# They send 20Million spams a day! Try this (and we'll count +# lines, not strings, just in case "cyberpromo.com" occurs twice in +# the subject: for example, a legitimate letter from a friend has a +# subject of "I'm sick of cyberpromo.com! Damn cyberpromo.com to +# hell!"). +# +# 1^1 ^.*\<cyberpromo\.com\> +# * -1^1 ^Subject:(.*\<)?cyberpromo.com\> +# +# While less "perfect", I can never remember the scoring rules, and I'd +# likely use something like the following; plus, it's probably faster: +# This catches "cyberpromo.com" in any header not starting with "S", and +# it happens that none of the ones we need to catch it in start with "S", +# so it probably works the same on "real-life" mail headers. The +# condition can be modified to check for headers not starting with "Su" +# by changing it to: +# +# * ^([^S]|S[^u]).*\<cyberpromo\.com\> +# +# if needed; further extensions should be obvious.) + +:0 +* ERROR ?? ^^^^ +* ^[^S].*\/\<cyberpromo\.com\> +{ + ERROR = "MegaSpammer" + ERROR_MATCH = $MATCH +} + +# }}} +# {{{ nslookup + +dummy = "pm-jaube.rc: Check nslooup" + +# Check if From address has valid domain. We can't check address, but this +# is closest we get. This check must be at the end so that faster "text" +# test are applied first. + +:0 +* ERROR ?? ^^^^ +* JA_UBE_FLAG_FROM_NSLOOKUP ?? yes +* ^From:\/.* +{ + INPUT = $MATCH + INCLUDERC = $PMSRC/pm-jaaddr.rc # explode address string + ERROR + + :0 + *$ SITE ?? $a + { + INPUT = $SITE + INCLUDERC = $PMSRC/pm-janslookup.rc + + :0 + * ERROR ?? yes + { + ERROR_MATCH = "From $SITE nslookup fail/$ERROR_MATCH" + ERROR = "From-nslookup" + } + :0 E + { + ERROR # Clear variable + } + } +} + +# }}} + +# ..................................................... &final-check ... + +:0 +* ! ERROR ?? ^^^^ +{ + ERROR_STATUS = "Bad" + + :0 + * ! JA_UBE_HDR ?? ^^^^ + { + jaubeHeader = "$JA_UBE_HDR: $ERROR_STATUS $ERROR $ERROR_MATCH" + + # Check if ERROR_MATCH is not set (empty) + + :0 + * ERROR_MATCH ?? ^^^^ + { + jaubeHeader = "$JA_UBE_HDR: $ERROR_STATUS $ERROR" + } + + :0 fhw + | ${FORMAIL:-"formail"} -I "$jaubeHeader" + } + + # If AWK fails, then we see "Rescue of unfiltered data succeeded" + # This might be due to message being too big + + :0 fbiw + * ERROR ?? Attachment.*FileSuspect + * JA_UBE_ATTACHMENT_SUSPECT_KILL ?? yes + * B ?? base64 + | $AWK '/[bB]ase64|BASE64/ { exit } { print }' + + :0 E fbiw + * ERROR ?? Attachment.*FileIllegal + * JA_UBE_ATTACHMENT_ILLEGAL_KILL ?? yes + * B ?? base64 + | $AWK '/[bB]ase64|BASE64/ { exit } { print }' +} + +dummy = "pm-jaube.rc: end: $ERROR" + +# pm-jaube.rc ends here diff --git a/share/procmail/pm-jaube1.rc b/share/procmail/pm-jaube1.rc @@ -0,0 +1,67 @@ +# pm-jaube1.rc -- Jari's UBE filter. Subroutine 1 +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Documentation +# +# This file is part of the "pm-jaube.rc". This subroutine is called +# when likely UBE message has been triggered. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This recipe file +# will include +# +# o pm-jastore.rc +# +# Change Log (none) + +# ............................................................ &code ... +# + +id = "pm-jaube1.rc" +dummy = " +======================================================================== +$id: init: +" + + +# Should we write log message to file which identifies this UBE + +:0 hic: $JA_UBE_LOG$LOCKEXT +* JA_UBE_LOG ?? [a-z] +|echo " [jaube; $ERROR; $ERROR_MATCH]" >> $JA_UBE_LOG + + +# Add new header to the message + +:0 fhw +* JA_UBE_HDR ?? [a-z] +| $FORMAIL -A "$JA_UBE_HDR: $ERROR, $ERROR_MATCH" + +# Should it be stored directly? + +:0 +* JA_UBE_MBOX ?? [a-z] +{ + MBOX = $JA_UBE_MBOX + INCLUDERC = $RC_STORE +} + +dummy = "$id: end:" + + +# pm-jaube1.rc ends here diff --git a/share/procmail/pm-javac.rc b/share/procmail/pm-javac.rc @@ -0,0 +1,144 @@ +# pm-javac.rc -- Procmail: Vacation framework recipe (id-cache) +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# Framework for all programs that need to reply to messages only once. +# Usually known as "vacation" feature. If you cahnge th cache file, +# you can attach this recipe to any messages that you want to deal with +# only once. +# +# Required settings +# +# PMSRC must point to source directory of procmail code. This subroutine +# will include +# +# o pm-javar.rc +# +# Call arguments (variables to set before calling) +# +# o JA_VAC, To activate vacation, set value to "yes" +# o JA_VAC_RC, When new message-id is found, run this includerc +# o JA_VAC_ID_CACHE, Remember to clear this file when you start +# the vacation. +# +# Usage example +# +# To turn on the vacation feature, create ~/.vac file and recipe below +# activates vacation. If the vacation is not active, then cache file +# is removed. (automatic cleanup). The VERBOSE is also turned off +# when you're on vacation; so that your procmail log will not get +# filled. +# +# So when you go to vacation, you 'touch ~/.vac' and update +# ~/vacation.msg. When you come back, you 'rm ~/.vac'. That's it. +# +# IMPORTANT: If you are subscribed to mailing lists, be sure to file +# messages from those services first and put the vacation recipe +# only after the list or bot messages. Also add sufficent "!" conditions +# in order not to reply to other "bot" service messages. +# +# JA_VAC_ID_CACHE = $HOME/.pm-vac.cache +# +# :0 +# *$ ? $IS_EXIST $HOME/.vac +# { +# VERBOSE = off +# JA_VAC = "yes" +# JA_VAC_RC = $PMSRC/pm-myvac.rc # my vacation recipe +# INCLUDERC = $PMSRC/pm-javac.rc # framework +# } +# :0 E # else +# * ? $IS_EXIST $JA_VAC_ID_CACHE +# { +# dummy = `$RM -f $JA_VAC_ID_CACHE` +# } +# +# Here is example of pm-myvac.rc recipe +# +# # Change subject +# +# :0 fhw +# * ^Subject: *\/[^ ].* +# | $FORMAIL -I "Subject: vacation (was: $MATCH)" +# +# :0 fb # put message to body +# | $CAT $HOME/.vacation.msg +# +# :0 # Send it +# | $SENDMAIL +# +# Change Log (none) + +dummy = " +======================================================================== +pm-javac.rc: init:" + +:0 +* ! WSPC ?? [ ] +{ + INCLUDERC = $PMSRC/pm-javar.rc +} + +# .......................................................... &public ... + +JA_VAC = ${JA_VAC:-"no"} +JA_VAC_RC = ${JA_VAC_RC:-""} +JA_VAC_XLOOP = ${JA_VAC_XLOOP:-"$LOGNAME@$HOST X-loop"} +JA_VAC_ID_CACHE = ${JA_VAC_ID_CACHE:-"$HOME/pm-vac.cache"} +JA_VAC_ID_CACHE_SIZE = ${JA_VAC_ID_CACHE_SIZE:-8192} + +# ........................................................... &do-it ... +# - The `! precedence' match should prevent from replying to "bot" +# messages +# - Mailing lists should use type "list" + +:0 +* JA_VAC ?? yes +*$ ! $JA:FROM_DAEMON +*$ ! ^X-Loop: $JA_VAC_XLOOP +* ! ^Precedence:.*(bulk|list|junk) +* JA_VAC_RC ?? [a-z] +{ + dummy = "pm-javac.rc: checking." + + oldLock = $LOCKFILE + LOCKFILE = ${JA_VAC_ID_CACHE}${LOCKEXT} + + :0 c + * ! ? $FORMAIL -rD $JA_VAC_ID_CACHE_SIZE $JA_VAC_ID_CACHE + { + # Compose reply and add some basic headers + + :0 fhw + | $FORMAIL -rt \ + -A "Precedence: junk" \ + -A "X-Loop: $JA_VAC_XLOOP" + + :0 a # Formail succeeded + { + # New user, call this rc to send a reply + INCLUDERC = $JA_VAC_RC + } + } + + LOCKFILE = $oldLock +} + +dummy = "pm-javac.rc: end:" + +# End of file diff --git a/share/procmail/pm-javar.rc b/share/procmail/pm-javar.rc @@ -0,0 +1,562 @@ +# pm-javar.rc -- Global variable definitions +# +# File id +# +# Copyright (C) 1997-2010 Jari Aalto +# +# 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 at +# <http://www.gnu.org/copyleft/gpl.html>. +# +# Description +# +# This file defines common variables that you can use in the recipe's +# condition line. Procmail does not know about escape sequences +# like `\t' or `\n' and it is therefore much more readable to use +# variables as substitute for common regular expression +# atoms. Pay attention that the line starts with "*$ ", where +# "$" expands the variables: In this file, the variable names +# represent the well known Perl regular expression names, so +# that $s is alost like Perl expression \s (whitespace) and $S +# is almost equivalent to `\S' (non-whitespace). Similarly, $d is +# `\d' (digit) and $D resembled `\D' (non-digit). +# +# :0 +# *$ $s+something+$s+$d+$a+ +# +# The equivalent without variables (you don't see the tabs and +# spaces here): +# +# :0 +# # Space + tab +# * [ ]something[ ][0-9]+[a-z]+ +# +# +# In addition all system dependent variables are defined in this module. +# For example if you have Gnu awk, it is strongly suggest that you set: +# +# AWK = "/path/to/gawk" # in Linux, this would be /usr/bin/awk +# +# You can define these variables before or after the module, just make +# sure the binaries reflect your operating system's paths. In general, +# if you "port" your setup to several system, dont' include absolute +# paths. In the other hand, if your setup is in the same place using +# absolute paths will speed up executions by a factor of 3 or more. +# (depending on how long your PATH is) +# +# Standard variables defined +# +# See pm-tips.txt file for full explanation or look at the source code. +# +# SPC WSPC NSPC SPCL # Whitespace, Non Whitespace, W+linefeed +# \s \d \D \w \W and \a \A # perl equivalents +# +# Special variable JA_FROM_DAEMON +# +# In order to boost procmail and to save extra CPU cycles, this module +# defines variable `JA_FROM_DAEMON' that caches the information of +# ^FROM_DAEMON. You can refer to `JA_FROM_DAEMON' as you would to +# big brother FROM_DAEMON. This has the advantage that procmail +# has already computed the result and the variable `JA_FROM_DAEMON' +# is used as a cache, thus avoiding repeated FROM_DAEMON regexp +# tests, which are expensive. Variable `JA_FROM_DAEMON_match' +# contains "" or the result of matched daemon text. +# +# *$ $JA_FROM_DAEMON +# +# or the familiar +# +# *$ ! $JA_FROM_DAEMON +# +# Instead of using the regexp parsing with +# +# * ^FROM_DAEMON +# +# and +# +# * ! ^FROM_DAEMON +# +# Special variable JA_FROM_MAILER +# +# Works like `JA_FROM_DAEMON' variable but in respect to FROM_MAILER. +# The matches text is in `JA_FROM_MAILER_MATCH' +# +# Usage example +# +# For your .procmailrc, you can simply put this, because you +# want to load the variables at startup +# +# PMSRC = "/path/to/install/location/of/this/library" +# INCLUDERC = $PMSRC/pm-javar.rc +# +# If you're developing your own modules that use these variables +# put these lines at the beginning. `~/.procmailrc'. It checks +# if WSPC variable does not include a space --> load the +# variable definitions. If the variable is already defined, the +# file is not loaded. The test line is something alike #ifdef -- +# #endif in C/C++ language or a conditional "import" command in +# other languages. +# +# :0 +# * ! WSPC ?? [ ] +# { +# INCLUDERC = $PMSRC/pm-javar.rc +# } +# +# Defined modules +# +# After this file loads, you can refer to any module with $RC_JA_MODULE. +# E.g. to call email spit module in your code you would use following. +# See at the end of this file for all defined module names. +# +# INCLUDERC = $RC_JA_UBE +# +# Change Log (none) + +dummy = " +======================================================================== +pm-javar.rc: init:" + +# pure newline, you could use is like: +# LOG = "message $NL" + +NL = " +" +LF = $NL # synonym, linefeed +CR = " " # Carriage return +TAB = " " # \t character, you won't see it. +WSPC = " $TAB" # whitespace in procmail: space + tab + +# These are the variables that you're likely to use in +# condition lines. Notice that there is Perl styles `s' variable +# for shorter name for most used SPC. + +SPC = "[$WSPC]" # Regexp space/tab +NSPC = "[^$WSPC]" # Negation, non-whitespace + +# Whitespace with linefeed +# Note that in regexps, the character class is faster that OR. +# Refer to O'Reilly book "Mastering Regular Expressions" +# +# space + tab + dollar +# +# ( | |$) is slower than ([ ]|$) + +SPCL = "($SPC|$|$CR)" # space or tab; linefeed; Carriage return + +# ..................................................... &perl-styled ... +# http://www.perl.com/ +# Shorter variable names, mimic perl token names. + +n = "$NL" # Newline -- Perl \n +t = "$TAB" # Tab -- Perl \t +s = "$SPC" # whitespcae -- Almost like perl \s +S = "$NSPC" # Non-Whitespace -- Almost like Perl \S +d = "[0-9]" # digit -- Perl \d +D = "[^0-9]" # Non-digit -- Perl \D +w = "[0-9a-z_A-Z]" # word -- Perl \w +W = "[^0-9a-z_A-Z]" # Non-word -- Perl \W + +# No perl equivalents for these, but handy anyway. + +a = "[a-zA-Z]" # alphabetic (7 bit) +A = "[^a-zA-Z]" # Non-alphabetic +h = "[0-9a-fA-F]" # Hex value +H = "[^0-9a-fA-F]" # Non-Hex value + +# ............................................................ &misc ... + +SUPREME = "9876543210" # The highest score value. See pm-tips.txt +OR = "$SUPREME" # Multiline OR-ing in score recipes +NOR = "-$SUPREME" + +# For IP addresses + +OCTET = "([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])" +DOTQUAD = "$OCTET[.]$OCTET[.]$OCTET[.]$OCTET" + + +# Getting month or month-number matches. See pm-jadate*rc modules +# for examples. + +mm2nbr = "Jan01Feb02Mar03Apr04May05Jun06Jul07Aug08Sep09Oct10Nov11Dec12" +nbr2mm = "01Jan02Feb03Mar04Apr05May06Jun07Jul08Aug09Sep10Oct11Nov12Dec" +weekdays = "(Sun|Mon|Tue|Wed|Thu|Fri|Sat)" + +TMPDIR = ${TMPDIR:-"/tmp"} + +# ........................................................ &programs ... +# Substitute these with absolute path names and binaries will run faster + +FORMAIL = ${FORMAIL:-"formail"} +PROCMAIL = ${PROCMAIL:-"procmail"} + +# Don't ever leave out flags -oi and -t + +SENDMAIL_FLAGS = "-oi -t" +SENDMAIL = ${SENDMAIL:-"sendmail $SENDMAIL_FLAGS"} + +# This _must_ be Perl 5.x version. Old version 4.0 is way too old +# and obsolete for statements like BEGIN{} + +PERL = ${PERL:-"perl"} + +LS = ${LS:-"/bin/ls"} +LS_BY_DATE = ${LS:-"/bin/ls -t"} +TR = ${TR:-"/bin/tr"} +RM = ${RM:-"/bin/rm"} +MV = ${MV:-"/bin/mv"} +CP = ${CP:-"/bin/cp"} +CAT = ${CAT:-"/bin/cat"} +SED = ${SED:-"/bin/sed"} +AWK = ${AWK:-"awk"} + +RMDIR = ${RMDIR-"/bin/rmdir"} +MKDIR = ${MKDIR-"/bin/mkdir"} + +TOUCH = ${TOUCH:-"touch"} +CHMOD = ${CHMOD:-"chmod"} +DATE = ${DATE:- "date"} # must accept POSIX % escapes as date(1) + +EGREP = ${EGREP:-"egrep"} +FGREP = ${EGREP:-"fgrep"} +GREP = ${EGREP:-"egrep"} # use "grep -E" if you have GNU version +NSLOOKUP = ${NSLOOKUP:-"nslookup"} +GZIP = ${GZIP:-"gzip"} +BZIP = ${BZIP:-"bzip2"} # Name BZIP is shorter than pedantic BZIP2 + +# ............................................................ &test ... +# The `test' command is not identical on every operating system, so they +# must be put behind variables. E.g. On Irix the -e +# option is not recognized so IS_EXIST must be changed to -r there. + +IS_READABLE = ${IS_READABLE:-"test -r"} +IS_EXIST = ${IS_READABLE:-"test -e"} +IS_EXECTABLEU = ${IS_READABLE:-"test -x"} +IS_FILE = ${IS_READABLE:-"test -f"} +IS_DIR = ${IS_READABLE:-"test -d"} +IS_NOT_EMPTY = ${IS_READABLE:-"test -s"} # exist and not empty + +# ............................................................ &mime ... +# Mime decode commands: Install package 'metamail' if the system +# does not have program `mimencode'. +# See <ftp://ftp.funet.fi/pub/unix/mail/metamail> and "mm2.7*" +# Metamail's description: +# +# Collection of MIME handling utilities Metamail is an implementation of +# MIME, the Multipurpose Internet Mail Extensions, a proposed standard +# for multimedia mail on the Internet. Metamail implements MIME, and also +# implements extensibility and configuration via the "mailcap" mechanism +# described in an informational RFC that is a companion to the MIME +# document. + +MIME_BIN = ${MIME_BIN:-"mimencode"} +MIME_BIN_QP = ${MIME_BIN_QP:-"$MIME_BIN -u -q"} # decode Quoted printable +MIME_BIN_64 = ${MIME_BIN_64:-"$MIME_BIN -u -b"} # decode base64 + +# encode commands with "E" at the end + +MIME_BIN_QP_E = ${MIME_BIN_QPE:-"$MIME_BIN -q"} +MIME_BIN_64_E = ${MIME_BIN_64E:-"$MIME_BIN -b"} + +# ...................................................... &exit-codes ... +# These should be pretty standard. See /usr/include/sysexits.h + +EX_OK = 0 # successful termination +EX__BASE = 64 # base value for error messages + +EX_USAGE = 64 # command line usage error +EX_DATAERR = 65 # data format error +EX_NOINPUT = 66 # cannot open input +EX_NOUSER = 67 # addressee unknown +EX_NOHOST = 68 # host name unknown +EX_UNAVAILABLE = 69 # service unavailable +EX_SOFTWARE = 70 # internal software error +EX_OSERR = 71 # system error (e.g., can't fork) +EX_OSFILE = 72 # critical OS file missing +EX_CANTCREAT = 73 # can't create (user) output file +EX_IOERR = 74 # input/output error +EX_TEMPFAIL = 75 # temp failure; user is invited to retry +EX_PROTOCOL = 76 # remote error in protocol +EX_NOPERM = 77 # permission denied + +# ........................................................ &messages ... +# Reserve string variables + +JA_MSG_ERROR = "ERROR: *** " # Message follows after this +JA_MSG_ERROR_FATAL = "ERROR: FATAL: *** " # Message follows after this + +# ................................................... character sets ... +# Define character sets grouped by language. +# Contact: <PSE-L@mail.professional.org> +# 2004-04-16 included from http://www.professional.org/procmail/furrin.rc +# See thread "furrin character sets" 2203-02-22 at +# http://info.ccone.at/INFO/Mail-Archives/procmail/Feb-2003/threads.html#00521 + +# In emacs, you can generate any character: See key C-x 8 C-h +# +# There are entities: u umlaut (small/big), SZ ligature +CHAR_LIST_GERMAN = "üÜß" + +# These are entities: a A ring, a A umlaut, o O umlaut +CHAR_LIST_FINLAND = "åÅäÄöÖé" +CHAR_LIST_SWEDEN = $CHAR_LIST_FINLAND + +# included entity: o slash +CHAR_LIST_NORWAY = "$CHAR_LIST_FINNISHøØ" + +# included entity: ae AE ligature +CHAR_LIST_DENMARK = "æÆ" + +CHAR_LIST_SCANDINAVIAN = "\ +$CHAR_LIST_FINLAND\ +$CHAR_LIST_NORWAY\ +$CHAR_LIST_DENMARK\ +" + +# You can make regular expressions like: +# +# unclean7bit = "[^$CHAR_7BIT_SET]" +# +# :0 : +# * HB ?? unclean7bit +# spam + +# Newline +CHAR_7BIT_CONTROL = " " + +CHAR_7BIT_PUNCTUATION = "-+^~\"\'\`&/\\|*@%!?,.:;\(\){}<>\[\]\$#" + +CHAR_7BIT_SET = "$TAB !-~" # This is range: from SPC to TILDE. +CHAR_7BIT_SCANDINAVIAN_SET = "$CHAR_7BIT_SET$CHAR_LIST_SCANDINAVIAN" + +CHARSET_JP = "WINDOWS-932|EUC-JP|(cs-?)?ISO-?2022-?JP(-[12])?|ISO-2022-D\ +|SHIFT[-_]JIS|JIS[-_]?X[-_]?02(08|01|12|13)|sjis|jis7|ms-kanji\ +|(x-)?mac(-)?japanese|x-EBCDIC-Japanese(Katakana|AndUSCanada\ +|AndJapaneseLatin|AndKana)" + +CHARSET_CN = "WINDOWS-(936|950)|EUC-CN|(hz-|x-euc-tw)?GB[-_]?2312\ +|(cn-)?(BIG5|gb)|ISO-2022-([EGHIJKLM]|cn|cn-ext)|ISO-IR-165\ +|GB8565\.2(-1988)?|x-euc-tw|hz|iso-ir-58|gbk|big5-hkscs|gb18030\ +|(x-)?mac(-)?chinese(trad|imp)|iso-ir-58\ +|x-EBCDIC-(Traditional|Simplified)Chinese|x-Chinese-(CNS|eten)" + +# non-standards compliant variations of chinese + +CHARSET_CN_BOGUS = "CHINESEBIG5|BIG-5" + +CHARSET_KR = "WINDOWS-949|EUC-KR|KS[-_ ]?C[-_ ]?5601([-_ ]?1987)?\ +|ISO-2022-(C|kr)|KS[-_]?X[-_]?1001|ksc5636|iso-646-kr|uhc\ +|johab|(x-)?mac(-)?korean|iso-ir-149|x-EBCDIC-(KoreanAnd)?KoreanExtended" + +# some mailer actually sets this + +CHARSET_BOGUS = "X-UNKNOWN|USER-DEFINED" + +# Not recommended to block these - they're all rather encompassing + +CHARSET_UNICODE = "UTF(-)?(7|8|16)]|UCS(-)?(2|4)\ +|UNICODE-1-1-UTF-7|ISO-10646-UCS-2|UNICODE-(16|32)(LITTLE|BIG)-ENDIAN)?\ +|unicodeFFFE|JAVA|x-EBCDIC-International(-euro)?" + +# If you're english, you probably don't want to block this one either. + +CHARSET_ENG = "US-ASCII|ASCII|iso-ir-6|iso646-us|x-EBCDIC-(cp-us|UK)(-euro)?" + +# Western European (English, but also French and many others. Standard) + +CHARSET_WESTEURO = "WINDOWS-1252|ISO-?8859-(1|15)|iso-ir-100\ +|(x-)?mac(-)?roman|latin-?(1|9)|macintosh|x-IA5(-German)?\ +|x-ebcdic-(spain|italy|germany|france)(-euro)?|x-europa" + +# Central/Eastern European (non-english) + +CHARSET_SLAVIC = "WINDOWS-1250|ISO-?8859-(2|16)\ +|iso-ir-(87|102)|(x-)?mac(-)?(central-europe|ce|croatian)\ +|latin-?2|CP870" + +# uncommon stuff and/or generally obsoleted. Includes maltese (eh, sorry if +# that's you) + +CHARSET_FUNKYLATIN = "ISO-?8859-[34]|iso-ir-109|latin-?3" + +# Russian, et-al. +# KOI8-T is Tajiki (Tajikistan) +# armscii-8 is Armenian + +CHARSET_CYRILLIC = "WINDOWS-1251|ISO-?8859-5|KOI8(-(RU|[RTU]))?\ +|ISO-IR-(101|111|144|147)|IBM866\ +|(x-)?mac(-)?(romanian?|cyrillic|ukran(e|ian))\ +|nunacom-8|armscii-8|x-EBCDIC-Cyrillic(SerbianBulgarian|Russian)" + +# Arabic + +CHARSET_ARABIC = "WINDOWS-1256|ISO-?8859-6|iso-ir-127\ +|(x-)?mac(-)?arabic|asmo-708|x-EBCDIC-Arabic" + +# Greek + +CHARSET_GREEK = "WINDOWS-1253|ISO-?8859-7|(x-)?mac(-)?greek\ +|iso-ir-(126|150)|x-EBCDIC-Greek(Modern)?" + +# Hebrew + +CHARSET_HEBREW = "WINDOWS-1255|ISO-?8859-8(-i)?|(x-)?mac(-)?hebrew\ +|iso-ir-138|x-EBCDIC-Hebrew" + +# Turkish + +CHARSET_TURKISH = "WINDOWS-1254|ISO-?8859-9|(x-)?mac(-)?turkish\ +|iso-ir-(109|148)|latin-?5|x-EBCDIC-Turkish|CP1026" + +# Icelandic/Nordic (i.e. Iceland, Greenland, Norway, Sweden...) + +CHARSET_NORDIC = "ISO-?8859-10|(x-)?mac(-)?iceland(ic)?|iso-ir-60\ +|x-IA5-(Norwegian|Swedish)\ +|x-EBCDIC-(FinlandSweden|DenmarkNorway|Icelandic)(-euro)?" + +# Thai (ISO not _actually_ used, but draft standard is same) + +CHARSET_THAI = "WINDOWS-874|TIS[-_]?620|ISO-?8859-11\ +|mulelao-1|ibm-cp1133|(x-)?mac(-)?thai|x-EBCDIC-Thai" + +# ISO-8859-12 is bogus (was suggested to be vietnamese, but can't fit). +# However, I've seen this encoding specified in spam though, and lacking an +# official designation, I'm hocking it here. + +CHARSET_VIETNAM = "WINDOWS-1258|ISO-?8859-12|viscii|tcvn5712|vps" + +# Baltic Rim + +CHARSET_BALTIC = "WINDOWS-1257|ISO-?8859-13|iso-ir-110" + +# Celtic (Irish and Welsh) + +CHARSET_CELTIC = "ISO-?8859-14" + +# Other stuff which escapes categorization at this time + +CHARSET_MISC = "isiri-3342|x-iscii-(as|be|de|gu|ka|ma|or|pa|ta|te)" + +# ..................................................... &from-daemon ... + +JA_FROM_DAEMON = "!" + +:0 +* ^FROM_DAEMON +{ + JA_FROM_DAEMON_MATCH = $MATCH + JA_FROM_DAEMON = "!!" # double !! means "OK" + + # 2000-01-08 This has been copied from procmail log file + # because we can't get the match otherwise. + # Procmail version: v3.11pre4 1995/10/29 + # + # The following recipe is dummy: It solely sets MATCH to show + # what procmail thinks triggered FROM_DAEMON + +# :0 +# * ()\/^(Precedence:.*(junk|bulk|list)|To: Multiple recipients of |(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )([^>]*[^(.%@a-z0-9])?(Post(ma?(st(e?r)?|n)|office)|(send)?Mail(er)?|daemon|mmdf|n?uucp|LIST(SERV|proc)|NETSERV|owner|r(e(quest|sponse)|oot)|b(ounce|bs\.smtp)|echo|mirror|s(erv(ices?|er)|mtp)|A(dmin(istrator)?|MMGR|utoanswer))(([^).!:a-z0-9][-_a-z0-9]*)?[%@> ][^<)]*(\(.*\).*)?)?$([^>]|$))) +# { } + +} + +# ..................................................... &from_mailer ... + +JA_FROM_MAILER = "!" + +:0 +* ^FROM_MAILER +{ + JA_FROM_MAILER_MATCH = $MATCH + JA_FROM_MAILER = "!!" # double !! means "OK" +} + +# .................................................. &define-modules ... + +:0 +* PMSRC ?? [a-z] +{ + RC_ADDR = $PMSRC/pm-jaaddr.rc + RC_BUP = $PMSRC/pm-jabup.rc + RC_COOKIE = $PMSRC/pm-jacookie.rc + RC_COOKIE1 = $PMSRC/pm-jacookie1.rc + RC_CRON = $PMSRC/pm-jacron.rc + RC_DAEMON = $PMSRC/pm-jadaemon.rc + RC_DATE = $PMSRC/pm-jadate.rc + RC_DATE1 = $PMSRC/pm-jadate1.rc + RC_DATE2 = $PMSRC/pm-jadate2.rc + RC_DATE3 = $PMSRC/pm-jadate3.rc + RC_DATE4 = $PMSRC/pm-jadate4.rc + RC_DATE5 = $PMSRC/pm-jadate5.rc + RC_DUP = $PMSRC/pm-jadup.rc + RC_EMPTY = $PMSRC/pm-jaempty.rc + RC_FROM = $PMSRC/pm-jafrom.rc + RC_FWD = $PMSRC/pm-jafwd.rc + RC_LIST = $PMSRC/pm-jalist.rc + + RC_MIME_DECODE = $PMSRC/pm-jamime-decode.rc + RC_MIME_KILL = $PMSRC/pm-jamime-kill.rc + RC_MIME_SAVE = $PMSRC/pm-jamime-save.rc + RC_MIME = $PMSRC/pm-jamime.rc + + RC_NETMIND = $PMSRC/pm-janetmind.rc + RC_NSLOOKUP = $PMSRC/pm-janslookup.rc + RC_ORIG = $PMSRC/pm-jaorig.rc + RC_PING = $PMSRC/pm-japing.rc + RC_POP3 = $PMSRC/pm-japop3.rc + RC_RANDF = $PMSRC/pm-jarandf.rc + RC_SRV_CHECK = $PMSRC/pm-jasrv-check.rc + RC_SRV_DAEMON = $PMSRC/pm-jasrv-daemon.rc + RC_SRV_ERR = $PMSRC/pm-jasrv-err.rc + RC_SRV_FROM = $PMSRC/pm-jasrv-from.rc + RC_SRV_MSG = $PMSRC/pm-jasrv-msg.rc + RC_SRV_MULTI = $PMSRC/pm-jasrv-multi.rc + RC_SRV_REQ = $PMSRC/pm-jasrv-req.rc + RC_SRV_SEND = $PMSRC/pm-jasrv-send.rc + RC_SRV = $PMSRC/pm-jasrv.rc + RC_STORE = $PMSRC/pm-jastore.rc + RC_SUBJECT = $PMSRC/pm-jasubject.rc + RC_TIME = $PMSRC/pm-jatime.rc + RC_UBE = $PMSRC/pm-jaube.rc + RC_UBE1 = $PMSRC/pm-jaube1.rc + RC_UBE_BMF = $PMSRC/pm-jaube-prg-bmf.rc + RC_UBE_BOGOFILTER = $PMSRC/pm-jaube-prg-bogofilter.rc + RC_UBE_IFILE = $PMSRC/pm-jaube-prg-ifile.rc + RC_UBE_SPAMASSASSIN = $PMSRC/pm-jaube-prg-spamassassin.rc + RC_UBE_SPAMPROBE = $PMSRC/pm-jaube-prg-spamprobe.rc + RC_UBE_SPAMORACLE = $PMSRC/pm-jaube-prg-spamoracle.rc + RC_UBE_ANNOYANCE = $PMSRC/pm-jaube-prg-annoyance-filter.rc + RC_UBE_BSFILTER = $PMSRC/pm-jaube-prg-bsfilter.rc + RC_UBE_RUNALL = $PMSRC/pm-jaube-prg-runall.rc + RC_UBE_KEYWORDS = $PMSRC/pm-jaube-keywords.rc + RC_VAC = $PMSRC/pm-javac.rc + RC_VAR = $PMSRC/pm-javar.rc +} + +:0 E +{ + # Set LINEBUF so that next message line is not truncated. + LINEBUF = 1024 + dummy = " +----------------------------------------------------------------------- + + pm-javar.rc: PANIC: Variable PMSRC does not point to procmail + recipe code directory. Add something like this to ~/.procmailrc + (using correct install location): + PMSRC = $HOME/procmail/procmail-lib/lib + +----------------------------------------------------------------------- +" +} + +dummy = "pm-javar.rc: end: variables defined." + +# End of file pm-javar.rc diff --git a/share/procmail/unread-default.rc b/share/procmail/unread-default.rc @@ -0,0 +1,48 @@ +# unread-default.rc +# +# procmail recipe to compute how many unread messages +# for the $DEFAULT delivery. +# +# $Id: unread-default.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Just count how many messages in $DEFAULT + + +UNREAD=no # default output + +# There are two basic methods: a fast way and a slow way + +# The fast way (loses sometimes -- but, really, who cares? we're +# just counting unread messages.) + +:0 +* ? test -f $DEFAULT +{ UNREAD=`egrep -c '^From ' $DEFAULT` } + +# The slow way, but, the "procmail" way :^) +# +#:0 +#* ? test -f $DEFAULT +#{ JUNK=`formail -e -s echo -n x < $DEFAULT` +# :0 +# * JUNK ?? 1^1 x +# { UNREAD = $= } +#} diff --git a/share/procmail/unread-mh.rc b/share/procmail/unread-mh.rc @@ -0,0 +1,90 @@ +# unread-mh.rc +# +# procmail recipe to compute how many unread messages +# for MH as the MUA (mail user agent). +# +# $Id: unread-mh.rc,v 1.1 2002/01/01 22:25:33 jaalto Exp $ +# +# Copyright (C) 1995 Alan K. Stebbens <aks@sgi.com> +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Usage: +# +# Referenced by "ackmail.rc" when MUA=mh and the text of the +# reply includes the string '$UNREAD' +# +# If MH_INFOLDERS is set, uses the output of "folder +$folder" +# for each folder mentioned in MH_INFOLDERS. The sum of the +# current message number subtracted from the last message +# number for each folder is returned. +# +# If MH_INFOLDERS is not set, then check for the Unseen-Sequence +# profile entry. If this is set, uses the number of messages +# in this sequence. +# +# If there is no Unseen-Sequence profile entry, or there is no +# sequence in the +inbox, then use the output of 'folders +inbox' +# as for MH_INFOLDERS above. +# + +# Note: PATH should include the MH bin directory + +UNREAD=no # default output +SHELL=/bin/sh # be sure + +# If the user has defined one or more explicit folders in the +# variable MH_INFOLDERS, then use a shell script to get UNREAD +:0 +* MH_INFOLDERS ?? .+ +{ + UNREAD=`(for f in $MH_INFOLDERS ; do folder +$f ; done) | + sed -n -e 's/^.*- *\([0-9]*\)); cur= *\([0-9]*\);.*/ok \1 \2/p' | + awk '/ok/ { s+=$2-$3 } END { print s }'` +} + +# If no explicit folder list, try using unseen sequences +:0 E +{ + # Get some MH info + MH_INBOX=`mhpath +inbox` + MH_UNSEENSEQ=`mhparam Unseen-Sequence` + MH_INSEQFILE=$MH_INBOX/.mh_sequences + + :0 chW + * MH_UNSEENSEQ ?? [a-z]+ + * ? test -f $MH_INSEQFILE + * ? grep "^$MH_UNSEENSEQ:" $MH_INSEQFILE + |UNREAD=`pick +inbox $MH_UNSEENSEQ 2>/dev/null | wc -l` + + # Ok -- no unseen sequence. Try last resort of using +inbox info. + :0 E + { + INFOLDER=`folder +inbox` + :0 + * INFOLDER ?? cur= *\/[0-9]+ + { CUR=$MATCH + :0 + * INFOLDER ?? messages *\( *[0-9]+- *\/[0-9]+ + { MAX=$MATCH + :0 + * ? test "$MAX" -gt "$CUR" + { UNREAD=`expr $MAX - $CUR` } + } + } + } +}