#!/bin/bash

source /usr/lib/ie-common

# usage
#	print usage and exit
usage() {
	cat << EOF
Usage: $0 [-rv] command [arguments...]

Commands:
  install		- perform automatic configuration and start the IE
  disable		- disable IE for the Exim and stop the daemons
  enable		- configure Exim and start the IE daemons
  postinstall		- run post-install checks and fixes
  set-nport [port]	- set DEC node server TCP port number
  set-nsr [rate]	- configure DEC sampling rate
  set-ntoken [token]	- install DEC security token
  set-qport [port]	- set quarantine server TCP port number
  set-qtoken [token]	- install quarantine security token
  set-rwc [token]	- set rspamd worker-controller configuration
  start			- start the imunify email daemons
  status		- print status of the imunify email system
  is-on 		- exit with 0 if IE is ON, 1 in other cases
  stop			- stop the imunify email daemons
  version-packages	- list all imunifyemail packages
  version		- print imunifyemail suite version
  enable-incoming   - enable incoming filtration feature
  disable-incoming  - disable incoming filtration feature

Options:
  -r			- submit last error message to the Imunify Email team
  -v			- be verbose about configuration progress
EOF
}

POSTFIX_MAIN_CF="/etc/postfix/main.cf"
POSTFIX_MASTER_CF="/etc/postfix/master.cf"
POSTFIX_CHECK_CMD="/usr/sbin/postfix check"
POSTFIX_RELOAD_CMD="/usr/sbin/postfix reload"
POSTFIX_RM_QREQ_CMD="/usr/sbin/postsuper -r ALL"

# svc_ie
#	start the imunify daemons, in order
svc_ie()
{
  _name="svc_ie"
  _cmd=$1

  case "$_cmd" in
    stop|status|enable|disable|restart|start)
      ;;
  *)
    err 1 "$_name: $1: bad command" ;;
  esac


  for _svc in rspamd ie-quarantine ie-dec-node ie-spamfilter; do
    dprint 2 "$_name: $_cmd $_svc"
    if ! /bin/systemctl $_cmd ${_svc}.service ; then
      err 5 "$_name: $_svc $_cmd failed"
    fi
  done
}


# cfg_postfix
#	configure Postfix to use the imunifyemail postfilter
cfg_postfix()
{
	_name="cfg_postfix"

	dprint 2 "$_name: analyzing files"
	if [ ! -w "$POSTFIX_MAIN_CF" ] ||  [ ! -w "$POSTFIX_MASTER_CF" ] ; then
		err 3 "$_name: $POSTFIX_MAIN_CF or $POSTFIX_MAIN_CF: file unwriteable"
	fi
	# postpone exim.conf rebuild until all necessary files will be updated
	_reloadconf=no

	if ! grep -q '^#imunifyemail_spamfilter.*BEGIN' $POSTFIX_MAIN_CF ; then
		dprint 2 "$_name: editing $POSTFIX_MAIN_CF"
		backup_file "$BACKUP" "$POSTFIX_MAIN_CF"
		_reloadconf=yes
    sed -i -e '$a\
#imunifyemail_spamfilter BEGIN\
content_filter = ie-scan:unix:imunifyemail/ie-scan\
receive_override_options = no_address_mappings\
#imunifyemail_spamfilter END' $POSTFIX_MAIN_CF || err 250 "$_name: unexpected error (sed)"
	else
		dprint 1 "$_name: $POSTFIX_MAIN_CF was edited before"
	fi

	if ! grep -q '^#imunifyemail_spamfilter.*BEGIN' $POSTFIX_MASTER_CF ; then
		dprint 2 "$_name: editing $POSTFIX_MASTER_CF"
		backup_file "$BACKUP" "$POSTFIX_MASTER_CF"
		_reloadconf=yes
	  sed -i -e '$a\
#imunifyemail_spamfilter BEGIN\
ie-scan      unix  -       -       n       -       -      lmtp\
        -o smtp_send_xforward_command=yes\
        -o disable_mime_output_conversion=yes\
        -o smtp_generic_maps=\
ie-reinject unix  n       -       n       -       -      smtpd\
        -o content_filter=\
        -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_milters\
        -o smtpd_helo_restrictions=\
        -o smtpd_client_restrictions=\
        -o smtpd_sender_restrictions=\
        -o smtpd_relay_restrictions=\
        -o smtpd_recipient_restrictions=permit_mynetworks,reject\
        -o mynetworks=127.0.0.0/8\
        -o smtpd_authorized_xforward_hosts=127.0.0.0/8\
#imunifyemail_spamfilter END' $POSTFIX_MASTER_CF || err 250 "$_name: unexpected error (sed)"

	else
		dprint 1 "$_name: $POSTFIX_MASTER_CF was edited before"
	fi

	if [ "$_reloadconf" = "yes" ] ; then
		dprint 2 "$_name: calling postfix reload"
		if ! $POSTFIX_CHECK_CMD || ! $POSTFIX_RELOAD_CMD ; then
			# XXX how to recover if it fails?
			err 5 "$_name: postfix config reloading failed; please check configs"
		fi
  fi
}

# uncfg_postfix
#	remove the spamfilter declarations from the postfix confs
uncfg_postfix()
{
	_name="uncfg_postfix"
  local _restart="${1:-true}"

	dprint 2 "$_name: analyzing files"
	if [ ! -f "$POSTFIX_MAIN_CF" ] ; then
		err 3 "$_name: $POSTFIX_MAIN_CF: no such file"
	fi
	if [ ! -w "$POSTFIX_MAIN_CF" ] ; then
		err 3 "$_name: $POSTFIX_MAIN_CF: file unwriteable"
	fi
	if [ ! -f "$POSTFIX_MASTER_CF" ] ; then
		err 3 "$_name: $POSTFIX_MASTER_CF: no such file"
	fi
	if [ ! -w "$POSTFIX_MASTER_CF" ] ; then
		err 3 "$_name: $POSTFIX_MASTER_CF: file unwriteable"
	fi
	# postpone exim.conf rebuild until all necessary files will be updated
	_reloadconf=no

	if grep -q '^#imunifyemail_spamfilter.*BEGIN' $POSTFIX_MAIN_CF ; then
		dprint 2 "$_name: editing $POSTFIX_MAIN_CF"
		backup_file "$BACKUP" "$POSTFIX_MAIN_CF"
		# For now, drop everything between the ^imunifyemail_spamfilter
		# and the end of the relevant block.
		# TODO: Would be nice to replace it with /^start/,/^stop/ logic though.
		sed -i '/^#imunifyemail_spamfilter.*BEGIN$/h
			/^#imunifyemail_spamfilter.*END/{h;d}
			/^[[:space:]]*$/!{
				x
				/^#imunifyemail_spamfilter.*BEGIN$/{
					x;d;b
				}
				x
			}' $POSTFIX_MAIN_CF || err 250 "$_name: unexpected error (sed)"

		_reloadconf==yes
	else
		dprint 1 "$_name: $POSTFIX_MAIN_CF is clean"
	fi

	if grep -q '^#imunifyemail_spamfilter.*BEGIN' $POSTFIX_MASTER_CF ; then
		dprint 2 "$_name: editing $POSTFIX_MASTER_CF"
		backup_file "$BACKUP" "$POSTFIX_MASTER_CF"
		# For now, drop everything between the ^imunifyemail_spamfilter
		# and the end of the relevant block.
		# TODO: Would be nice to replace it with /^start/,/^stop/ logic though.
		sed -i '/^#imunifyemail_spamfilter.*BEGIN$/h
			/^#imunifyemail_spamfilter.*END/{h;d}
			/^[[:space:]]*$/!{
				x
				/^#imunifyemail_spamfilter.*BEGIN$/{
					x;d;b
				}
				x
			}' $POSTFIX_MASTER_CF || err 250 "$_name: unexpected error (sed)"

		_reloadconf==yes
	else
		dprint 1 "$_name: $POSTFIX_MASTER_CF is clean"
	fi

	if [ "$_reloadconf" = "yes" ] && [ "$_restart" == true ] ;then
		dprint 2 "$_name: calling postfix reload"
		if ! $POSTFIX_RM_QREQ_CMD ; then
			# XXX how to recover if it fails?
			err 5 "$_name: postfix remove filtering request records cmd failed; please check configs"
		fi
		if ! $POSTFIX_CHECK_CMD || ! $POSTFIX_RELOAD_CMD ; then
			# XXX how to recover if it fails?
			err 5 "$_name: postfix reload failed; please check configs"
		fi
	fi
}

# Postfix conf status
_postfix_status()
{
  _name="postfix_status"

  if [ -r "$POSTFIX_MAIN_CF" ] ; then
    if grep -q '^#imunifyemail_spamfilter.*BEGIN' "$POSTFIX_MAIN_CF" ; then
      echo "enabled"
    else
      echo "disabled"
    fi
  else
    warn "$_name: $POSTFIX_MAIN_CF: unreadable"
  fi
}

# print_status
#	check the imunify email system status
print_status()
{
	_name="print_status"
	dprint 2 "$_name: checking system state"

	echo -n "spamfilter postfix configuration: "
  echo $(_postfix_status)

	for _svc in ie-spamfilter rspamd ie-quarantine ie-dec-node ; do
		echo -n "$_svc state: "
		/bin/systemctl show $_svc --property=ActiveState,SubState \
			| sort \
			| sed '/^ActiveState=/{
				N
				s/^ActiveState=\([^ ]*\)/\1/
				s/\nSubState=\([^ ]*\)$/ (\1)/
			}'
	done

	incoming_state=$(_incoming_filtration_state)
	echo "incoming filtration: ${incoming_state}"
}

# is_on
# check the imunify email system status, exit 0 if IE enabled and 1 in other cases
is_on()
{
  if [ -r "$POSTFIX_MAIN_CF" ] ; then
    if grep -q '^#imunifyemail_spamfilter.*BEGIN' "$POSTFIX_MAIN_CF" ; then
      exit 0
    fi
  else
    warn "is_on: $POSTFIX_MAIN_CF: unreadable"
  fi

  exit 1
}

# postinstall
#	run positinstall checks and fixes
postinstall()
{
  _name="postinstall"

  add_user_in_group _imunify _rspamd

  cfg_ntoken      # DEC security token
  cfg_qtoken      # rspamd security token
  /usr/sbin/ie_ruleupdate
  #get the first line of the output, parse the string after : and remove leading and trailing spaces
  local _status="$(_postfix_status)"
  if [  "$_status" == "enabled" ]; then
    echo "" # need end of line
    echo "Restarting services..."
    svc_ie restart  # restart everything because of the global password changes
    uncfg_postfix false
    cfg_postfix
  fi

  dprint 1 "trigger rules and scores update"
  old_backup_cleanup
}

#
#	Entry point
#

# we don't want the environment to affect the script
export LC_ALL=C
export LC_CTYPE=C
export LANG=""
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export HOME=$(getpwuid_dir $(id -u))

# use global backup archive to save everything
BACKUP=$(date +"$HOME/imunifyemail-backup-%s-$$.tar")
export BACKUP

export DEBUG_LEVEL=0
export REPORT_ERROR=no

while getopts qrv f ; do
	case "$f" in
		q)	;; # OBSOLETE, will be removed in future
		r)	export REPORT_ERROR="yes" ;;
		v)	export DEBUG_LEVEL=2 ;;
		\?)	usage ; exit 0 ;;
	esac
done
shift $(expr $OPTIND - 1)

case "$1" in
install)
	auth_root
	cfg_ntoken
	cfg_qtoken
	svc_ie enable
	svc_ie start
	/usr/sbin/ie_ruleupdate
	;;
enable)
	auth_root
	svc_ie enable
	svc_ie start
	cfg_postfix
	;;
disable)
	auth_root
	uncfg_postfix
	svc_ie stop
	svc_ie disable
	;;
checkperms)
	#TODO
	err 255 'checkperms: not implemented'
	;;
set-qport)
	arg=$2
	auth_root
	cfg_qport "$arg"
	;;
set-qtoken)
	arg=$2
	auth_root
	cfg_qtoken "$arg"
	;;
set-nport)
	arg=$2
	auth_root
	cfg_nport "$arg"
	;;
set-ntoken)
	arg=$2
	auth_root
	cfg_ntoken "$arg"
	;;
set-nsr)
	arg=$2
	auth_root
	cfg_nsr "$arg"
	;;
start)
	auth_root
	svc_ie start
	;;
stop)
	auth_root
	svc_ie stop
	;;
status)
	print_status
	;;
is-on)
  auth_root
  is_on
  ;;
postinstall)
	auth_root
	postinstall
	;;
version)
	print_version
	;;
version-packages)
	print_version packages
	;;
enable-incoming)
	_toggle_incoming_filtration "enabled"
	;;
disable-incoming)
	_toggle_incoming_filtration "disabled"
	;;
*)
	usage
	exit 1
	;;
esac

dprint 2 "finished successfully"
backup_cleanup "$BACKUP"
