#! /bin/ksh
#
# ident @(#)immonitor-queue	1.12 12/03/98 SMI
#
# Copyright 1998 Sun Microsystems, Inc. All Rights Reserved.
# All Rights Reserved.
#
# Internet Mail System Queue Monitoring Script
# Reports the status of the IMTA queues
#
# Best viewed with tabstop=4

PATH=$PATH:/opt/SUNWmail/sbin:/usr/sbin:.
export PATH

PID=$$; export PID
export gettext=/usr/bin/gettext
export TEXTDOMAIN=monitor_script

export QUEUEDIR=/var/opt/SUNWmail/imta/queue

export QUEUEFILES=/tmp/queue.files.$PID
export MAIL_FILE=/tmp/queue.mailfile.$PID
export SUBJ_FILE=/tmp/queue.subj.$PID
export RCPTS_FILE=/tmp/queue.mailto.$PID
export TOP_FILE=/tmp/queue.top.$PID
export LOG_FILE=/tmp/queue.log.$PID

qflag=0; Hflag=0; cflag=0; Debug=0;
channel="" ; AltHost="" ; stkmsgnum=0; qmaxnum=0 ; heldmsgnum=0 ;

trap 'rm -f $QUEUEFILES $MAIL_FILE $LOG_FILE $SUBJ_FILE $RCPTS_FILE $TOP_FILE' 0 1 2 3 15

touch $MAIL_FILE $TOP_FILE # Prevent sort/grep from cribbing.
rm -f $LOG_FILE

Usage ()
{
	#
	# L10N:
	# Translate num. (number), channel and alert_recipients
	#

	echo `$gettext "Usage:"`
	echo "\timmonitor queue [-q num] [-s num] [-H num]"
	echo "\t [-c channel] [-r alert_recipients] [-A host] [-hdv]\n"

	echo `$gettext " [-h]: Display the usage message"`
	echo `$gettext " [-d]: Display the execution steps"`
	echo `$gettext " [-v]: Run in verbose mode"`
	# L10N: num is number
	echo `$gettext " [-q num]: Monitor the queue for <num> messages"`
	echo `$gettext " [-s num]: Display the top <num> non-responding domains"`
	echo `$gettext " [-H num]: Monitor the queue for <num> HELD messages"`
	echo `$gettext " [-c channel]: Associate all the options with channel"`
	echo `$gettext " [-r alert_recipients]: Comma separated list of mail recipients to notify"`
	echo `$gettext " [-A Host]: Alternate SMTP host to connect to."`
	echo
}


while getopts :q:s:c:r:A:H:hdv var
do
	case $var in
	q)	qmaxnum=$OPTARG
		qflag=1 ;;

	s)	stkmsgnum=$OPTARG
		sflag=1 ;;

	H)	heldmsgnum=$OPTARG ;
		Hflag=1 ;;

	c)	channel=$OPTARG
		cflag=1 ;;

	r)	Recpts=$OPTARG
		rflag=1 ;;

	A)	AltHost=$OPTARG  ;; # Alternate SMTP host to connect to

	d | v)	Debug=1 ;;

	: | \?)	Usage
		exit 64 ;;

	h)	Usage ;
		exit 64 ;;
	esac
done

Validate_User () {
	uid=`/usr/xpg4/bin/id -u`
	inet_uid=`/usr/xpg4/bin/id -u inetmail`

	if [[ ($uid -ne 0) && ($uid -ne $inet_uid) ]]; then
		echo `$gettext "Permission denied. You need to be root/inetmail"`
		exit 77 ; # EX_NOPERM of sysexits.h
	fi
}

if [[ ($qflag -eq 0) && ($Hflag -eq 0) && ($sflag -eq 0) ]]; then
	doAll=1;
else
	doAll=0 ;
fi

if [[ $Debug -eq 1 ]]; then
set -x
fi

Validate_User ;

if [[ ! -d $QUEUEDIR ]]
then
	echo "$QUEUEDIR : \c"
	echo `$gettext "no such file or directory"`
	exit 66 ; # EX_NOINPUT of sysexits.h
fi

if [[ ! -r $QUEUEDIR ]]
then
	echo "$QUEUEDIR : \c"	
	echo `$gettext "permission denied"`
	exit 77 ; # EX_NOINPUT of sysexits.h
fi

# doAll == 1 indicates that this command is being used to report the
# state of the system and not to monitor any service.

find $QUEUEDIR -type f -name "*.*"  > $QUEUEFILES 2>/dev/null

if [[ ($doAll -eq 1) || ($qflag -eq 1) || ($Hflag -eq 1) ]]
then
	# Strip the pathname to contain only the channel_name/*/message_files

	sed "1,$ s/.*queue\///" $QUEUEFILES | nawk -F "/" -v qFlag=$qflag \
		-v HFlag=$Hflag -v doall=$doAll -v qsize=$qmaxnum \
		-v logfile=$LOG_FILE -v heldnum=$heldmsgnum -v chnl=$channel '
	BEGIN { 
		size=0; num = 0; heldmsgs=0; stkmsgs=0; okmsgs=0 ;
		prevchnl = "" 
		gettext = "/usr/bin/gettext"
	}
	
	function report (chnlname) {
		size = heldmsg[chnlname] + stkmsg[chnlname] + okmsg[chnlname] ;

	# A variable msGstr is used to help  xgettextsh.sh pick up the messages
	# For localization. While adding a new message take care to add a msGstr
	# with the same values. msGstr contains the actual message.

		msGstr = gettext "Channel name: %s" ;
		"gettext \"Channel name: %s\" " | getline format ;
		close ("gettext \"Channel name: %s\" ");
		printf format, chnlname ; printf "\n"; 

		msGstr = gettext "\tNumber of HELD messages: %d" ;
		"gettext \"\tNumber of HELD messages: %d\" " | getline format ;
		close ("gettext \"\tNumber of HELD messages: %d\" ");
		printf format, heldmsg[chnlname] ; printf "\n";

		msGstr = gettext "\tNumber of failed delivery messages: %d" ;
		"gettext \"\tNumber of failed delivery messages: %d\" " | getline format ;
		close ("gettext \"\tNumber of failed delivery messages: %d\" ");
		printf format, stkmsg[chnlname] ; printf "\n";

		msGstr = gettext "\tNumber of messages pending delivery: %d" ;
		"gettext \"\tNumber of messages pending delivery: %d\" " | getline format;
		close ("gettext \"\tNumber of messages pending delivery: %d\" ");
		printf format, okmsg[chnlname] ; printf "\n";

		msGstr = gettext "\tTotal messages in channel: %d" ;
		"gettext \"\tTotal messages in channel: %d\" " | getline format;
		close ("gettext \"\tTotal messages in channel: %d\" ");
		printf format, size ; printf "\n\n" ;
	}

	function alert (str, tot, thr) {
		# L10N: Dont translate 
		msGstr = gettext "ALERT: <%s>  exceeds threshold" ;
		"gettext \"ALERT: <%s>  exceeds threshold\" " | getline format
		close ("gettext \"ALERT: <%s>  exceeds threshold\" ");
		printf format, str ; printf "\n";

		msGstr = gettext "\tCurrent value = %d/Threshold = %d" ;
		"gettext \"\tCurrent value = %d/Threshold = %d\" " | getline format
		close ("gettext \"\tCurrent value = %d/Threshold = %d\" ");
		printf format, tot, thr; printf "\n" ;

		# syslog cant handle Internationalized data, so ...

		printf "ALERT: <%s>  exceeds threshold\n", str >> logfile ;
		printf "Current Value = %d/Threshold = %d\n", tot, thr >> logfile ;
	}

	{
		if ($1 != prevchnl) 
			channel[num++] = $1; # Store the channel names

		if ($NF ~ "HELD") {
			heldmsg[$1]++; heldmsgs++;
		}
		else {
			if ($NF !~ /ZZ.*\.[0-9A-Za-z][0-9A-Za-z]/) { 
				# Only the messages which have not yet been 
				# processed are of the form ZZ*.[:alnum:][:alnum:]

				stkmsg[$1]++;  stkmsgs++ ;
			}
			else  {  # OK messages
				okmsg[$1]++; okmsgs++;
			}
		}

		prevchnl = $1 ;
	}

	END {
		if (doall) {
			if (chnl)
				report(chnl);
			else {
				for (i=0; (name = channel[i]); i++)
					report(name);

				msGstr = gettext "Total messages in queue: %d" ;
				"gettext \"Total messages in queue: %d\" " | getline format
				close ("gettext \"Total messages in queue: %d\" ");
				printf format, (heldmsgs+stkmsgs+okmsgs) ; printf "\n\n"
			}
		} # If not doall

		else {
			if (qFlag) {
				if (chnl) {
					buf = sprintf ("Channel %s", chnl); 
					currTotSize = heldmsg[chnl] + stkmsg[chnl] + okmsg[chnl];
					if (currTotSize > qsize)
						alert(buf, currTotSize, qsize);
				}
				else {
					currTotSize = heldmsgs + stkmsgs + okmsgs ;
					if (currTotSize > qsize)
						alert("Queue", currTotSize, qsize);
				}
			}
					
			if (HFlag)
				if (chnl) {
					buf = sprintf ("HELD messages for channel %s", chnl);
					if (heldmsg[chnl] > heldnum)
						alert(buf, heldmsg[chnl], heldnum);
				}
				else {
					if (heldmsgs > heldnum)
						alert("HELD messages for queue", heldmsgs, heldnum);
				}
		} # End of alerting
	}' > $MAIL_FILE 2>/dev/null
fi

# MAIL_FILE contains the alert if -q/-H is used or it contains the state
# if no option is specified (doall == 1)

if [[ ($doAll -eq 1) || ($sflag -eq 1) ]]
then
	if [[ $cflag -eq 1 ]]; then
		files=`grep $channel $QUEUEFILES 2>/dev/null | nawk -F "/" '{ 
			if ( ($NF !~ /ZZ.*\.[0-9A-Za-z][0-9A-Za-z]/) && 
					($0 ~ /.*\.[0-9A-Za-z][0-9A-Za-z]/) && ($NF !~ "HELD") ) 
				print $0
		}'`
	else
		files=`nawk -F "/" '{
			if ( ($NF !~ /ZZ.*\.[0-9A-Za-z][0-9A-Za-z]/) && 
					($0 ~ /.*\.[0-9A-Za-z][0-9A-Za-z]/) && ($NF !~ "HELD") )
				print $0
		}' $QUEUEFILES` 2>/dev/null
	fi

	if [[ -z $files ]]
	then
		echo `$gettext "Messages with failed delivery : 0"` > $TOP_FILE
	else
		# Mail files contain the destination in f;xx@yy.com
		# The o/p of nawk is of form: "filename domain"
		# sort on the second field (domain)
		# Get only the uniq lines (ignore 1st field (uniq -1))
		# reverse sort

		nawk '{ if ($0 ~ /^f;/) {
					if (split ($0, domain, "@") == 2) # Exactly 2 fields
						printf "%s %s\n", FILENAME, domain[2]
				# Dont Internationalize here, this file is for internal use only
				}
		}' $files | sort -k 2 | uniq -1 -c | sort -r |
		nawk -v Num=$stkmsgnum '
		BEGIN { 
				gettext = "/usr/bin/gettext"
				msGstr = gettext "The top non-responding domain(s): " ;
				"gettext \"The top non-responding domain(s):\" " | getline format;
				close ("gettext \"The top non-responding domain(s):\" ");
				printf format ; printf "\n";

				if (Num <= 0) {  # Invoked without -s (doall == 1)
					Default=1; Num=10; 
				}
				else
					Default=0;
			}

			{
				gsub (/.*queue\//, "", $2);
				split ($2, channel, "/");
				if (NR <= Num)
					printf "\t%d.\t%s (%d) (%s)\n", NR, $NF, $1, channel[1] ;
			}

		END { if ((Default == 0) && (NR < Num)) {
				msGstr = gettext "Only %d unique domain(s) found." ;
				"gettext \"Only %d unique domain(s) found.\" "| getline format
				printf "\n" ; printf format, NR ; printf "\n";
			}
		}' > $TOP_FILE
	fi

fi

SendMail ()
{

# Do not indent. Some of the commands to mconnect need to
# appear before any space/tab.

mconnect $1 << _EOF > /dev/null
helo `uname -n`
mail from: `logname`
`cat $RCPTS_FILE`
data
`cat $SUBJ_FILE`
From: SIMS Admin <`logname`>

`cat $MAIL_FILE`
.
quit
_EOF

}

RetStat=0;

Log_Message () 
{
	# ^$ strips off the empty lines from the file.

	grep -v '^$' $LOG_FILE | /usr/bin/logger -p mail.alert \
	-t "SUNWmail.Monitor.queues" -i 
}

# Mail only if we have the -r and !doAll

if [[ ($rflag -eq 1) && ($doAll -ne 1) ]]
then
	# The Recpts can be comma separated mail addresses.  So we use nawk to
	# break then up and put them in a file. This is required since each of
	# the recipients to mconnect need to be specified with "rpct to:"

	echo $Recpts | nawk '{
		i=1;
		split ($0, Arr,",");
		while ( Arr[i])
			printf "rcpt to: %s\n", Arr[i++]	

	}' > $RCPTS_FILE
		
	# If AltHost is not specified, localhost is used by default.

	if [[ (-s $MAIL_FILE) && (-s $RCPTS_FILE) ]]
	then

# L10N: Dont translate "Subject: ......" string,
# "Content-Type:" and  "charset=" 

		$gettext "Subject: ALERT: immonitor: Queue threshold exceeded for: " > $SUBJ_FILE
		echo `hostname` >> $SUBJ_FILE
		echo "MIME-Version: 1.0" >> $SUBJ_FILE

#
# L10N: Look up the following table and insert the charset corresponding to
# your language
# --------------------------------------------------------------------------
# English       :   US-ASCII
# Japanese      :   EUC-JP
# European languages:   ISO-8859-1
# Simplified Chinese:   EUC-CN
# Traditional Chinese:   EUC-TW
# Korean      :   EUC-KR
# --------------------------------------------------------------------------
#
		echo `$gettext "Content-Type: text/plain ; charset=US-ASCII"` >> $SUBJ_FILE
		echo `$gettext "Content-Transfer-Encoding: 8bit"` >> $SUBJ_FILE

		SendMail $AltHost
		if [[ $? -eq 0 ]]; then
			echo `$gettext "Mail sent to :-"` $Recpts
		else
			echo `$gettext "Could not send mail to :-"` $Recpts
		fi
		Log_Message ;
		RetStat=1 ;
	fi
else
	# If the MAIL_FILE has some data AND the doAll == 0, then one/all of the
	# thresholds have been crossed, so we return a non-zero exit value.

	if [[ (-s $MAIL_FILE) && ($doAll -eq 0) ]] ; then
		Log_Message ; # Logs to syslog
		RetStat=1 ;
	fi
	cat $MAIL_FILE
fi

cat $TOP_FILE

exit $RetStat
