#!/bin/bash
# Ultima modificación: [arturo@2021-5-25][arturo@2021-4-7] [arturo@2020-4-1]
# desc: defimos funciones que se puedan reutilizar y llamar desde cualquier otro script

# Declaramos todas las funciones que se definen posteriormente para evitar ejecuciones indeseadas:
declare -a MYFUNCS
MYFUNCS=(vx-arrays_compare
    vx-arrays_sort
    vx-check_escritorio_congelado
    vx-check_if_is_directory
    vx-check_if_is_file
    vx-check_is_decimal
    vx-check_is_decimal_con_signo
    vx-check_is_integer
    vx-check_need_help
    vx-check_user_root
    vx-check_username
    vx-check_var_is_number
    vx-check_write_access_right
    vx-colorear_command_output
    vx-colorear_command_output_azul
    vx-colorear_command_output_rojo
    vx-colorear_command_output_verde
    vx-colorear_echo
    vx-colorear_echo_azul_negrita
    vx-colorear_echo_rojo_negrita
    vx-colorear_echo_verde_negrita
    vx-del_tags
    vx-detectar_gui
    vx-echo_log_error
    vx-echo_log_ok
    vx-echo_log_titulo1
    vx-echo_log_titulo2
    vx-echo-titulo-azul
    vx-fecha
    vx-lista_directorios_perfil
    vx-lista_uniq
    vx-log_xsession
    vx-mensaje
    vx-mensaje_cli
    vx-mensaje_gui
    vx-mensaje_y_salir
    vx-obtener_extension_archivo
    vx-obtener_nombre_archivo
    vx-obtener_nombre_archivo_con_extension
    vx-obtener_ruta_absoluta
    vx-regex_path_absolute
    vx-regex_url
    vx-show_help
    vx-show_help_script
    vx-trim
    vx-usuario_grafico
    vx-vitalinux_version
    vx-yad-checkbox
    vx-yad-file-select
    vx-yad-question-yes-no
)

# Configuramos el autocomplete para el vx-funcs-bash:
complete -W "${MYFUNCS[*]}" "$(basename "${0}")"

# Mostramos la lista de funciones disponibles en el caso de que se pase como parámetro "-h" o "--help":
MIREGEX='^-h$|^--help$'
[[ "${1}" =~ ${MIREGEX} ]] && echo "${MYFUNCS[@]}" | tr -s " " "\n" | sort | more

function vx-check_username() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA='Devuelve un 0 en el caso de que el nombre de usuario pasado como parámetro cumpla las siguientes condiciones
    #  1) Permitimos que el nombre del usuario pueda contener letras minúsculas y mayúsculas: [a-zA-Z] o ([[:lower:]]|[[:upper:]])
    #  2) Le puede seguir [a-z], "-", ".", "_" (el "|" es una OR lógica) => ([[:lower:]]|[[:digit:]]|-|_|\.)
    #  3) A priori no hay límite en la longitud del nombre de usuario'
    EJEMPLOS=("${FUNCNAME[0]} Docente-centro")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} NombreUsuario")
    if vx-check_need_help "${1}" || [[ -z "${1}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    #  Un nombre de usuario:
    #  1) Debe empezar por: [a-z] => ^[[:lower:]]
    #  2) Le puede seguir [a-z], "-", ".", "_" (el "|" es una OR lógica) => ([[:lower:]]|[[:digit:]]|-|_|\.)
    #  3) A priori no hay límite en la longitud del nombre de usuario
    # Si hubiera límite de 16 carac: REGEXP="^[[:lower:]]([[:lower:]]|[[:digit:]]|-|_|\.){2,15}$"
    #
    ## REGEXP="^[[:lower:]]([[:lower:]]|[[:digit:]]|-|_|\.)*$"
    # 1*) Permitimos que el nombre del usuario pueda contener letras minúsculas y mayúsculas: [a-zA-Z] o ([[:lower:]]|[[:upper:]])
    REGEXP="^[a-zA-Z]([a-zA-Z]|[[:digit:]]|-|_|\.)*$"
    [[ "${1}" =~ $REGEXP ]] && return 0 || return 1
}

function vx-vitalinux_version() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Informa de la versión de Vitalinux.  Devuelve un 1 (vx-1.0), un 2 (vx-2.0) o un 3 (vx-3.x)"
    EJEMPLOS=("${FUNCNAME[0]}")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]}")
    if vx-check_need_help "${1}" || [[ -z "${1}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    VER_VITA="$(vx-trim "$(lsb_release -a 2>/dev/null | grep "Release:" | tr -s " " " " | cut -d":" -f2)")"
    [[ "${VER_VITA}" == "14.04" ]] && return 1
    [[ "${VER_VITA}" == "18.04" ]] && return 2
    [[ "${VER_VITA}" == "22.04" ]] && return 3
}

function vx-arrays_sort() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Recibe una lista de valores y la devuelve ordenada"
    EJEMPLOS=("${FUNCNAME[0]} \"\$\{LISTADO_A_ORDENAR\[@\]\}\"")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} \"hola adios comer jugar\"")
    if vx-check_need_help "${1}" || [[ -z "${1}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    _LISTA=("${@}")
    echo "${_LISTA[*]}" | tr -s " " "\n" | sort | tr -s "\n" " "
    return 0
}

function vx-arrays_compare() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Recibe dos arrays o listas referenciadas por nombre y compara sus valores para saber si son iguales. Devuelve 0 o 1"
    EJEMPLOS=("${FUNCNAME[0]} \"LISTA1 LISTA2\"")
    if vx-check_need_help "${1}" || [[ -z "${1}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    local -n _LISTA1="${1}"
    local -n _LISTA2="${2}"
    local -a _LISTA1_ORDENADA=($(vx-arrays_sort "${_LISTA1[@]}"))
    local -a _LISTA2_ORDENADA=($(vx-arrays_sort "${_LISTA2[@]}"))
    [[ "${_LISTA1_ORDENADA[*]}" == "${_LISTA2_ORDENADA[*]}" ]] &&
        return 0 ||
        return 1
}

function vx-regex_url() {
    # REGEX='^(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]\.[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]$'
    REGEX='(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'
    [[ "${1}" =~ ${REGEX} ]] && return 0 || return 1
}

function vx-regex_path_absolute() {
    REGEX='^/[^/].*'
    [[ "${1}" =~ ${REGEX} ]] && return 0 || return 1
}

function vx-echo_log_error() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Devuelve el texto formateado listo para auditar como título de Error en color rojo. Un parámetro: Descripción"
    EJEMPLOS=("${FUNCNAME[0]} \"¡¡Error!!. No se ha podido regenerar los Entornos de Escritorio\"")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} \"¡¡Error!!. No se ha podido regenerar los Entornos de Escritorio\"")
    if vx-check_need_help "${1}" || [[ -z "${1}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    vx-colorear_echo "rojo" "=> ${1}"
    return 0
}

function vx-echo_log_ok() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Devuelve el texto formateado listo para auditar como título ok en color verde. Un parámetro: Descripción"
    EJEMPLOS=("${FUNCNAME[0]} \"Todo Ok. Se ha procedido a regenerar los Entornos de Escritorio\"")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} \"Todo Ok. Se ha procedido a regenerar los Entornos de Escritorio\"")
    if vx-check_need_help "${1}" || [[ -z "${1}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    vx-colorear_echo "verde" "=> ${1}"
    return 0
}

function vx-echo_log_titulo2() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Devuelve el texto formateado listo para auditar como título secundario en color Azul. Dos parámetros: Asunto y Descripción"
    EJEMPLOS=("${FUNCNAME[0]} \"SRV-CONGELACION\" \"Se procede a regenerar los Entornos de Escritorio\"")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} \"SRV-CONGELACION\" \"Se procede a regenerar los Entornos de Escritorio\"")
    if vx-check_need_help "${1}" || [[ -z "${2}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    vx-colorear_echo "azul" "## [$(vx-fecha)] ${1}: ${2} ##"
    return 0
}

function vx-echo_log_titulo1() {
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Devuelve el texto formateado listo para auditar como título principal en color magenta. Dos parámetros: Asunto y Descripción"
    EJEMPLOS=("${FUNCNAME[0]} \"SRV-CONGELACION\" \"Se procede a regenerar los Entornos de Escritorio\"")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} \"SRV-CONGELACION\" \"Se procede a regenerar los Entornos de Escritorio\"")
    if vx-check_need_help "${1}" || [[ -z "${2}" ]]; then
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    fi
    # Help-End
    vx-colorear_echo "magenta" "[$(vx-fecha)] ${1}: ${2}" | sudo vx-auditar-syslog
    return 0
}

function vx-check_need_help() {
    MIREGEX='^-h$|^--help$'
    [[ "${1}" =~ ${MIREGEX} ]] && return 0 || return 1
}

function vx-show_help() {
    echo "=> Nombre de la función: $(vx-colorear_echo_azul_negrita "${1}")"
    shift
    echo -e "=> Descripción: \n$(vx-colorear_echo "cyan" "${1}")"
    shift
    echo "=> Ejemplos de uso:"
    for EJEMPLO in "${@}"; do
        vx-colorear_echo "cyan" "${EJEMPLO:-No se indican}"
    done
    return 0
}

function vx-show_help_script() {
    echo "=> Nombre del script: $(vx-colorear_echo_azul_negrita "${1}")"
    shift
    echo -e "=> Descripción: \n$(vx-colorear_echo "cyan" "${1}")"
    shift
    echo "=> Ejemplos de uso:"
    for EJEMPLO in "${@}"; do
        vx-colorear_echo "cyan" "${EJEMPLO:-No se indican}"
    done
    return 0
}

function vx-check_var_is_number() {
    # Devuelve un 0 si el valor pasado como parámetro es un número:
    # Help-Begin: Descripción de la ayuda de la función:
    AYUDA="Devuelve un 0 si el parámetro pasado a la función es un número entero. Por el contrario devuelve un 1"
    EJEMPLOS=("${FUNCNAME[0]} 678 # Devuelve 0")
    EJEMPLOS+=("vx-funcs-bash ${FUNCNAME[0]} 7830 # Devuelve 0")
    EJEMPLOS+=("${FUNCNAME[0]} m678 # Devuelve 1")
    vx-check_need_help "${1}" &&
        vx-show_help "${FUNCNAME[0]}" "${AYUDA}" "${EJEMPLOS[@]}" && return 0
    # Help-End
    regexnum='^[0-9]+$'
    [[ "${1}" =~ ${regexnum} ]] && return 0 || return 1
}

function vx-lista_uniq() {
    local LISTA=()
    for ELEM in ${@}; do
        [[ ! "${LISTA[@]}" =~ ${ELEM} ]] &&
            LISTA+=("${ELEM}")
    done
    echo "${LISTA[@]}"
}

function vx-fecha() {
    # Muestra la fecha en el siguiente formato: 20-03-31_martes_12:13:45
    date +%y-%m-%d_%A_%T
}

function vx-check_is_integer() {
    # Devuelve 0 en caso de que el parametro pasado sea un número entero:
    REGEX='^[0-9]+$'
    if [[ ${1} =~ ${REGEX} ]]; then
        return 0
    else
        return 1
    fi
}

function vx-check_is_decimal() {
    # Devuelve 0 en caso de que el parametro pasado sea un número entero o decimal sin signo:
    REGEX='^[0-9]+([.][0-9]+)?$'
    if [[ ${1} =~ ${REGEX} ]]; then
        return 0
    else
        return 1
    fi
}

function vx-check_is_decimal_con_signo() {
    # Devuelve 0 en caso de que el parametro pasado sea un número entero o decimal con signo:
    REGEX='^[+-]?[0-9]+([.][0-9]+)?$'
    if [[ ${1} =~ ${REGEX} ]]; then
        return 0
    else
        return 1
    fi
}

function vx-trim() {
    # Elimina los espacios al comienzo y final del texto pasado como parámetro
    local TEXTO="$*"
    # Elimina los espacios al comienzo - remove leading whitespace characters
    TEXTO="${TEXTO#"${TEXTO%%[![:space:]]*}"}"
    # Elimina los espacios al final - remove trailing whitespace characters
    TEXTO="${TEXTO%"${TEXTO##*[![:space:]]}"}"
    echo -n "$TEXTO"
}

function vx-colorear_command_output() {
    case "${1}" in
    "rojo") COLOR=31 ;;
    "verde") COLOR=32 ;;
    "azul") COLOR=34 ;;
    esac
    shift
    eval "${@}" | xargs -i echo -e "\e[${COLOR}m\e[1m{}\e[0m"
}

function vx-colorear_echo() {
    # https://misc.flogisoft.com/bash/tip_colors_and_formatting
    case "${1}" in
    "rojo") COLOR=31 ;;
    "verde") COLOR=32 ;;
    "azul") COLOR=34 ;;
    "magenta") COLOR=35 ;;
    "cyan") COLOR=96 ;;
    esac
    shift
    echo -e "\e[${COLOR}m\e[1m${*}\e[0m"
}

function vx-colorear_command_output_rojo() {
    eval "${@}" | xargs -i echo -e "\e[31m\e[1m{}\e[0m"
}

function vx-colorear_command_output_verde() {
    eval "${@}" | xargs -i echo -e "\e[32m\e[1m{}\e[0m"
}

function vx-colorear_command_output_azul() {
    eval "${@}" | xargs -i echo -e "\e[34m\e[1m{}\e[0m"
}

function vx-colorear_echo_rojo_negrita() {
    echo -e "\e[31m\e[1m${1}\e[0m"
}

function vx-colorear_echo_azul_negrita() {
    echo -e "\e[34m\e[1m${1}\e[0m"
}

function vx-colorear_echo_verde_negrita() {
    echo -e "\e[32m\e[1m${1}\e[0m"
}

function vx-echo-titulo-azul() {
    # Titulo con las siguientes características:
    # 1) En azul y negrita
    # 2) Titulo parpadeante
    # 3) Intertido el color y su background
    echo -e "\e[34m\e[1m\e[5m\e[7m${1}\e[0m"
}

function vx-log_xsession() {
    #
    # Funcion que audita el proceso. Si no se pasa como parámetro el nombre del fichero, dejará un log en /tmp
    # Se auditará en /var/log/vitalinux en el archivo indicado: log_xsession -o nombre_fichero
    #
    # Ejemplo de llamada: LOG="vx-fichero.log" && vx-log_xsession -o "${LOG}"
    #
    local EJECUTOR="$(whoami)"
    local USUGRAF="$(vx-usuario-grafico)"
    local HOMEUSUGRAF="$(vx-home-usuario-grafico "${EJECUTOR}")"
    while getopts 'o:' OPT; do
        case ${OPT} in
        o) LOGFILE=${OPTARG} ;;
        *) LOGFILE="vx-log-${USUGRAF}-$(vx-fecha)" ;;
        esac
    done

    if [ "${LOGFILE}" ]; then
        [ "${EJECUTOR}" == "root" ] &&
            DIRLOG="/var/log/vitalinux" ||
            DIRLOG="${HOMEUSUGRAF}/.vx-logs"
        [ ! -d "${DIRLOG}" ] && mkdir -p "${DIRLOG}"
        LOGFILE="${DIRLOG}/${LOGFILE}"
    else
        LOGFILE="/tmp/vx-log-${USUGRAF}-$(vx-fecha)"
    fi
    exec 2>&1
    exec > >(tee -ia "${LOGFILE}")
}

function vx-del_tags() {
    # Elimina del texto que recibe las etiquetas tipo HTML, pango markup, etc.: <..> </..>
    echo "${1}" | sed -e 's/<[^>]*>//g'
}

function vx-mensaje_cli() {
    TITULO="$(vx-del_tags "${1}")"
    TEXTO="$(vx-del_tags "${2}")"
    echo -e "${TITULO}: ${TEXTO}"
}

function vx-mensaje_gui() {
    yad --title "${1}" \
        --window-icon "vitalinux" \
        --image "${3}" \
        --center \
        --text="  ${2}" \
        --text-align="center" \
        --buttons-layout center \
        --fixed \
        --button="<b>${4}</b>":0
}

function vx-detectar_gui() {
    if xhost >&/dev/null; then
        # echo "Display existente"
        return 0
    else
        # echo "Display invalido"
        return 1
    fi
}

function vx-mensaje() {
    # Le pasamos: 1) un titulo, 2) Un mensaje y 3) un estado de salida
    TITULO="${1}"
    MENSAJE="${2}"
    if vx-detectar_gui; then
        vx-mensaje_gui "${TITULO}" "${MENSAJE}" "${3:-"vitalinux"}" "${4:-"Continuar"}"
    else
        vx-mensaje_cli "${TITULO}" "${MENSAJE}"
    fi
}

function vx-mensaje_y_salir() {
    # Le pasamos: 1) un titulo, 2) Un mensaje y 3) un estado de salida
    TITULO="${1}"
    MENSAJE="${2}"
    if vx-detectar_gui; then
        vx-mensaje_gui "${TITULO}" "${MENSAJE}" "${4:-"vitalinux"}" "${5:-"Continuar"}"
    else
        vx-mensaje_cli "${TITULO}" "${MENSAJE}"
    fi
    (("${3}" >= 0)) && exit "${3}"
}

function vx-usuario_grafico() {
    SEAT_ACTIVO="seat0"
    SESION_ACTIVA=$(loginctl show-seat ${SEAT_ACTIVO} | grep 'ActiveSession' | cut -d'=' -f2)
    loginctl list-sessions | grep "${SEAT_ACTIVO}" | grep "${SESION_ACTIVA}" | tr -s ' ' ' ' | cut -d' ' -f4
}

function vx-check_escritorio_congelado() {
    if dpkg -l vx-dga-l-congelar-escritorio >&/dev/null; then
        return 0
    else
        return 1
    fi
}

function vx-check_user_root() {
    if [[ "$(whoami)" != "root" ]]; then
        MENSAJE="${1:-"Debes acceder con permisos de root para ejecutar este script ..."}"
        vx-mensaje_y_salir "Problema de Acceso" "${MENSAJE}" "1" "error" "Salir"
        return 1
    else
        return 0
    fi
}

function vx-obtener_nombre_archivo_con_extension() {
    # Equivalente a: echo ${1} | awk -F "/" '{print $NF}'
    basename "${1}"
}

function vx-obtener_nombre_archivo() {
    # Equivalente a:  basename -s .$(echo "${1}" | awk -F'.' '{ print $NF }') "${1}"
    basename "${1%.${1##*.}}"
}

function vx-obtener_extension_archivo() {
    echo "${1##*.}"
}

function vx-check_write_access_right() {
    # Devuelve un "0" si el USER tiene permisos de Escritura sobre el DIR:
    USER="${1}"
    DIR="${2}"

    [[ "${USER}" == "root" ]] && echo "Eres el root con permisos de Escritura sobre ${DIR} ..." && return 0

    # Use -L to get information about the target of a symlink,
    # not the link itself, as pointed out in the comments
    # INFO: permisos grupo_propietario propietario
    INFO=($(stat -L -c "%A %G %U" "${DIR}")) # p.e. drwxrwxr-x grupo owner
    PERM=${INFO[0]}
    GROUP=${INFO[1]}
    OWNER=${INFO[2]}

    #ACCESS=no
    # Comenzamos chequeando el permiso de escritura para todos los usuarios:
    if [[ "${PERM:8:1}" == "w" ]]; then
        echo "Todos tienen permiso de escritura sobre ${DIR} ..."
        return 0
    # Seguimos comprobando los permisos del grupo y si el usuario pertenece al grupo:
    elif [[ "${PERM:5:1}" == "w" ]]; then
        [[ "$(id -Gn "${USER}" | tr -s " " ":" | sed "s/.*/:&:/g")" =~ :${GROUP}: ]] &&
            echo "El usuario ${USER} tiene permiso de escritura en ${DIR} por pertenecer al grupo propietario ${GROUP} ..." &&
            return 0
    #ACCESS=yes
    # En última instancia comprobamos que seamos el propietario de la carpeta:
    elif [[ "${PERM:2:1}" == "w" ]]; then
        [[ "${USER}" == "${OWNER}" ]] &&
            echo "${USER} es el propietario de ${DIR} ..." && return 0
        #ACCESS=yes
    fi
    echo "${USER} no tiene permisos de Escritura sobre ${DIR} ..."
    return 1
}

function vx-yad-question-yes-no() {
    TITULO="${1:-"Vitalinux"}"
    TEXTO="${2}"
    IMAGEN="${3:-"vitalinux"}"
    BOTON1="${4:-"Ok"}"
    BOTON2="${5:-"Cerrar"}"
    yad --title "${TITULO}" \
        --text "${TEXTO}" \
        --text-align "center" \
        --window-icon vitalinux \
        --image "${IMAGEN}" \
        --width "450" \
        --fixed \
        --center \
        --justify="center" \
        --button "${BOTON1}":0 \
        --button "${BOTON2}":1
    return $?
}

function vx-yad-file-select() {
    TITULO="${1:-"Selecciona un Archivo o Directorio"}"
    TEXTO="${2:-"  \n<b>Selecciona</b> el <span foreground='blue'><b>Archivo o Directorio</b></span> que desees ...\n"}"
    IMAGEN="${3:-"vitalinux"}"
    BOTON="${4:-"Seleccionar"}"
    if RUTA=$(yad --title "${TITULO}" \
        --window-icon vitalinux \
        --image "${IMAGEN}" \
        --file \
        --width 700 --height 500 \
        --center \
        --text "${TEXTO}" \
        --text-align "center" \
        --button="${BOTON}":0 \
        --button="Cancelar":1); then
        echo "${RUTA}"
        return 0
    else
        exit 1
    fi
}

function vx-yad-checkbox() {
    TITULO="${1:-"Vitalinux Checkbox"}"
    TEXTO="${2:-"  \n<b>Lee</b> y <span foreground='blue'><b>marca la casilla</b></span> si lo crees conveniente ...\n"}"
    IMAGEN="${3:-"vitalinux"}"
    BOTON="${4:-"Aceptar"}"
    shift 4
    #OPCIONES="${@}"
    if RESULTADO=$(yad --title "${TITULO}" \
        --window-icon vitalinux \
        --image "${IMAGEN}" \
        --width 600 --fixed \
        --center \
        --text "${TEXTO}" \
        --text-align "center" \
        --form \
        "${@}" \
        --button="${BOTON}":0 \
        --button="Cancelar":1); then
        echo "${RESULTADO}"
        return 0
    else
        exit 1
    fi
}

function vx-lista_directorios_perfil() {
    HOMEUSU="$(vx-home-usuario-grafico)"
    ## Obtenemos el directorio que hace de Escritorio en el usuario:
    # DIRDESKTOP=$(xdg-user-dir DESKTOP)
    if [ -f "${HOMEUSU}/.config/user-dirs.dirs" ]; then
        # shellcheck source=/dev/null
        . "${HOMEUSU}/.config/user-dirs.dirs"
    else
        salir "Problema: El usuario no tiene Directorios básicos en su perfíl ..."
        return 1
    fi

    DIRDESKTOP="${HOMEUSU}/$(basename "${XDG_DESKTOP_DIR}")"
    #echo "=> DESKTOR DIR de $(vx-usuario-grafico): \"${DIRDESKTOP}\""
    DIRDOCUMENTS="${HOMEUSU}/$(basename "${XDG_DOCUMENTS_DIR}")"
    DIRDOWNLOAD="${HOMEUSU}/$(basename "${XDG_DOWNLOAD_DIR}")"
    DIRMUSIC="${HOMEUSU}/$(basename "${XDG_MUSIC_DIR}")"
    DIRPICTURES="${HOMEUSU}/$(basename "${XDG_PICTURES_DIR}")"
    DIRVIDEOS="${HOMEUSU}/$(basename "${XDG_VIDEOS_DIR}")"
    DIRTEMPLATES="${HOMEUSU}/$(basename "${XDG_TEMPLATES_DIR}")"
    DIRPUBLICSHARE="${HOMEUSU}/$(basename "${XDG_PUBLICSHARE_DIR}")"
    LISTA=("${DIRDESKTOP}"
        "${DIRDOCUMENTS}"
        "${DIRDOWNLOAD}"
        "${DIRMUSIC}"
        "${DIRPICTURES}"
        "${DIRVIDEOS}"
        "${DIRTEMPLATES}"
        "${DIRPUBLICSHARE}")
    case "${1}" in
    "Escritorio") echo "${DIRDESKTOP}" ;;
    "Documentos") echo "${DIRDOCUMENTS}" ;;
    "Descargas") echo "${DIRDOWNLOAD}" ;;
    "Musica") echo "${DIRMUSIC}" ;;
    "Imagenes") echo "${DIRPICTURES}" ;;
    "Videos") echo "${DIRVIDEOS}" ;;
    "Plantillas") echo "${DIRTEMPLATES}" ;;
    "Publico") echo "${DIRPUBLICSHARE}" ;;
    *) echo "${LISTA[@]}" ;;
    esac

    return 0
}

function vx-obtener_ruta_absoluta() {
    # Comprobamos si la ruta es relativa o comienza por ~:
    # [[ "hola que tal" =~ ^([^/]|~) ]] && echo ... || echo ...
    [[ "${1}" =~ ^[^/] ]] && RUTA="$(pwd)/${1}"
    [[ "${1}" =~ ^\./ ]] && RUTA="$(pwd)/${1/\.\//}"
    [[ "${1}" =~ ^\.\./ ]] && RUTA="$(dirname "$(pwd)")/${1/\.\.\//}"
    [[ "${1}" =~ ^~ ]] && RUTA="${1//\~/$(vx-home-usuario-grafico)}"
    [[ "${1}" =~ ^/ ]] && RUTA="${1}"
    ! [[ -d "${RUTA}" || -f "${RUTA}" ]] && return 1
    echo "${RUTA}"
    return 0
}

function vx-devolver_ruta_absoluta() {
    # Igual que la función vx-obtener_ruta_absoluta pero devuelve la ruta resultante independientemente de que exista o no
    # Comprobamos si la ruta es relativa o comienza por ~:
    # [[ "hola que tal" =~ ^([^/]|~) ]] && echo ... || echo ...
    [[ "${1}" =~ ^[^/] ]] && RUTA="$(pwd)/${1}"
    [[ "${1}" =~ ^\./ ]] && RUTA="$(pwd)/${1/\.\//}"
    [[ "${1}" =~ ^\.\./ ]] && RUTA="$(dirname "$(pwd)")/${1/\.\.\//}"
    [[ "${1}" =~ ^~ ]] && RUTA="${1//\~/$(vx-home-usuario-grafico)}"
    [[ "${1}" =~ ^/ ]] && RUTA="${1}"
    echo "${RUTA}"
    return 0
}

function vx-check_if_is_directory() {
    # Comprueba si todos los parámetros pasados son directorios:
    until [ -z "${1}" ]; do
        ! [ -d "${1}" ] && return 1
        shift
    done
    return 0
}

function vx-check_if_is_file() {
    # Comprueba si todos los parámetros pasados son ficheros:
    until [ -z "${1}" ]; do
        ! [ -f "${1}" ] && return 1
        shift
    done
    return 0
}

# Exportamos las funciones anteriores:
# for FUNCION in "${MYFUNCS[@]}"; do
#     export -f "${FUNCION}"
# done

# Comprobamos si los parámetros pasados se corresponden con la llamada a una de las funciones para ejecutarla
# En caso de que el parámetro no sea una de las funciones definidas sólo se quieren importar, no ejecutar
LISTADO_FUNCIONES=":${MYFUNCS[*]}:"
LISTADO_FUNCIONES="${LISTADO_FUNCIONES// /:}"
MIREGEX=":${1}:"
[[ "${LISTADO_FUNCIONES}" =~ ${MIREGEX} ]] &&
    "$@" 2>/dev/null
