#!/bin/csh -f

# Script to mail output of a command to specified user(s).
# No mail is sent if there is no output.

# Typical usage:

# mailoutput -r username@hostname -s "Subject goes here" "command (with arguments)"
# (when used in cron, specify full path to mailouput)
# other possibly interesting switches:
#   -c username@hostname	cc output to username@hostname
#   -b username@hostname	bcc output to username@hostname
#   -gr "pattern" username@hostname	send output to username@hostname
#    					if output contains pattern
#   -grf filename username@hostname	send output to username@hostname
#    					if output contains pattern contained in filename
#   -noerr			only send stdout (suppress stderr)

# Revamping 1/12/21

# Addition of source of .rc file
# Use "-t" to get info from headers for Linux ("-c|-b" no longer available some places)
# addition of "-f" (From)

switch (`uname -s``uname -r`)
case SunOS5*:
	set ECHON = "/usr/ucb/echo -n"
	set GGREP = "/usr/local/gnu/bin/grep"
	set MAIL = /usr/ucb/mail
	set WHOAMI = /usr/ucb/whoami
	breaksw
case Linux[2-5]*:
	set ECHON = "/bin/echo -n"
	set GGREP = "/bin/grep"
	set MAIL = /bin/mail
# dragon hack copied from hourly: 1/14/10
	if (-e /bin/LegacyMail)	set MAIL = /bin/LegacyMail
# Ubuntu put mail somewhere else! 1/14/10
	if (! -e $MAIL)	set MAIL = /usr/bin/mail
	set WHOAMI = /usr/bin/whoami
	breaksw
default:
	exec /bin/echo ${0}: does not run on `uname -s` `uname -r`
endsw

# See whether we can use "mail -t" ; 2/22/21

$MAIL -t < /dev/null > & /tmp/`basename $0`.$$
egrep "No message|Null message body" /tmp/`basename $0`.$$ > /dev/null
if ($status) then
    egrep "invalid option" /tmp/`basename $0`.$$ > /dev/null
    if ($status) then
	echo "I don't know whether I can use" '"mail -t"' on `hostname`
	sed 's;.;    &;' /tmp/`basename $0`.$$
    endif
else
    set USET
endif
/bin/rm -f /tmp/`basename $0`.$$

set NOSEP		# stdout and stderr now mixed by default; 10/19/07
set GR			# grep recipient initial setup
set GRF			# grep file recipient initial setup

if (! -e $MAIL) exec echo ${0}: $MAIL does not exist

while($#argv)
	switch ("$1")
	case -b:
		if ($?BCC) then
		    set BCC = "$BCC $2"
		else
		    set BCC = "$2"
		endif
		shift; shift
		breaksw
	case -c:
		if ($?CC) then
		    set CC = "$CC $2"
		else
		    set CC = "$2"
		endif
		shift; shift
		breaksw
	case -d:
		set DEBUG
		shift
		breaksw
	case -r:
		# handle -r "" ; 12/4/15
		if ("$2" != "") then
		    if ($?RECIP) then
			set RECIP = "$RECIP,$2"
		    else
			set RECIP = "$2"
		    endif
		endif
		shift; shift
		breaksw
	case -gr:		# grep recipient
				# (additional recipient if output contains target)
#		set GR = ( $GR $2 $3 )
# Handle possibility of -gr "text" "recip1 recip2"
		set GRRS = ( $3 )
		foreach GRR ( $GRRS )
		    set GR = ( $GR $2 $GRR )
		end
		shift; shift; shift
		breaksw
	case -grf:		# grep recipient
				# (additional recipient if output contains target)
		if (! -e $GGREP) exec echo ${0}: Gnu grep does not exist on `hostname`
		if (! -e $2) exec echo ${0}: $2 does not exist on `hostname`
#		set GRF = ( $GRF $2 $3 )
# as above
		set GRRS = ( $3 )
		foreach GRR ( $GRRS )
		    set GRF = ( $GRF $2 $GRR )
		end
		shift; shift; shift
		breaksw
	case -ovr:		# on vacation recipient
				# (additional recipient if I'm on vacation)
#		if (-e ~/Batch/on-vacation) then
#		    if ( { ~/Batch/on-vacation } ) then
#			if ($?RECIP) then
#			    set RECIP = "$RECIP $2"
#			else
#			    set RECIP = "$2"
#			endif
#		    endif
#		endif
# determine whether I'm on vacation at time of mailing!  6/30/09
# (sometimes my cron jobs may run *hours*)
		if ($?VRECIP) then
		    set VRECIP = "$VRECIP $2"
		else
		    set VRECIP = "$2"
		endif
		shift; shift
		breaksw
	case -s:
		set SUBJECT = "$2"
		shift; shift
		breaksw
	case -f:
		set FROM = "$2"
		shift; shift
		breaksw
	case -his:
		set HOSTINSUBJECT
		shift
		breaksw
	case -v:
		set VERBOSE
		shift
		breaksw
	case -sep:
		unset NOSEP	# separate stdout and stderr
		shift
		breaksw
	case -nosep:
		set NOSEP	# don't separate stdout and stderr
		shift
		breaksw
	case -noerr:
		set NOMERR	# don't mail stderr
				# (as for when output is to user)
		unset NOSEP	# need to separate it if excluding it
		shift
		breaksw
	case -k:
		set KEEP	# keep output/error files
		shift
		breaksw
	case -shlock:
		set SHLOCK
		shift
		breaksw
	case -trace:
		set TRACE
		shift
		breaksw
	case -ss:
		set SHORTSUB	# remove initial path from automatically generated subject line
				# Subject: Results of '/koko/system/cron-user/program -args'
				#   =>
				# Subject: Results of 'program -args'
		shift
		breaksw
	case -debugt:		# debug headers for "-t" 
		set DEBUGT
		if ($?USET) then
		    echo USET set on `hostname`
		else
		    echo USET not set on `hostname`
		endif
		shift
		breaksw
	case -filter:		# Filter output so it isn't sent in base64
		set NOTTEXT
		set FILTER
		shift
		breaksw
	default:
		set COMMAND = "$*"
		goto gotcmd
	endsw
end

set DQ = '"'
exec /bin/echo usage: "$0 -r <recipient> ${DQ}command$DQ"

gotcmd:

# make sure we have some commands
which egrep | egrep -v "^no|:" >& /dev/null
if ($status) exec echo ${0}: Where is egrep command\?
which file | egrep -v "^no|:" >& /dev/null
if ($status) exec echo ${0}: Where is file command\?
which strings | egrep -v "^no|:" >& /dev/null
if ($status) exec echo ${0}: Where is strings command\?

umask 77
set DQ = '"'
set BASE = `basename $0`
set OUT = /tmp/$BASE.out.$$
set ERR = /tmp/$BASE.err.$$
set MSG = /tmp/$BASE.msg.$$
set HEADERS = /tmp/$BASE.hdrs.$$
set MCMD = /tmp/$BASE.mcmd.$$
set CMD = /tmp/$BASE.cmd.$$
set CMD1 = `echo "$COMMAND" | sed 's; .*;;'`
set LOCK = /tmp/`basename $CMD1`.lock
# postpone determination of recipients; 6/30/09
#if (! $?RECIP) set RECIP = `$WHOAMI`
if (! $?BCC) then
    set BCC; set BCSW
else
    set BCSW = -b
endif
if (! $?CC) then
    set CC; set CSW
else
    set CSW = -c
endif
if ($?TRACE) then
    set TRACE = /tmp/$BASE.trace.$$
    touch $TRACE
else
    set TRACE = /dev/null    
endif

set DOLLAR0 = `which $0`
set WATROUS = `/usr/bin/dirname $DOLLAR0`
if ($?DEBUG) echo WATROUS = $WATROUS

set RCFILE = `echo $DOLLAR0 | sed 's;\(.*/\)\(.*\);\1.\2rc;'`
if ($?DEBUG) echo RCFILE = $RCFILE
if (-e $RCFILE) source $RCFILE

if ($?SHLOCK) then
    $WATROUS/Sys/shlock -f $LOCK -p $$
    if ($status) exec echo ${0}: shlock failed
    echo `date` shlock succeeded					>>& $TRACE
endif

if ($?DEBUG) echo COMMAND = "$COMMAND"

#set SCOMMAND = `echo "$COMMAND" | sed 's;^[^ ]*/;;'`
#echo "$COMMAND" > $CMD
#set SCOMMAND = "`sed 's;^[^ ]*/;;' $CMD`"

echo "$COMMAND" > $CMD
set SCOMMAND = "`sed 's;^[^ ]*/;;' $CMD`"
if ($?DEBUG) then
    echo $CMD contains
    sed 's;.;    &;' $CMD
endif
echo `date +%T` $CMD contains						>>& $TRACE
sed 's;.;    &;' $CMD							>>& $TRACE

if (! $?NOSEP) then
    if ($?VERBOSE) echo `date +%T` \( $CMD \> $OUT \) \>\& $ERR
		   echo `date +%T` \( $CMD \> $OUT \) \>\& $ERR		>>& $TRACE
    ( csh $CMD > $OUT ) >& $ERR
    echo `date +%T` exit status = $status				>>& $TRACE
else
    if ($?VERBOSE) echo `date +%T` csh $CMD \>\& $OUT
		   echo `date +%T` csh $CMD \>\& $OUT		>>& $TRACE
    csh $CMD >& $OUT
    echo `date +%T` exit status = $status				>>& $TRACE
endif

# Don't try to email "binary" data
#set FILETYPE = `file $OUT | sed 's;.*:;;'`
set FILETYPE = `file $OUT | sed "s;${OUT}:;;"`
echo `date +%T` FILETYPE = "$FILETYPE"					>>& $TRACE
if ($?VERBOSE) echo FILETYPE is $DQ$FILETYPE$DQ on `/bin/hostname | /bin/sed 's;\.rutgers\.edu;;'`
switch ("$FILETYPE")

# These are ok

case "777 archive data":					# spock.cs
case "'diff' output text":					# klinzhai
case "Apple Old Partition data block size*":	# klinzhai
case "ASCII C++ program text":	# klinzhai
case "ASCII C++ program text, with very long lines":		# klinzhai
case "ASCII English text":
case "ASCII English text, with CRLF, LF line terminators":	# klinzhai
case "ASCII English text, with very long lines":		# spock.cs
case "ASCII English text, with very long lines, with CRLF, LF line terminators": #klinzhai
case "ASCII mail text":						# klinzhai
case "ASCII news text":						# klinzhai
case "ASCII news text, with CRLF, LF line terminators":		# klinzhai
case "ASCII text":
case "ascii text with garbage":					# athos
case "ASCII text, with CR, LF line terminators":		# klinzhai
# This is now problem on klinzhai.lcsr; 4/26/18
#case "ASCII text, with CRLF line terminators":			# klinzhai
case "ASCII text, with CRLF, CR, LF line terminators":		# klinzhai
case "ASCII text, with very long lines":
case "ASCII text, with very long lines, with CR, LF line terminators": #klinzhai
case "ASCII text, with very long lines, with CRLF, LF line terminators": #klinzhai
case "C source, ASCII text":	# klinzhai
case "C source, UTF-8 Unicode text":				# farside.lcsr
case "C++ source, ASCII text":					# farside.lcsr
case "English text":						# ns-lcsr
case "FORTRAN program, ASCII text":				# farside.lcsr
case "UTF-8 Unicode English text":				# orichelieu
case "UTF-8 Unicode text":					# farside.lcsr
case "UTF-8 Unicode text, with very long lines":		# farside.lcsr
case "ascii text":
case "assembler source, ASCII text":				# farside.lcsr
case "assembler source, UTF-8 Unicode text":			# farside.lcsr
case "c program text":						# athos
case "diff output, ASCII text":					# farside.lcsr
case "empty file":
case "empty":
case "shell archive or script for antique kernel text":		# klinzhai

    breaksw

# These need strings

case "ASCII text, with CRLF line terminators":			# klinzhai.lcsr
case "ASCII text, with CRLF, LF line terminators":		# klinzhai
case "UTF-8 Unicode text, with CRLF, LF line terminators":	# farside.lcsr
case "UTF-8 Unicode text, with CRLF, CR, LF line terminators":	# farside.lcsr
case "data":			# first occurrance (on athos) not problem, but...
case "diff output, ASCII text, with CRLF, LF line terminators":	# klinzhai.lcsr
    set NOTTEXT
    breaksw
default:
    set NOTTEXT
    set NOTOK			# not seen before -- do a little debugging
endsw

# All the above was to avoid messages like this:
cat >> /dev/null <<EOF
X-Coding-System: undecided-unix
Mail-from: From watrous@cs.rutgers.edu  Sun Mar  3 20:02:20 2019
Received: from farside.lcsr.rutgers.edu (farside.lcsr.rutgers.edu [128.6.26.62])
	by farside.rutgers.edu (8.15.2/8.8.8) with ESMTP id x2412Kf9021961;
	Sun, 3 Mar 2019 20:02:20 -0500 (EST)
Received: by farside.lcsr.rutgers.edu (Postfix, from userid 1002)
	id 86A053000898; Sun,  3 Mar 2019 20:02:20 -0500 (EST)
Date: Sun, 03 Mar 2019 20:02:20 -0500
To: watrous@mx.farside.rutgers.edu, mcgrew@mx.farside.rutgers.edu,
        admin-hanz@mx.farside.rutgers.edu
Subject: farside.lcsr status (20:02)
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Message-Id: <20190304010220.86A053000898@farside.lcsr.rutgers.edu>
From: watrous@cs.rutgers.edu (Donald Watrous)

bmlnaHRseSBzdGlsbCBhY3RpdmUgb24gZmFyc2lkZS5sY3NyOiA1ODk2IFwgByAwIDEgMiAz
IDQgNSA2IDcgOCA5IGEgZyBwIHYgdyBTcyAwOjAwIC9iaW4vY3NoIC1mIC4vbWFpbG91dHB1
dCAtciBhZG1pbi1rb2tvQGNzLnJ1dGdlcnMuZWR1IC1iIHdhdHJvdXNAbXguZmFyc2lkZS5y
dXRnZXJzLmVkdSAuL25ldGFwcC1uaWdodGx5MiBrb2tvLmxjc3IK
EOF
# which is not too readable with emacs RMAIL.   So.....
# The next two lines force always using strings.
set NOTTEXT			# this causes strings to be used
unset NOTOK			# this avoids the complaint/debugging

if ($?NOTTEXT) then
    if ($?NOTOK && 0) then
	echo FILETYPE is $DQ$FILETYPE$DQ
	echo Preserving $OUT as $OUT.odd
	/bin/cp -p $OUT{,.odd}
	chmod 600 $OUT.odd
    endif
#    strings $OUT > $OUT.new
    set PRESERVESTRING = "_empty-line-preserved-by-$BASE-on-"`date +%y%m%d`"_"
# need to preserve tabs through strings on Solaris
    set PRESERVETAB = "_tab-preserved-by-$BASE-on-"`date +%y%m%d`"_"
    sed -e "s;^"'$'";$PRESERVESTRING;" -e "s;	;$PRESERVETAB;g" $OUT | \
	strings -n1 | \
	sed -e "s;$PRESERVETAB;	;g" -e "s;^$PRESERVESTRING"'$'";;" > $OUT.new
#    echo ${0}: $PRESERVESTRING
#    if (-z $OUT.new) then
    if (-z $OUT.new && ! $?FILTER && 0) then   # if I asked for filter, don't worry about this
	echo FILETYPE is $FILETYPE and ${DQ}strings $OUT$DQ produced an empty file
# Hmmm.  Let's have a look at this.
	echo Preserving $OUT as $OUT.odd
	/bin/cp -p $OUT{,.odd}
	chmod 600 $OUT.odd
    else
	if ($?VERBOSE) echo `date +%T` FILETYPE is $DQ$FILETYPE$DQ -- using result of ${DQ}strings $OUT$DQ
	mv $OUT{.new,}
    endif
    /bin/rm -f $OUT.new
endif

if ($?VERBOSE) echo `date +%T` Creating message to be mailed
touch $MSG

if (! -z $OUT) then
	if ($?VERBOSE) echo `date +%T` Using standard output
	mv $OUT $MSG
else
	if ($?VERBOSE) echo `date +%T` There was no standard output
endif

if (-e $ERR && ! -z $ERR) then
    if (! $?NOMERR) then
	if ($?VERBOSE) echo `date +%T` Adding standard error
	/bin/echo "" >> $MSG
	/bin/echo "	error output:" >> $MSG
	/bin/echo "" >> $MSG
	/bin/cat $ERR >> $MSG
    else
	if ($?VERBOSE) echo `date +%T` Not adding standard error "(-noerr set)"
	/bin/echo ""
	/bin/echo "	error output:"
	/bin/echo ""
	/bin/cat $ERR
    endif
else
	if ($?VERBOSE) echo `date +%T` There was no standard error
endif

# Finished -- determine who should receive message now; 6/30/09

if (-e $WATROUS/Batch/on-vacation && $?VRECIP) then
    if ( { $WATROUS/Batch/on-vacation } ) then
	if ($?RECIP) then
	    set RECIP = "$RECIP,$VRECIP"
	else
	    set RECIP = "$VRECIP"
	endif
    endif
endif
if (! $?RECIP) set RECIP = `$WHOAMI`

if (! -z $MSG) then
	while ($#GR > 1)
	    grep -i $GR[1] $MSG > /dev/null
	    if (! $status) then
		if ($?VERBOSE) echo Found \"$GR[1]\" in message -- adding $GR[2] to recipient list
		set RECIP = ( $RECIP,$GR[2] )
	    else
		if ($?VERBOSE) echo Did not find \"$GR[1]\" in message
	    endif
	    shift GR; shift GR
	end
	while ($#GRF > 1)
	    $GGREP -i -f $GRF[1] $MSG > /dev/null
	    if (! $status) then
		if ($?VERBOSE) echo Found something in $GRF[1] in message -- adding $GRF[2] to recipient list
		set RECIP = ( $RECIP,$GRF[2] )
	    else
		if ($?VERBOSE) echo Did not find anything in $GRF[1] in message
	    endif
	    shift GRF; shift GRF
	end
	if ($?DEBUGT) then
	    echo ""
	    echo RECIP = $DQ$RECIP$DQ
	endif
	echo "To: $RECIP" > $HEADERS
	if ($?HOSTINSUBJECT) then
	    set ONHOST = " on `/bin/hostname | /bin/sed 's;\.rutgers\.edu;;'`"
	else
	    set ONHOST
	endif
	if (! $?SUBJECT) then
	    set SUBJECT = "Results of '$COMMAND'"
	    if ($?SHORTSUB) set SUBJECT = "Results of '$SCOMMAND'"
	endif
	if ($?FROM) then
	    if ($?DEBUGT) echo FROM = $FROM
	    echo "From: $FROM" >> $HEADERS
	endif
	if ("$SUBJECT" != "") then
	    if ($?DEBUGT) echo SUBJECT = $DQ$SUBJECT$ONHOST$DQ
	    echo "Subject: $SUBJECT$ONHOST" >> $HEADERS
	endif
	if ($?CC) then
	    if ($?DEBUGT) echo CC = $DQ$CC$DQ
	    if ("$CC" != "") echo "Cc: $CC" >> $HEADERS
	endif
	if ($?BCC) then
	    if ($?DEBUGT) echo BCC = $DQ$BCC$DQ
	    if ("$BCC" != "") echo "Bcc: $BCC" >> $HEADERS
	endif
	if ($?DEBUGT) echo ""
	echo "" >> $HEADERS
	if ($?DEBUGT) then
	    echo Headers:
	    sed 's;.;    &;' $HEADERS
	endif
	if ($?DEBUG) then
		if ($?VERBOSE) echo `date +%T` This is what would be mailed:
		/bin/cat $MSG
		echo RECIP = $RECIP
		echo CC = $CC "(CSW = $CSW)"
		echo BCC = $BCC "(BCSW = $BCSW)"
	else
		if { echo ~watrous > /dev/null } set WATROUS
		if ($?VERBOSE) then
		    echo `date +%T` "Mailing output to recipient(s)"
		    echo "   " RECIP = $RECIP
		    echo "   " CC = $CC "(CSW = $CSW)"
		    echo "   " BCC = $BCC "(BCSW = $BCSW)"
		endif
		$ECHON $MAIL -s > $MCMD
		if ($?WATROUS && $?NOTOK) $ECHON $MAIL -s > $MCMD.odd
		if ($?HOSTINSUBJECT) then
		    set ONHOST = " on `/bin/hostname | /bin/sed 's;\.rutgers\.edu;;'`"
		else
		    set ONHOST
		endif
		if ($?SUBJECT) then
		    $ECHON "" \""$SUBJECT$ONHOST"\" >> $MCMD
		    if ($?WATROUS && $?NOTOK) $ECHON "" \""$SUBJECT$ONHOST (no strings)"\" >> $MCMD.odd
		    if ($?NOTOK) echo "    ($SUBJECT$ONHOST)"
		else
		    $ECHON "" \""results of '$COMMAND'$ONHOST"\" >> $MCMD
		    if ($?WATROUS && $?NOTOK) $ECHON "" \""results of '$COMMAND'$ONHOST (no strings)"\" >> $MCMD.odd
		    if ($?NOTOK) echo "    (results of '$COMMAND'$ONHOST)"
		endif
		if ("$CC" != "") then
		    $ECHON "" -c \""$CC"\" >> $MCMD
#		    if ($?WATROUS && $?NOTOK) $ECHON "" -c \""$CC"\" >> $MCMD.odd
		endif
		if ("$BCC" != "") then
		    $ECHON "" -b \""$BCC"\" >> $MCMD
#		    if ($?WATROUS && $?NOTOK) $ECHON "" -b \""$BCC"\" >> $MCMD.odd
		endif
		echo "" $RECIP \< $MSG >> $MCMD
		if ($?WATROUS && $?NOTOK) echo "" watrous@mx.farside.rutgers.edu \< $OUT.odd >> $MCMD.odd
		if ($?VERBOSE) echo Mail command: `cat $MCMD`
		if ($?USET) then
		    cat $HEADERS $MSG | $MAIL -t
		else
		    sh $MCMD
		    if ($?WATROUS && $?NOTOK) sh $MCMD.odd
#		/bin/rm -f $MCMD.odd
		endif
	endif
else
		if ($?VERBOSE) echo `date +%T` No output to be mailed
endif

if (! $?KEEP) then
    if ($?VERBOSE) echo `date +%T` Removing work files
#    /bin/rm -f $OUT $ERR $MSG $MCMD $CMD $LOCK
# Tripping over $MCMD.odd; 1/8/18
    /bin/rm -f $OUT $ERR $MSG $HEADERS $MCMD{,.odd} $CMD $LOCK
    if ("$TRACE" != "/dev/null") /bin/rm $TRACE
else
    if ($?VERBOSE) echo `date +%T` Not removing work files "($OUT $ERR $MSG $HEADERS $MCMD)"
endif

if ($?VERBOSE) echo `date +%T` Done
