#!/bin/sh

## This script makes sure that CourierIMAP actually
# uses authpsa module.

COURIERIMAP_CONFDIR="/etc/courier-imap";

die()
{
        echo "$@" >&2
        exit 1
}

trap_handler()
{
	trap - EXIT
	rm -f -- "$1"
	exit
}

# The marks should not contain any "suspicious symbols" like quotes or ticks
CHANGE_MARK='# *** AUTHMODULES changed by Parallels Plesk ***'
ADD_MARK='# *** AUTHMODULES added by Parallels Plesk ***'

add_authpsa()
{
        local conf temp
        conf=$1
        temp=$2
        local change_mark add_mark

        awk -v change_mark="$CHANGE_MARK" -v add_mark="$ADD_MARK" '\
BEGIN { found=0; changed=0; }
{
        str=$0;
        if (sub(/^[[:space:]]*AUTHMODULES[[:space:]]*=[[:space:]]*"?[[:space:]]*/, "", str)) {
		if (found) {
			# Whee, duplicated AUTHMODULES! Comment out this entry!
			print "# *** Duplicated AUTHMODULES commented out by Parallels Plesk ***"
			print "### " $0;
			print "Duplicated AUTHMODULES entry" > "/dev/stderr"
			changed=110;
			next;
		}
		found=1; # Got AUTHMODULES
		sub(/#.*$/, "", str);
                sub(/[[:space:]]*"?[[:space:]]*$/, "", str);
		split(str, modules, /[[:space:]]+/);
		had_authpsa=0;
		for(mod in modules) {
			if (modules[mod] == "authpsa") {
				had_authpsa=1;
				break;
			}
		}
		if (had_authpsa) {
			print $0;
		} else {
			if (length(str)) {
                                print
				print change_mark;
				print "### " $0;
			}
			print "AUTHMODULES=\"authpsa\""
			print "AUTHMODULES entry was changed" > "/dev/stderr"
			changed=110;
		}
        } else {
                print $0;
        }
}
END {
        if (!found) {
                print
		print add_mark;
                print "AUTHMODULES=\"authpsa\"";
		changed=110;
	}
	exit changed;
}\
' $conf >>$temp
}

remove_authpsa()
{
	local conf temp
	conf=$1
	temp=$2
	awk  -v change_mark="$CHANGE_MARK" -v add_mark="$ADD_MARK" '\
BEGIN { found=0; changed=0; got_change_mark=0; got_add_mark=0; old_authmodules=""; }
$0 == change_mark {
	got_change_mark=1;
	got_add_mark=0;
	next;
}
$0 == add_mark {
	got_change_mark=0;
	got_add_mark=1;
	next;
}
$0 ~ /^###[[:space:]]+AUTHMODULES[[:space:]]*=/ && got_change_mark {
	got_change_mark=0;
	old_authmodules=$0;
	sub(/^###[[:space:]]*/,"",old_authmodules);
	next;
}
{
	# "proper" change_mark should be followed by preserved AUTHMODULES,
	# handled above so reset the state uncoditionally
	got_change_mark=0;

        str=$0;

	if (sub(/^[[:space:]]*AUTHMODULES[[:space:]]*=[[:space:]]*"?[[:space:]]*/, "", str)) {
		if (found) {
			# Whee, duplicated AUTHMODULES! Comment out this entry!
			print "# *** Duplicated AUTHMODULES commented out by Parallels Plesk ***"
			print "### " $0;
			print "Duplicated AUTHMODULES entry" > "/dev/stderr"
			changed=110;
			next;
		}
		found=1;
                sub(/[[:space:]]*"?[[:space:]]*$/, "", str);
		split(str, modules, /[[:space:]]+/);
		had_authpsa=0;
		mod_str=""
		for(mod in modules) {
			if (modules[mod] == "authpsa") {
				had_authpsa=1;
				continue;
			}
			mod_str=mod_str " " modules[mod];
		}
		if (!had_authpsa) {
			print $0;
		} else {
			changed=110;
			# be conservative, according to FreeBSD awk manpage substr has three arguments
			mod_str=substr(mod_str, 2, length(mod_str)-1);
			if (length(mod_str)) {
				# mod_str is still non-emtpy even without authpsa. Prefer this setting
				# (probably configured by system administrator)
				print "AUTHMODULES=\"" mod_str "\"";
			} else if (length(old_authmodules)) {
				print old_authmodules; # whatever it is
			} else if (!got_add_mark) {
				print "AUTHMODULES=\"\""; # no better choice
			}
		}
	} else {
		print $0;
	}
	# regardless of what has been done above reset old_authmodules
	old_authmodules="";
	got_add_mark=0;
}
END { exit changed; }
' "$conf" >> "$temp"
}

export LANG="C"
export LC_ALL="C"

cd "$COURIERIMAP_CONFDIR" || exit 1

conf="$1"
shift

case "$1" in
	add)
		action=add_authpsa
		;;

	remove)
		action=remove_authpsa
		;;
	*)
		echo "Utility to configure Parallels Plesk specific authentication for Courier IMAP" >&2
		echo "usage: $0 <service_config> (add|remove)" >&2
		exit 1
		;;
esac

restart_needed=0;

[ ! -f "$conf" ] && die "$conf doesn't exist or not a plain text file"

bak="${conf}.saved_by_plesk"
temp=$(mktemp "$conf.XXXXXX")
[ $? != 0 ] && die "Unable to create temporary file"
trap "trap_handler \"$temp\"" HUP PIPE INT TERM EXIT
$action "$conf" "$temp"

rc=$?
case $rc in
	0)
		;;
	110)
		echo "updating conf file $conf" >&2
		rm -f "$bak" 2>/dev/null; # errors will be reported later
		ln "$conf" "$bak" &&
			mv -f "$temp" "$conf" || die "unable to save new configuration"
		restart_needed=110;
		;;
	*)
		die "unable to process \"$conf\""
		;;
esac
rm -f "$temp"
trap - HUP PIPE INT TERM EXIT

exit $restart_needed
