#!/bin/ksh
#
# Component: dicom
#
# Description:
#  Control script of component dicom
#

#--- INIT ------------------------------
#needs $HOME
. $HOME/etc/ctrl.main.shi

[ -f $HOME/etc/setenv.sh ] && . $HOME/etc/setenv.sh

#--- FUNC ------------------------------
do_shell_()
{
	if [ -f "$ETC/virthost.sh" ]; then
		. "$ETC/virthost.sh"
	fi
	[ -z "$DICOM_PORT" ] && DICOM_PORT=104
	[ -z "$DICOM_TLS_PORT" ] && DICOM_TLS_PORT=2762

	cat <<-EndOfInlineData
		DICOM_HOME=$HOME/component/dicom
		DICOM_VAR=$VAR/dicom
		DICOM_SERVERIP=$BINDIP
		DICOM_PORT=$DICOM_PORT
		DICOM_TLS_PORT=$DICOM_TLS_PORT
		DICOM_AE_TITLE="PBUILDER"
		DICOM_PID=$RUN/pb-scp.pid
		MPPSTBL=MPPS
	EndOfInlineData
} #do_shell_()

do_crontab_()
{
	# Get time for starting getorders.sh from crontabSchedule settings
	[ -f "$CONF/crontabSchedule.shi" ] && . $CONF/crontabSchedule.shi
	[ -z "$GetOrders" ] && GetOrders="18,48 *"

	cat <<-EOI
		$GetOrders * * * $DICOM_HOME/bin/getorders.sh >/dev/null 2>&1
	EOI
} #do_crontab_()


do_start_()
{
	PB_SCP_CONFIG="$DICOM_VAR/pb-scp.cfg"

	# create DICOM_VAR
	# check and move config files from DCMTK_VAR to DICOM_VAR
	if [ ! -d "$DICOM_VAR" ] ; then
		mkdir $DICOM_VAR 2>/dev/null

		# check for qr.cfg
		[ -f "$DCMTK_VAR/qr.cfg" ] && mv -f $DCMTK_VAR/qr.cfg $DICOM_VAR/qr.cfg 2>/dev/null

		if [ -f "$DCMTK_VAR/pb-scp.cfg" ] ; then
			# pb-scp.cfg exists, should be moved to DICOM_VAR
			mv -f $DCMTK_VAR/pb-scp.cfg $PB_SCP_CONFIG 2>/dev/null

		else
			# there's no pb-scp.cfg in DCMTK_VAR.
			# pb-scp should be created in DICOM_VAR
			# from old style config files and from environment variables

			# ae.cfg, port.cfg, ts.cfg and pdu.cfg are obsoleted
			# We should only check for them and save their values
			# then we should remove these files

			# PB-SCP AE Title
			AE_CFG=`cat $DCMTK_VAR/ae.cfg 2>/dev/null`
			[ -z "$AE_CFG" ] && AE_CFG="$DICOM_AE_TITLE"
			echo "AE_TITLE=\"$AE_CFG\"" >> $PB_SCP_CONFIG
			rm $DCMTK_VAR/ae.cfg 2>/dev/null

			# PB-SCP Port
			PORT_CFG=`cat $DCMTK_VAR/port.cfg 2>/dev/null`
			[ -z "$PORT_CFG" ] && PORT_CFG="$DICOM_PORT"
			echo "PORT=\"$PORT_CFG\"" >> $PB_SCP_CONFIG
			rm $DCMTK_VAR/port.cfg 2>/dev/null

			# PB-SCP TLS Port
			TLS_PORT_CFG="$DICOM_TLS_PORT"
			echo "TLS_PORT=\"$TLS_PORT_CFG\"" >> $PB_SCP_CONFIG

			# Default Transfer Syntax = SCU Defined
			# Originally ts.cfg contained 't[i|e|b]'
			# we need to change them to 'x[i|e|b]'
			# Factory Default is Little Endian Preferred
			TS_CFG="`sed 's/t/x/' $DCMTK_VAR/ts.cfg 2>/dev/null`"
			[ -z "$TS_CFG" ] && TS_CFG="xe"
			echo "TRANSFER_SYNTAX=\"$TS_CFG\"" >> $PB_SCP_CONFIG
			rm $DCMTK_VAR/ts.cfg 2>/dev/null

			# PDU Size
			PDU_CFG="`cat $DCMTK_VAR/pdu.cfg 2>/dev/null`"
			[ -z "$PDU_CFG" ] && PDU_CFG="`grep ^MaxPDUSize $DICOM_VAR/qr.cfg 2>/dev/null \
																		| sed 's/^.*= *\(.*\)$/\1/' 2>/dev/null`"
			[ -z "$PDU_CFG" ] && PDU_CFG=65536
			echo "PDU_SIZE=\"$PDU_CFG\"" >> $PB_SCP_CONFIG
			rm $DCMTK_VAR/pdu.cfg 2>/dev/null

			# Max Associations
			QR_MAXASSOC="`grep ^MaxAssociations $DICOM_VAR/qr.cfg 2>/dev/null \
									 | sed 's/^.*= *\(.*\)$/\1/' 2>/dev/null`"
			[ -z "$QR_MAXASSOC" ] && QR_MAXASSOC=16
			echo "MAX_ASSOCIATIONS=\"$QR_MAXASSOC\"" >> $PB_SCP_CONFIG

			# Case sensitive/insensitive search setting for Q/R
			echo "CASE_INSENSITIVE=\"true\"" >> $PB_SCP_CONFIG

			# Q/R setting for matching empty and null values
			echo "EMPTY_MATCHING=\"false\"" >> $PB_SCP_CONFIG

			# Promiscuous Mode setting
			P_MODE="true"
			if [ -f "$DICOM_VAR/qr.cfg" ] ; then
				HostTable="`grep ^HostTable $DICOM_VAR/qr.cfg 2>/dev/null`"
				[ -n "$HostTable" ] && P_MODE="false"
			else
				if [ -f "$DCMTK_VAR/enabledIPs" ] ; then
					P_MODE="false"
					rm $DCMTK_VAR/enabledIPs
				fi
			fi
			echo "PROMISCUOUS_MODE=\"$P_MODE\"" >> $PB_SCP_CONFIG

			# STORESCU flag
			# This flag is used by the objfwd.sh when calls storescu
			STORESCU_FLAG="`cat $DCMTK_VAR/storescu.flag 2>/dev/null`"
			[ -z "$STORESCU_FLAG" ] && STORESCU_FLAG="-R"
			echo "STORESCU_FLAG=\"$STORESCU_FLAG\"" >> $PB_SCP_CONFIG
			rm $DCMTK_VAR/storescu.flag 2>/dev/null

		fi # creating pb-scp.cfg

		# Move VAR/resultsmgmt/peer.cfg
		[ -f "$VAR/resultsmgmt/peer.cfg" ] && mv -f $VAR/resultsmgmt/peer.cfg $DICOM_VAR/resultsmgmt_peer.cfg
		[ -f "$VAR/resultsmgmt/server.cfg" ] && rm -f $VAR/resultsmgmt/server.cfg
		[ -d "$VAR/resultsmgmt" ] && rm -fr $VAR/resultsmgmt 2>/dev/null
		
	fi # creating and initializing dicom/var

	# moved here from cases/ctrl, because it needs var/dicom folder
	CLASSPATH=$CLASSPATH:$HOME/component
	export CLASSPATH
	$JAVA_HOME/bin/java $LOG4J_ARGS ${CASES_HOME#$HOME/component/}.GenPbrOnlyFieldList


	# Check and create mappings directory
	[ ! -d "$DICOM_VAR/mappings" ] && mkdir "$DICOM_VAR/mappings"

	# Check and create devices directory
	[ ! -d "$DICOM_VAR/devices" ] && mkdir "$DICOM_VAR/devices"

	# Check and move MWL settings from $VAR/mitra
	# Upgrade to v5.2
	if [ -d "$VAR/mitra" ] ; then
		if [ ! -f "$DICOM_VAR/mwl.cfg" ] ; then
			[ -f "$VAR/mitra/mwl.cfg" ] && mv $VAR/mitra/mwl.cfg $DICOM_VAR/mwl.cfg 
		fi
		if [ ! -f "$DICOM_VAR/mwlquery.dcm" ] ; then
			[ -f "$VAR/mitra/mwlquery.dcm" ] && mv $VAR/mitra/mwlquery.dcm $DICOM_VAR/mwlquery.dcm
		fi

		# remove $VAR/mitra
		rm -fr "$VAR/mitra" 2>/dev/null
	fi
	
	# Convert old device specific settings to the new form.
	# VERSION 1.0
	[ -z "$TMP" ] && TMP="."  

	tmpFile=$TMP/tmpConvert.$$

	for cfgFile in `find $DICOM_VAR/devices/ -name "*.cfg" | grep -v "_localIPs.cfg$"` ; do
		grep -q "VERSION" $cfgFile
		if [ $? != 0 ] ; then
				echo 'VERSION="1"' >> $tmpFile
				(
					. "$cfgFile"
					if [ "$HardEdit" == "Auto" ] ; then
						echo 'HARD_EDIT="AUTO"' >> $tmpFile
					fi	
					
					if [ "$HardEdit" == "No" ] ; then
						echo 'HARD_EDIT="NO"' >> $tmpFile
					fi	
					
					if [ "$HardEdit" == "Yes" ] ; then
						echo 'HARD_EDIT="YES"' >> $tmpFile
					fi	
					
					if [ "$RemovePrivateTags" == "No" ] ; then
						echo 'RemovePrivateTags="NO"' >> $tmpFile
					fi	
					
					if [ "$RemovePrivateTags" == "Yes" ] ; then
						echo 'RemovePrivateTags="YES"' >> $tmpFile
					fi	
					
					[ -n "$defaultRedirectProtocol" ] && echo "defaultRedirectProtocol=\"$defaultRedirectProtocol\"" >> $tmpFile
				)
		mv $tmpFile $cfgFile 
		fi
	done
	
	# Move deviece specific settings send timeout and receive timeout from the database to device.cfg file
	# VERSION 2.0
	echo "select ID, RECVTO, SENDTO from $TARGETTBL" | $MYSQL_HOME/bin/mysql -N $DBNAME | 
	while read ID RECVTO SENDTO 
	do
		cfgFile=$DICOM_VAR/devices/$ID.cfg
		if [ -f $cfgFile ] ; then
			(
			. $cfgFile
			if [ "$VERSION" -lt 2 ] ; then
					if [ -z "$SEND_TIMEOUT" ] ; then
						if [ $SENDTO -ne 0 ] ; then
							echo "SEND_TIMEOUT=\"$SENDTO\"" >> $cfgFile
						fi
						
					fi

					if [ -z "$RECEIVE_TIMEOUT" ] ; then
						if [ $RECVTO -ne 0 ] ; then
							echo "RECEIVE_TIMEOUT=\"$RECVTO\"" >> $cfgFile
						fi
					fi
					
					cat $cfgFile | sed -e 's/VERSION="1"/VERSION="2"/g' >$tmpFile
					mv $tmpFile $cfgFile
				fi
			)	
		else		
			echo 'VERSION="2"' >> $cfgFile
			if [ "$SENDTO" -ne 0 ] ; then
				echo "SEND_TIMEOUT=\"$SENDTO\"" >> $cfgFile
			fi
			if [ "$RECVTO" -ne 0 ] ; then
				echo "RECEIVE_TIMEOUT=\"$RECVTO\"" >> $cfgFile
			fi
		fi
	done	

	
	# Check and generate pb-scp.cfg

	. $PB_SCP_CONFIG

	[ -z "$AE_TITLE" ] && AE_TITLE="$DICOM_AE_TITLE"
	[ -z "$PORT" ] && PORT="$DICOM_PORT"
	[ -z "$TLS_PORT" ] && TLS_PORT="$DICOM_TLS_PORT"
	[ -z "$TRANSFER_SYNTAX" ] && TRANSFER_SYNTAX="xd"
	[ -z "$PDU_SIZE" ] && PDU_SIZE="65536"
	[ -z "$MAX_ASSOCIATIONS" ] && MAX_ASSOCIATIONS="16"
	[ -z "$PROMISCUOUS_MODE" ] && PROMISCUOUS_MODE="true"
	# storage + query/retrieve (legacy)
	[ -z "$PROMISCUOUS_SERVICES" ] && PROMISCUOUS_SERVICES="00000003" 
	[ -z "$CASE_INSENSITIVE" ] && CASE_INSENSITIVE="true"
	[ -z "$EMPTY_MATCHING" ] && EMPTY_MATCHING="false"
	[ -z "$RECEIVE_TIMEOUT" ] && RECEIVE_TIMEOUT="30"
	[ -z "$SEND_TIMEOUT" ] && SEND_TIMEOUT="30"

	# Disable PROMISCUOUS_MODE on CWL servers (ProcessMode = Database)
	ProcessMode=""
	[ -f "$CONF/self.rec" ] && . "$CONF/self.rec"
	[ "$ProcessMode" = "Database" ] && PROMISCUOUS_MODE="false"

	# Generating qr.cfg

	SELECT_PREFIX="select ID,HOSTNAME,AE,PORT,PROTOCOL,SERVICE from $TARGETTBL, $DEVSERVTBL "
	if [ "$1" = "service" ] ; then
		# In service mode allow only Child/Parent connections to let the queues to be emptied
		# !! also disable promiscuous mode
		PROMISCUOUS_MODE="false"
		TMP_HOST_TABLE=`echo "$SELECT_PREFIX where TYPE='C' or TYPE='P' and ID=DEVICE order by ID;" | \
				$MYSQL_HOME/bin/mysql -N $DBNAME 2>/dev/null`
	else
		TMP_HOST_TABLE=`echo "$SELECT_PREFIX where TYPE != 'H' and ID=DEVICE order by ID;" | \
				$MYSQL_HOME/bin/mysql -N $DBNAME 2>/dev/null`
	fi

	GEN_RES=$?

	if [ $GEN_RES -ne 0 ] ; then
		if [ ! -f "$DICOM_VAR/qr.cfg" ] ; then
			# Get the config file generated by the GUI
			[ -f "$DICOM_VAR/qr.cfg.gui" ] && cp -p "$DICOM_VAR/qr.cfg.gui" "$DICOM_VAR/qr.cfg"
		else
			echo "$DICOM_VAR/qr.cfg could not be created" >&2
		fi
	else
		HOST_TABLE=`echo "$TMP_HOST_TABLE" | \
		sed 's/[ ,(=)]/_/g' | \
		$DICOM_HOME/mkhosttable.awk -vFS='\t' \
				-vip="$SERVERIP" -vport="$PORT" -vdae="$DICOM_AE_TITLE" -vae="$AE_TITLE"`

		AUTHORIZED_HOSTS="ANY"
		[ "$PROMISCUOUS_MODE" = "false" -a "$GEN_RES" -eq 0 ] && AUTHORIZED_HOSTS="_-_ALLOWED_-_"

		cat >$DICOM_VAR/qr.cfg <<-ENDOfHostTable
			NetworkTCPPort = $PORT
			NetworkTLSPort = $TLS_PORT
			MaxPDUSize = $PDU_SIZE
			MaxAssociations = $MAX_ASSOCIATIONS
			ReceiveTimeout = $RECEIVE_TIMEOUT
			SendTimeout = $SEND_TIMEOUT
			ConnectionTimeout = $CONNECTION_TIMEOUT
			EmptyMatching = $EMPTY_MATCHING
			CaseInsensitive = $CASE_INSENSITIVE
			TransferSyntax = $TRANSFER_SYNTAX
			PromiscuousServices = $PROMISCUOUS_SERVICES
			AllowFallbackTLS = $ALLOW_FALLBACK_TLS
			
			$HOST_TABLE

			AETable BEGIN
			$AE_TITLE $TMP RW (0,0mb) $AUTHORIZED_HOSTS
		ENDOfHostTable

		# ksh can't resolve new lines within variables in a 'here document' block :(
		if [ -n "${ALTERNATIVE_AE_TITLES}" ] ; then
			for ALT_AE_TITLE in ${ALTERNATIVE_AE_TITLES} ; do
				echo "${ALT_AE_TITLE} ${TMP} RW (0,0mb) ${AUTHORIZED_HOSTS}" >>"${DICOM_VAR}/qr.cfg"
			done
		fi

		if [ -n "$ARCHIVE_AETITLE" ] ; then
			echo "$ARCHIVE_AETITLE ARCHIVE RW (0,0mb) $AUTHORIZED_HOSTS" >>"${DICOM_VAR}/qr.cfg"
		fi

		echo "AETable END" >>"${DICOM_VAR}/qr.cfg"

	fi # endOf generating qr

	[ -n "$TRANSFER_SYNTAX" ] && PB_SCP_OPT="+$TRANSFER_SYNTAX"

	# TLS options
	TLS_KEY_FILE="$OPENSSL_PRIVKEY"
	TLS_CERT_FILE="$OPENSSL_CERT_DEFAULT"
	PB_SCP_OPT="$PB_SCP_OPT +tls $TLS_KEY_FILE $TLS_CERT_FILE -ic +ps -dhl"

	# asroot needs PB_SCP_OPT, pb-scp needs CASE_INSENSITIVE
	export PB_SCP_OPT CASE_INSENSITIVE EMPTY_MATCHING

	if [ -f "$CONF/charset.cfg" ] ; then
		# Character set settings - set environment variables
		. "$CONF/charset.cfg"

		export PB_CHARSET PB_DCM_CHARSET
	fi
	
	if [ "$1" = "debug" ] ; then
		cat <<-ENDDICOMOPTION > $RUN/dicom.options
			DICOM_OPTIONS="-v -d"
		ENDDICOMOPTION
	elif [ "$1" = "nodebug" ] ; then
		[ -f "$RUN/dicom.options" ] && rm $RUN/dicom.options
	fi

	$ASROOT dicom.asr start

} #do_start_()

do_stop_()
{
	$ASROOT dicom.asr stop

} #do_stop_()


#
# Counts the child processes of pb-scp
#
# $1 - the process ID of the root pb-scp process
#
# output: the count of the child processes
#
count_child_processes_() {
	local procId="$1"

	ps -o pid= --ppid "${procId}" | wc -l
}


#
# Checks if the count of the child processes is above the 'full' threshold.
#
# To be called only when the C-Echo fails. Receives the process count before the C-Echo in a parameter,
# but also gets the current process count. Both process counts will be checked.
#
# Exits with a warning when either process count reaches the threshold.
#
# $1 - the process ID of the root pb-scp process
# $2 - the threshold
# $3 - the process count (before the echo)
#
check_threshold_() {
	local procId="$1"
	local threshold="$2"
	local procCount="$3"

	# process count before echo
	if [ ${procCount} -ge ${threshold} ] ; then
		/usr/bin/logger -p $LOG_FACILITY.error -t "dicom-ctrl[$$]" "pb-scp echo failed, but current association count (${procCount}) reached threshold (${threshold})"
		echo "WARNING"
		exit
	fi

	# process count after echo
	procCount=$( count_child_processes_ "${procId}" )
	if [ ${procCount} -ge ${threshold} ] ; then
		/usr/bin/logger -p $LOG_FACILITY.error -t "dicom-ctrl[$$]" "pb-scp echo failed, but current association count (${procCount}) reached threshold (${threshold})"
		echo "WARNING"
		exit
	fi
}


do_status_()
{
	local pbscpPid;
	local procName;
	local MAX_ASSOCIATIONS;
	local assocThreshold;
	local countAssoc;

	if [ ! -f $DICOM_PID ]; then
		echo "STOPPED"
		exit
	fi

	pbscpPid=$( cat "$DICOM_PID" )
	procName=$( ps -o comm= --pid ${pbscpPid} )

	if [ "pb-scp" != "${procName}" ] ; then
		/usr/bin/logger -p $LOG_FACILITY.error -t "dicom-ctrl[$$]" "${pbscpPid} does not exist or is not a pb-scp process ('${procName}')"
		echo "ERROR"
		exit
	fi

	. $DICOM_VAR/pb-scp.cfg

	[ -z "$AE_TITLE" ] && AE_TITLE="$DICOM_AE_TITLE"
	[ -z "$PORT" ] && PORT="$DICOM_PORT"
	[ -z "$TLS_PORT" ] && TLS_PORT="$DICOM_TLS_PORT"
	[ -z "${MAX_ASSOCIATIONS}" ] && MAX_ASSOCIATIONS=16

	# 90%
	assocThreshold=$(( ${MAX_ASSOCIATIONS} * 9 / 10 ))
	countAssoc=$( count_child_processes_ "${pbscpPid}" )
	if [ ${countAssoc} -ge ${MAX_ASSOCIATIONS} ] ; then
		/usr/bin/logger -p $LOG_FACILITY.error -t "dicom-ctrl[$$]" "pb-scp hit max associations (${MAX_ASSOCIATIONS})"
		echo "WARNING"
		exit
	fi

	# Checking transparent TCP connection
	$DCMTK_HOME/bin/echoscu --call $AE_TITLE -aet $AE_TITLE $SERVERIP $PORT >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		check_threshold_ "${pbscpPid}" "${assocThreshold}" "${countAssoc}"
		/usr/bin/logger -p $LOG_FACILITY.error -t "dicom-ctrl[$$]" "DICOM C-Echo failed (TCP)"
		echo "ERROR"
		exit
	fi

	# Checking TLS TCP connection
	TLS_KEY_FILE="$OPENSSL_PRIVKEY"
	TLS_CERT_FILE="$OPENSSL_CERT_DEFAULT"
	TLS_OPT="+tls $TLS_KEY_FILE $TLS_CERT_FILE -ic +ps"

	$OPENSSL_PASS | $DCMTK_HOME/bin/echoscu --call $AE_TITLE -aet $AE_TITLE $TLS_OPT $SERVERIP $TLS_PORT >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		check_threshold_ "${pbscpPid}" "${assocThreshold}" "${countAssoc}"
		/usr/bin/logger -p $LOG_FACILITY.error -t "dicom-ctrl[$$]" "DICOM C-Echo failed (TLS)"
		echo "ERROR"
		exit
	fi

	echo "OK"
	exit

} #do_status_()

do_beforesubmit_()
{
	do_stop_

} #do_beforesubmit_()

do_aftersubmit_()
{
	do_start_

} #do_aftersubmit_()

do_emergency_()
{
	do_stop_
	do_start_

} #do_emergency_()


do_monitor_()
{
	# checking number of pb-scp processes
	numProc=$(ps -C pb-scp h -o "%u" | grep "\<$USER\>" | wc -l)
	MAX_ASSOCIATIONS="16"
	[ -f "$DICOM_VAR/pb-scp.cfg" ] && . "$DICOM_VAR/pb-scp.cfg"

	echo "$numProc ${MAX_ASSOCIATIONS}" | awk '{printf("dicom_proc=%1.2f\n", $1 * 100 / $2);}'
}

#
# List files/tables to be backed up grouped by categories
#
# output lines should be in '<category> <type> <names>' format
#
do_listbackup_()
{
	cat <<-EOFLISTBACKUP
		config.devices FILE ${DICOM_VAR#$HOME/}
		config.devices DATABASE Target DevServ
		data.mpps DATABASE MPPS
	EOFLISTBACKUP
}

#--- MAIN ------------------------------

check_action_ $1
if [ 0 = $? ]; then
	cmd=$1
	shift
	do_${cmd}_ "$@"

else
	echo "--- Component dicom [ctrl $$]: Bad command: $1" >&2
	exit 1

fi
