#!/bin/sh

po_domain="alterator-vsftpd"

#variables

MAIN_CONFIG_DIR=/etc/vsftpd
USER_CONFIG_DIR=/etc/vsftpd/user_conf

MAIN_CONFIG=$MAIN_CONFIG_DIR/conf

UPLOAD_DIR=/var/ftp/incoming

USER_CONFIG()
{
	echo $USER_CONFIG_DIR/$1
}

set -f

. alterator-sh-functions

#helper functions

#get default param value
#arg0: param-name
default_param()
{
	if [ "$1" = "anonymous_enable" ];then
		echo "YES"
	elif [ "$1" = "write_enable" ];then
		echo "DEFAULT"
	else	
		echo "NO"
	fi
}


#read some parameter from config
#arg0:config-name
#arg1:param-name
read_param()
{
	[ -f "$1" ] || return 1
	local retval="$(grep -G "^$2=" "$1" |cut -d= -f2-)"
	[ -n "$retval" ] || retval="$(default_param "$2")"
	echo "$retval"
}

to_scm()
{
	sed -r 's,YES,#t,i;s,NO,#f,i;s,DEFAULT,#f,'
}

from_scm()
{
	sed -r 's,#t,YES,;s,#f,NO,i'
}

to_string()
{
	sed -r "s,YES,`_ "yes"`,;s,NO,`_ "no"`,;s,DEFAULT,`_ "default"`,"
}

#read_param "a1" "par" || read_param "a2" "par"

#write some parameter to config
#arg0:config-name
#arg1:param-name
#arg2:parame-value
write_param()
{
	if grep -qsG "^$2=" "$1" 2>/dev/null;then
		sed -i "s,^$2=.*,$2=$3," $1
	elif grep -qsG "^#$2=" "$1" 2>/dev/null;then
		sed -i "s,^#$2=.*,$2=$3," $1;
	else
		echo "$2=$3" >>"$1"
	fi
}

#delete some parameter from config
#arg0:config-name
#arg1:param-name
del_param()
{
	sed -i "/^$2=/ d" $1;
}

on_message()
{
	case "$in_action" in
		constraints)
		    local required="$([ "in_orig_action" = "new" ] && echo "#t" || echo "#f")"
		    echo '('
		    printf ' user (required %s label "%s" match ("^[a-z_][a-z0-9_-]*$" "%s"))' \
			"$required" \
			"`_ "User"`" \
			"`_ "only small latin letters, digits and '_' allowed"`"
		    printf ' service_state (default #f label "%s" %s)' \
			"`_ "Enable FTP service"`" \
			"$(for i in anon_state anon_mkdir anon_upload anon_other write_state local_state local_detailed;do
			    printf ' exclude (#f %s)' "$i"
			 done)"
		    printf ' anon_state (default #f label "%s" exclude (#f anon_mkdir) exclude (#f anon_upload) exclude (#f anon_other))' \
			"`_ "Allow anonymous login"`"
		    printf ' anon_mkdir (default #f label "%s")' \
			"`_ "Allow mkdir"`"
		    printf ' anon_upload (default #f exclude (#f anon_upload_dir) label "%s")' \
			"`_ "Allow upload"`"
		    printf ' anon_upload_dir (default #f label "%s")' \
			"`_ "Default upload directory (/var/ftp/incoming)"`" #"
		    printf ' anon_other (default #f label "%s")' \
			"`_ "Allow rename/delete"`"

		    printf ' write_state (default #f exclude (#f anon_upload) exclude (#f anon_upload_dir) exclude (#f anon_mkdir) exclude (#f anon_other)  label "%s")' \
			"`_ "Allow write"`"

		    printf ' user_state (default #f label "%s")' \
			"`_ "Write access"`"

		    printf ' local_state (default #f label "%s")' \
			"`_ "Allow local users login"`"
		    printf ' local_detailed (default #f label "%s")' \
			"`_ "Enable per user settings"`"
		    echo ')'
		    ;;
		read)
		    local detailed=$(read_param "$MAIN_CONFIG" "user_config_dir")
		    if [ "$detailed" = "NO" ]; then
		    		detailed="#f"
		    else
				detailed="#t"
		    fi
		    
		    local service="#f"
		    LANG=C chkconfig vsftpd --list|grep -qs 'on$' && service="#t"


		    local upload_dir="#f"
		    [ -d "$UPLOAD_DIR" ] && upload_dir="#t"
		    
		    echo '('
		    printf ' service_state %s' "$service"

		    printf ' anon_state %s' "$(read_param "$MAIN_CONFIG" "anonymous_enable"|to_scm)"
		    printf ' anon_mkdir %s' "$(read_param "$MAIN_CONFIG" "anon_mkdir_write_enable"|to_scm)"
		    printf ' anon_upload %s' "$(read_param "$MAIN_CONFIG" "anon_upload_enable"|to_scm)"
		    printf ' anon_upload_dir %s' "$upload_dir"
		    printf ' anon_other %s' "$(read_param "$MAIN_CONFIG" "anon_other_write_enable"|to_scm)"

		    printf ' write_state %s' "$(read_param "$MAIN_CONFIG" "write_enable"|to_scm)"
		    
		    printf ' local_state %s' "$(read_param "$MAIN_CONFIG" "local_enable"|to_scm)"
		    printf ' local_detailed %s' "$detailed"
		    echo ')'
		    ;;
		list)
		    echo '('
		    if [  "$in__objects" = "users" ]; then
			find "$USER_CONFIG_DIR" -mindepth 1 -maxdepth 1 -type f |
			    while read name;do
				local name=${name##*/}
				printf '("%s" user_state "%s")\n' \
			    	    "$name" \
			    	    "$(read_param "$(USER_CONFIG "$name")" "write_enable"|to_string)" #"
			    done
		    elif [ "$in__objects" = "avail_users" ] ;then
			local UID_MIN="$(grep -s ^UID_MIN /etc/login.defs |awk '{print $2;exit}')"
			[ -n "$UID_MIN" ] || UID_MIN=500

			local installed="$(mktemp -t installed.XXXXXX)"
			find "$USER_CONFIG_DIR" -mindepth 1 -maxdepth 1 -type f -printf '%f\n' | sort >"$installed"

			getent passwd |
			    awk -F: -v "uid_min=$UID_MIN" '$3>=uid_min && $1!="root" && $7!="/dev/null"{print $1}'|
			    sort |
			    comm -23 - "$installed" |
			    sed 's,.*,("&"),'
			rm -f "$installed"
		    else
			printf '("enable" label "%s")' "`_ "enable write access"`"
			printf '("disable" label "%s")' "`_ "disable write access"`"
			printf '("delete" label "%s")' "`_ "remove from list"`"
		    fi
		    echo ')'
		    ;;
		write)
    		    [ -n "$in_anon_state" ] &&
		    	write_param "$MAIN_CONFIG" "anonymous_enable" "$(echo "$in_anon_state"|from_scm)"
		    [ -n "$in_anon_mkdir" ] &&
			write_param "$MAIN_CONFIG" "anon_mkdir_write_enable" "$(echo "$in_anon_mkdir"|from_scm)"

		    [ -n "$in_anon_upload" ] &&
			write_param "$MAIN_CONFIG" "anon_upload_enable" "$(echo "$in_anon_upload"|from_scm)"

		    if test_bool "$in_anon_upload_dir"; then
			mkdir -p "$UPLOAD_DIR" >&2
			chgrp vsftpd "$UPLOAD_DIR" >&2
			chmod 02775 "$UPLOAD_DIR"
		    else
			rmdir "$UPLOAD_DIR" >&2
		    fi

		    [ -n "$in_anon_other" ] &&
			    write_param "$MAIN_CONFIG" "anon_other_write_enable" "$(echo "$in_anon_other"|from_scm)"

		    [ -n "$in_write_state" ] &&
			    write_param "$MAIN_CONFIG" "write_enable" "$(echo "$in_write_state"|from_scm)"

		    [ -n "$in_local_state" ] &&
			    write_param "$MAIN_CONFIG" "local_enable" "$(echo "$in_local_state"|from_scm)"

		    if test_bool "$in_local_detailed";then
			    write_param "$MAIN_CONFIG" "user_config_dir" "$USER_CONFIG_DIR"
		    else
			    del_param  "$MAIN_CONFIG" "user_config_dir"
		    fi

		    if test_bool "$in_service_state";then
		        chkconfig vsftpd on 
		        service xinetd start >&2 #chkconfig can stop xinetd
		    else
		        chkconfig vsftpd off
		        service xinetd start >&2 #chkconfig can stop xinetd
		    fi
		    write_nop
		    ;;
		delete)
		    [ "$in__objects" == "/" ] || rm -f "$(USER_CONFIG "${in__objects##*/}")"
		    write_nop
		    ;;
		enable)
		    write_param "$(USER_CONFIG "${in__objects##*/}")" "write_enable" "YES"
		    write_nop
		    ;;
		disable)
		    write_param "$(USER_CONFIG "${in__objects##*/}")" "write_enable" "NO"
		    write_nop
		    ;;
		new)
		    local path="$(USER_CONFIG "$in_user")"
		    if [ -f "$path" ];then
			write_error "`_ "Same user already exists"`"
		    else
		        touch "$path"
			write_nop
		    fi
		    ;;
		*)
		    echo '#f'
		    ;;
	esac
}

message_loop
