#!/bin/sh
#
# Copyright (C) 2023  Etersoft
# Copyright (C) 2023  Vitaly Lipatov <lav@etersoft.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

load_helper epm-query


#glob_to_regexp() {
#    sed -e 's/[.[\*^$()+?{|]/\\&/g' \
#        -e 's/\\\*/.*/g' \
#        -e 's/\\\?/.?/g' \
#        -e 's|^|^|' -e 's|$|$|'
#}

__convert_pkgallowscripts_to_regexp()
{
    local tmpalf
    tmpalf="$(mktemp)" || fatal
    # copied from eget's filter_glob
    # check man glob
    # remove commentы and translate glob to regexp
    # TODO: Replaced only * and ?, not escaped . + | ( ) [ ] { } ^ $
    grep -v "^[[:space:]]*#" "$1" | grep -v "^[[:space:]]*$" | sed -e "s|\*|.*|g" -e "s|?|.|g" -e "s|^|^|" -e "s|$|\$|" >$tmpalf
    echo "$tmpalf"
}

__epm_package_name_ok_scripts()
{
    local name="$1"
    local alf="$CONFIGDIR/pkgallowscripts.list"
    [ -s "$alf" ] || return 1
    [ -n "$name" ] || return 1
    local tmpalf=$(__convert_pkgallowscripts_to_regexp "$alf")
    remove_on_exit $tmpalf
    echo "$name" | grep -q -f $tmpalf
    local res=$?
    rm $tmpalf
    return $res
}

__epm_package_ok_scripts()
{
    local pkg="$1"
    local name
    # TODO: improve epm print name and use it here
    name="$(epm print field Name for "$pkg" 2>/dev/null)"
    [ -n "$name" ] || return 1
    __epm_package_name_ok_scripts "$name"
}

__epm_vendor_ok_scripts()
{
    local vendor="$1"
    local alf="$CONFIGDIR/vendorallowscripts.list"
    [ -s "$alf" ] || return 1
    [ -n "$vendor" ] || return 1
    local tmpalf=$(__convert_pkgallowscripts_to_regexp "$alf")
    remove_on_exit $tmpalf
    echo "$vendor" | grep -q -f $tmpalf
    local res=$?
    rm $tmpalf
    return $res
}

#  check if the package is installed and the version is enough (if the version is specified)
epm_status_installed()
{
    local pkg="$1"
    local needed="$2"
    local ver

    is_installed "$pkg" || return

    [ -z "$needed" ] && return

    ver=$(epm print version for package "$pkg" | head -n1)
    if [ -n "$ver" ] && [ "$(epm print compare version "$ver" "$needed")" = "-1" ] ; then
        return 1
    fi

    return 0
}


epm_status_installable()
{
    local pkg="$1"
    #LANG=C epm policy "$pkg" | grep Candidate >/dev/null 2>/dev/null
    if [ -n "$verbose" ] ; then
        docmd epm install --simulate "$pkg"
    else
        epm install --simulate "$pkg" >/dev/null
    fi
}

# allowed to use scripts 
epm_status_certified()
{
    local pkg="$1"
    load_helper epm-install
    __epm_package_ok_scripts "$pkg" && return

    local vendor
    vendor="$(epm print field Vendor for "$pkg" 2>/dev/null)"
    [ -n "$vendor" ] || return
    __epm_vendor_ok_scripts "$vendor" && return
}


epm_status_supported() {
    local distro
    distro=$(epm print info -s)
    case "$distro" in
        alt|redos|rosa*|mos|astra|fedora|debian|ubuntu)
            return 0
            ;;
        *)
            return 1
            ;;
    esac
}

# check if the package is really package (check accessibility)
epm_status_validate()
{
    local pkg="$1"
    local version="$(epm print field Version for "$pkg" 2>/dev/null)"
    [ -n "$version" ]
}

__epm_status_have_sign()
{
    local pkg="$1"
    local sig="$(epm print field sigpgp for "$pkg" 2>/dev/null)"
    [ "$sig" != "(none)" ] && return 0
    # check DSA signature (old packages signed with DSA key)
    sig="$(epm print field siggpg for "$pkg" 2>/dev/null)"
    [ "$sig" != "(none)" ]
}

epm_status_signed()
{
    local pkg="$1"
    case $DISTRNAME in
        ALTLinux)
            # use alt-rpmkeys-checksig for cryptographic signature verification
            assure_exists alt-rpmkeys-checksig alt-rpmkeys-utils || return 1
            if [ -n "$quiet" ] ; then
                alt-rpmkeys-checksig "$pkg" >/dev/null 2>&1
            else
                docmd alt-rpmkeys-checksig "$pkg"
            fi
            ;;
        *)
            # TODO: implement for other distros
            return 1
            ;;
    esac
}

epm_status_original()
{
    local pkg="$1"

    #is_installed $pkg || fatal "FIXME: implemented for installed packages as for now"
    local distribution="$(epm print field Distribution for "$pkg" 2>/dev/null )"
    local release="$(epm print release from package "$pkg" 2>/dev/null )"

    case $DISTRNAME in
        ALTLinux)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            # not for all packages
            #[ "$(epm print field Vendor for package $pkg)" = "ALT Linux Team" ] || return

            echo "$distribution" | grep -q "^ALT" || return 1

            # mc in Sisyphus has not a signature
            #local sig
            #sig="$(epm print field sigpgp for "$pkg" 2>/dev/null )"
            #[ "$sig" = "(none)" ] && return 1

            # FIXME: how to check if the package is from ALT repo (verified)?
            echo "$release" | grep -q "^alt" || return 1

            local packager="$(epm print field Packager for "$pkg" 2>/dev/null )"
            # altlinux.ru, altlinux.org, altlinux.com, altlinux dot
            echo "$packager" | grep -q "altlinux" || return 1
            # otherwise any package from hasher is original
            local disttag="$(epm print field disttag for "$pkg" 2>/dev/null )"
            [ "$disttag" = "(none)" ] && return 1
            return 0
            ;;
        RedOS)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            echo "$distribution" | grep -q "RED SOFT" || return 1
            echo "$release" | grep -q "el7" || return 1
            return 0
            ;;
        ROSA*|MOSDesktop)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            echo "$distribution" | grep -q "ROSA" || return 1
            return 0
            ;;
        Fedora)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            echo "$distribution" | grep -q "Fedora Project" || return 1
            echo "$release" | grep -q "fc" || return 1
            return 0
            ;;
        Uncom)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            echo "$release" | grep -qi "uncom" || return 1
            return 0
            ;;
        Ubuntu)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            echo "$release" | grep -qi "ubuntu" || return 1
            return 0
            ;;
        Debian)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            echo "$release" | grep -qi "debian" || return 1
            return 0
            ;;
        AstraLinux*)
            epm_status_validate $pkg || return 1
            epm_status_repacked $pkg && return 1

            local maintainer="$(epm print field Maintainer for "$pkg" 2>/dev/null)"
            echo "$release" | grep -qi "astra" && return 0
            echo "$maintainer" | grep -q "astralinux" && return 0
            echo "$maintainer" | grep -q "rusbitech" && return 0
            echo "$maintainer" | grep -q "Debian" && return 0
            echo "$maintainer" | grep -q "@debian.org" && return 0
            return 1
            ;;
        *)
            warning 'Status checking is not supported yet for $DISTRNAME'
            return 1
            ;;
    esac
    return 1
}

epm_status_repacked()
{
    local pkg="$1"

    # dpkg package missing packager field
    local repacked="$(epm print field Description for "$1" 2>/dev/null | grep -i "with EPM")"
    local packager="$(epm print field Packager for "$1" 2>/dev/null)"

    #is_installed $pkg || fatal "FIXME: implemented for installed packages as for now"

    case $PKGFORMAT in
        rpm)
            epm_status_validate $pkg || return
            [ "$packager" = "EPM <support@etersoft.ru>" ] && return 0
            [ "$packager" = "EPM <support@eepm.ru>" ] && return 0
            ;;
        deb)
            epm_status_validate $pkg || return

            # In packages repackaged via alien maintainer equal to $USER, it is better to use the package description
            [ ! -z "$repacked" ] && return 0
            ;;
        *)
            fatal 'epm_status_repacked: unsupported $PKGNAME ($BASEDISTRNAME)'
            ;;
    esac
    return 1
}


epm_status_thirdparty()
{
    local pkg="$1"
    local distribution
    local repacked
    local maintainer

    #is_installed $pkg || fatal "FIXME: implemented for installed packages as for now"
    distribution="$(epm print field Distribution for "$pkg" 2>/dev/null )"
    #repacked="$(epm print field Description for "$1" 2>/dev/null | grep -qi "alien")"
    maintainer="$(epm print field Maintainer for "$pkg" 2>/dev/null)"

    case $BASEDISTRNAME in
        alt)
            epm_status_validate $pkg || return 1

            echo "$distribution" | grep -q "^EEPM" && return 1

            echo "$distribution" | grep -q "^ALT" || return 0

            local packager="$(epm print field Packager for "$pkg" 2>/dev/null )"
            # altlinux.ru, altlinux.org, altlinux.com, altlinux dot
            echo "$packager" | grep -q "altlinux" && return 1
            #echo "$packager" && grep -q "basealt" && return 1
            return 0
            ;;
        redos)
            epm_status_validate $pkg || return 1

            echo "$distribution" | grep -q "^RED SOFT" && return 1
            echo "$distribution" | grep -q "^EEPM" && return 1
            return 0
            ;;
        rosa*|mos)
            epm_status_validate $pkg || return 1

            echo "$distribution" | grep -q "^ROSA" && return 1
            echo "$distribution" | grep -q "^EEPM" && return 1
            return 0
            ;;
        fedora)
            epm_status_validate $pkg || return 1

            echo "$distribution" | grep -q "^Fedora Project" && return 1
            echo "$distribution" | grep -q "^EEPM" && return 1
            return 0
            ;;
        debian|ubuntu)
            epm_status_validate $pkg || return 1

            # On UncomOS maintainer Ubuntu and Debian * team
            echo "$maintainer" | grep -q "Debian" && return 1
            echo "$maintainer" | grep -q "Ubuntu" && return 1
            epm_status_repacked $pkg && return 1
            return 0
            ;;
        astra)
            epm_status_validate $pkg || return 1

            local release="$(epm print release from package "$pkg" 2>/dev/null)"
            echo "$release" | grep -qi "astra" && return 1
            echo "$maintainer" | grep -q "Debian" && return 1
            echo "$maintainer" | grep -q "@debian.org" && return 1
            echo "$maintainer" | grep -q "astralinux" && return 1
            echo "$maintainer" | grep -q "rusbitech" && return 1
            epm_status_repacked $pkg && return 1
            return 0
            ;;
        *)
            fatal "Unsupported $BASEDISTRNAME"
            ;;
    esac
    return 1
}


epm_status_help()
{
    message 'epm status - check status of the package and return result via exit code
Usage: epm status [options] <package> [version]'
    echo ''
    echog 'Options:'
    get_help HELPOPT $SHAREDIR/epm-status
}

epm_status()
{
    local option="$1"

    if [ -z "$1" ] ; then
        epm_status_help >&2
        exit 1
    fi

    shift

    # TODO: allow both option
    case "$option" in
        -h|--help)            # HELPOPT: show this help
            epm_status_help
            return
            ;;
        --installed)          # HELPOPT: check if package is installed (not older than version if specified)
            epm_status_installed "$@"
            return
            ;;
        --installable)        # HELPOPT: check if package can be installed from the repo
            epm_status_installable "$@"
            return
            ;;
        --original)           # HELPOPT: check if package is from distro repo
            epm_status_original "$@"
            return
            ;;
        --certified)          # HELPOPT: check if package is certified for install without repacking
            epm_status_certified "$@"
            return
            ;;
        --thirdparty)         # HELPOPT: check if package is from a third-party source
            epm_status_thirdparty "$@"
            return
            ;;
        --repacked)           # HELPOPT: check if package was repacked with epm repack
            epm_status_repacked "$@"
            return
            ;;
        --validate)           # HELPOPT: check if package is accessible (we can get fields from it)
            epm_status_validate "$@"
            return
            ;;
        --supported)          # HELPOPT: check if distribution is supported by epm status
            epm_status_supported
            return
            ;;
        --allowed-scripts|--third-party|--thirdpart)
            # aliases handled by corresponding options above
            case "$option" in
                --allowed-scripts) epm_status_certified "$@" ;;
                *) epm_status_thirdparty "$@" ;;
            esac
            return
            ;;
        -*)
            fatal 'Unknown option $option, use epm status --help to get info'
            ;;
        *)
            fatal 'No option before $option, use epm status --help to get info'
            ;;
    esac

    epm_status_help >&2
    fatal "Run with appropriate option"
}
