#!/bin/sh

po_domain="alterator-postfix-dovecot"
alterator_api_version=1

. alterator-sh-functions
. shell-quote
. shell-config

CONF_PREFIX=/etc/postfix
MYDESTINATION=$CONF_PREFIX/mydestination
MYNETWORKS=$CONF_PREFIX/mynetworks
ACCESS_SUFFIX=_access
ALIASES=$CONF_PREFIX/aliases
TEMPLATES_DIR=/usr/share/alterator-postfix-dovecot
DOVECOT_CONF=/etc/dovecot/dovecot.conf
network_file=/etc/sysconfig/network

### postfix main.cf list attributes like smtpd_client_restrictions
delim1_re='[[:space:]]\+'
delim2_re='[[:space:]]*,[[:space:]]*'
delim_re="\(^\|$delim1_re\|$delim2_re\)"
end_delim_re="\($delim1_re\|$delim2_re\|$\)"
value_re='[^[:space:],]\+'


read_hostname()
{
    local value="$(shell_config_get "$network_file" HOSTNAME)"
    [ -n "$value" ] || value="localhost.localdomain"
    echo "$value"
}

postconf_read()
{
    /usr/sbin/postconf -h "$1"
}

postconf_write()
{
    /usr/sbin/postconf -e "$1=$2"
}

postconf_has()
{
    local name="$(quote_sed_regexp "$2")"
    postconf_read "$1"|
	grep -qs "${delim_re}$name${end_delim_re}"
}

postconf_cons()
{
    printf '%s %s, %s' "$1" "$2" "$3"
}

postconf_skip()
{
    local name="$(quote_sed_regexp "$2")"
    echo "$1" |
	sed -e "s/${delim_re}$name${end_delim_re}/\1/g" \
	    -e 's/^[[:space:]]*,[[:space:]]*//'
}


write_limit_param()
{
    local v="$(postconf_read "$1")"
    write_string_param "$1" "$(($v / 1048576))"
}

read_limit_param()
{
    [ -z "$2" ] || postconf_write  "$1" "$(($2 * 1048576))"
}

auth_check()
{
    echo "$1"|
	grep -qs "${delim_re}permit_sasl_authenticated${end_delim_re}"
}

sasl_server_on()
{
    if rpm -q postfix-dovecot && rpm -q dovecot; then
	postconf_write smtpd_sasl_type dovecot
	postconf_write smtpd_sasl_path private/auth
	/usr/sbin/control dovecot-auth postfix
	daemon_on dovecot
    else
	write_error "`_ "Authentication server (dovecot) is not installed"`"
    fi
}

auth_on()
{
    local v="$(postconf_read smtpd_recipient_restrictions)"

    auth_check "$v" ||
	v="$(echo "$v"|sed "s/permit_mynetworks${end_delim_re}/permit_mynetworks, permit_sasl_authenticated\1/")"

    postconf_write smtpd_recipient_restrictions "$v"
    postconf_write smtpd_sasl_auth_enable yes
}

sasl_server_off()
{
    /usr/sbin/control dovecot-auth none
}

auth_off()
{
    postconf_write smtpd_sasl_auth_enable no
}

auth_secure_on()
{
    local v="$(postconf_read smtpd_sasl_security_options)"

    test -n "$v" || v=noanonymous
    postconf_has smtpd_sasl_security_options noplaintext ||
	v="$(echo "$v"|sed "s/${delim_re}/noplaintext, /")"
    postconf_write smtpd_sasl_security_options "$v"

    postconf_has smtpd_sasl_tls_security_options '$smtpd_sasl_security_options' &&
	postconf_write smtpd_sasl_tls_security_options noanonymous

#    postconf_write smtpd_tls_auth_only yes
}

auth_secure_off()
{
    local v="$(postconf_read smtpd_sasl_security_options)"

    v="$(postconf_skip "$v" noplaintext)"
    postconf_write smtpd_sasl_security_options "$v"

#    postconf_write smtpd_tls_auth_only no
}

control_postfix()
{
    if [ -n "$1" ]; then
	/usr/sbin/control postfix "$1"
    else
	/usr/sbin/control postfix
    fi
}

daemon_status()
{
    test -n "$1" || return
    local IFS=' '
    local runlevel="$(/sbin/runlevel | cut -c3)"

    LANG=C LC_ALL=C /sbin/chkconfig --list "$1"|grep -qs "${runlevel}:on" || return 1
    /sbin/service "$1" status >/dev/null || return 1
}

daemon_on()
{
    test -n "$1" || return
    daemon_status "$1" && return 0

    /sbin/chkconfig "$1" on
    /sbin/service "$1" start >&2 || :
}

daemon_off()
{
    test -n "$1" || return
    /sbin/service "$1" condstop >&2
    /sbin/chkconfig "$1" off
}

daemon_condreload()
{
	test -n "$1" || return
	/sbin/service "$1" condreload
}

postconf_restrict_on()
{
    local args=

    local v="$(postconf_read smtpd_helo_restrictions)"
    postconf_has smtpd_helo_restrictions reject_non_fqdn_hostname ||
	v="$(echo "$v"|sed "s/${delim_re}permit${end_delim_re}/\1reject_non_fqdn_hostname, permit\2/")"
    postconf_has smtpd_helo_restrictions reject_invalid_hostname ||
	v="$(echo "$v"|sed "s/${delim_re}permit${end_delim_re}/\1reject_invalid_hostname, permit\2/")"
    args="$args \"$(quote_shell smtpd_helo_restrictions=$v)\""

    v="$(postconf_read smtpd_client_restrictions)"
    postconf_has smtpd_client_restrictions "reject_rbl_client xbl.spamhaus.org" ||
	v="$(echo "$v"|sed "s/${delim_re}permit${end_delim_re}/\1reject_rbl_client xbl.spamhaus.org, permit\2/")"
    args="$args \"$(quote_shell smtpd_client_restrictions=$v)\""

    v="$(postconf_read smtpd_sender_restrictions)"
    postconf_has smtpd_sender_restrictions reject_non_fqdn_sender ||
	v="$(echo "$v"|sed "s/${delim_re}permit${end_delim_re}/\1reject_non_fqdn_sender, permit\2/")"
    postconf_has smtpd_sender_restrictions reject_unknown_sender_domain ||
	v="$(echo "$v"|sed "s/${delim_re}permit${end_delim_re}/\1reject_unknown_sender_domain, permit\2/")"
    args="$args \"$(quote_shell smtpd_sender_restrictions=$v)\""

    v="$(postconf_read smtpd_recipient_restrictions)"
    postconf_has smtpd_recipient_restrictions reject_non_fqdn_recipient ||
	v="$(echo "$v"|sed "s/${delim_re}reject_unauth_destination${end_delim_re}/\1reject_non_fqdn_recipient, reject_unauth_destination\2/")"
    postconf_has smtpd_recipient_restrictions reject_unknown_recipient_domain ||
	v="$(echo "$v"|sed "s/${delim_re}reject_unauth_destination${end_delim_re}/\1reject_unknown_recipient_domain, reject_unauth_destination\2/")"
    args="$args \"$(quote_shell smtpd_recipient_restrictions=$v)\""

    eval /usr/sbin/postconf -e $args
}

postconf_restrict_off()
{
    local args=

    local v="$(postconf_read smtpd_helo_restrictions)"
    v="$(postconf_skip "$v" reject_non_fqdn_hostname)"
    v="$(postconf_skip "$v" reject_invalid_hostname)"
    args="$args \"$(quote_shell smtpd_helo_restrictions=$v)\""

    v="$(postconf_read smtpd_client_restrictions)"
    v="$(postconf_skip "$v" "reject_rbl_client xbl.spamhaus.org")"
    args="$args \"$(quote_shell smtpd_client_restrictions=$v)\""

    v="$(postconf_read smtpd_sender_restrictions)"
    v="$(postconf_skip "$v" reject_non_fqdn_sender)"
    v="$(postconf_skip "$v" reject_unknown_sender_domain)"
    args="$args \"$(quote_shell smtpd_sender_restrictions=$v)\""

    v="$(postconf_read smtpd_recipient_restrictions)"
    v="$(postconf_skip "$v" reject_non_fqdn_recipient)"
    v="$(postconf_skip "$v" reject_unknown_recipient_domain)"
    args="$args \"$(quote_shell smtpd_recipient_restrictions=$v)\""

    eval /usr/sbin/postconf -e $args
}

postconf_list()
{
    test -n "$1" || return
    sed -e :a \
	-e '$!{N; s/\n[ \t]\+/ /; s/\n#.*$//; s/\n[ \t]*$//; ba}' \
	"$1"
}

list_name()
{
    test -n "$1" || return
    echo "$CONF_PREFIX/$1$ACCESS_SUFFIX"
}

reject_list()
{
    test -n "$1" || return
    postconf_list "$(list_name "$1")" |
	sed -e "/${delim_re}REJECT${end_delim_re}/!d" \
	    -e "s/^\([^[:space:]]\+\).*/\1/"
}

reject_has()
{
    grep -qs "^$2[[:space:]]\+REJECT\b" "$1"
}

reject_add()
{
    test -n "$1" -a -n "$2" || return
    echo -e "$2\tREJECT" >> "$1"
}

reject_clean()
{
    test -n "$1" || return
    sed -i \
	-e '/^#/b' \
	-e '/^[ \t]*$/b' \
	-e "/${delim_re}REJECT${end_delim_re}/d" \
	"$1"
}

dovecot_write()
{
    test -n "$1" -a -n "$2" || return
    if grep -qs "^[[:space:]]*#*[[:space:]]*$1\b" "$DOVECOT_CONF"; then
	sed -i \
	    -e "s/^[[:space:]]*#*[[:space:]]*$1[[:space:]]*=.*/$1 = $2/" \
	    "$DOVECOT_CONF"
    else
	echo "$1 = $2" >> "$DOVECOT_CONF"
    fi
}

dovecot_read()
{
    test -n "$1" || return
    sed -n \
	-e "s/^[[:space:]]*$1[[:space:]]*=[[:space:]]*\([^#]\+\)/\1/p" \
	"$DOVECOT_CONF"
}

rootmail_read()
{
	shell_config_get "$ALIASES" root ':[[:space:]]*' | head -n1
}

rootmail_write()
{
	test -n "$1" || return
	shell_config_set "$ALIASES" root "$1" ':[[:space:]]*' ': '
	/usr/bin/newaliases
}

on_message() {
	set | grep '^in_' >&2
	echo >&2
	case "$in_action" in
		init)
			cp -fR "$TEMPLATES_DIR"/* /etc/
			/etc/hooks/hostname.d/22-postfix "" "$(read_hostname)"
			/etc/hooks/hostname.d/23-dovecot "" "$(read_hostname)"
			daemon_condreload postfix
			daemon_condreload dovecot
			;;
		type)
			write_type_item relayhost		hostname
			write_type_item message_size_limit	postfix-limit
			write_type_item domainlist		hostname-list
#			write_type_item filtered_recipients	hostname-list
			;;
		list)
			case "$in__objects" in
				modes)
					write_enum_item relay "`_ "Relay"`"
					write_enum_item mx "`_ "MX"`"
					;;
			esac
			;;
		read)
			! daemon_status postfix
			write_bool_param postfix_daemon "$?"
			if dovecot_read protocols | grep -qs '\bimap imaps pop3 pop3s\b'; then
			    ! daemon_status dovecot
			    write_bool_param pop3_imap "$?"
			else
			    write_bool_param pop3_imap no
			fi
			if [ -n "$(postconf_read relayhost)" ]; then
				write_string_param mode 'relay'
			else
				write_string_param mode 'mx'
			fi
			write_string_param relayhost "$(postconf_read relayhost)"
			write_string_param domainlist "$(cat "$MYDESTINATION" | tr '\n' ' ')"
			write_string_param rootmail "$(rootmail_read)"
			write_limit_param message_size_limit

			if test "$(postconf_read smtpd_sasl_auth_enable)" = "yes"; then
			    ! daemon_status dovecot
			    write_bool_param auth_state "$?"
			else
			    write_bool_param auth_state no
			fi
			if postconf_has smtpd_sasl_security_options noplaintext ; then
				write_bool_param auth_secure yes
			else
				write_bool_param auth_secure no
			fi

			test "$(control_postfix)" = "filter" && write_bool_param spamfilter 'yes'
			if postconf_has smtpd_client_restrictions reject_rbl_client ; then
				write_bool_param filter_senders yes
			else
				write_bool_param filter_senders no
			fi

			if grep -qs '\bREJECT\b' "$(list_name recipient)"; then
				write_bool_param filter_recipients yes
				write_string_param filtered_recipients "$(reject_list recipient | tr '\n' ' ')"
			else
				write_bool_param filter_recipients no
			fi

			write_string_param mynetworks "$(cat "$MYNETWORKS" | tr '\n' ' ')"
			write_bool_param imap_secure "$(dovecot_read disable_plaintext_auth)"
			;;
		write)
			case "$in_mode" in
				mx)
					postconf_write relayhost ""
					echo -n > "$MYDESTINATION"
					for i in $in_domainlist; do
					     echo "$i" >> "$MYDESTINATION"
					done
					;;
				relay)
					postconf_write relayhost "$in_relayhost"
#					echo -n > "$MYDESTINATION"
					;;
			esac
			rootmail_write "$in_rootmail"
			read_limit_param message_size_limit "$in_message_size_limit"

			if test_bool "$in_auth_state"; then
			    sasl_server_on && auth_on
			else
			    sasl_server_off && auth_off
			fi

			if test_bool "$in_auth_secure"; then
				auth_secure_on
			else
				auth_secure_off
			fi

			if test_bool "$in_filter_senders"; then
				postconf_restrict_on
			else
				postconf_restrict_off
			fi

			if test_bool "$in_filter_recipients"; then
				for i in $in_filtered_recipients; do
				    reject_has "$(list_name recipient)" "$i" ||
					reject_add "$(list_name recipient)" "$i"
				done
			else
				reject_clean "$(list_name recipient)"
			fi

			echo -n > "$MYNETWORKS"
			for i in $in_mynetworks; do
			     echo "$i" >> "$MYNETWORKS"
			done

			if test_bool "$in_imap_secure"; then
				dovecot_write disable_plaintext_auth yes && daemon_condreload dovecot
			else
				dovecot_write disable_plaintext_auth no && daemon_condreload dovecot
			fi

			if test_bool "$in_postfix_daemon"; then
				daemon_on postfix
			else
				daemon_off postfix
			fi

			if test_bool "$in_pop3_imap"; then
				dovecot_write protocols "imap imaps pop3 pop3s"
				daemon_condreload dovecot
				daemon_on dovecot
			else
				dovecot_write protocols "none"
				daemon_condreload dovecot
			fi

			if test_bool "$in_spamfilter"; then
				daemon_on spamd
				if [ "$(control_postfix)" = "filter" ]; then
					daemon_condreload postfix
				else
					control_postfix filter
				fi
			else
				if [ "$(control_postfix)" = "server" ]; then
					daemon_condreload postfix
				else
					control_postfix server
				fi
				daemon_off spamd
			fi
			;;
	esac
}

message_loop
# vim: set ts=4 sts=4 sw=4:
