Subject: Re: Vacation(1) emulation

From: Adam Shostack <[email-masked]>
Date: Wed, 19 Apr 1995 14:38:31 -0400 (EDT)

| 	* !^Precedence.*(bulk|junk)

This is part of FROM_DAEMON.  I find a bigger problem with vacation by
procmail is that folks with experience know that vacation uses
.vacationmsg or somesuch to control the sending of messages.  They
remove .vacationmsg, and start sending blank messages to people.

I use the following, it seems to work as people expect vacation to
work:

# vacation controled by existance of vacation.msg
#  partially tested

:0 hc: 	
* ?  [ -r $MAILDIR/.vacationlist ]
* !? [ -r $MAILDIR/.vacation.msg ]
| rm -f $MAILDIR/.vacationlist

:0
* ? [ -s $MAILDIR/.vacation.msg ] 
* !^FROM_DAEMON
{
 FROM=`formail -rx To:`
 ALREADYSENT=$MAILDIR/.vacationlist
   :0 hc:
   * !? fgrep -e "$FROM" $ALREADYSENT
   | echo "$FROM" >> $ALREADYSENT;\
 	(formail -rA"Precedence: junk";\
	cat $MAILDIR/.vacation.msg ;\
   ) | $SENDMAIL -t
}

---

From: Alan Stebbens <[email-masked]>
Date: Wed, 19 Apr 1995 17:48:30 -0700

> remove .vacationmsg, and start sending blank messages to people.

Here's the "ackmail.rc" script, which I created as a "library" routine
for procmail users at our site.

Enjoy.

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 02/28/1995 17:39 UTC by ???@dokoka
# Source directory /a/eci1/fs.real/eci1c/home/staff/aks/src/mail/procmail/lib
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   5247 -r--r--r-- ackmail.rc
#    519 -r--r--r-- dupcheck.rc
#   2249 -r--r--r-- headers.rc
#
# ============= ackmail.rc ==============
if test -f 'ackmail.rc' -a X"$1" != X"-c"; then
	echo 'x - skipping ackmail.rc (File already exists)'
else
echo 'x - extracting ackmail.rc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ackmail.rc' &&
# ackmail.rc -- procmail rc to acknowledge mail (with either a 
#		vacation message, or an acknowledgement)
#
# Author: Alan Stebbens <[email-masked]>
#
# $Id: ackmail.rc,v 1.2 1995/02/10 04:16:13 aks Exp $
# $Source: /fs/eci1c/home/staff/aks/src/mail/procmail/lib/RCS/ackmail.rc,v $
#
# 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
#
# ACKS		- file containing the acknowledgment cache;
#		  defaults to $MAILDIR/.acks.cache
#
# ACKMSG	- file containing the message to reply with;
#		  defaults to $MAILDIR/ackmsg
#
# VACAMSG	- file containing the message to reply with;
#		  defaults to $MAILDIR/vacation.msg
#
# FROMSIG	- From: header to use in the auto-ack; defaults
#		  to "Mailer-Daemon of $USER"
#
# And be sure PATH includes the directory containing "formail".
X
# If the mail is directly to me, and not an auto-reply itself 
# then do the auto-ack 
X
MY_NAMES=${MY_NAMES:-${SIGNATURE:-`cat $HOME/.signature 2>/dev/null`}}
ACKS=${ACKS:-$MAILDIR/.acks.cache}
ACKMSG=${ACKMSG:-$MAILDIR/ackmsg}
VACAMSG=${VACAMSG:-$MAILDIR/vacation.msg}
FROMSIG=${FROMSIG:-"Mailer-Daemon of $USER"}
NOACKS=${NOACKS:-$MY_ADDR}
X
# Handy regexp patterns (taken from "headers.rc")
PRE_ADDR_SPAN='(.*[^-(.%@a-zA-Z0-9])?'
POST_ADDR_SPAN='(([^),.!:a-zA-Z0-9].*)?(,|$[^>]))'
FROM="(^(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )$PRE_ADDR_SPAN)"
X
# 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?
X
:0ch
* $ ^TO($USER|$MY_ADDR|$MY_NAMES)
* ? test -f $ACKMSG -o -f $VACAMSG
* ! ^FROM_DAEMON
* !$ $FROM(Majordomo|Listserv)
* ! ^Subject: .*(\[(ack(nowledge?ment)?|on vacation)\]|\
X		auto(matic)[- ]reply|\
X		away from mail|\
X		out of town|\
X		can ?not (reply|answer)|\
X		(on |via )vacation( program)?)
* !$ ^X-Loop: $MY_ADDR
* !$ $FROM($NOACKS)$POST_ADDR_SPAN
{
X    # Okay -- we're donig to do the auto-ack or vacation mail
X    #
X    # We're forking for the auto-ack, shut up comsat, and assume that,
X    # in this process, the mail is delivered
X    COMSAT=off
X    DELIVERED=yes
X
X    # Don't output logfile info; the user can query $ACKS to see which
X    # users have been acknowledged.  This only affects the child
X    # process.
X    LOGABSTRACT=no
X
X    # Check the mail to see if we have replied recently, and if so, if
X    # we should reply again
X    DATE=`date +'%D'`
X
X    # Get the from address by having formail generate a reply address
X    FROMADDR=`formail -rzx To:`
X
X    # Get the subject sans "Re:" and replacing double-quotes
X    SUBJ=`formail -zx Subject: | sed -e 's/^Re: *//g' -e 's/["~]/_/g'`
X
X    # Get which file: "vacation.msg" has precedence over "ackmsg"
X    ACKFILE=`if [ -f $VACAMSG ]; then echo $VACAMSG ; else echo $ACKMSG ; fi`
X
X    # Get either the string "on vacation" or "acknowledgement" 
X    ACKM="`if [ -f $VACAMSG ]; then echo 'on vacation' ; else echo acknowledgment ; fi`"
X
X    # Check the cache for a recent ack
X    :0:$ACKS.$LOCKEXT
X    * !? fgrep -s "$FROMADDR $DATE" $ACKS
X    | ( fgrep -v "$FROMADDR" $ACKS ; echo "$FROMADDR $DATE" ) >$ACKS.new ; \
X      rm -f $ACKS ; mv $ACKS.new $ACKS ; \
X      ( formail -rI"From:       $FROMSIG" \
X		 -I"Reply-To:   $MY_ADDR" \
X		 -I"Precedence: junk" \
X		 -I"Subject:    Re: $SUBJ [$ACKM]" \
X		 -I"X-Loop:     $MY_ADDR" \
X		 -I"References:" ; \
X	sed -e "s~\$SUBJECT~$SUBJ~" $ACKFILE ) \
X      | $SENDMAIL -oi -t
}
X
SHAR_EOF
chmod 0444 ackmail.rc ||
echo 'restore of ackmail.rc failed'
Wc_c="`wc -c < 'ackmail.rc'`"
test 5247 -eq "$Wc_c" ||
	echo 'ackmail.rc: original size 5247, current size' "$Wc_c"
fi
# ============= dupcheck.rc ==============
if test -f 'dupcheck.rc' -a X"$1" != X"-c"; then
	echo 'x - skipping dupcheck.rc (File already exists)'
else
echo 'x - extracting dupcheck.rc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dupcheck.rc' &&
# procmailrc to check for duplicates
# check for duplicate mail using the msgid
#
# Author: Alan K. Stebbens <[email-masked]>
# $Id: dupcheck.rc,v 1.1 1994/12/06 02:39:13 aks Exp $
# $Source: /fs/eci1c/home/staff/aks/src/mail/procmail/lib/RCS/dupcheck.rc,v $
X
# Turn off comsat -- so it won't get called
# notifing the user about mail "delivered" via
# the formail check.
X
OLDCOMSAT=${COMSAT:-off}
COMSAT=off
X
# Remove duplicate messages
:0 Wh: .msgid.lock
| formail -D 8192 .msgid.cache
X
COMSAT=$OLDCOMSAT
OLDCOMSAT
SHAR_EOF
chmod 0444 dupcheck.rc ||
echo 'restore of dupcheck.rc failed'
Wc_c="`wc -c < 'dupcheck.rc'`"
test 519 -eq "$Wc_c" ||
	echo 'dupcheck.rc: original size 519, current size' "$Wc_c"
fi
# ============= headers.rc ==============
if test -f 'headers.rc' -a X"$1" != X"-c"; then
	echo 'x - skipping headers.rc (File already exists)'
else
echo 'x - extracting headers.rc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'headers.rc' &&
# procmail rc to define patterns to recognize the headers
#
# Author: Alan K. Stebbens <[email-masked]>
# $Id: headers.rc,v 1.2 1994/12/14 19:49:31 aks Exp $
# $Source: /fs/eci1c/home/staff/aks/src/mail/procmail/lib/RCS/headers.rc,v $
#
# 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/.
# 
# 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.
X
PRE_ADDR_SPAN='(.*[^-(.%@a-zA-Z0-9])?'
X
# 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].*)?(,|$[^>]))'
X
# 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$_:.+=/]+'
X
# Use $HOSTADDR to match the FQDN hostname part of an address
HOSTADDR='[-a-zA-Z0-9$_:.+=/]+'
X
# Use $HOSTNAME to match the "plain" hostname (not include any domains)
HOSTNAME='[-a-zA-Z0-9$_:+=/]+'
X
# Use $ADDR to match either an RFC 822 or UUCP email address
ADDRESS="<?($USERADDR(@$HOSTADDR)?|($HOSTADDR!)+$USERADDR)>?"
X
# Use $FROM to match mail from someone
FROM="(^(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )$PRE_ADDR_SPAN)"
X
# Use $TO to match mail to someone (but only "To:", not "Cc:")
TO="(^((Original-)?(Resent-)?To|(X-Envelope|Apparently(-Resent)?)-To):$PRE_ADDR_SPAN)"
X
# Use $CC to match mail to someone (but only "Cc:", not "To")
CC="(^((Original-)?(Resent-)?Cc|(X-Envelope|Apparently(-Resent)?)-Cc):$PRE_ADDR_SPAN)"
X
# For completeness, this should be roughly equivalent to ^TO
TOCC="($TO|$CC)"
X
# Pattern to recognize lists by precedence
LIST_PRECEDENCE='(^Precedence:.*(junk|bulk|list))'
X
# Names of common list mailers
LIST_MAILERS='((Mailer-)?daemon|root|LISTSERV|[a-zA-Z0-9-]+-(list|request|owner)|\
Majordomo|Mailagent|Postmaster|mmdf|news|n?uucp)'
X
# Pattern to put them all together
FROM_LIST="($LIST_PRECEDENCE|$FROM$LIST_MAILERS$POST_ADDR_SPAN)"
SHAR_EOF
chmod 0444 headers.rc ||
echo 'restore of headers.rc failed'
Wc_c="`wc -c < 'headers.rc'`"
test 2249 -eq "$Wc_c" ||
	echo 'headers.rc: original size 2249, current size' "$Wc_c"
fi
exit 0