#!/usr/bin/env bash
#
# Author: Dmitry Razumov <asmeron@ublinux.com>
# Copyright (c) 2021-2025 UBLinux <support@ublinux.com>
#
# Extended pattern matching: https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching
shopt -s extglob

ENABLED=yes
[[ ${ENABLED} == yes ]] || exit 0

SOURCE=/usr/lib/ublinux/functions; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=/usr/lib/ublinux/default; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null

SOURCE=${SYSCONF}/config; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
SOURCE=${SYSCONF}/kiosk; [ -f ${SOURCE} ] && . ${SOURCE} 2>/dev/null

##  Назначение модулей:
##  account   подтвердить личность, проверив учетные данные, такие как пароль, ключ, токен и другие
##  auth      проверить авторизацию для таких действий, как разрешения, ограничения и т. д.
##  password  обновить учетные данные
##  session   распределять ресурсы во время входа в систему, такие как личные данные, лимиты и другие.
##
##  Выполнение из /etc/pam.d/system-login
##  Тип модуля: session
##  Глобальные переменные:
##    PAM_RHOST    Удалённый хост
##    PAM_RUSER    Удалённый пользователь
##    PAM_SERVICE  Сервис выполняющий вход /etc/pam.d/service_name
##    PAM_TTY      Консоль, может быть как "/dev/tty2" так и ":0"
##    PAM_USER     Текущий пользователь
##    PAM_TYPE     Тип сессии, возможные значения: account, auth, password, open_session, close_session
##
## PAM_RHOST=        PAM_RUSER= PAM_SERVICE=login             PAM_TTY=/dev/tty2 PAM_USER=superadmin PAM_TYPE=open_session
## PAM_RHOST=        PAM_RUSER= PAM_SERVICE=login             PAM_TTY=/dev/tty2 PAM_USER=superadmin PAM_TYPE=close_session
## PAM_RHOST=        PAM_RUSER= PAM_SERVICE=lightdm-autologin PAM_TTY=:0        PAM_USER=superadmin PAM_TYPE=open_session
## PAM_RHOST=        PAM_RUSER= PAM_SERVICE=systemd-user      PAM_TTY=          PAM_USER=lightdm    PAM_TYPE=open_session
## PAM_RHOST=        PAM_RUSER= PAM_SERVICE=systemd-user      PAM_TTY=          PAM_USER=user-2     PAM_TYPE=open_session
## PAM_RHOST=        PAM_RUSER= PAM_SERVICE=lightdm           PAM_TTY=:0        PAM_USER=user-2     PAM_TYPE=open_session
## PAM_RHOST=1.2.3.4 PAM_RUSER= PAM_SERVICE=sshd              PAM_TTY=ssh       PAM_USER=user-2     PAM_TYPE=open_session


if [[ ${PAM_TYPE} == "open_session" && -n ${PAM_USER} ]]; then
# Выполнение функции вызвано используя PAM, получаем имя пользователя вызвавшего PAM, будем пременять только для пользователя
    SELECT_USER="${PAM_USER}"
fi

declare -A APPDESKTOP_PLACEONDESKTOP APPDESKTOP_PLACEONDESKTOP_INIT

exec_01_place_on_desktop_ubinstall(){
    [[ $(cmdline_value ub.sgnfiles) =~ .*"-iso.sgn" ]] && APPDESKTOP_PLACEONDESKTOP+=",${UBINSTALL_DESKTOP}"
}

## На рабочий стол поместить ярлыки приложений из /usr/share/applications/ , только для нового пользователя
## APPDESKTOP_PLACEONDESKTOP_INIT[<users>|<@groups>|*]=<desktop_file_1>[@lock],<desktop_files_n>[@lock]
##   [<users>]          # Применить для пользователя, пример: [superadmin,user-1]. Разделитель запятая(,) или точка с запятой(;)
##   [<@groups>]        # Применить для группы, пример: [@whell,@users]
##                      # Можно комбинировать группы с пользователями, пример: @wheel,user-1
##   [*]                # Все пользователи системы. Если не указано, то все пользователи системы
##   =<desktop_file_n>  # Файлы *.desktop. Разделитель: запятая(,) или точка с запятой(;). Указывается без суфикса ".desktop"
##   =<desktop_file_n>@lock  # Файл *.desktop с установленным владельцем:группой root:root и ACL правами только чтения
##   =@lock             # Установить владельца:группу root:root и права ACL только чтения на каталог "Рабочего стола" рекурсивно
##   =@dislock          # Установить владельца:группу домашний_пользователь:домашний_пользователь и очистить ACL права на каталог "Рабочего стола" рекурсивно
## APPDESKTOP_PLACEONDESKTOP_INIT[superadmin,@wheel]=ubinstall,htop@lock
## APPDESKTOP_PLACEONDESKTOP_INIT=gimp,pinta
exec_02_place_on_desktop_init(){
    [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
    [[ -n ${COMMAND} ]] || local COMMAND="set="
    [[ $(declare -p APPDESKTOP_PLACEONDESKTOP_INIT 2>/dev/null) =~ ^"declare -A" ]] || declare -gA APPDESKTOP_PLACEONDESKTOP_INIT
    local PARAM="$@"
    if [[ -n ${PARAM} ]]; then
	local APPDESKTOP_PLACEONDESKTOP_INIT=
	declare -A APPDESKTOP_PLACEONDESKTOP_INIT=()
	[[ ${PARAM} =~ ^[[:alnum:]_]+("="|"[".*"]=") ]] && eval "${PARAM%%=*}=\${PARAM#*=}"
    fi
    if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#APPDESKTOP_PLACEONDESKTOP_INIT[@]} -ne 0 ]]; then
	local ID_GROUPS= SELECT_USER_HOME=
	for SELECT_USERS_GROUPS in "${!APPDESKTOP_PLACEONDESKTOP_INIT[@]}"; do
	    while IFS= read -r READ_USER_GROUP; do
		if [[ -n ${SELECT_USER} ]]; then
		# Применить для PAM пользователя
		    [[ -z ${ID_GROUPS} ]] && ID_GROUPS=$(id --name --groups ${SELECT_USER})
		    if [[ ${READ_USER_GROUP} == "0" ]] || [[ ${READ_USER_GROUP} == ${SELECT_USER} ]] || [[ ${READ_USER_GROUP} =~ ^'@' && ${ID_GROUPS} =~ (^| )${READ_USER_GROUP//@/}( |$) ]]; then
			SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
			[[ -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init ]] && continue
			copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && touch ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
		    fi
		elif [[ ${READ_USER_GROUP} == "0" ]]; then
		# Применить для всех пользователей
		    for SELECT_USER in $(getent passwd | cut -d: -f1 | xargs); do
			SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
			[[ -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init ]] && continue
			copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && touch ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		elif [[ ! ${READ_USER_GROUP} =~ ^'@' ]] && getent passwd "${READ_USER_GROUP}" &>/dev/null; then
		# Применить для выбанного пользователь
		    SELECT_USER=${READ_USER_GROUP}
		    SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
		    [[ -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init ]] && continue
		    copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && touch ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
		    SELECT_USER=; SELECT_USER_HOME=
		elif [[ ${READ_USER_GROUP} =~ ^'@' ]] && getent group "${READ_USER_GROUP//@/}" &>/dev/null; then
		# Применить для выбраной группа
		    for SELECT_USER in $(getent group "${READ_USER_GROUP//@/}" | cut -d: -f4 | tr , ' '); do
			SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
			[[ -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init ]] && continue
			copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && touch ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		fi
	    done <<< ${SELECT_USERS_GROUPS//@(,|;)/$'\n'}
	done
    elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
	if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' && ${BASH_REMATCH[1]} == @("*"|"**"|"/"|"//") ]]; then
	    PARAM_VALUE="${PARAM#*=}"
	    APPDESKTOP_PLACEONDESKTOP_INIT+="${PARAM_VALUE// /,}"
	fi
	local ID_GROUPS= SELECT_USER_HOME=
	for SELECT_USERS_GROUPS in "${!APPDESKTOP_PLACEONDESKTOP_INIT[@]}"; do
	    while IFS= read -r READ_USER_GROUP; do
		if [[ ${READ_USER_GROUP} == "0" ]]; then
		# Применить для всех пользователей
		    for SELECT_USER in $(getent passwd | cut -d: -f1 | xargs); do
			SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
			remove_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && rm -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		elif [[ ! ${READ_USER_GROUP} =~ ^'@' ]] && getent passwd "${READ_USER_GROUP}" &>/dev/null; then
		# Применить для выбанного пользователь
		    SELECT_USER=${READ_USER_GROUP}
		    SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
		    remove_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && rm -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
		    SELECT_USER=; SELECT_USER_HOME=
		elif [[ ${READ_USER_GROUP} =~ ^'@' ]] && getent group "${READ_USER_GROUP//@/}" &>/dev/null; then
		# Применить для выбраной группа
		    for SELECT_USER in $(getent group "${READ_USER_GROUP//@/}" | cut -d: -f4 | tr , ' '); do
			SELECT_USER_HOME_INIT=$(getent passwd ${SELECT_USER} | cut -d: -f6)
			remove_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP_INIT[${SELECT_USERS_GROUPS}]}" && rm -f ${SELECT_USER_HOME_INIT}/.config/.place_on_desktop_init
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		fi
	    done <<< ${SELECT_USERS_GROUPS//@(,|;)/$'\n'}
	done
    fi

}

## На рабочий стол поместить ярлыки приложений из /usr/share/applications/
## APPDESKTOP_PLACEONDESKTOP[<users>|<@groups>|*]=<desktop_file_1>[@lock],<desktop_files_n>[@lock]
##   [<users>]          # Применить для пользователя, пример: [superadmin,user-1]. Разделитель запятая(,) или точка с запятой(;)
##   [<@groups>]        # Применить для группы, пример: [@whell,@users]
##                      # Можно комбинировать группы с пользователями, пример: @wheel,user-1
##   [*]                # Все пользователи системы. Если не указано, то все пользователи системы
##   =<desktop_file_n>  # Файлы *.desktop. Разделитель: запятая(,) или точка с запятой(;). Указывается без суфикса ".desktop"
##   =<desktop_file_n>@lock  # Файл *.desktop с установленным владельцем:группой root:root и ACL правами только чтения
##   =@lock             # Установить владельца:группу root:root и права ACL только чтения на каталог рабочего стола рекурсивно
##   =@dislock          # Установить владельца:группу домашний_пользователь:домашний_пользователь и очистить ACL права на каталог рабочего стола рекурсивно
## APPDESKTOP_PLACEONDESKTOP[superadmin,@wheel]=ubinstall,htop
## APPDESKTOP_PLACEONDESKTOP[user-1]=htop@lock
## APPDESKTOP_PLACEONDESKTOP[user-2]=*@lock
## APPDESKTOP_PLACEONDESKTOP=gimp,pinta
exec_03_place_on_desktop(){
    [[ $1 == @("set="|"set+="|"set++="|"set-="|"set--="|"remove") ]] && local COMMAND=$1 && shift
    [[ -n ${COMMAND} ]] || local COMMAND="set="
    [[ $(declare -p APPDESKTOP_PLACEONDESKTOP 2>/dev/null) =~ ^"declare -A" ]] || declare -gA APPDESKTOP_PLACEONDESKTOP
    local PARAM="$@"
    if [[ -n ${PARAM} ]]; then
	local APPDESKTOP_PLACEONDESKTOP=
	declare -A APPDESKTOP_PLACEONDESKTOP=()
	[[ ${PARAM} =~ ^[[:alnum:]_]+("="|"[".*"]=") ]] && eval "${PARAM%%=*}=\${PARAM#*=}"
    fi
    if [[ ${COMMAND} == @("set="|"set+="|"set++=") ]] && [[ ${#APPDESKTOP_PLACEONDESKTOP[@]} -ne 0 ]]; then
	local ID_GROUPS= SELECT_USER_HOME=
	for SELECT_USERS_GROUPS in "${!APPDESKTOP_PLACEONDESKTOP[@]}"; do
	    while IFS= read -r READ_USER_GROUP; do
		if [[ -n ${SELECT_USER} ]]; then
		# Применить для PAM пользователя
		    [[ -z ${ID_GROUPS} ]] && ID_GROUPS=$(id --name --groups ${SELECT_USER})
		    [[ ${READ_USER_GROUP} == "0" ]] || [[ ${READ_USER_GROUP} == ${SELECT_USER} ]] || [[ ${READ_USER_GROUP} =~ ^'@' && ${ID_GROUPS} =~ (^| )${READ_USER_GROUP//@/}( |$) ]] \
		    && copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
		elif [[ ${READ_USER_GROUP} == "0" ]]; then
		# Применить для всех пользователей
		    for SELECT_USER in $(getent passwd | cut -d: -f1 | xargs); do
			copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		elif [[ ! ${READ_USER_GROUP} =~ ^'@' ]] && getent passwd "${READ_USER_GROUP}" &>/dev/null; then
		# Применить для выбанного пользователь
		    SELECT_USER=${READ_USER_GROUP}
		    copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
		    SELECT_USER=; SELECT_USER_HOME=
		elif [[ ${READ_USER_GROUP} =~ ^'@' ]] && getent group "${READ_USER_GROUP//@/}" &>/dev/null; then
		# Применить для выбраной группа
		    for SELECT_USER in $(getent group "${READ_USER_GROUP//@/}" | cut -d: -f4 | tr , ' '); do
			copy_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		fi
	    done <<< ${SELECT_USERS_GROUPS//@(,|;)/$'\n'}
	done
    elif [[ ${COMMAND} == @("set-="|"set--="|"remove") ]]; then
	if [[ ${PARAM%%=*} =~ ^.*'['(.*)']' && ${BASH_REMATCH[1]} == @("*"|"**"|"/"|"//") ]]; then
	    PARAM_VALUE="${PARAM#*=}"
	    APPDESKTOP_PLACEONDESKTOP+="${PARAM_VALUE// /,}"
	fi
	local ID_GROUPS= SELECT_USER_HOME=
	for SELECT_USERS_GROUPS in "${!APPDESKTOP_PLACEONDESKTOP[@]}"; do
	    while IFS= read -r READ_USER_GROUP; do
		if [[ ${READ_USER_GROUP} == "0" ]]; then
		# Применить для всех пользователей
		    for SELECT_USER in $(getent passwd | cut -d: -f1 | xargs); do
			remove_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		elif [[ ! ${READ_USER_GROUP} =~ ^'@' ]] && getent passwd "${READ_USER_GROUP}" &>/dev/null; then
		# Применить для выбанного пользователь
		    SELECT_USER=${READ_USER_GROUP}
		    remove_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
		    SELECT_USER=; SELECT_USER_HOME=
		elif [[ ${READ_USER_GROUP} =~ ^'@' ]] && getent group "${READ_USER_GROUP//@/}" &>/dev/null; then
		# Применить для выбраной группа
		    for SELECT_USER in $(getent group "${READ_USER_GROUP//@/}" | cut -d: -f4 | tr , ' '); do
			remove_desktop "${SELECT_USER}" "${APPDESKTOP_PLACEONDESKTOP[${SELECT_USERS_GROUPS}]}"
			SELECT_USER_HOME=
		    done
		    SELECT_USER=
		fi
	    done <<< ${SELECT_USERS_GROUPS//@(,|;)/$'\n'}
	done
    fi
}

##
## $1 SELECT_USER
## $2 APPDESKTOP_PLACEONDESKTOP
##
copy_desktop(){
    local SELECT_USER="$1"
    local APPDESKTOP_PLACEONDESKTOP="$2"
    [[ -n ${SELECT_USER} ]] || return 1
    [[ -n ${APPDESKTOP_PLACEONDESKTOP} ]] || return 1
    if [[ -z ${SELECT_USER_HOME} ]]; then
	SELECT_USER_HOME=$(getent passwd ${SELECT_USER} | cut -d: -f6)
	[[ -n ${SELECT_USER_HOME} ]] || return 1
	local HOME=${SELECT_USER_HOME}
	local XDG_DESKTOP_DIR=
	SOURCE=${SELECT_USER_HOME}/.config/user-dirs.dirs; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
	[[ -d ${XDG_DESKTOP_DIR} && ${XDG_DESKTOP_DIR} != ${SELECT_USER_HOME} ]] || XDG_DESKTOP_DIR="${SELECT_USER_HOME}/$(gettext -d xdg-user-dirs "Desktop")"
	[[ -d ${XDG_DESKTOP_DIR} && ${XDG_DESKTOP_DIR} != ${SELECT_USER_HOME} ]] || XDG_DESKTOP_DIR="${SELECT_USER_HOME}/Desktop"
	[[ -d ${XDG_DESKTOP_DIR} && ${XDG_DESKTOP_DIR} != ${SELECT_USER_HOME} ]] || return 1
    fi
    APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP//.desktop/}
    APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP//;/,}; APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP//,,/,}
    [[ ${APPDESKTOP_PLACEONDESKTOP:0:1} == ',' ]] && APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP:1}
    [[ ${APPDESKTOP_PLACEONDESKTOP} =~ ','$ ]] && APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP%*,}
    #find /usr/share/applications -type f $(awk 'NR > 1 {print "-o"}; {print "-name", $0".desktop"}' <<< "${APPDESKTOP_PLACEONDESKTOP//@(,|;)/$'\n'}") | while IFS= read -r FIND_SELECT_DESKTOP; do
    while IFS= read -r FIND_SELECT_ITEM; do
	local FIND_SELECT_DESKTOP_LOCK=
	local FIND_SELECT_DESKTOP=
	if [[ ${FIND_SELECT_ITEM} =~ (.+)"@lock"$ ]]; then
	    FIND_SELECT_DESKTOP="${BASH_REMATCH[1]}"
	    FIND_SELECT_DESKTOP_LOCK=yes
	else
	    FIND_SELECT_DESKTOP=${FIND_SELECT_ITEM}
	fi
	if [[ -f ${FIND_SELECT_DESKTOP}.desktop ]]; then
	    FILE_DESKTOP="${FIND_SELECT_DESKTOP}.desktop"
	elif [[ -f /usr/share/applications/${FIND_SELECT_DESKTOP}.desktop ]]; then
	    FILE_DESKTOP="/usr/share/applications/${FIND_SELECT_DESKTOP}.desktop"
	elif [[ -f ${FIND_SELECT_DESKTOP} ]]; then
	    FILE_DESKTOP=${FIND_SELECT_DESKTOP}
	fi
	if [[ ${FIND_SELECT_DESKTOP} == "@lock" ]]; then
	    # Если система загружена в режимах песочницы без сохранённого профиля, то в AUFS не применить аттрибут chattr -i (immutable)
	    # Для этого в песочнице каталог /home перемонтируется в tmpfs
	    #[[ ${SYSTEMBOOT_STATEMODE} == @(sandbox|sandbox_hdd) ]]
	    chattr -R -i "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs" 2>/dev/null
	    chown -R root:root "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    chmod -R u+rwX,go-rwx "${XDG_DESKTOP_DIR}"
	    chmod -R u+rwX,go-rwx  "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    setfacl -R -m u:${SELECT_USER}:rX "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    setfacl -R -m d:u:${SELECT_USER}:rX "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    chattr +i "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs" 2>/dev/null
	elif [[ ${FIND_SELECT_DESKTOP} == "@dislock" ]]; then
	    chattr -R -i "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs" 2>/dev/null
	    setfacl --remove-all --recursive "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    setfacl --remove-all --recursive --default "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    chmod -R u+rwX,g+rX,g-w,o+rX,o-w "${XDG_DESKTOP_DIR}"
	    chmod -R u+rw,u-x,go-rwx "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    chown -R ${SELECT_USER}:${SELECT_USER} "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	elif [[ -n ${FILE_DESKTOP} ]]; then
	    [[ -f "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}" ]] || cp -f "${FILE_DESKTOP}" "${XDG_DESKTOP_DIR}"
	    if [[ -n ${FIND_SELECT_DESKTOP_LOCK} ]]; then
		chattr -i "${XDG_DESKTOP_DIR}" "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}" "${SELECT_USER_HOME}/.config/user-dirs.dirs" 2>/dev/null
		chown root:root "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
		if [[ ${FILE_DESKTOP##*/} =~ .*".desktop"$ ]]; then
		    chmod o-rwx,ug+rwx "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		    setfacl -m u:${SELECT_USER}:rx "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		else
		    chmod o-rwx,ug+rwX "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		    setfacl -m u:${SELECT_USER}:rX "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		fi
		chmod u+rw,u-x,go-rwx "${SELECT_USER_HOME}/.config/user-dirs.dirs"
		setfacl -m u:${SELECT_USER}:r "${SELECT_USER_HOME}/.config/user-dirs.dirs"
		chattr +i "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}" "${SELECT_USER_HOME}/.config/user-dirs.dirs" 2>/dev/null
	    else
		chattr -i "${XDG_DESKTOP_DIR}" "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}" 2>/dev/null
		setfacl --remove-all --recursive "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		setfacl --remove-all --recursive --default "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		if [[ ${FILE_DESKTOP##*/} =~ .*".desktop"$ ]]; then
		    chmod -R u+rwx,g+rx,g-w,o+rx,o-w "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		else
		    chmod -R u+rwX,g+rX,g-w,o+rX,o-w "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
		fi
		chown ${SELECT_USER}:${SELECT_USER} "${XDG_DESKTOP_DIR}/${FILE_DESKTOP##*/}"
	    fi
	    #grep "#!/usr/bin/env xdg-open" "${XDG_DESKTOP_DIR}/${FIND_SELECT_DESKTOP##*/}" || sed -i 1s%^%'\#\!/usr/bin/env xdg-open\n'% "${XDG_DESKTOP_DIR}/${FIND_SELECT_DESKTOP##*/}"
	fi
    done <<< "${APPDESKTOP_PLACEONDESKTOP//@(,|;)/$'\n'}"
}

##
## $1 SELECT_USER
## $2 APPDESKTOP_PLACEONDESKTOP
##
remove_desktop(){
    local SELECT_USER="$1"
    local APPDESKTOP_PLACEONDESKTOP="$2"
    [[ -n ${SELECT_USER} ]] || return 1
    [[ -n ${APPDESKTOP_PLACEONDESKTOP} ]] || return 1
    if [[ -z ${SELECT_USER_HOME} ]]; then
	SELECT_USER_HOME=$(getent passwd ${SELECT_USER} | cut -d: -f6)
	[[ -n ${SELECT_USER_HOME} ]] || return 1
	local HOME=${SELECT_USER_HOME}
	local XDG_DESKTOP_DIR=
	SOURCE=${SELECT_USER_HOME}/.config/user-dirs.dirs; [[ -f ${SOURCE} ]] && . ${SOURCE} 2>/dev/null
	[[ -d ${XDG_DESKTOP_DIR} && ${XDG_DESKTOP_DIR} != ${SELECT_USER_HOME} ]] || XDG_DESKTOP_DIR="${SELECT_USER_HOME}/$(gettext -d xdg-user-dirs "Desktop")"
	[[ -d ${XDG_DESKTOP_DIR} && ${XDG_DESKTOP_DIR} != ${SELECT_USER_HOME} ]] || XDG_DESKTOP_DIR="${SELECT_USER_HOME}/Desktop"
	[[ -d ${XDG_DESKTOP_DIR} && ${XDG_DESKTOP_DIR} != ${SELECT_USER_HOME} ]] || return 1
    fi
    APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP//.desktop/}
    APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP//;/,}; APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP//,,/,}
    [[ ${APPDESKTOP_PLACEONDESKTOP:0:1} == ',' ]] && APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP:1}
    [[ ${APPDESKTOP_PLACEONDESKTOP} =~ ','$ ]] && APPDESKTOP_PLACEONDESKTOP=${APPDESKTOP_PLACEONDESKTOP%*,}
    while IFS= read -r FIND_SELECT_ITEM; do
	local FIND_SELECT_DESKTOP_LOCK=
	local FIND_SELECT_DESKTOP=
	if [[ ${FIND_SELECT_ITEM} =~ (.+)"@lock"$ ]]; then
	    FIND_SELECT_DESKTOP="${BASH_REMATCH[1]}"
	    FIND_SELECT_DESKTOP_LOCK=yes
	else
	    FIND_SELECT_DESKTOP=${FIND_SELECT_ITEM}
	fi
	if [[ -f ${XDG_DESKTOP_DIR}/${FIND_SELECT_DESKTOP##*/}.desktop ]]; then
	    FILE_DESKTOP="${XDG_DESKTOP_DIR}/${FIND_SELECT_DESKTOP##*/}.desktop"
	elif [[ -f ${XDG_DESKTOP_DIR}//${FIND_SELECT_DESKTOP##*/} ]]; then
	    FILE_DESKTOP="${XDG_DESKTOP_DIR}//${FIND_SELECT_DESKTOP##*/}"
	fi
	if [[ ${FIND_SELECT_DESKTOP} == @("@lock"|"@dislock") ]]; then
	    chattr -R -i "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs" 2>/dev/null
	    setfacl --remove-all --recursive "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    setfacl --remove-all --recursive --default "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    chmod -R u+rwX,g+rX,g-w,o+rX,o-w "${XDG_DESKTOP_DIR}"
	    chmod -R u+rw,u-x,go-rwx "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	    chown -R ${SELECT_USER}:${SELECT_USER} "${XDG_DESKTOP_DIR}" "${SELECT_USER_HOME}/.config/user-dirs.dirs"
	elif [[ -n ${FILE_DESKTOP} ]]; then
	    [[ -f "${FILE_DESKTOP}" ]] && chattr -i "${FILE_DESKTOP}" && rm -f "${FILE_DESKTOP}"
	fi
    done <<< "${APPDESKTOP_PLACEONDESKTOP//@(,|;)/$'\n'}"
}


################
##### MAIN #####
################


    # Если файл подключен как ресурс с функциями, то выйти
    return 0 2>/dev/null && return 0
    if [[ -z $@ ]]; then
        while read -r FUNCTION; do
            $"${FUNCTION##* }"
        done < <(declare -F | grep "declare -f exec_")
    else
	FUNCTION=
	while [[ $# -gt 0 ]]; do
	    [[ -z ${1} ]] || { declare -f "${1}" &>/dev/null && FUNCTION+="; ${1}" || FUNCTION+=" '${1//\'/}'"; }
	    shift
	done
	eval ${FUNCTION#*; }
    fi
    true
