#!/bin/sh
# /usr/local/bin/procmail.sh			by Julian H. Stacey
# Installed by	cd ~jhs/public_html/src/bsd/jhs/bin/local/mail ; make bin_bin
# From		~jhs/public_html/src/bsd/jhs/bin/local/mail/procmail.sh
# To		/usr/local/bin/procmail.sh

# Purpose:
#	Procmail.sh can be called both by crontab & manually.
#	It reads mail from the localhost /var/mail/jhs & sorts it in my mail
#	directories, It can run on any of my home internal hosts, (but is
#	Slow over NFS), It does not read from the central mail host, just
#	the local host. It''s the job of my sendmail (+ named) to deliver
#	mail from world via gateway to my receiving maildrop host.

# Procmail.sh is not used at site js.berklix.net,
#	where gate.js.berklix.net runs fetchmail & passes it via SMTP to
#	host user.js.berklix.net, where ~jhs/.forward calls procmail.

# Procmail.sh is used on roaming laptop lapr.no.berklix.net
#	which first calls fetchmail (Or sftp if fetchmail fails).

# Procmail.sh is also useful for when I return from weeks away, & on server I
# then gzip & ftp my remote mail, & manually append to /var/mail/jhs

# PS I do not let exmh auto include mail from /var/mail/jhs
#	as exmh hangs the graphical update (in fact it becomes unusable for
#	hours) while procmail pattern matching on bulk mails for all
#	spam phrases.

# Bug: If you get error message:
#		lockfile: Try praying, giving up on "/var/mail/jhs.lock"
#		lockfile: Can''t unlock "/var/mail/jhs.lock"
#	ls -l /var | grep mail
#		drwxr-xr-x 2 root mail 512 Aug 20 13:30 ./
#	chmod g+w /var/mail ; ls -l /var | grep mail
#		drwxrwxr-x 2 root mail 512 Feb 18 11:42 mail/

# Path for lockfile & formail to avoid mail(*) complaining: "Cannot fork" ,
#	when host=home ~jhs/.forward contains "|/usr/local/bin/procmail"
#	, as then there is no local in PATH; However when manually
#	running this procmail.sh , PATH normally already includes
#	/usr/local/bin , so we are just harmlessly appending a 2nd instance.
PATH=$PATH:/usr/local/bin ; export PATH

# ORGMAIL=/host/user/var/mail/$LOGNAME
ORGMAIL=/var/mail/$LOGNAME

if test ! -s $ORGMAIL ; then	#{{
		# echo "No mail for $LOGNAME on `hostname`"
		exit 0
	else	#}{
		# ls -l $ORGMAIL
		# Show how long it may take.
	fi			#}}

cd
if test ! -d mail ; then	#{{
	echo "No mail directory under `pwd`/ on `hostname`"
	exit 1
else	# }{
		# echo ~/mail directory exists
		# Note this detects a directory even if it is a long chain of
		# symbolic links finaly arriving at a directory.
fi			#}}

if [ "X`whoami`" = "Xjhs" ] ; then	#{
	# Test if public mail list archives exist,
	# as I dont want to try saving some stuff there, only for it to
	# bounce & allend up cluttering my personal Inbox/
	# Old; PUB_FREEBSD_MAIL=/pub/FreeBSD/mail
	# grep PUB_FREEBSD_MAIL ~jhs/.procmailrc
	PUB_FREEBSD_MAIL=/pub/mail/freebsd
	if cd ${PUB_FREEBSD_MAIL} ; then	# {{
		true
	else	# }{
		echo -n "Warning cannot cd ${PUB_FREEBSD_MAIL}, "
		echo    "~/mail/Inbox may flood with dups."
		echo "${PUB_FREEBSD_MAIL} is defined in ~/.procmailrc"
		echo "${PUB_FREEBSD_MAIL} is used by ~/.procmailrc_lists"
	fi	# }}
	PUB_MAIL_LIST=/pub/mail/list
	if cd ${PUB_MAIL_LIST} ; then	# {{
		true
	else	# }{
		echo -n "Warning cannot cd ${PUB_MAIL_LIST}, "
		echo    "~/mail/Inbox may flood with dups."
		echo "${PUB_MAIL_LIST} is defined in ~/.procmailrc"
		echo "${PUB_MAIL_LIST} is used in    ~/.procmailrc_berklix"
		echo "${PUB_MAIL_LIST} is used in    ~/.procmailrc_lists"
		echo "${PUB_MAIL_LIST} is used in    ~/.procmailrc_private_keep"
	fi	# }}
fi					#}

set SETWAIT = -8	# default
#	8 seconds is default, probably pointless, JJLATER try commenting out.

DIR=$HOME/tmp/.procmail_sh_`date -u +%Y-%m-%dT%H:%M:%SZ`.tmpdir
# Pre 2022-07-04 it was	in ~/mail/
# but that was in laptop space limited /crypt/fs/1700m
# so now use spacious ~/tmp/

mkdir -p $DIR
# echo "Made by `basename $0`" > $DIR/.created_by_`basename $0`

EXECNAME=`basename $0`
DIRLOCK=$DIR/$EXECNAME.lock
#	DIRLOCK: JJLATER consider if NFS[+AMD] might present performance penalties
#	or unreliability, should DIRLOCK perhaps be direct under ~ . not under
#	~/mail which might be on another FS or another NFS''d server ?

DIRTEMPMAIL=$DIR/$EXECNAME.tempmail.tmp
#	On hosts eg lapr.no.berklix.net withlittle free space under ~jhs/
#	ln -s /data/jhs/mail/.tmp ~/mail/.tmp
#	Useful as until the mail is extracted it takes up
#	double space, one contiguoes file in $DIRTEMPMAIL, & split individual
#	files in the file system.

CLEARWAIT=43200
#	"10800" = 3 hours, 21600 = 6 hours, 43200 = 12 hours
#	12 hours might be enough for human to sleep, wake up, &
#	realise a disaster pending soon.

# Assert a lock unique to this script name.
if cd $HOME && lockfile $SETWAIT -r 0 -l $CLEARWAIT $DIRLOCK 2> /dev/null # {
#	Allow $CLEARWAIT to:
#	- manually resolve a reboot that leaves a dangling lock.
#	- avoid crontab called close running (every 2 mins) invocations of
#	  procmail.sh trampling each other as some big CTM deltas & spams
#	  & unexpected pictures not from people on my expected white list
#	  might take much longer than 2 mins to process scanning for
#	  40k phrases, plus several mails may come from different
#	  senders in 1 x 2 min. period, + there willbe a Big backlog
#	  of mail after first connecting towlan i the morningf after
#	  off line overnight.
#	After $CLEARWAIT it gets deleted at next attempt to lock.
#	-r 0	# JJLATER default so later try omitting.
then	# {	Normal, there was not a prior procmail.sh lock, so Process mail.
	# Arrange to remove lock if error occurs.
	trap "rm -f $DIRLOCK" 1 2	# 1=hangup 2=interrupt
		# JJLATER add more signals here.
		# Last time I did # a `reboot`, it left a dangling lock file.
		# I also need to use shutdown not reboot.

	# List mail gets copied to public archive,
	# so consider making legible to all with mode 033.
	# umask 033
	# (If so, assume ~/mail/ is 0700 to protect private mail privacy).

	# Lock the user mail box by creating $ORGMAIL.lock
	lockfile $SETWAIT -l$CLEARWAIT -ml
		# I used to specify just 3600 but maybe this doesnt allow
		# enough time on return from holiday with mega heaps of
		# mail & /or named timeouts ?

	if test -e $DIRTEMPMAIL ; then	# {
		echo "Unexpected temporary file from a previous $EXECNAME:"
		ls -l $DIRTEMPMAIL
		DIRSAVE=$DIR/$EXECNAME.abandoned.`date -u +%Y-%m-%dT%H:%M:%SZ`.tmp
		echo "Copying $DIRTEMPMAIL"
		echo "To $DIRSAVE"
		cp $DIRTEMPMAIL $DIRSAVE
		echo "Copied $DIRTEMPMAIL"
		echo "To: $DIRSAVE"
	fi	# }

	cat $ORGMAIL >> $DIRTEMPMAIL && cat /dev/null >$ORGMAIL

	# Unlock user mailbox by removing $ORGMAIL.lock
	lockfile $SETWAIT -mu

	formail -q- -s procmail -t < $DIRTEMPMAIL && rm -f $DIRTEMPMAIL
	# JJLATER Maybe one day add "-D -I Received" before -s
	# -t added 2007-06-18 after losing mail day before with a bad rule
	# man procmail: -t
	#	Make procmail fail softly, i.e., if procmail cannot
	#	deliver the mail to any of the destinations
	#	you gave, the mail will not bounce, but will return
	#	to the mailqueue. Another delivery attempt
	#	will be made at some time in the future.

	# Remove the lock unique to this script name.
	rm -f $DIRLOCK # -f needed as lock file is created read-only
	rmdir $DIR
	exit 0

else	# }{	Abnormal: A Lock file exists.
	echo "$EXECNAME Failed to lock, presuming a pre-existing lock existed: $DIRLOCK, "
	echo "$EXECNAME abandoning, and will not touch mail."
	if test -f $DIRLOCK ; then #{
		echo -n "Lock file exists: "
		ls -l $DIRLOCK
		# Content of lock is probably a single byte, Ascii of '0'.
		cat $DIRLOCK
		echo "If lock is stale (old), compared with now `date`,"
		echo -n "Lock might be from power failure or over heating "
		echo "crash or forced reboot ?"
		echo "If not old, perhaps a collision of overlapping"
		echo "invocations with crontab, before last was complete?"
		echo "Be aware after $CLEARWAIT seconds this $EXECNAME will cease"
		echo "abandoning & may then trample data."

		# One way of getting stale lock message above is
		# when by accident when switching frequency from 5
		# to 10 min. intervals, I forgot to comment out one
		# of these 2 crontab lines:
	# 2,7,12,17,22,27,32,37,42,47,52,57 * * * * /usr/local/bin/procmail.sh
	# 2,12,22,32,42,52		    * * * * /usr/local/bin/procmail.sh
		echo " "
	fi			#}
	echo "Before manually removing a stale lock file with"
	echo "	rm $DIRLOCK"
	echo "First save any transient mail file created by $EXECNAME, eg:"
	if test -f $DIRTEMPMAIL ; then		#{
		ls -l $DIRTEMPMAIL
		echo "Try: cp $DIRTEMPMAIL $DIRTEMPMAIL.rescued.`date -u +%Y-%m-%dT%H:%M:%SZ`.tmp"
	fi					#}
	if test -f $ORGMAIL ; then		#{
		echo "Current unprocessed mail:"
		ls -l $ORGMAIL
	fi					#}
	if test -f $ORGMAIL.lock ; then		#{
		echo "Current mail is locked, probably by a procmail:"
		ls -l $ORGMAIL.lock
		ps -laxww | grep procmail
	fi					#}
	rmdir $DIR
	exit 1
fi	# }}
