#!/bin/sh -e
#
# 2012-2016 Steven Armstrong (steven-cdist at armstrong.cc)
# 2016 Carlos Ortigoza (carlos.ortigoza at ungleich.ch)
# 2016 Nico Schottelius (nico.schottelius at ungleich.ch)
# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Configure system-wide locale by modifying i18n file.
#

version_ge() {
    awk -F '[^0-9.]' -v target="${1:?}" '
    function max(x, y) { return x > y ? x : y }
    BEGIN {
        getline
        nx = split($1, x, ".")
        ny = split(target, y, ".")
        for (i = 1; i <= max(nx, ny); ++i) {
            diff = int(x[i]) - int(y[i])
            if (diff == 0) continue
            exit (diff < 0)
        }
    }'
}


key=$__object_id
onchange_cmd=  # none, by default
quote_value=false

catval() {
    # shellcheck disable=SC2059
    printf "$($quote_value && echo '"%s"' || echo '%s')" "$(cat "$1")"
}

state_should=$(cat "${__object}/parameter/state")

os=$(cat "$__global/explorer/os")

case $os
in
    debian)
        if version_ge 4 <"${__global}/explorer/os_version"
        then
            # Debian 4 (etch) and later
            locale_conf="/etc/default/locale"
        else
            locale_conf="/etc/environment"
        fi
        ;;
    devuan)
        locale_conf="/etc/default/locale"
        ;;
    ubuntu)
        if version_ge 6.10 <"${__global}/explorer/os_version"
        then
            # Ubuntu 6.10 (edgy) and later
            locale_conf="/etc/default/locale"
        else
            locale_conf="/etc/environment"
        fi
        ;;
    archlinux)
        locale_conf="/etc/locale.conf"
        ;;
    centos|redhat|scientific)
        # shellcheck source=/dev/null
        version_id=$(. "${__global}/explorer/os_release" && echo "${VERSION_ID:-0}")
        if echo "${version_id}" | version_ge 7
        then
            locale_conf="/etc/locale.conf"
        else
            locale_conf="/etc/sysconfig/i18n"
        fi
        ;;
    fedora)
        # shellcheck source=/dev/null
        version_id=$(. "${__global}/explorer/os_release" && echo "${VERSION_ID:-0}")
        if echo "${version_id}" | version_ge 18
        then
            locale_conf="/etc/locale.conf"
            quote_value=false
        else
            locale_conf="/etc/sysconfig/i18n"
        fi
        ;;
    gentoo)
        case $(cat "${__global}/explorer/init")
        in
            (*openrc*)
                locale_conf="/etc/env.d/02locale"
                onchange_cmd="env-update --no-ldconfig"
                quote_value=true
                ;;
            (systemd)
                locale_conf="/etc/locale.conf"
                ;;
        esac
        ;;
    freebsd|netbsd)
        # NetBSD doesn't have a separate configuration file to set locales.
        # In FreeBSD locales could be configured via /etc/login.conf but parsing
        # that would be annoying, so the shell login file will have to do.
        # "Non-POSIX" shells like csh will not be updated here.

        locale_conf="/etc/profile"
        quote_value=true
        value="$(catval "${__object}/parameter/value"); export ${key}"
        ;;
    solaris)
        locale_conf="/etc/default/init"
        locale_conf_group="sys"

        if version_ge 5.11 <"${__global}/explorer/os_version"
        then
            # mode on Oracle Solaris 11 is actually 0444,
            # but the write bit makes sense, IMO
            locale_conf_mode=0644

            # Oracle Solaris 11.2 and later uses SMF to store environment info.
            # This is a hack, but I didn't feel like modifying the whole type
            # just for some Oracle nonsense.
            # 11.3 apparently added nlsadm(1m), but it is missing from 11.2.
            # Illumos continues to use /etc/default/init
            # NOTE: Remember not to use "cool" POSIX features like -q or -e with
            # Solaris grep.
            release_regex='Oracle Solaris 11.[2-9][0-9]*'
            case $state_should
            in
                (present)
                    svccfg_cmd="svccfg -s svc:/system/environment:init setprop environment/${key} = astring: '$(cat "${__object}/parameter/value")'"
                    ;;
                (absent)
                    svccfg_cmd="svccfg -s svc:/system/environment:init delprop environment/${key}"
                    ;;
            esac
            refresh_cmd='svcadm refresh svc:/system/environment'
            onchange_cmd="grep '${release_regex}' /etc/release >&- || exit 0; ${svccfg_cmd:-:} && ${refresh_cmd}"
        else
            locale_conf_mode=0555
        fi
        ;;
    slackware)
        # NOTE: lang.csh (csh config) is ignored here.
        locale_conf="/etc/profile.d/lang.sh"
        locale_conf_mode=0755
        key="export ${__object_id}"
        ;;
    suse)
        if test -s "${__global}/explorer/os_release"
        then
            # shellcheck source=/dev/null
            os_version=$(. "${__global}/explorer/os_release" && echo "${VERSION}")
        else
            os_version=$(sed -n 's/^VERSION\ *=\ *//p' "${__global}/explorer/os_version")
        fi
        os_major=$(expr "${os_version}" : '\([0-9]\{1,\}\)')

        # https://documentation.suse.com/sles/15-SP2/html/SLES-all/cha-suse.html#sec-suse-l10n
        if expr "${os_major}" '>=' 15 \& "${os_major}" != 42
        then
            # It seems that starting with SuSE 15 the systemd /etc/locale.conf
            # is the preferred way to set locales, although
            # /etc/sysconfig/language is still available.
            # Older documentation doesn't mention /etc/locale.conf, even though
            # is it created when localectl is used.
            locale_conf="/etc/locale.conf"
        else
            locale_conf="/etc/sysconfig/language"
            quote_value=true
            key="RC_${__object_id}"
        fi
        ;;
    voidlinux)
        locale_conf="/etc/locale.conf"
        ;;
    *)
        echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2
        echo "Please contribute an implementation for it if you can." >&2
        exit 1
        ;;
esac

__file "${locale_conf}" --state exists \
    --owner "${locale_conf_owner:-0}" \
    --group "${locale_conf_group:-0}" \
    --mode "${locale_conf_mode:-0644}"

require="__file/${locale_conf}" \
__key_value "${locale_conf}:${key#export }" \
    --file "${locale_conf}" \
    --key "${key}" \
    --delimiter '=' --exact_delimiter \
    --state "${state_should}" \
    --value "${value:-$(catval "${__object}/parameter/value")}" \
    --onchange "${onchange_cmd}"
