<commit_before>#!/bin/bash

##########################################################################
# >> DEFAULT VARS
#
# add them here.
# Example: DEFAULT_VARS["KEY"]="VALUE"
##########################################################################
declare -A DEFAULT_VARS
DEFAULT_VARS["ENABLE_CLAMAV"]="${ENABLE_CLAMAV:="0"}"
DEFAULT_VARS["ENABLE_SPAMASSASSIN"]="${ENABLE_SPAMASSASSIN:="0"}"
DEFAULT_VARS["ENABLE_POP3"]="${ENABLE_POP3:="0"}"
DEFAULT_VARS["ENABLE_FAIL2BAN"]="${ENABLE_FAIL2BAN:="0"}"
DEFAULT_VARS["ENABLE_MANAGESIEVE"]="${ENABLE_MANAGESIEVE:="0"}"
DEFAULT_VARS["ENABLE_FETCHMAIL"]="${ENABLE_FETCHMAIL:="0"}"
DEFAULT_VARS["FETCHMAIL_POLL"]="${FETCHMAIL_POLL:="300"}"
DEFAULT_VARS["ENABLE_LDAP"]="${ENABLE_LDAP:="0"}"
DEFAULT_VARS["LDAP_START_TLS"]="${LDAP_START_TLS:="no"}"
DEFAULT_VARS["DOVECOT_TLS"]="${DOVECOT_TLS:="no"}"
DEFAULT_VARS["DOVECOT_MAILBOX_FORMAT"]="${DOVECOT_MAILBOX_FORMAT:="maildir"}"
DEFAULT_VARS["ENABLE_POSTGREY"]="${ENABLE_POSTGREY:="0"}"
DEFAULT_VARS["POSTGREY_DELAY"]="${POSTGREY_DELAY:="300"}"
DEFAULT_VARS["POSTGREY_MAX_AGE"]="${POSTGREY_MAX_AGE:="35"}"
DEFAULT_VARS["POSTGREY_AUTO_WHITELIST_CLIENTS"]="${POSTGREY_AUTO_WHITELIST_CLIENTS:="5"}"
DEFAULT_VARS["POSTGREY_TEXT"]="${POSTGREY_TEXT:="Delayed by postgrey"}"
DEFAULT_VARS["POSTFIX_MESSAGE_SIZE_LIMIT"]="${POSTFIX_MESSAGE_SIZE_LIMIT:="10240000"}"  # ~10 MB by default
DEFAULT_VARS["POSTFIX_MAILBOX_SIZE_LIMIT"]="${POSTFIX_MAILBOX_SIZE_LIMIT:="0"}"        # no limit by default
DEFAULT_VARS["POSTFIX_INET_PROTOCOLS"]="${POSTFIX_INET_PROTOCOLS:="all"}"
DEFAULT_VARS["ENABLE_SASLAUTHD"]="${ENABLE_SASLAUTHD:="0"}"
DEFAULT_VARS["SMTP_ONLY"]="${SMTP_ONLY:="0"}"
DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}"
DEFAULT_VARS["OVERRIDE_HOSTNAME"]="${OVERRIDE_HOSTNAME}"
DEFAULT_VARS["POSTSCREEN_ACTION"]="${POSTSCREEN_ACTION:="enforce"}"
DEFAULT_VARS["SPOOF_PROTECTION"]="${SPOOF_PROTECTION:="0"}"
DEFAULT_VARS["TLS_LEVEL"]="${TLS_LEVEL:="modern"}"
DEFAULT_VARS["ENABLE_SRS"]="${ENABLE_SRS:="0"}"
DEFAULT_VARS["SRS_SENDER_CLASSES"]="${SRS_SENDER_CLASSES:="envelope_sender"}"
DEFAULT_VARS["REPORT_RECIPIENT"]="${REPORT_RECIPIENT:="0"}"
DEFAULT_VARS["LOGROTATE_INTERVAL"]="${LOGROTATE_INTERVAL:=${REPORT_INTERVAL:-"daily"}}"
DEFAULT_VARS["LOGWATCH_INTERVAL"]="${LOGWATCH_INTERVAL:="none"}"
DEFAULT_VARS["SPAMASSASSIN_SPAM_TO_INBOX"]="${SPAMASSASSIN_SPAM_TO_INBOX:="0"}"
DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}"

##########################################################################
# << DEFAULT VARS
##########################################################################

##########################################################################
# >> GLOBAL VARS
#
# add your global script variables here.
#
# Example: KEY="VALUE"
##########################################################################
HOSTNAME="$(hostname -f)"
DOMAINNAME="$(hostname -d)"
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
##########################################################################
# << GLOBAL VARS
##########################################################################


##########################################################################
# >> REGISTER FUNCTIONS
#
# add your new functions/methods here.
#
# NOTE: position matters when registering a function in stacks. First in First out
# 		Execution Logic:
# 			> check functions
# 			> setup functions
# 			> fix functions
# 			> misc functions
# 			> start-daemons
#
# Example:
# if [ CONDITION IS MET ]; then
#   _register_{setup,fix,check,start}_{functions,daemons} "$FUNCNAME"
# fi
#
# Implement them in the section-group: {check,setup,fix,start}
##########################################################################
function register_functions() {
	notify 'taskgrp' 'Initializing setup'
	notify 'task' 'Registering check,setup,fix,misc and start-daemons functions'

	################### >> check funcs

	_register_check_function "_check_environment_variables"
	_register_check_function "_check_hostname"

	################### << check funcs

	################### >> setup funcs

	_register_setup_function "_setup_default_vars"
	_register_setup_function "_setup_file_permissions"

	if [ "$SMTP_ONLY" != 1 ]; then
		_register_setup_function "_setup_dovecot"
                _register_setup_function "_setup_dovecot_dhparam"
		_register_setup_function "_setup_dovecot_quota"
		_register_setup_function "_setup_dovecot_local_user"
	fi

	if [ "$ENABLE_LDAP" = 1 ];then
		_register_setup_function "_setup_ldap"
	fi

	if [ "$ENABLE_SASLAUTHD" = 1 ];then
		_register_setup_function "_setup_saslauthd"
	fi

	if [ "$ENABLE_POSTGREY" = 1 ];then
		_register_setup_function "_setup_postgrey"
	fi

	_register_setup_function "_setup_dkim"
	_register_setup_function "_setup_ssl"
	if [ "$POSTFIX_INET_PROTOCOLS" != "all" ]; then
    _register_setup_function "_setup_inet_protocols"
  fi
	_register_setup_function "_setup_docker_permit"

	_register_setup_function "_setup_mailname"
	_register_setup_function "_setup_amavis"
	_register_setup_function "_setup_dmarc_hostname"
	_register_setup_function "_setup_postfix_hostname"
	_register_setup_function "_setup_dovecot_hostname"

	_register_setup_function "_setup_postfix_smtputf8"
	_register_setup_function "_setup_postfix_sasl"
	_register_setup_function "_setup_postfix_sasl_password"
	_register_setup_function "_setup_security_stack"
	_register_setup_function "_setup_postfix_aliases"
	_register_setup_function "_setup_postfix_vhost"
	_register_setup_function "_setup_postfix_dhparam"
	_register_setup_function "_setup_postfix_postscreen"
	_register_setup_function "_setup_postfix_sizelimits"

  if [ "$SPOOF_PROTECTION" = 1  ]; then
		_register_setup_function "_setup_spoof_protection"
	fi

	if [ "$ENABLE_SRS" = 1 ];  then
		_register_setup_function "_setup_SRS"
		_register_start_daemon "_start_daemons_postsrsd"
	fi

  _register_setup_function "_setup_postfix_access_control"

	if [ ! -z "$AWS_SES_HOST" -a ! -z "$AWS_SES_USERPASS" ]; then
		_register_setup_function "_setup_postfix_relay_hosts"
	fi

	if [ ! -z "$DEFAULT_RELAY_HOST" ]; then
		_register_setup_function "_setup_postfix_default_relay_host"
	fi

	if [ ! -z "$RELAY_HOST" ]; then
		_register_setup_function "_setup_postfix_relay_hosts"
	fi

	if [ "$ENABLE_POSTFIX_VIRTUAL_TRANSPORT" = 1  ]; then
		_register_setup_function "_setup_postfix_virtual_transport"
	fi

	_register_setup_function "_setup_postfix_override_configuration"

  _register_setup_function "_setup_environment"
  _register_setup_function "_setup_logrotate"

	if [ "$PFLOGSUMM_TRIGGER" != "none" ]; then
		_register_setup_function "_setup_mail_summary"
	fi

	if [ "$LOGWATCH_TRIGGER" != "none" ]; then
		_register_setup_function "_setup_logwatch"
	fi

	_register_setup_function "_setup_user_patches"

        # Compute last as the config files are modified in-place
        _register_setup_function "_setup_chksum_file"

	################### << setup funcs

	################### >> fix funcs

	_register_fix_function "_fix_var_mail_permissions"
	_register_fix_function "_fix_var_amavis_permissions"
	if [ "$ENABLE_CLAMAV" = 0 ]; then
        	_register_fix_function "_fix_cleanup_clamav"
	fi
	if [ "$ENABLE_SPAMASSASSIN" = 0 ]; then
		_register_fix_function "_fix_cleanup_spamassassin"
	fi

	################### << fix funcs

	################### >> misc funcs

	_register_misc_function "_misc_save_states"

	################### << misc funcs

	################### >> daemon funcs

	_register_start_daemon "_start_daemons_cron"
	_register_start_daemon "_start_daemons_rsyslog"

	if [ "$SMTP_ONLY" != 1 ]; then
		_register_start_daemon "_start_daemons_dovecot"
	fi

	# needs to be started before saslauthd
	_register_start_daemon "_start_daemons_opendkim"
	_register_start_daemon "_start_daemons_opendmarc"

	#postfix uses postgrey, needs to be started before postfix
	if [ "$ENABLE_POSTGREY" = 1 ]; then
		_register_start_daemon "_start_daemons_postgrey"
	fi

	_register_start_daemon "_start_daemons_postfix"

	if [ "$ENABLE_SASLAUTHD" = 1 ];then
		_register_start_daemon "_start_daemons_saslauthd"
	fi

	# care needs to run after postfix
	if [ "$ENABLE_FAIL2BAN" = 1 ]; then
		_register_start_daemon "_start_daemons_fail2ban"
	fi

	if [ "$ENABLE_FETCHMAIL" = 1 ]; then
		_register_start_daemon "_start_daemons_fetchmail"
	fi

	if [ "$ENABLE_CLAMAV" = 1 ]; then
		_register_start_daemon "_start_daemons_clamav"
	fi
    # Change detector
    if [ "$ENABLE_LDAP" = 0 ]; then
	    _register_start_daemon "_start_changedetector"
    fi

	_register_start_daemon "_start_daemons_amavis"
	################### << daemon funcs
}
##########################################################################
# << REGISTER FUNCTIONS
##########################################################################



# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !  CARE --> DON'T CHANGE, unless you exactly know what you are doing
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# >>


##########################################################################
# >> CONSTANTS
##########################################################################
declare -a FUNCS_SETUP
declare -a FUNCS_FIX
declare -a FUNCS_CHECK
declare -a FUNCS_MISC
declare -a DAEMONS_START
declare -A HELPERS_EXEC_STATE
##########################################################################
# << CONSTANTS
##########################################################################


##########################################################################
# >> protected register_functions
##########################################################################
function _register_start_daemon() {
	DAEMONS_START+=($1)
	notify 'inf' "$1() registered"
}

function _register_setup_function() {
	FUNCS_SETUP+=($1)
	notify 'inf' "$1() registered"
}

function _register_fix_function() {
	FUNCS_FIX+=($1)
	notify 'inf' "$1() registered"
}

function _register_check_function() {
	FUNCS_CHECK+=($1)
	notify 'inf' "$1() registered"
}

function _register_misc_function() {
	FUNCS_MISC+=($1)
	notify 'inf' "$1() registered"
}
##########################################################################
# << protected register_functions
##########################################################################


function notify () {
	c_red="\e[0;31m"
	c_green="\e[0;32m"
	c_brown="\e[0;33m"
	c_blue="\e[0;34m"
	c_bold="\033[1m"
	c_reset="\e[0m"

	notification_type=$1
	notification_msg=$2
	notification_format=$3
	msg=""

	case "${notification_type}" in
		'taskgrp')
			msg="${c_bold}${notification_msg}${c_reset}"
			;;
		'task')
			if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
				msg="  ${notification_msg}${c_reset}"
			fi
			;;
		'inf')
			if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
				msg="${c_green}  * ${notification_msg}${c_reset}"
			fi
			;;
		'started')
			msg="${c_green} ${notification_msg}${c_reset}"
			;;
		'warn')
			msg="${c_brown}  * ${notification_msg}${c_reset}"
			;;
		'err')
			msg="${c_red}  * ${notification_msg}${c_reset}"
			;;
		'fatal')
			msg="${c_red}Error: ${notification_msg}${c_reset}"
			;;
		*)
			msg=""
			;;
	esac

	case "${notification_format}" in
		'n')
			options="-ne"
	  	;;
		*)
  		options="-e"
			;;
	esac

	[[ ! -z "${msg}" ]] && echo $options "${msg}"
}

function defunc() {
	notify 'fatal' "Please fix your configuration. Exiting..."
	exit 1
}

function display_startup_daemon() {
  $1 &>/dev/null
  res=$?
  if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
	  if [ $res = 0 ]; then
			notify 'started' " [ OK ]"
		else
	  	echo "false"
			notify 'err' " [ FAILED ]"
		fi
  fi
	return $res
}

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !  CARE --> DON'T CHANGE, except you know exactly what you are doing
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# <<



##########################################################################
# >> Check Stack
#
# Description: Place functions for initial check of container sanity
##########################################################################
function check() {
	notify 'taskgrp' 'Checking configuration'
	for _func in "${FUNCS_CHECK[@]}";do
		$_func
		[ $? != 0 ] && defunc
	done
}

function _check_hostname() {
	notify "task" "Check that hostname/domainname is provided or overidden (no default docker hostname/kubernetes) [$FUNCNAME]"

	if [[ ! -z ${DEFAULT_VARS["OVERRIDE_HOSTNAME"]} ]]; then
		export HOSTNAME=${DEFAULT_VARS["OVERRIDE_HOSTNAME"]}
		export DOMAINNAME=$(echo $HOSTNAME | sed s/[^.]*.//)
	fi

	notify 'inf' "Domain has been set to $DOMAINNAME"
	notify 'inf' "Hostname has been set to $HOSTNAME"

	if ( ! echo $HOSTNAME | grep -E '^(\S+[.]\S+)$' > /dev/null ); then
		notify 'err' "Setting hostname/domainname is required"
		kill `cat /var/run/supervisord.pid` && return 1
	else
		return 0
	fi
}

function _check_environment_variables() {
	notify "task" "Check that there are no conflicts with env variables [$FUNCNAME]"
	return 0
}
##########################################################################
# << Check Stack
##########################################################################


##########################################################################
# >> Setup Stack
#
# Description: Place functions for functional configurations here
##########################################################################
function setup() {
	notify 'taskgrp' 'Configuring mail server'
	for _func in "${FUNCS_SETUP[@]}";do
		$_func
	done
}

function _setup_default_vars() {
	notify 'task' "Setting up default variables [$FUNCNAME]"

	# update POSTMASTER_ADDRESS - must be done done after _check_hostname()
	DEFAULT_VARS["POSTMASTER_ADDRESS"]="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"

	# update REPORT_SENDER - must be done done after _check_hostname()
	DEFAULT_VARS["REPORT_SENDER"]="${REPORT_SENDER:=mailserver-report@${HOSTNAME}}"
	DEFAULT_VARS["PFLOGSUMM_SENDER"]="${PFLOGSUMM_SENDER:=${REPORT_SENDER}}"

	# set PFLOGSUMM_TRIGGER here for backwards compatibility
	# when REPORT_RECIPIENT is on the old method should be used
	if [ "$REPORT_RECIPIENT" == "0" ]; then
		DEFAULT_VARS["PFLOGSUMM_TRIGGER"]="${PFLOGSUMM_TRIGGER:="none"}"
	else
		DEFAULT_VARS["PFLOGSUMM_TRIGGER"]="${PFLOGSUMM_TRIGGER:="logrotate"}"
	fi

	# Expand address to simplify the rest of the script
	if [ "$REPORT_RECIPIENT" == "0" ] || [ "$REPORT_RECIPIENT" == "1" ]; then
		REPORT_RECIPIENT="$POSTMASTER_ADDRESS"
		DEFAULT_VARS["REPORT_RECIPIENT"]="${REPORT_RECIPIENT}"
	fi
	DEFAULT_VARS["PFLOGSUMM_RECIPIENT"]="${PFLOGSUMM_RECIPIENT:=${REPORT_RECIPIENT}}"
	DEFAULT_VARS["LOGWATCH_RECIPIENT"]="${LOGWATCH_RECIPIENT:=${REPORT_RECIPIENT}}"

	for var in ${!DEFAULT_VARS[@]}; do
		echo "export $var=\"${DEFAULT_VARS[$var]}\"" >> /root/.bashrc
		[ $? != 0 ] && notify 'err' "Unable to set $var=${DEFAULT_VARS[$var]}" && kill -15 `cat /var/run/supervisord.pid` && return 1
		notify 'inf' "Set $var=${DEFAULT_VARS[$var]}"
	done
}

# File/folder permissions are fine when using docker volumes, but may be wrong
# when file system folders are mounted into the container.
# Set the expected values and create missing folders/files just in case.
function _setup_file_permissions() {
	notify 'task' "Setting file/folder permissions"

	mkdir -p /var/log/supervisor

	mkdir -p /var/log/mail
	chown syslog:root /var/log/mail

	touch /var/log/mail/clamav.log
	chown clamav:adm /var/log/mail/clamav.log
	chmod 640 /var/log/mail/clamav.log

	touch /var/log/mail/freshclam.log
	chown clamav:adm /var/log/mail/freshclam.log
	chmod 640 /var/log/mail/freshclam.log
}

function _setup_chksum_file() {
        notify 'task' "Setting up configuration checksum file"


        if [ -d /tmp/docker-mailserver ]; then
          pushd /tmp/docker-mailserver

          declare -a cf_files=()
          for file in postfix-accounts.cf postfix-virtual.cf postfix-aliases.cf dovecot-quotas.cf; do
            [ -f "$file" ] && cf_files+=("$file")
          done

          notify 'inf' "Creating $CHKSUM_FILE"
          sha512sum ${cf_files[@]/#/--tag } >$CHKSUM_FILE

          popd
        else
          # We could just skip the file, but perhaps config can be added later?
          # If so it must be processed by the check for changes script
          notify 'inf' "Creating empty $CHKSUM_FILE (no config)"
          touch $CHKSUM_FILE
        fi
}

function _setup_mailname() {
	notify 'task' 'Setting up Mailname'

	notify 'inf' "Creating /etc/mailname"
	echo $DOMAINNAME > /etc/mailname
}

function _setup_amavis() {
	notify 'task' 'Setting up Amavis'

	notify 'inf' "Applying hostname to /etc/amavis/conf.d/05-node_id"
	sed -i 's/^#\$myhostname = "mail.example.com";/\$myhostname = "'$HOSTNAME'";/' /etc/amavis/conf.d/05-node_id
}

function _setup_dmarc_hostname() {
	notify 'task' 'Setting up dmarc'

	notify 'inf' "Applying hostname to /etc/opendmarc.conf"
	sed -i -e 's/^AuthservID.*$/AuthservID          '$HOSTNAME'/g' \
	       -e 's/^TrustedAuthservIDs.*$/TrustedAuthservIDs  '$HOSTNAME'/g' /etc/opendmarc.conf
}

function _setup_postfix_hostname() {
	notify 'task' 'Applying hostname and domainname to Postfix'

	notify 'inf' "Applying hostname to /etc/postfix/main.cf"
	postconf -e "myhostname = $HOSTNAME"
	postconf -e "mydomain = $DOMAINNAME"
}

function _setup_dovecot_hostname() {
	notify 'task' 'Applying hostname to Dovecot'

	notify 'inf' "Applying hostname to /etc/dovecot/conf.d/15-lda.conf"
	sed -i 's/^#hostname =.*$/hostname = '$HOSTNAME'/g' /etc/dovecot/conf.d/15-lda.conf
}

function _setup_dovecot() {
	notify 'task' 'Setting up Dovecot'

        # Moved from docker file, copy or generate default self-signed cert
        if [ -f /var/mail-state/lib-dovecot/dovecot.pem -a "$ONE_DIR" = 1 ]; then
                notify 'inf' "Copying default dovecot cert"
                cp /var/mail-state/lib-dovecot/dovecot.key /etc/dovecot/ssl/
                cp /var/mail-state/lib-dovecot/dovecot.pem /etc/dovecot/ssl/
        fi
        if [ ! -f /etc/dovecot/ssl/dovecot.pem ]; then
                notify 'inf' "Generating default dovecot cert"
                pushd /usr/share/dovecot
                ./mkcert.sh
                popd

                if [ "$ONE_DIR" = 1 ];then
                        mkdir -p /var/mail-state/lib-dovecot
                        cp /etc/dovecot/ssl/dovecot.key /var/mail-state/lib-dovecot/
                        cp /etc/dovecot/ssl/dovecot.pem /var/mail-state/lib-dovecot/
                fi
        fi

	cp -a /usr/share/dovecot/protocols.d /etc/dovecot/
	# Disable pop3 (it will be eventually enabled later in the script, if requested)
	mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab
	mv /etc/dovecot/protocols.d/managesieved.protocol /etc/dovecot/protocols.d/managesieved.protocol.disab
	sed -i -e 's/#ssl = yes/ssl = yes/g' /etc/dovecot/conf.d/10-master.conf
	sed -i -e 's/#port = 993/port = 993/g' /etc/dovecot/conf.d/10-master.conf
	sed -i -e 's/#port = 995/port = 995/g' /etc/dovecot/conf.d/10-master.conf
	sed -i -e 's/#ssl = yes/ssl = required/g' /etc/dovecot/conf.d/10-ssl.conf
	sed -i 's/^postmaster_address = .*$/postmaster_address = '$POSTMASTER_ADDRESS'/g' /etc/dovecot/conf.d/15-lda.conf

    # Set mail_location according to mailbox format
    case "$DOVECOT_MAILBOX_FORMAT" in
        sdbox|mdbox|maildir )
            notify 'inf' "Dovecot $DOVECOT_MAILBOX_FORMAT format configured"
            sed -i -e 's/^mail_location = .*$/mail_location = '$DOVECOT_MAILBOX_FORMAT':\/var\/mail\/%d\/%n/g' /etc/dovecot/conf.d/10-mail.conf
            ;;
        * )
            notify 'inf' "Dovecot maildir format configured (default)"
            sed -i -e 's/^mail_location = .*$/mail_location = maildir:\/var\/mail\/%d\/%n/g' /etc/dovecot/conf.d/10-mail.conf
            ;;
    esac

	# Enable Managesieve service by setting the symlink
	# to the configuration file Dovecot will actually find
	if [ "$ENABLE_MANAGESIEVE" = 1 ]; then
		notify 'inf' "Sieve management enabled"
		mv /etc/dovecot/protocols.d/managesieved.protocol.disab /etc/dovecot/protocols.d/managesieved.protocol
	fi

	# Copy pipe and filter programs, if any
	rm -f /usr/lib/dovecot/sieve-filter/*
	rm -f /usr/lib/dovecot/sieve-pipe/*
	[ -d /tmp/docker-mailserver/sieve-filter ] && cp /tmp/docker-mailserver/sieve-filter/* /usr/lib/dovecot/sieve-filter/
	[ -d /tmp/docker-mailserver/sieve-pipe ] && cp /tmp/docker-mailserver/sieve-pipe/* /usr/lib/dovecot/sieve-pipe/
	if [ -f /tmp/docker-mailserver/before.dovecot.sieve ]; then
		sed -i "s/#sieve_before =/sieve_before =/" /etc/dovecot/conf.d/90-sieve.conf
		cp /tmp/docker-mailserver/before.dovecot.sieve /usr/lib/dovecot/sieve-global/
		sievec /usr/lib/dovecot/sieve-global/before.dovecot.sieve
	else
		sed -i "s/  sieve_before =/  #sieve_before =/" /etc/dovecot/conf.d/90-sieve.conf
	fi

	if [ -f /tmp/docker-mailserver/after.dovecot.sieve ]; then
		sed -i "s/#sieve_after =/sieve_after =/" /etc/dovecot/conf.d/90-sieve.conf
		cp /tmp/docker-mailserver/after.dovecot.sieve /usr/lib/dovecot/sieve-global/
		sievec /usr/lib/dovecot/sieve-global/after.dovecot.sieve
	else
		sed -i "s/  sieve_after =/  #sieve_after =/" /etc/dovecot/conf.d/90-sieve.conf
	fi
	chown docker:docker -R /usr/lib/dovecot/sieve*
	chmod 550 -R /usr/lib/dovecot/sieve*
	chmod -f +x /usr/lib/dovecot/sieve-pipe/*
}

function _setup_dovecot_quota() {
    notify 'task' 'Setting up Dovecot quota'

    if [ "$ENABLE_LDAP" = 1 ]; then
      notify 'inf' "Dovecot quota is not implemented with LDAP."

      # LDAP => postfix service for dovecot quota not enabled
      sed -i "s/check_policy_service inet:localhost:65265//g" /etc/postfix/main.cf

      if [ -f /etc/dovecot/conf.d/90-quota.conf ]; then
        mv /etc/dovecot/conf.d/90-quota.conf /etc/dovecot/conf.d/90-quota.conf.disab
        sed -i "s/mail_plugins = \$mail_plugins quota/mail_plugins = \$mail_plugins/g" /etc/dovecot/conf.d/10-mail.conf
        sed -i "s/mail_plugins = \$mail_plugins imap_quota/mail_plugins = \$mail_plugins/g" /etc/dovecot/conf.d/20-imap.conf
      fi
    else
      if [ -f /etc/dovecot/conf.d/90-quota.conf.disab ]; then
        mv /etc/dovecot/conf.d/90-quota.conf.disab /etc/dovecot/conf.d/90-quota.conf
        sed -i "s/mail_plugins = \$mail_plugins/mail_plugins = \$mail_plugins quota/g" /etc/dovecot/conf.d/10-mail.conf
        sed -i "s/mail_plugins = \$mail_plugin/mail_plugins = \$mail_plugins imap_quota/g" /etc/dovecot/conf.d/20-imap.conf
      fi

      message_size_limit_mb=$((DEFAULT_VARS["POSTFIX_MESSAGE_SIZE_LIMIT"] / 1000000))
      mailbox_limit_mb=$((DEFAULT_VARS["POSTFIX_MAILBOX_SIZE_LIMIT"] / 1000000))

      sed -i "s/quota_max_mail_size =.*/quota_max_mail_size = ${message_size_limit_mb}$([ "$message_size_limit_mb" == 0 ] && echo "" || echo "M")/g" /etc/dovecot/conf.d/90-quota.conf
      sed -i "s/quota_rule = \*:storage=.*/quota_rule = *:storage=${mailbox_limit_mb}$([ "$mailbox_limit_mb" == 0 ] && echo "" || echo "M")/g" /etc/dovecot/conf.d/90-quota.conf

      if [ ! -f /tmp/docker-mailserver/dovecot-quotas.cf ]; then
        notify 'inf' "'config/docker-mailserver/dovecot-quotas.cf' is not provided. Using default quotas."
		    echo -n >/tmp/docker-mailserver/dovecot-quotas.cf
      fi

      if [ "$SMTP_ONLY" = 1 ]; then
        sed -i "s/check_policy_service inet:localhost:65265//g" /etc/postfix/main.cf
      else
        sed -i "s/reject_unknown_recipient_domain, reject_rbl_client zen.spamhaus.org/reject_unknown_recipient_domain, check_policy_service inet:localhost:65265, reject_rbl_client zen.spamhaus.org/g" /etc/postfix/main.cf
      fi
    fi
}

function _setup_dovecot_local_user() {
	notify 'task' 'Setting up Dovecot Local User'
	echo -n > /etc/postfix/vmailbox
	echo -n > /etc/dovecot/userdb
	if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then
		notify 'inf' "Checking file line endings"
		sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
		notify 'inf' "Regenerating postfix user list"
		echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox<commit_msg>remove start-mailserver nested conditions dovecot quota <commit_after>#!/bin/bash

##########################################################################
# >> DEFAULT VARS
#
# add them here.
# Example: DEFAULT_VARS["KEY"]="VALUE"
##########################################################################
declare -A DEFAULT_VARS
DEFAULT_VARS["ENABLE_CLAMAV"]="${ENABLE_CLAMAV:="0"}"
DEFAULT_VARS["ENABLE_SPAMASSASSIN"]="${ENABLE_SPAMASSASSIN:="0"}"
DEFAULT_VARS["ENABLE_POP3"]="${ENABLE_POP3:="0"}"
DEFAULT_VARS["ENABLE_FAIL2BAN"]="${ENABLE_FAIL2BAN:="0"}"
DEFAULT_VARS["ENABLE_MANAGESIEVE"]="${ENABLE_MANAGESIEVE:="0"}"
DEFAULT_VARS["ENABLE_FETCHMAIL"]="${ENABLE_FETCHMAIL:="0"}"
DEFAULT_VARS["FETCHMAIL_POLL"]="${FETCHMAIL_POLL:="300"}"
DEFAULT_VARS["ENABLE_LDAP"]="${ENABLE_LDAP:="0"}"
DEFAULT_VARS["LDAP_START_TLS"]="${LDAP_START_TLS:="no"}"
DEFAULT_VARS["DOVECOT_TLS"]="${DOVECOT_TLS:="no"}"
DEFAULT_VARS["DOVECOT_MAILBOX_FORMAT"]="${DOVECOT_MAILBOX_FORMAT:="maildir"}"
DEFAULT_VARS["ENABLE_POSTGREY"]="${ENABLE_POSTGREY:="0"}"
DEFAULT_VARS["POSTGREY_DELAY"]="${POSTGREY_DELAY:="300"}"
DEFAULT_VARS["POSTGREY_MAX_AGE"]="${POSTGREY_MAX_AGE:="35"}"
DEFAULT_VARS["POSTGREY_AUTO_WHITELIST_CLIENTS"]="${POSTGREY_AUTO_WHITELIST_CLIENTS:="5"}"
DEFAULT_VARS["POSTGREY_TEXT"]="${POSTGREY_TEXT:="Delayed by postgrey"}"
DEFAULT_VARS["POSTFIX_MESSAGE_SIZE_LIMIT"]="${POSTFIX_MESSAGE_SIZE_LIMIT:="10240000"}"  # ~10 MB by default
DEFAULT_VARS["POSTFIX_MAILBOX_SIZE_LIMIT"]="${POSTFIX_MAILBOX_SIZE_LIMIT:="0"}"        # no limit by default
DEFAULT_VARS["POSTFIX_INET_PROTOCOLS"]="${POSTFIX_INET_PROTOCOLS:="all"}"
DEFAULT_VARS["ENABLE_SASLAUTHD"]="${ENABLE_SASLAUTHD:="0"}"
DEFAULT_VARS["SMTP_ONLY"]="${SMTP_ONLY:="0"}"
DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}"
DEFAULT_VARS["OVERRIDE_HOSTNAME"]="${OVERRIDE_HOSTNAME}"
DEFAULT_VARS["POSTSCREEN_ACTION"]="${POSTSCREEN_ACTION:="enforce"}"
DEFAULT_VARS["SPOOF_PROTECTION"]="${SPOOF_PROTECTION:="0"}"
DEFAULT_VARS["TLS_LEVEL"]="${TLS_LEVEL:="modern"}"
DEFAULT_VARS["ENABLE_SRS"]="${ENABLE_SRS:="0"}"
DEFAULT_VARS["SRS_SENDER_CLASSES"]="${SRS_SENDER_CLASSES:="envelope_sender"}"
DEFAULT_VARS["REPORT_RECIPIENT"]="${REPORT_RECIPIENT:="0"}"
DEFAULT_VARS["LOGROTATE_INTERVAL"]="${LOGROTATE_INTERVAL:=${REPORT_INTERVAL:-"daily"}}"
DEFAULT_VARS["LOGWATCH_INTERVAL"]="${LOGWATCH_INTERVAL:="none"}"
DEFAULT_VARS["SPAMASSASSIN_SPAM_TO_INBOX"]="${SPAMASSASSIN_SPAM_TO_INBOX:="0"}"
DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}"

##########################################################################
# << DEFAULT VARS
##########################################################################

##########################################################################
# >> GLOBAL VARS
#
# add your global script variables here.
#
# Example: KEY="VALUE"
##########################################################################
HOSTNAME="$(hostname -f)"
DOMAINNAME="$(hostname -d)"
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
##########################################################################
# << GLOBAL VARS
##########################################################################


##########################################################################
# >> REGISTER FUNCTIONS
#
# add your new functions/methods here.
#
# NOTE: position matters when registering a function in stacks. First in First out
# 		Execution Logic:
# 			> check functions
# 			> setup functions
# 			> fix functions
# 			> misc functions
# 			> start-daemons
#
# Example:
# if [ CONDITION IS MET ]; then
#   _register_{setup,fix,check,start}_{functions,daemons} "$FUNCNAME"
# fi
#
# Implement them in the section-group: {check,setup,fix,start}
##########################################################################
function register_functions() {
	notify 'taskgrp' 'Initializing setup'
	notify 'task' 'Registering check,setup,fix,misc and start-daemons functions'

	################### >> check funcs

	_register_check_function "_check_environment_variables"
	_register_check_function "_check_hostname"

	################### << check funcs

	################### >> setup funcs

	_register_setup_function "_setup_default_vars"
	_register_setup_function "_setup_file_permissions"

	if [ "$SMTP_ONLY" != 1 ]; then
		_register_setup_function "_setup_dovecot"
                _register_setup_function "_setup_dovecot_dhparam"
		_register_setup_function "_setup_dovecot_quota"
		_register_setup_function "_setup_dovecot_local_user"
	fi

	if [ "$ENABLE_LDAP" = 1 ];then
		_register_setup_function "_setup_ldap"
	fi

	if [ "$ENABLE_SASLAUTHD" = 1 ];then
		_register_setup_function "_setup_saslauthd"
	fi

	if [ "$ENABLE_POSTGREY" = 1 ];then
		_register_setup_function "_setup_postgrey"
	fi

	_register_setup_function "_setup_dkim"
	_register_setup_function "_setup_ssl"
	if [ "$POSTFIX_INET_PROTOCOLS" != "all" ]; then
    _register_setup_function "_setup_inet_protocols"
  fi
	_register_setup_function "_setup_docker_permit"

	_register_setup_function "_setup_mailname"
	_register_setup_function "_setup_amavis"
	_register_setup_function "_setup_dmarc_hostname"
	_register_setup_function "_setup_postfix_hostname"
	_register_setup_function "_setup_dovecot_hostname"

	_register_setup_function "_setup_postfix_smtputf8"
	_register_setup_function "_setup_postfix_sasl"
	_register_setup_function "_setup_postfix_sasl_password"
	_register_setup_function "_setup_security_stack"
	_register_setup_function "_setup_postfix_aliases"
	_register_setup_function "_setup_postfix_vhost"
	_register_setup_function "_setup_postfix_dhparam"
	_register_setup_function "_setup_postfix_postscreen"
	_register_setup_function "_setup_postfix_sizelimits"

  if [ "$SPOOF_PROTECTION" = 1  ]; then
		_register_setup_function "_setup_spoof_protection"
	fi

	if [ "$ENABLE_SRS" = 1 ];  then
		_register_setup_function "_setup_SRS"
		_register_start_daemon "_start_daemons_postsrsd"
	fi

  _register_setup_function "_setup_postfix_access_control"

	if [ ! -z "$AWS_SES_HOST" -a ! -z "$AWS_SES_USERPASS" ]; then
		_register_setup_function "_setup_postfix_relay_hosts"
	fi

	if [ ! -z "$DEFAULT_RELAY_HOST" ]; then
		_register_setup_function "_setup_postfix_default_relay_host"
	fi

	if [ ! -z "$RELAY_HOST" ]; then
		_register_setup_function "_setup_postfix_relay_hosts"
	fi

	if [ "$ENABLE_POSTFIX_VIRTUAL_TRANSPORT" = 1  ]; then
		_register_setup_function "_setup_postfix_virtual_transport"
	fi

	_register_setup_function "_setup_postfix_override_configuration"

  _register_setup_function "_setup_environment"
  _register_setup_function "_setup_logrotate"

	if [ "$PFLOGSUMM_TRIGGER" != "none" ]; then
		_register_setup_function "_setup_mail_summary"
	fi

	if [ "$LOGWATCH_TRIGGER" != "none" ]; then
		_register_setup_function "_setup_logwatch"
	fi

	_register_setup_function "_setup_user_patches"

        # Compute last as the config files are modified in-place
        _register_setup_function "_setup_chksum_file"

	################### << setup funcs

	################### >> fix funcs

	_register_fix_function "_fix_var_mail_permissions"
	_register_fix_function "_fix_var_amavis_permissions"
	if [ "$ENABLE_CLAMAV" = 0 ]; then
        	_register_fix_function "_fix_cleanup_clamav"
	fi
	if [ "$ENABLE_SPAMASSASSIN" = 0 ]; then
		_register_fix_function "_fix_cleanup_spamassassin"
	fi

	################### << fix funcs

	################### >> misc funcs

	_register_misc_function "_misc_save_states"

	################### << misc funcs

	################### >> daemon funcs

	_register_start_daemon "_start_daemons_cron"
	_register_start_daemon "_start_daemons_rsyslog"

	if [ "$SMTP_ONLY" != 1 ]; then
		_register_start_daemon "_start_daemons_dovecot"
	fi

	# needs to be started before saslauthd
	_register_start_daemon "_start_daemons_opendkim"
	_register_start_daemon "_start_daemons_opendmarc"

	#postfix uses postgrey, needs to be started before postfix
	if [ "$ENABLE_POSTGREY" = 1 ]; then
		_register_start_daemon "_start_daemons_postgrey"
	fi

	_register_start_daemon "_start_daemons_postfix"

	if [ "$ENABLE_SASLAUTHD" = 1 ];then
		_register_start_daemon "_start_daemons_saslauthd"
	fi

	# care needs to run after postfix
	if [ "$ENABLE_FAIL2BAN" = 1 ]; then
		_register_start_daemon "_start_daemons_fail2ban"
	fi

	if [ "$ENABLE_FETCHMAIL" = 1 ]; then
		_register_start_daemon "_start_daemons_fetchmail"
	fi

	if [ "$ENABLE_CLAMAV" = 1 ]; then
		_register_start_daemon "_start_daemons_clamav"
	fi
    # Change detector
    if [ "$ENABLE_LDAP" = 0 ]; then
	    _register_start_daemon "_start_changedetector"
    fi

	_register_start_daemon "_start_daemons_amavis"
	################### << daemon funcs
}
##########################################################################
# << REGISTER FUNCTIONS
##########################################################################



# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !  CARE --> DON'T CHANGE, unless you exactly know what you are doing
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# >>


##########################################################################
# >> CONSTANTS
##########################################################################
declare -a FUNCS_SETUP
declare -a FUNCS_FIX
declare -a FUNCS_CHECK
declare -a FUNCS_MISC
declare -a DAEMONS_START
declare -A HELPERS_EXEC_STATE
##########################################################################
# << CONSTANTS
##########################################################################


##########################################################################
# >> protected register_functions
##########################################################################
function _register_start_daemon() {
	DAEMONS_START+=($1)
	notify 'inf' "$1() registered"
}

function _register_setup_function() {
	FUNCS_SETUP+=($1)
	notify 'inf' "$1() registered"
}

function _register_fix_function() {
	FUNCS_FIX+=($1)
	notify 'inf' "$1() registered"
}

function _register_check_function() {
	FUNCS_CHECK+=($1)
	notify 'inf' "$1() registered"
}

function _register_misc_function() {
	FUNCS_MISC+=($1)
	notify 'inf' "$1() registered"
}
##########################################################################
# << protected register_functions
##########################################################################


function notify () {
	c_red="\e[0;31m"
	c_green="\e[0;32m"
	c_brown="\e[0;33m"
	c_blue="\e[0;34m"
	c_bold="\033[1m"
	c_reset="\e[0m"

	notification_type=$1
	notification_msg=$2
	notification_format=$3
	msg=""

	case "${notification_type}" in
		'taskgrp')
			msg="${c_bold}${notification_msg}${c_reset}"
			;;
		'task')
			if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
				msg="  ${notification_msg}${c_reset}"
			fi
			;;
		'inf')
			if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
				msg="${c_green}  * ${notification_msg}${c_reset}"
			fi
			;;
		'started')
			msg="${c_green} ${notification_msg}${c_reset}"
			;;
		'warn')
			msg="${c_brown}  * ${notification_msg}${c_reset}"
			;;
		'err')
			msg="${c_red}  * ${notification_msg}${c_reset}"
			;;
		'fatal')
			msg="${c_red}Error: ${notification_msg}${c_reset}"
			;;
		*)
			msg=""
			;;
	esac

	case "${notification_format}" in
		'n')
			options="-ne"
	  	;;
		*)
  		options="-e"
			;;
	esac

	[[ ! -z "${msg}" ]] && echo $options "${msg}"
}

function defunc() {
	notify 'fatal' "Please fix your configuration. Exiting..."
	exit 1
}

function display_startup_daemon() {
  $1 &>/dev/null
  res=$?
  if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
	  if [ $res = 0 ]; then
			notify 'started' " [ OK ]"
		else
	  	echo "false"
			notify 'err' " [ FAILED ]"
		fi
  fi
	return $res
}

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !  CARE --> DON'T CHANGE, except you know exactly what you are doing
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# <<



##########################################################################
# >> Check Stack
#
# Description: Place functions for initial check of container sanity
##########################################################################
function check() {
	notify 'taskgrp' 'Checking configuration'
	for _func in "${FUNCS_CHECK[@]}";do
		$_func
		[ $? != 0 ] && defunc
	done
}

function _check_hostname() {
	notify "task" "Check that hostname/domainname is provided or overidden (no default docker hostname/kubernetes) [$FUNCNAME]"

	if [[ ! -z ${DEFAULT_VARS["OVERRIDE_HOSTNAME"]} ]]; then
		export HOSTNAME=${DEFAULT_VARS["OVERRIDE_HOSTNAME"]}
		export DOMAINNAME=$(echo $HOSTNAME | sed s/[^.]*.//)
	fi

	notify 'inf' "Domain has been set to $DOMAINNAME"
	notify 'inf' "Hostname has been set to $HOSTNAME"

	if ( ! echo $HOSTNAME | grep -E '^(\S+[.]\S+)$' > /dev/null ); then
		notify 'err' "Setting hostname/domainname is required"
		kill `cat /var/run/supervisord.pid` && return 1
	else
		return 0
	fi
}

function _check_environment_variables() {
	notify "task" "Check that there are no conflicts with env variables [$FUNCNAME]"
	return 0
}
##########################################################################
# << Check Stack
##########################################################################


##########################################################################
# >> Setup Stack
#
# Description: Place functions for functional configurations here
##########################################################################
function setup() {
	notify 'taskgrp' 'Configuring mail server'
	for _func in "${FUNCS_SETUP[@]}";do
		$_func
	done
}

function _setup_default_vars() {
	notify 'task' "Setting up default variables [$FUNCNAME]"

	# update POSTMASTER_ADDRESS - must be done done after _check_hostname()
	DEFAULT_VARS["POSTMASTER_ADDRESS"]="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"

	# update REPORT_SENDER - must be done done after _check_hostname()
	DEFAULT_VARS["REPORT_SENDER"]="${REPORT_SENDER:=mailserver-report@${HOSTNAME}}"
	DEFAULT_VARS["PFLOGSUMM_SENDER"]="${PFLOGSUMM_SENDER:=${REPORT_SENDER}}"

	# set PFLOGSUMM_TRIGGER here for backwards compatibility
	# when REPORT_RECIPIENT is on the old method should be used
	if [ "$REPORT_RECIPIENT" == "0" ]; then
		DEFAULT_VARS["PFLOGSUMM_TRIGGER"]="${PFLOGSUMM_TRIGGER:="none"}"
	else
		DEFAULT_VARS["PFLOGSUMM_TRIGGER"]="${PFLOGSUMM_TRIGGER:="logrotate"}"
	fi

	# Expand address to simplify the rest of the script
	if [ "$REPORT_RECIPIENT" == "0" ] || [ "$REPORT_RECIPIENT" == "1" ]; then
		REPORT_RECIPIENT="$POSTMASTER_ADDRESS"
		DEFAULT_VARS["REPORT_RECIPIENT"]="${REPORT_RECIPIENT}"
	fi
	DEFAULT_VARS["PFLOGSUMM_RECIPIENT"]="${PFLOGSUMM_RECIPIENT:=${REPORT_RECIPIENT}}"
	DEFAULT_VARS["LOGWATCH_RECIPIENT"]="${LOGWATCH_RECIPIENT:=${REPORT_RECIPIENT}}"

	for var in ${!DEFAULT_VARS[@]}; do
		echo "export $var=\"${DEFAULT_VARS[$var]}\"" >> /root/.bashrc
		[ $? != 0 ] && notify 'err' "Unable to set $var=${DEFAULT_VARS[$var]}" && kill -15 `cat /var/run/supervisord.pid` && return 1
		notify 'inf' "Set $var=${DEFAULT_VARS[$var]}"
	done
}

# File/folder permissions are fine when using docker volumes, but may be wrong
# when file system folders are mounted into the container.
# Set the expected values and create missing folders/files just in case.
function _setup_file_permissions() {
	notify 'task' "Setting file/folder permissions"

	mkdir -p /var/log/supervisor

	mkdir -p /var/log/mail
	chown syslog:root /var/log/mail

	touch /var/log/mail/clamav.log
	chown clamav:adm /var/log/mail/clamav.log
	chmod 640 /var/log/mail/clamav.log

	touch /var/log/mail/freshclam.log
	chown clamav:adm /var/log/mail/freshclam.log
	chmod 640 /var/log/mail/freshclam.log
}

function _setup_chksum_file() {
        notify 'task' "Setting up configuration checksum file"


        if [ -d /tmp/docker-mailserver ]; then
          pushd /tmp/docker-mailserver

          declare -a cf_files=()
          for file in postfix-accounts.cf postfix-virtual.cf postfix-aliases.cf dovecot-quotas.cf; do
            [ -f "$file" ] && cf_files+=("$file")
          done

          notify 'inf' "Creating $CHKSUM_FILE"
          sha512sum ${cf_files[@]/#/--tag } >$CHKSUM_FILE

          popd
        else
          # We could just skip the file, but perhaps config can be added later?
          # If so it must be processed by the check for changes script
          notify 'inf' "Creating empty $CHKSUM_FILE (no config)"
          touch $CHKSUM_FILE
        fi
}

function _setup_mailname() {
	notify 'task' 'Setting up Mailname'

	notify 'inf' "Creating /etc/mailname"
	echo $DOMAINNAME > /etc/mailname
}

function _setup_amavis() {
	notify 'task' 'Setting up Amavis'

	notify 'inf' "Applying hostname to /etc/amavis/conf.d/05-node_id"
	sed -i 's/^#\$myhostname = "mail.example.com";/\$myhostname = "'$HOSTNAME'";/' /etc/amavis/conf.d/05-node_id
}

function _setup_dmarc_hostname() {
	notify 'task' 'Setting up dmarc'

	notify 'inf' "Applying hostname to /etc/opendmarc.conf"
	sed -i -e 's/^AuthservID.*$/AuthservID          '$HOSTNAME'/g' \
	       -e 's/^TrustedAuthservIDs.*$/TrustedAuthservIDs  '$HOSTNAME'/g' /etc/opendmarc.conf
}

function _setup_postfix_hostname() {
	notify 'task' 'Applying hostname and domainname to Postfix'

	notify 'inf' "Applying hostname to /etc/postfix/main.cf"
	postconf -e "myhostname = $HOSTNAME"
	postconf -e "mydomain = $DOMAINNAME"
}

function _setup_dovecot_hostname() {
	notify 'task' 'Applying hostname to Dovecot'

	notify 'inf' "Applying hostname to /etc/dovecot/conf.d/15-lda.conf"
	sed -i 's/^#hostname =.*$/hostname = '$HOSTNAME'/g' /etc/dovecot/conf.d/15-lda.conf
}

function _setup_dovecot() {
	notify 'task' 'Setting up Dovecot'

        # Moved from docker file, copy or generate default self-signed cert
        if [ -f /var/mail-state/lib-dovecot/dovecot.pem -a "$ONE_DIR" = 1 ]; then
                notify 'inf' "Copying default dovecot cert"
                cp /var/mail-state/lib-dovecot/dovecot.key /etc/dovecot/ssl/
                cp /var/mail-state/lib-dovecot/dovecot.pem /etc/dovecot/ssl/
        fi
        if [ ! -f /etc/dovecot/ssl/dovecot.pem ]; then
                notify 'inf' "Generating default dovecot cert"
                pushd /usr/share/dovecot
                ./mkcert.sh
                popd

                if [ "$ONE_DIR" = 1 ];then
                        mkdir -p /var/mail-state/lib-dovecot
                        cp /etc/dovecot/ssl/dovecot.key /var/mail-state/lib-dovecot/
                        cp /etc/dovecot/ssl/dovecot.pem /var/mail-state/lib-dovecot/
                fi
        fi

	cp -a /usr/share/dovecot/protocols.d /etc/dovecot/
	# Disable pop3 (it will be eventually enabled later in the script, if requested)
	mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab
	mv /etc/dovecot/protocols.d/managesieved.protocol /etc/dovecot/protocols.d/managesieved.protocol.disab
	sed -i -e 's/#ssl = yes/ssl = yes/g' /etc/dovecot/conf.d/10-master.conf
	sed -i -e 's/#port = 993/port = 993/g' /etc/dovecot/conf.d/10-master.conf
	sed -i -e 's/#port = 995/port = 995/g' /etc/dovecot/conf.d/10-master.conf
	sed -i -e 's/#ssl = yes/ssl = required/g' /etc/dovecot/conf.d/10-ssl.conf
	sed -i 's/^postmaster_address = .*$/postmaster_address = '$POSTMASTER_ADDRESS'/g' /etc/dovecot/conf.d/15-lda.conf

    # Set mail_location according to mailbox format
    case "$DOVECOT_MAILBOX_FORMAT" in
        sdbox|mdbox|maildir )
            notify 'inf' "Dovecot $DOVECOT_MAILBOX_FORMAT format configured"
            sed -i -e 's/^mail_location = .*$/mail_location = '$DOVECOT_MAILBOX_FORMAT':\/var\/mail\/%d\/%n/g' /etc/dovecot/conf.d/10-mail.conf
            ;;
        * )
            notify 'inf' "Dovecot maildir format configured (default)"
            sed -i -e 's/^mail_location = .*$/mail_location = maildir:\/var\/mail\/%d\/%n/g' /etc/dovecot/conf.d/10-mail.conf
            ;;
    esac

	# Enable Managesieve service by setting the symlink
	# to the configuration file Dovecot will actually find
	if [ "$ENABLE_MANAGESIEVE" = 1 ]; then
		notify 'inf' "Sieve management enabled"
		mv /etc/dovecot/protocols.d/managesieved.protocol.disab /etc/dovecot/protocols.d/managesieved.protocol
	fi

	# Copy pipe and filter programs, if any
	rm -f /usr/lib/dovecot/sieve-filter/*
	rm -f /usr/lib/dovecot/sieve-pipe/*
	[ -d /tmp/docker-mailserver/sieve-filter ] && cp /tmp/docker-mailserver/sieve-filter/* /usr/lib/dovecot/sieve-filter/
	[ -d /tmp/docker-mailserver/sieve-pipe ] && cp /tmp/docker-mailserver/sieve-pipe/* /usr/lib/dovecot/sieve-pipe/
	if [ -f /tmp/docker-mailserver/before.dovecot.sieve ]; then
		sed -i "s/#sieve_before =/sieve_before =/" /etc/dovecot/conf.d/90-sieve.conf
		cp /tmp/docker-mailserver/before.dovecot.sieve /usr/lib/dovecot/sieve-global/
		sievec /usr/lib/dovecot/sieve-global/before.dovecot.sieve
	else
		sed -i "s/  sieve_before =/  #sieve_before =/" /etc/dovecot/conf.d/90-sieve.conf
	fi

	if [ -f /tmp/docker-mailserver/after.dovecot.sieve ]; then
		sed -i "s/#sieve_after =/sieve_after =/" /etc/dovecot/conf.d/90-sieve.conf
		cp /tmp/docker-mailserver/after.dovecot.sieve /usr/lib/dovecot/sieve-global/
		sievec /usr/lib/dovecot/sieve-global/after.dovecot.sieve
	else
		sed -i "s/  sieve_after =/  #sieve_after =/" /etc/dovecot/conf.d/90-sieve.conf
	fi
	chown docker:docker -R /usr/lib/dovecot/sieve*
	chmod 550 -R /usr/lib/dovecot/sieve*
	chmod -f +x /usr/lib/dovecot/sieve-pipe/*
}

function _setup_dovecot_quota() {
    notify 'task' 'Setting up Dovecot quota'

    if [ "$ENABLE_LDAP" = 1 ] || [ "$SMTP_ONLY" = 1 ]; then
      # Dovecot quota is disabled when using LDAP or SMTP_ONLY

      # disable dovecot quota in docevot confs
      if [ -f /etc/dovecot/conf.d/90-quota.conf ]; then
        mv /etc/dovecot/conf.d/90-quota.conf /etc/dovecot/conf.d/90-quota.conf.disab
        sed -i "s/mail_plugins = \$mail_plugins quota/mail_plugins = \$mail_plugins/g" /etc/dovecot/conf.d/10-mail.conf
        sed -i "s/mail_plugins = \$mail_plugins imap_quota/mail_plugins = \$mail_plugins/g" /etc/dovecot/conf.d/20-imap.conf
      fi

      # disable quota policy check in postfix
      sed -i "s/check_policy_service inet:localhost:65265//g" /etc/postfix/main.cf
    else
      if [ -f /etc/dovecot/conf.d/90-quota.conf.disab ]; then
        mv /etc/dovecot/conf.d/90-quota.conf.disab /etc/dovecot/conf.d/90-quota.conf
        sed -i "s/mail_plugins = \$mail_plugins/mail_plugins = \$mail_plugins quota/g" /etc/dovecot/conf.d/10-mail.conf
        sed -i "s/mail_plugins = \$mail_plugin/mail_plugins = \$mail_plugins imap_quota/g" /etc/dovecot/conf.d/20-imap.conf
      fi

      message_size_limit_mb=$((DEFAULT_VARS["POSTFIX_MESSAGE_SIZE_LIMIT"] / 1000000))
      mailbox_limit_mb=$((DEFAULT_VARS["POSTFIX_MAILBOX_SIZE_LIMIT"] / 1000000))

      sed -i "s/quota_max_mail_size =.*/quota_max_mail_size = ${message_size_limit_mb}$([ "$message_size_limit_mb" == 0 ] && echo "" || echo "M")/g" /etc/dovecot/conf.d/90-quota.conf
      sed -i "s/quota_rule = \*:storage=.*/quota_rule = *:storage=${mailbox_limit_mb}$([ "$mailbox_limit_mb" == 0 ] && echo "" || echo "M")/g" /etc/dovecot/conf.d/90-quota.conf

      if [ ! -f /tmp/docker-mailserver/dovecot-quotas.cf ]; then
        notify 'inf' "'config/docker-mailserver/dovecot-quotas.cf' is not provided. Using default quotas."
		    echo -n >/tmp/docker-mailserver/dovecot-quotas.cf
      fi

      # enable quota policy check in postfix
      sed -i "s/reject_unknown_recipient_domain, reject_rbl_client zen.spamhaus.org/reject_unknown_recipient_domain, check_policy_service inet:localhost:65265, reject_rbl_client zen.spamhaus.org/g" /etc/postfix/main.cf
    fi
}

function _setup_dovecot_local_user() {
	notify 'task' 'Setting up Dovecot Local User'
	echo -n > /etc/postfix/vmailbox
	echo -n > /etc/dovecot/userdb
	if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then
		notify 'inf' "Checking file line endings"
		sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
		notify 'inf' "Regenerating postfix user list"
		echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox
{'fraction_non_alphanumeric': 0.2251324064879179, 'fraction_numerical': 0.009165011585567692, 'mean_word_length': 4.817426886508605, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 90, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2854494', 'n_tokens_mistral': 18001, 'n_tokens_neox': 16720, 'n_words': 3068}