#----------------------------------------------------------------------------
# /var/install/include/jedlib - library for eisfair scripts
#
# Copyright (c) 2001-2020  The Eisfair Team, team(at)eisfair(dot)org
#
# Creation:     2006-03-29  jed
# Last Update:  $Id: jedlib 78541 2020-06-24 14:19:48Z jed $
#
# Usage:        jed-lib --version - print jedlib version number
#
# This program 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 2 of the License, or
# (at your option) any later version.
#----------------------------------------------------------------------------

_jedlib_date=`/bin/date +%Y-%m-%d`
_jedlib_time=`/bin/date +%H:%M:%S`

#----------------------------------------------------------------------------
# interface description
#----------------------------------------------------------------------------
# Variables:
#   configlog_file          This variable needs to contain a valid path
#                           to the configlog file.
#   force_quiet_run         This variable need to be set to 'true' or '1'
#                           to suppress screen output
#
# Routines:
#   update_jedlib()         update jedlib function_library
#
#   myecho()                special echo command which allows to suppress
#                           screen output based on the global variable
#                           ${force_quiet_run} and the '--force-output'
#                           switch.
#   myanykey()              special anykey command which allows to suppress
#                           a hard key input and replace it by a delay based
#                           on the global variable $force_quiet_run and the
#                           '--force-input' switch.
#
#   install_config()        install/update package configuration file
#
#   write_to_config_log()   writes a message to config log
#   compress_config_log()   compress config log to given number of configuration logs
#   display_config_log()    display config log file if it exists
#
#   print_short_header()    print a short file header which references to
#                           the config file
#
#   insert_date()           insert date_stamp into text string
#   insert_hostname()       insert hostname into text string
#
#   trim_spaces()           return string with no spaces
#
#   get_accessrights()      get file/directory ownership and access rights
#   set_accessrights()      set file/directory ownership and access rights
#
#   rand_char()             return random character
#   rand_string()           return random string
#
#   shorten_string()        return shortened string
#
#   get_last_day_of_month() return date of last day of the month
#   get_yesterday()         return date of previous day
#   get_tomorrow()          return date of next day
#   get_diff_days()         return number of days between two dates
#   get_diff_dates()        return number of years, month, days, hours,
#                           minutes and seconds between two dates
#   sec_to_formated_time()  return formated time "[HH:]MM:SS" from pure seconds
#   formated_time_to_sec()  return seconds from formated time "[HH:]MM:SS"
#
#   unit_to_numeric()       return pure integer value from value incl. unit (k/M/G/T)
#   numeric_to_unit()       return value incl. unit (k/M/G/T/P) from pure integer
#
#   abs_path()              return the absolute path to a given file
#
#   delay_script_exec()     delay script execution, except the current script
#                           is the first one on the list
#
#   format_version()        format version number, e.g. 1.002.3. -> 1.2.3.0
#   compare_version()       compare two version numbers, e.g. 1.0.2 and 1.1.0
#
#   imaputf7_encode()       return IMAP-UTF7 encoded string from normal string
#   imaputf7_decode()       return normal string from IMAP-UTF7 encoded string
#
#   mime_encode()           return a MIME-encoded string (quoted printable/Base64)
#   mime_decode()           return a decoded MIME string
# 
# Functions:
#   is_root()               check if root equivalent user
#   is_numeric()            check if numeric value
#   is_date()               check if date value [YYYY-MM-DD]
#   is_time()               check if time value [HH:MM:SS]
#
#   called_from_install()   check if script was called from the install
#                           process
#
#   host_exists()           check if host exists
#   get_ipaddr_port()       return ip address type, ip address, tcp port, or
#                           all three options in one string
#
#----------------------------------------------------------------------------

#============================================================================
# only include this file once
#============================================================================

if [ "$_JEDLIB" != 'true' ]
then
    _JEDLIB='true'

    if [ "$1" = "version" -o "$1" = '-version' -o "$1" = '--version' ]
    then
        _jedlib_version=`grep -E "Last Update *:" $0 | sed "s/.*jedlib[-_.a-z0-9]* //g" | cut -d' ' -f1`
        echo ${_jedlib_version}
        exit 0
    fi

    #
    # update_jedlib
    # -------------
    #
    # update shared jedlib library file
    #
    # Parameters:      $1    name of package
    #
    update_jedlib ()
    {
        local _uj_destfile
        local _uj_destver
        local _uj_packfile
        local _uj_srcfile
        local _uj_srcver

        _uj_srcfile=/var/install/include/jedlib.${1}
        _uj_destfile=/var/install/include/jedlib

        # extract jedlib from archive
        _uj_packfile=`find /tmp -maxdepth 1 -type l -name "${1}.*" ! -name "*.info" | head -n1`

        if [ -n "${_uj_packfile}" ]
        then
            if [ -s "${_uj_packfile}" ]
            then
                tar xjf ${_uj_packfile} var/install/include/jedlib.${1} -C /
            fi
        fi

        if [ -f ${_uj_srcfile} ]
        then
            # src file exists, go on ...
            if [ -f ${_uj_destfile} ]
            then
                # file exists - check versions
                _uj_srcver=`/bin/sh ${_uj_srcfile} version`
                _uj_destver=`/bin/sh ${_uj_destfile} version`

                if [ -n "${_uj_destver}" ]
                then
                    # version number exists - compare version numbers
                    if [ `echo "${_uj_srcver} > ${_uj_destver}" | bc` -eq 1 ]
                    then
                        # update file
                        echo "updating shared library file (${_uj_destver}->${_uj_srcver}) ..."
                        mv -v ${_uj_srcfile} ${_uj_destfile}
                    fi
                else
                    # no version number exists - update file
                    echo "updating shared library file ..."
                    mv -v ${_uj_srcfile} ${_uj_destfile}
                fi
            else
                # file doesn't exist - update file
                echo "updating shared library file ..."
                mv -v ${_uj_srcfile} ${_uj_destfile}
            fi

            # make sure that the file is world readable
            chmod 644 ${_uj_destfile}

            # remove copy of shared library file
            rm -f ${_uj_srcfile}
        fi
    }

    #
    # myecho
    # ------
    #
    # special echo command which allows to suppress screen output
    # based on the global variable '$force_quiet_run'.
    #
    # Parameters:      $1/$2  '--package <package>' and optionally
    #                         '--force-output' and/or
    #                  $3-$n  normal mecho switches and text
    #
    # Output:          output text
    #
    myecho ()
    {
        local _me_exit
        local _me_force_output
        local _me_outstr
        local _me_switch
        local _me_quiet

        if [ "${_EISLIB}" != 'true' ]
        then
            # load eislib if not already loaded
            . /var/install/include/eislib
        fi

        # check if quiet run has been requested
        _me_quiet=false
        if is_numeric "${force_quiet_run}"
        then
            if [ ${force_quiet_run} -eq 1 ]
            then
                _me_quiet=true
            fi
        else
            if [ -n "${force_quiet_run}" ]
            then
                _me_quiet=${force_quiet_run}
            fi
        fi

        _me_exit=0
        _me_force_output=0
        while [ ${_me_exit} -eq 0 ]
        do
            case $1 in
                *-force-output )
                    _me_force_output=1
                    shift
                    ;;
                *-pack|*-package )
                    _me_package="$2"
                    shift; shift
                    ;;
                * )
                    _me_exit=1
                    ;;
            esac
        done

        if [ ${_me_force_output} -eq 1 ]
        then
            _me_quiet=false
        else
            if called_from_install --pack "${_me_package}"
            then
                _me_quiet=true
            fi
        fi

        if ! ${_me_quiet:-false}
        then
            _me_exit=0
            _me_switch=''
            _me_outstr=''
            while [ ${_me_exit} -eq 0 ]
            do
                case $1 in
                    -n|*-std|*stdbr|*-info|*-warn|*-error|*-link|*-ok|*-fail|*-tty|*-html|*-file )
                        _me_switch="${_me_switch}$1 "
                        shift
                        ;;
                    * )
                        _me_outstr="$*"
                        _me_exit=1
                        ;;
                esac
            done

            # be verbose
            mecho ${_me_switch} "${_me_outstr}"
        fi
    }

    #
    # myanykey
    # --------
    #
    # special anykey command which allows to suppress a hard
    # key input and replace it by a delay based on the global
    # variable 'force_quiet_run'.
    #
    # Parameters:      $1     '--package <package>' and optionally
    #                         '--force-input' and/or optionally
    #                         '--timeout <time>'
    #
    myanykey ()
    {
        local _ma_exit
        local _ma_force_input
        local _ma_package
        local _ma_quiet
        local _ma_timeout

        _ma_timeout=3

        # check if quiet run has been requested
        _ma_quiet=false
        if is_numeric "${force_quiet_run}"
        then
            if [ ${force_quiet_run} -eq 1 ]
            then
                _ma_quiet=true
            fi
        else
            if [ -n "${force_quiet_run}" ]
            then
                _ma_quiet=${force_quiet_run}
            fi
        fi

        _ma_exit=0
        _ma_force_input=0
        while [ ${_ma_exit} -eq 0 ]
        do
            case $1 in
                *-force-input )
                    _ma_force_input=1
                    shift
                    ;;
                *-pack|*-package )
                    _ma_package="$2"
                    shift; shift
                    ;;
                *-timeout )
                    _ma_timeout="$2"
                    shift; shift
                    ;;
                * )
                    _ma_exit=1
                    ;;
            esac
        done

        if [ ${_ma_force_input} -eq 1 ]
        then
            _ma_quiet=false
        else
            if called_from_install --pack "${_ma_package}"
            then
                _ma_quiet=true
            fi
        fi

        if ${_ma_quiet:-false}
        then
            sleep ${_ma_timeout}
        else
            anykey
        fi
    }

    #
    # install_config
    # --------------
    #
    # install/update package configuration file
    #
    # Parameters:      $1    name of package
    #                        if the first parameter is '--quiet'
    #                        all screen outputs are suppressed.
    #
    # Output:          0  -  upgrade configuration
    #                  1  -  new configuration
    #
    install_config ()
    {
        local _ic_modname
        local _ic_retval
        local _ic_quiet

        _ic_quiet=0
        if [ "$1" = '--quiet' ]
        then
            _ic_quiet=1
            shift
        fi

        _ic_modname=${1}
        _ic_retval=1

        if [ -f /var/run/${_ic_modname}.install ]
        then
            # previous version found - upgrading
            if [ ${_ic_quiet} -eq 0 ]
            then
                echo "loading previous configuration file ..."
            fi
            /var/install/config.d/${_ic_modname}-update.sh update
            _ic_retval=0
        elif [ ! -f /etc/config.d/${_ic_modname} ]
        then
            # new installation - parameter check
            if [ ${_ic_quiet} -eq 0 ]
            then
                echo "loading initial configuration file ..."
            fi
            cp /etc/default.d/${_ic_modname} /var/run/${_ic_modname}.install
            /var/install/config.d/${_ic_modname}-update.sh update
        fi

        rm -f /var/run/${_ic_modname}.install

        return ${_ic_retval}
    }

    # Generell information about the functions 'write_to_config_log',
    # 'compress_config_log' and 'display_config_log':
    #
    # The function 'write_to_config_log' writes new log messages to
    #   the file ${configlog_file}.tmp.
    # The function 'compress_config_log' adds these messages to the
    #   default logfile ${configlog_file} and then removes the
    #   ${configlog_file}.tmp file. If new messages have been added
    #   a marker file ${configlog_file}.newlines will be created.
    # The function 'display_config_log' displays the content of the
    #   file ${configlog_file} if also a file ${configlog_file}.newlines
    #   exists.

    #
    # write_to_config_log
    # -------------------
    #
    # writes a message to config log
    #
    # Parameters:      $1    function
    #                        --header   print header message
    #                        --info     print info message (default)
    #                        --warn     print warning message
    #                        --error    print error message
    #                        --ff       followup entry, don't print label
    #
    #                  $2    message text, e.g. "This is a log message."
    #

    write_to_config_log()
    {
        local _w2cl_configdir
        local _w2cl_fup
        local _w2cl_label
        local _w2cl_opt

        _w2cl_label='Info:'
        _w2cl_fup=0
        _w2cl_opt=''

        while [ 1 ]
        do
            case "$1" in
                -header|--header)
                    _w2cl_opt='-e'
                    _w2cl_label="\nDate: `date`\n"
                    shift
                    ;;
                -info|--info)
                    _w2cl_label='  Info:'
                    shift
                    ;;
                -warn|--warn)
                    _w2cl_label='  Warning:'
                    shift
                    ;;
                -error|--error)
                    _w2cl_label='  Error:'
                    shift
                    ;;
                -ff|--ff)
                    _w2cl_fup=1
                    shift
                    ;;
                *)
                    break
                    ;;
            esac
        done

        if [ ${_w2cl_fup} -eq 1 ]
        then
            _w2cl_label="`echo \"${_w2cl_label}\"|tr 'a-zA-Z' ' '`"
        fi

        # check if destination directory exists
        if [ -n "${configlog_file}" ]
        then
            _w2cl_configdir="`dirname ${configlog_file}`/"
            if [ ! -d ${_w2cl_configdir} ]
            then
                # create directory
                mkdir -p ${_w2cl_configdir}
            fi

            {
                if [ "${_w2cl_opt}" = "-e" ]
                then
                    # force print of date header
                    echo ${_w2cl_opt} "${_w2cl_label} $*"
                else
                    # print normal entry
                    if [ ! -s ${configlog_file}.tmp ]
                    then
                        # file doesn't exist or is empty - prefix entry with date header
                        printf "\nDate: `date`\n\n"
                    fi

                    echo ${_w2cl_opt} "${_w2cl_label} $*"
                fi
            } >> ${configlog_file}.tmp
        else
            echo "ERROR: Variable '\${configlog_file\}' not set!"
        fi
    }

    #
    # compress_config_log
    # -------------------
    #
    # compress config log to given number of configuration logs
    #
    # Parameters:      $1    maximum number of previous config logs
    #                        default: 5
    #

    compress_config_log()
    {
        local _ccl_idxmax
        local _ccl_isnum
        local _ccl_maxnum
        local _ccl_sedstr
        local _ccl_tmpfile
        local _ccl_tmpnum1
        local _ccl_tmpnum2

        _ccl_idxmax=$1

        if [ -z "${_ccl_idxmax}" ]
        then
            # set default number of entries
            _ccl_idxmax=5
        elif [ ${_ccl_idxmax} -le 1 ]
        then
            # set default number of entries
            _ccl_idxmax=5
        fi

        #
        # remove previous newline marker file
        #
        if [ -f ${configlog_file}.newlines ]
        then
            rm -f ${configlog_file}.newlines
        fi

        #
        # check if previous logfile contains valid log entries
        # and delete it if no entries are found.
        #
        if [ -f ${configlog_file} ]
        then
            # file exists - check number of lines after removing
            # '^Date'-lines and all empty lines and spaces
            _ccl_isnum=`grep -v "^Date" ${configlog_file} | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g' -e '/^$/d' | wc -l`

            if [ ${_ccl_isnum} -eq 0 ]
            then
                # delete file if it does not contain log entries
                rm -f ${configlog_file}
            fi
        fi

        #
        # append new log entries if some entries exist.
        #
        if [ -f ${configlog_file}.tmp ]
        then
            # file exists - check number of lines after removing
            # '^Date'-lines and all empty lines and spaces
            _ccl_isnum=`grep -v "^Date" ${configlog_file}.tmp | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g' -e '/^$/d' | wc -l`

            if [ ${_ccl_isnum} -gt 0 ]
            then
                # add newly created logfile to default logfile
                cat ${configlog_file}.tmp >> ${configlog_file}

                # create newline marker file
                echo "new loglines added" > ${configlog_file}.newlines
            fi

            rm ${configlog_file}.tmp
        fi

        #
        # reduce number of log entries to given limit
        #
        if [ -f ${configlog_file} ]
        then
            # file exists
            _ccl_tmpfile=${configlog_file}.$$

            # get number of configuration blocks
            _ccl_maxnum=`grep -n "^Date" ${configlog_file} | wc -l`

            if [ ${_ccl_maxnum} -gt ${_ccl_idxmax} ]
            then
                # more than (_ccl_idxmax - 1) lines found, strip surplus lines
                _ccl_tmpnum1=`expr ${_ccl_maxnum} - ${_ccl_idxmax} + 1`
                _ccl_tmpnum2=`grep -n "^Date" ${configlog_file} | sed -n "${_ccl_tmpnum1}p" | cut -d: -f1`
                _ccl_sedstr=1\,`expr ${_ccl_tmpnum2} - 1`d

                {
                    echo
                    sed "${_ccl_sedstr}" ${configlog_file}
                } > ${_ccl_tmpfile}

                mv ${_ccl_tmpfile} ${configlog_file}
            fi
        fi
    }

    #
    # display_config_log
    # ------------------
    #
    # display config log file if it exists
    #

    display_config_log()
    {
        local _dcl_answer
        local _dcl_ask_tmpfile
        local _dcl_color
        local _dcl_frame
        local _dcl_rc

        _dcl_color=''
        _dcl_frame=''

        if [ "${_EISLIB}" != 'true' ]
        then
            # load eislib if not already loaded
            . /var/install/include/eislib
        fi

        if $(grep -qE "^MENU=['\"]/var/install/bin/show-menu['\"]"  /etc/config.d/setup)
        then
            _dcl_color='--nocolor'
            _dcl_frame='--noframe'
        fi

        if [ -f ${configlog_file} -a -f ${configlog_file}.newlines ]
        then
            _dcl_ask_tmpfile=$(/bin/mktemp -t XXXXXXXXXXXX)
            sleep 5
            clrhome
            mecho --info "Configuration messages appeared, please check configuration"
            mecho
            /var/install/bin/ask "Continue" "yes" >${_dcl_ask_tmpfile}
            _dcl_rc=${?}
            _dcl_answer=$(cat ${_dcl_ask_tmpfile})
            rm -f ${_dcl_ask_tmpfile}

            # if ask break, ask returned 255
            if [ ${_dcl_rc} = 255 ]
            then
                _dcl_answer=no
            fi
            if [ "${_dcl_answer}" = 'yes' ]
            then
                /var/install/bin/show-doc.cui ${_dcl_color} ${_dcl_frame} --follow --title ${configlog_file} ${configlog_file}
            else
                exit 0
            fi
            mecho
        fi
    }

#============================================================================

    #
    # print_short_header
    # ------------------
    #
    # print a short file header which references to the config file
    #
    # Parameters:      $1    file name
    #                  $2    program name
    #                  $3    module name
    #                  $4    program version
    #

    print_short_header()
    {
        local _psh_cname
        local _psh_fname
        local _psh_pname
        local _psh_pver

        _psh_fname=$1
        _psh_pname=$2
        _psh_cname=$3
        _psh_pver=$4

        if [ $# -eq 3 ]
        then
            # 'old' format
            _psh_cname=${_psh_pname}
        fi

        # program name
        _psh_pname=`basename ${_psh_pname}`

        # check version number
        echo ${_psh_pver} | grep -q "^v"

        if [ $? -ne 0 ]
        then
            _psh_pver="v${_psh_pver}"
        fi

        echo "#------------------------------------------------------------------"
        echo "# ${_psh_fname} file generated by ${_psh_pname} ${_psh_pver}"
        echo "#"
        echo "# Do not edit this file, edit /etc/config.d/${_psh_cname}"
        echo "# Creation Date: ${_jedlib_date} Time: ${_jedlib_time}"
        echo "#------------------------------------------------------------------"
    }

#============================================================================

    #
    # insert_date
    # -----------
    #
    # insert date_stamp into text string. The position at which the date will be
    # inserted is being defined by the standard date placeholders.
    # e.g. %d.%m.%Y
    #
    # Parameters:      $1    text string
    #
    # Output:          modified text string
    #

    insert_date()
    {
        local _id_tmp_str1
        local _id_tmp_str2
        local _id_work_str

        _id_work_str="$1"

        for _RSTR in d m y Y H M S R c C e F I k l a A b B D g G h j n N p P r s t T u U V w W x X z Z
        do
            while [ 1 ]
            do
                echo "${_id_work_str}" | grep -E -q "%${_RSTR}[][\(\)\$\%\/ .,_0-9-]|%${_RSTR}$"

                if [ $? -eq 0 ]
                then
                    _id_tmp_str1=`expr "${_id_work_str}" : "\(.*\)\%${_RSTR}"`
                    _id_tmp_str2=`expr "${_id_work_str}" : ".*\%${_RSTR}\(.*\)"`
                    _id_work_str="${_id_tmp_str1}`date +\"%${_RSTR}\"`${_id_tmp_str2}"
                else
                    break
                fi
            done
        done

        echo "${_id_work_str}"
    }

    #
    # insert_hostname
    # ---------------
    # Insert hostname into text string. The position at which the hostname will be
    # inserted is being defined by %HN placeholder.
    #
    # Parameters:      $1    text string
    #
    # Output:          modified text string
    #

    insert_hostname()
    {
        local _ih_tmp_str1
        local _ih_tmp_str2
        local _ih_work_str

        _ih_work_str="$1"

        _RSTR="HN"
        while [ 1 ]
        do
            echo "${_ih_work_str}"|grep -q "%${_RSTR}[][\(\)\$\%\/ .,_0-9-]*"

            if [ $? -eq 0 ]
            then
                _ih_tmp_str1=`expr "${_ih_work_str}" : "\(.*\)\%${_RSTR}"`
                _ih_tmp_str2=`expr "${_ih_work_str}" : ".*\%${_RSTR}\(.*\)"`
                _ih_work_str="${_ih_tmp_str1}`hostname`${_ih_tmp_str2}"
            else
                break
            fi
        done

        echo "${_ih_work_str}"
    }

    #
    # trim_spaces
    # -----------
    # Return string with no spaces
    #
    # Parameters:      $1    string to format
    #                  $2    action: left, right, both [ optional, default: both]
    #
    # Output:          string with no leading, no trailing or no leading and no
    #                  trailing spaces
    #
    trim_spaces ()
    {
        local _ts_action
        local _ts_str

        _ts_str="$1"
        _ts_action="$2"

        case ${_ts_action} in
            left|l )
                echo "${_ts_str}"|sed -e 's/^ *//'
                ;;
            right|r )
                echo "${_ts_str}"|sed -e 's/ *$//'
                ;;
            all|a )
                echo "${_ts_str}"|sed -e 's/ //g'
                ;;
            * ) # both | l
                echo "${_ts_str}"|sed -e 's/^ *//' -e 's/ *$//'
                ;;
        esac
    }

    #
    # get_accessrights
    # ----------------
    # get file/directory ownership and access rights and return as string
    #
    # Parameters:      $1    filename/directory
    #
    # Output:          string which contains access rights, owner and group
    #                  in the following format: 'mask:owner:group'
    #                  e.g. '1666:tim:nogroup'
    #
    get_accessrights ()
    {
        local _ga_name
        local _ga_oldifs
        local _ga_str
        local _ga_access
        local _ga_owner
        local _ga_group
        local _ga_bin2
        local _ga_bin3
        local _ga_bin4
        local _ga_dec1
        local _ga_dec2
        local _ga_dec3
        local _ga_dec4
        local _ga_txt2
        local _ga_txt3
        local _ga_txt4

        # mask '&' characters by adding a slash -> '\&'
        # this allows to process IMAP-UTF-7 encoded mail folder names
        _ga_name=`echo "$1" | sed 's#\([^\]\)\&#\1\\\\\&#g'`

        if [ -f ${_ga_name} -o -d ${_ga_name} ]
        then
            if [ -L ${_ga_name} ]
            then
                # symbolic link, get target folder
                _ga_name=`readlink -f ${_ga_name}`
            fi

            # read file data
            # dir : drwx------:5:otto:mailtest:4096:Nov:18:00:16:/home/otto/.imapmail
            # file: -rw-------:1:otto:mailtest:78892:Oct:15:20:11:/home/otto/.imapmail/INBOX
            _ga_str=`ls -ld ${_ga_name} | tr -s ' ' ':'`

            # change IFS
            _ga_oldifs=${IFS}
            IFS=' '

            # file ownership data, owner, group
            _ga_access=`echo ${_ga_str} | cut -d: -f1`
            _ga_owner=`echo ${_ga_str}  | cut -d: -f3`
            _ga_group=`echo ${_ga_str}  | cut -d: -f4`

            # change IFS
            IFS=${_ga_oldifs}

            # extract text strings
            _ga_txt2=`echo ${_ga_access} | cut -c2-4`
            _ga_txt3=`echo ${_ga_access} | cut -c5-7`
            _ga_txt4=`echo ${_ga_access} | cut -c8-10`

            # convert to binary values
            _ga_bin2=`echo ${_ga_txt2} | tr '\-rwxsS' '011110'`
            _ga_bin3=`echo ${_ga_txt3} | tr '\-rwxsS' '011110'`
            _ga_bin4=`echo ${_ga_txt4} | tr '\-rwxtT' '011110'`

            # check if setuid bit has been set
            _ga_dec1=0
            echo "${_ga_txt2}" | grep -E -q "s|S"
            if [ $? -eq 0 ]
            then
                _ga_dec1=`expr ${_ga_dec1} + 4`
            fi

            # check if setguid bit has been set
            echo "${_ga_txt3}" | grep -E -q "s|S"
            if [ $? -eq 0 ]
            then
                _ga_dec1=`expr ${_ga_dec1} + 2`
            fi

            # check if sticky-bit bit has been set
            echo "${_ga_txt4}" | grep -E -q "t|T"
            if [ $? -eq 0 ]
            then
                _ga_dec1=`expr ${_ga_dec1} + 1`
            fi

            # convert to decimal values
            _ga_dec2=`echo "ibase=2;${_ga_bin2}" | bc`
            _ga_dec3=`echo "ibase=2;${_ga_bin3}" | bc`
            _ga_dec4=`echo "ibase=2;${_ga_bin4}" | bc`

            # output: ownership data, owner, group
            echo "${_ga_dec1}${_ga_dec2}${_ga_dec3}${_ga_dec4}:${_ga_owner}:${_ga_group}"
        fi
    }

    #
    # set_accessrights
    # ----------------
    # set file/directory ownership and access rights
    #
    # Parameters:      $0    optional: -R/-Rall     - recursive for access rights, owner, group
    #                                  -Ra|-Raccess - recursive for access rights only
    #                                  -Ro|-Rowner  - recursive for owner only
    #                                  -Rg|-Rgroup  - recursive for group only
    #
    #                  $1    filename/directory
    #                  $2    string which contains access rights, owner and group
    #                        in the following format: 'mask:owner:group'
    #
    set_accessrights ()
    {
        local _sa_access_option=''
        local _sa_owner_option=''
        local _sa_group_option=''
        local _sa_name
        local _sa_data
        local _sa_access
        local _sa_owner
        local _sa_group

        while [ $# -gt 0 ]
        do
            case "$1" in
                -R|-Rall )
                    # all
                    _sa_access_option='-R'
                    _sa_owner_option='-R'
                    _sa_group_option='-R'
                    shift
                    ;;
                -Ra )
                    # access rights
                    _sa_access_option='-R'
                    shift
                    ;;
                -Ro )
                    # owner
                    _sa_owner_option='-R'
                    shift
                    ;;
                -Rg )
                    # group
                    _sa_group_option='-R'
                    shift
                    ;;
                * )
                    break
                    ;;
            esac
        done

        # mask '&' characters by adding a slash -> '\&'
        # this allows to process IMAP-UTF-7 encoded mail folder names
        _sa_name=`echo "$1" | sed 's#\([^\]\)\&#\1\\\\\&#g'`
        _sa_data="$2"

        if [ -f ${_sa_name} -o -d ${_sa_name} ]
        then
            # file ownership data, owner, group
            _sa_access=`echo "${_sa_data}" | cut -d: -f1`
            _sa_owner=`echo "${_sa_data}" | cut -d: -f2`
            _sa_group=`echo "${_sa_data}" | cut -d: -f3`

            # set access rights
            if [ -n "${_sa_access}" ]
            then
                chmod ${_sa_access_option} ${_sa_access} ${_sa_name}
            fi

            if [ -n "${_sa_owner}" ]
            then
                chown ${_sa_owner_option} ${_sa_owner} ${_sa_name}
            fi

            if [ -n "${_sa_group}" ]
            then
                chgrp ${_sa_group_option} ${_sa_group} ${_sa_name}
            fi
        fi
    }

    #
    # rand_char
    # ---------
    # return random char
    #
    # Output:          string which contains a random char
    #
    # eisfair-2: bsdmainutils package need to be installed which contains the 'hexdump'
    #
    rand_char ()
    {
        local _rc_chars
        local _rc_max
        local _rc_nbr
        local _rc_rand

        # array of allowed characters
        # first character is a placebo and will never be used
        _rc_max=64
        _rc_chars="aabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
        _rc_rand="`hexdump -n 2 -e '/2 "%u"' /dev/urandom`"
        _rc_nbr=$(( ( ${_rc_rand} % ${_rc_max} ) + 1 ))

        echo "`expr substr "${_rc_chars}" ${_rc_nbr} 1`"
    }

    #
    # rand_string
    # -----------
    # return random string
    #
    # Parameters:      $1    length of string
    #
    # Output:          string which contains a random string
    #
    rand_string ()
    {
        local _rs_idx
        local _rs_randstr
        local _rs_strlen

        _rs_strlen=${1}

        # create random string
        _rs_idx=1
        _rs_randstr=""
        while [ ${_rs_idx} -le ${_rs_strlen} ]
        do
            _rs_randstr="${_rs_randstr}`rand_char`"
            _rs_idx=`expr ${_rs_idx} + 1`
        done

        echo "${_rs_randstr}"
    }

    #
    # shorten_string
    # --------------
    # return shorten string, e.g. "this-is-...long-text"
    #
    # Parameters:      $1    input string
    #                  $2    max. length of string
    #                  $3    optional: separator string
    #
    # Output:          shortend string
    #
    shorten_string ()
    {
        local _ss_hlen
        local _ss_inlen
        local _ss_instr
        local _ss_len
        local _ss_outstr
        local _ss_seplen
        local _ss_sepstr
        local _ss_spos
        local _ss_width

        _ss_instr="${1}"
        _ss_width=${2}
        _ss_sepstr="${3}"

        if [ -z "${_ss_sepstr}" ]
        then
            _ss_sepstr="..."
        fi

        _ss_inlen=`expr length "${_ss_instr}"`

        if [ ${_ss_inlen} -gt ${_ss_width} ]
        then
            _ss_seplen=`expr length ${_ss_sepstr}`          # length of separator string
            _ss_len=`expr ${_ss_width} - ${_ss_seplen}`     # substract length of separator
            _ss_hlen=`expr ${_ss_len} \/ 2`                 # devide by 2
            _ss_spos=`expr ${_ss_inlen} - ${_ss_hlen} + 1`  # start position of 2. string

            _ss_outstr="`expr substr "${_ss_instr}" 1 ${_ss_hlen}`${_ss_sepstr}`expr substr "${_ss_instr}" ${_ss_spos} ${_ss_hlen}`"
        else
            _ss_outstr="${_ss_instr}"
        fi

        echo "${_ss_outstr}"
    }

    #
    # get_last_day_of_month
    # ---------------------
    #
    # get last day of month
    #
    # Parameters:      $1    date string: yyyy-mm[-dd], if no date
    #                        is given the current date is used
    #
    # Output:          date string
    #
    get_last_day_of_month()
    {
        local _ld_lastday
        local _ld_month
        local _ld_year

        # get the command line input(day month year)
        if [ $# -ne 1 ]
        then
            # use current date
            _ld_year=`date +'%Y'`
            _ld_month=`date +'%m'`
        else
            _ld_year=`echo ${1} |cut -d- -f1`
            _ld_month=`echo ${1}|cut -d- -f2`
        fi

        _ld_lastday=`cal ${_ld_month} ${_ld_year} | awk 'NF != 0{ last = $0 }; END{ print last }' |  awk '{ print $NF }'`

        # print formated date
        date -d "${_ld_year}-${_ld_month}-${_ld_lastday}" +'%Y-%m-%d'
    }

    # get_yesterday
    # -------------
    #
    # get previous day of of given date
    #
    # Parameters:      $1    date string: yyyy-mm-dd, if no date
    #                        is given the current date will be used
    #
    # Output:          date string
    #
    get_yesterday()
    {
        local _gy_date
        local _gy_day
        local _gy_month
        local _gy_prev_month
        local _gy_prev_year
        local _gy_year

        # get the command line input(day month year)
        if [ $# -ne 1 ]
        then
            # use current date
            _gy_year=`date +'%Y'`
            _gy_month=`date +'%m'`
            _gy_day=`date +'%d'`
        else
            _gy_year=`echo ${1} |cut -d- -f1`
            _gy_month=`echo ${1}|cut -d- -f2`
            _gy_day=`echo ${1}  |cut -d- -f3`
        fi

        if [ ${_gy_day} -eq 1 ]
        then
            # get last day of previous month
            if [ ${_gy_month} -eq 1 ]
            then
                # last month of previous year
                _gy_prev_year=`expr ${_gy_year} - 1`
                _gy_date=`get_last_day_of_month "${_gy_prev_year}-12-01"`
            else
                # previous month
                _gy_prev_month=`expr ${_gy_month} - 1`
                _gy_date=`get_last_day_of_month "${_gy_year}-${_gy_prev_month}-01"`
            fi
        else
            _gy_date="${_gy_year}-${_gy_month}-`expr ${_gy_day} - 1`"
        fi

        # print formated date
        date -d "${_gy_date}" +'%Y-%m-%d'
    }

    #
    # get_tomorrow
    # ------------
    #
    # get next day of of given date
    #
    # Parameters:      $1    date string: yyyy-mm-dd, if no date
    #                        is given the current date will be used
    #
    # Output:          date string
    #
    get_tomorrow()
    {
        local _gt_day
        local _gt_lastday
        local _gt_month
        local _gt_year

        # get the command line input(day month year)
        if [ $# -ne 1 ]
        then
            # use current date
            _gt_year=`date +'%Y'`
            _gt_month=`date +'%m'`
            _gt_day=`date +'%d'`
        else
            _gt_year=`echo ${1} |cut -d- -f1`
            _gt_month=`echo ${1}|cut -d- -f2`
            _gt_day=`echo ${1}  |cut -d- -f3`
        fi

        # get last day of the month use cal command, discard blank lines,
        # take last field of last line, first awk command is used to get
        # the last useful line of the calendar cmd, second awk command is
        # used to get the last field of this last useful line, NF is no.
        # of fields, $NF is value of last field
        _gt_lastday=`cal ${_gt_month} ${_gt_year} | awk 'NF != 0{ last = $0 }; END{ print last }' |  awk '{ print $NF }'`

        # if it is the last day of the month
        if [ ${_gt_day} -eq ${_gt_lastday} ]
        then
            # make the day as 01
            _gt_day=01

            # if it is the last month of the year
            if [ ${_gt_month} -eq 12 ]
            then
                # make the month as 01
                _gt_month=01

                # increment the year by one
                _gt_year=`expr ${_gt_year} + 1`
            else
                # increment the month by one
                _gt_month=`expr ${_gt_month} + 1`
            fi
        else
            # increment the day by one
            _gt_day=`expr ${_gt_day} + 1`
        fi

        # print formated date
        date -d "${_gt_year}-${_gt_month}-${_gt_day}" +'%Y-%m-%d'
    }

    # get_diff_days
    # -------------
    #
    # get number of days between two dates
    #
    # Switch:          $1    optional: --with-sign - output value with leading +/- sign
    #
    # Parameters:      $1    date string: yyyy-mm-dd, if no date
    #                        is given -1 will be returned
    #                  $2    date string: yyyy-mm-dd, if no date
    #                        is given the current date will be used
    #
    # Output:          date string
    #
    get_diff_days ()
    {
        local _gdd_with_sign=0
        if [ "$1" = '--with-sign' ]
        then
            _gdd_with_sign=1
            shift
        fi
        local _gdd_date_val1
        local _gdd_date_val2
        local _gdd_diff_days=''
        local _gdd_diff_secs

        # get the command line input
        if [ -n "${1}" ]
        then
            if [ -n "`echo "${1}" | sed 's/^[0-9 :-]*//g'`" ]
            then
                # date includes timezone, like e.g. '2020-07-10 23:13 CEST'
                _gdd_date_val1=`date +'%s' -d "${1}"`
            else
                # append default time zone UTC
                _gdd_date_val1=`date +'%s' -d "${1} 00:00:00 UTC"`
            fi

            if [ -z "${2}" ]
            then
                _gdd_date_val2=`date +'%s' -d "00:00:00 UTC"`
            else
                if [ -n "`echo "${2}" | sed 's/^[0-9 :-]*//g'`" ]
                then
                    # date includes timezone, like e.g. '2020-07-10 23:13 CEST'
                    _gdd_date_val2=`date +'%s' -d "${2}"`
                else
                    # append default time zone UTC
                    _gdd_date_val2=`date +'%s' -d "${2} 00:00:00 UTC"`
                fi
            fi

            if [ ${_gdd_date_val1} -eq ${_gdd_date_val2} ]
            then
                # same day
                _gdd_diff_days=0
            else
                # dates differ
                _gdd_diff_secs=`expr ${_gdd_date_val1} - ${_gdd_date_val2}`

                # devide by number of seconds per day
                _gdd_diff_days=`expr ${_gdd_diff_secs} \/ 86400`
            fi
        fi

        if [ ${_gdd_with_sign} -eq 1 ]
        then
            # prepend leading + sign
            echo "${_gdd_diff_days}" | sed 's/^\([0-9]\)/+\1/'
        else
            # strip-off leading +/- sign
            echo "${_gdd_diff_days}" | sed 's/^[+-]//'
        fi
    }

    # get_diff_dates
    # --------------
    #
    # get number of years, month, days, hours, minutes and seconds
    # between two dates
    #
    # Parameters:      $1    date string: yyyy-mm-dd, if no date
    #                        is given -1 will be returned
    #                  $2    date string: yyyy-mm-dd, if no date
    #                        is given the current date will be used
    #
    # Output:          date diff string
    #
    get_diff_dates ()
    {
        local _gdd_date_val1
        local _gdd_date_val2
        local _gdd_diff_days
        local _gdd_diff_secs
        local _gdd_days
        local _gdd_operator
        local _gdd_temp
        local _gdd_years

        if [ $# -ge 1 ]
        then
            _gdd_date_val1=`date +'%s' -ud "${1}"`

            if [ $# -ge 2 ]
            then
                _gdd_date_val2=`date +'%s' -ud "${2}"`
            else
                # use current date
                _gdd_date_val2=`date +'%s'`
            fi

            if [ ${_gdd_date_val1} -gt ${_gdd_date_val2} ]
            then
                # date1 greater than date2
                _gdd_diff_secs=`expr ${_gdd_date_val1} - ${_gdd_date_val2}`
            elif [ ${_gdd_date_val2} -gt ${_gdd_date_val1} ]
            then
                # date2 greater than date1
                _gdd_diff_secs=`expr ${_gdd_date_val2} - ${_gdd_date_val1}`
            else
                # date2 equal date1
                _gdd_diff_secs=0
            fi

            if [ ${_gdd_diff_secs} -ne 0 ]
            then
                _gdd_diff_days=''

                # years
                _gdd_temp=`date -d@${_gdd_diff_secs} +'%Y'`
                _gdd_years=`expr ${_gdd_temp} - 1970`

                if [ ${_gdd_years} -gt 0 ]
                then
                    _gdd_diff_days="${_gdd_years} years "
                fi

                # months
                _gdd_temp=`date -d@${_gdd_diff_secs} +'%m' | sed 's/^0//'`
                _gdd_months=`expr ${_gdd_temp} - 1`

                _gdd_operator='ge'
                if [ -z "${_gdd_diff_days}" ]
                then
                    _gdd_operator='gt'
                fi

                if [ ${_gdd_months} -${_gdd_operator} 0 ]
                then
                    if [ ${_gdd_months} -eq 1 ]
                    then
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_months} month "
                    else
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_months} months "
                    fi
                fi

                # days
                _gdd_temp=`date -d@${_gdd_diff_secs} +'%d' | sed 's/^0//'`
                _gdd_days=`expr ${_gdd_temp} - 1`

                _gdd_operator='ge'
                if [ -z "${_gdd_diff_days}" ]
                then
                    _gdd_operator='gt'
                fi

                if [ ${_gdd_days} -${_gdd_operator} 0 ]
                then
                    if [ ${_gdd_days} -eq 1 ]
                    then
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_days} day "
                    else
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_days} days "
                    fi
                fi

                # hours
                _gdd_temp=`date -d@${_gdd_diff_secs} +'%H' | sed 's/^0//'`
                _gdd_hours=`expr ${_gdd_temp} - 1`

                _gdd_operator='ge'
                if [ -z "${_gdd_diff_days}" ]
                then
                    _gdd_operator='gt'
                fi

                if [ ${_gdd_hours} -${_gdd_operator} 0 ]
                then
                    if [ ${_gdd_hours} -eq 1 ]
                    then
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_hours} hour "
                    else
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_hours} hours "
                    fi
                fi

                # minute
                _gdd_temp=`date -d@${_gdd_diff_secs} +'%M' | sed 's/^0//'`
                _gdd_minutes=`expr ${_gdd_temp} - 1`

                _gdd_operator='ge'
                if [ -z "${_gdd_diff_days}" ]
                then
                    _gdd_operator='gt'
                fi

                if [ ${_gdd_minutes} -${_gdd_operator} 0 ]
                then
                    if [ ${_gdd_minutes} -eq 1 ]
                    then
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_minutes} minute "
                    else
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_minutes} minutes "
                    fi
                fi

                # seconds
                _gdd_seconds=`date -d@${_gdd_diff_secs} +'%S' | sed 's/^0//'`

                _gdd_operator='ge'
                if [ -z "${_gdd_diff_days}" ]
                then
                    _gdd_operator='gt'
                fi

                if [ ${_gdd_seconds} -${_gdd_operator} 0 ]
                then
                    if [ ${_gdd_seconds} -eq 1 ]
                    then
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_seconds} second"
                    else
                        _gdd_diff_days="${_gdd_diff_days}${_gdd_seconds} seconds"
                    fi
                else
                    _gdd_diff_days="both dates are the same"
                fi
            else
                _gdd_diff_days="both dates are the same"
            fi
        else
            # invalid number of parameters given
            _gdd_diff_days=-1
        fi

        echo "${_gdd_diff_days}"
    }

    # sec_to_formated_time
    # --------------------
    #
    # convert seconds to a formated time "[HH:]MM:SS"
    #
    # Parameters:      $1  seconds
    #                  $2  'full-length' or empty ''
    #
    # Output:          formated time "[HH:]MM:SS"
    #
    sec_to_formated_time ()
    {
        local _stft_length
        local _stft_ret
        local _stft_value

        _stft_value=`echo "${1}" | sed 's/[^0-9]*//g'`
        _stft_length=`echo "${2}" | tr '[:upper:]' '[:lower:]'`
        _stft_ret=''

        if [ -n "${_stft_value}" ]
        then
            if [ ${_stft_value} -lt 3600 -a "${_stft_length}" != 'full-length' ]
            then
                # MM:SS
                _stft_ret=`date --date="@${_stft_value}" -u +'%M:%S'`
            elif [ ${_stft_value} -lt 86400 ]
            then
                # HH:MM:SS
                _stft_ret=`date --date="@${_stft_value}" -u +'%H:%M:%S'`
            else
                _stft_ret="value to big"
            fi
        fi

        echo "${_stft_ret}"
    }

    # formated_time_to_sec
    # --------------------
    #
    # convert formated time "[HH:]MM:SS" to seconds
    #
    # Parameters:      $1  formated time "[HH:]MM:SS"
    #
    # Output:          seconds
    #
    formated_time_to_sec ()
    {
        local _ftts_count
        local _ftts_result
        local _ftts_time
        local _ftts_hour
        local _ftts_min
        local _ftts_sec

        _ftts_time="${1}"
        _ftts_result=''

        if [ -n "${_ftts_time}" ]
        then
            _ftts_count=`echo "${_ftts_time}" | awk -F: '{print NF}'`

            case ${_ftts_count} in
                3 )
                    _ftts_hour=`echo "${_ftts_time}" | cut -d: -f1`
                    _ftts_min=`echo "${_ftts_time}"  | cut -d: -f2`
                    _ftts_sec=`echo "${_ftts_time}"  | cut -d: -f3`
                    ;;
                2 )
                    _ftts_hour=0
                    _ftts_min=`echo "${_ftts_time}" | cut -d: -f1`
                    _ftts_sec=`echo "${_ftts_time}" | cut -d: -f2`
                    ;;
                1 )
                    _ftts_hour=0
                    _ftts_min=0
                    _ftts_sec=`echo "${_ftts_time}" | cut -d: -f1`
                    ;;
                * )
                    echo "error in function 'formated_time_to_sec', invalid time format!"
                    ;;
            esac

            _ftts_result=`echo "(${_ftts_hour} * 60 * 60) + (${_ftts_min} * 60) + ${_ftts_sec}" | bc`
        fi

        echo "${_ftts_result}"
    }

    # unit_to_numeric
    # ---------------
    #
    # convert integer value including unit to a pure integer value
    #
    # Parameters:      $1  value incl. unit (k)ilo, (m)ega, (g)iga, (t)erabyte
    #
    # Output:          pure integer value
    #
    unit_to_numeric ()
    {
        local _u2n_ret
        local _u2n_unit
        local _u2n_value

        _u2n_value=`echo ${1} | sed -e 's/[kKmMgGtT]//g' -e 's/,/\./g'`
        _u2n_unit=`echo ${1} | sed 's/[0-9.,]//g'`

        case ${_u2n_unit} in
            k|K)
                # kilobyte given - *1024
                # 1. calculate, 2. round, 3. take integer
                _u2n_ret=`bc <<< "${_u2n_value} * 1024 + 0.5" | sed 's/[.,].*$//'`
                ;;
            m|M)
                # megabyte given - *1024*1024
                # 1. calculate, 2. round, 3. take integer
                _u2n_ret=`bc <<< "${_u2n_value} * 1048576 + 0.5" | sed 's/[.,].*$//'`
                ;;
            g|G)
                # gigabyte given - *1024*1024*1024
                # 1. calculate, 2. round, 3. take integer
                _u2n_ret=`bc <<< "${_u2n_value} * 1073741824 + 0.5" | sed 's/[.,].*$//'`
                ;;
            t|T)
                # terabyte given - *1024*1024*1024*1024
                # 1. calculate, 2. round, 3. take integer
                _u2n_ret=`bc <<< "${_u2n_value} * 1099511627776 + 0.5" | sed 's/[.,].*$//'`
                ;;
            *)
                # return original value
                _u2n_ret=${1}
                ;;
        esac

        echo ${_u2n_ret}
    }

    # numeric_to_unit
    # ---------------
    #
    # convert a pure integer value to value including unit (divisor: 1024)
    #
    # Parameters:      $1  pure integer value
    #                  $2  optional, unit string, default: '. k M G T P'
    #                  $3  optional, number of decimal figures
    #
    # Output:          value incl. unit (k)ilo, (M)ega, (G)iga, (T)era, (P)eta,
    #                  by default rounded with 3 decimals
    #
    numeric_to_unit ()
    {
        local _n2u_curr_unit=''
        local _n2u_curr_value=''
        local _n2u_default_units=". k M G T P"
        local _n2u_idx
        local _n2u_maxidx
        local _n2u_mode
        local _n2u_value=${1}
        local _n2u_unit=${2}
        local _n2u_decimals=${3}
        local _n2u_zero_string

        # set unit automatically
        if [ -z "${_n2u_unit}" ]
        then
            _n2u_unit='a'
        fi

        # set default number of decimals
        if [ -z "${_n2u_decimals}" ]
        then
            _n2u_decimals='3'
        fi

        if [ -n "${_n2u_value}" ]
        then
            if [ "${_n2u_unit}" = 'a' ]
            then
                # automatic unit mode, set to max value
                _n2u_mode='==AUTO-MODE=='

                _n2u_idx=1
                _n2u_maxidx=`echo ${_n2u_default_units} | wc -w`
                while [ ${_n2u_idx} -le ${_n2u_maxidx} ]
                do
                    if [ -z "${_n2u_curr_value}" ]
                    then
                        _n2u_curr_value=${_n2u_value}
                    fi

                    _n2u_int_value=`echo "${_n2u_curr_value}" | sed 's/^\(.*\)\..*$/\1/'`

                    if [ ${_n2u_int_value} -ge 1024 ]
                    then
                        # devide value
                        _n2u_curr_value=`echo "${_n2u_curr_value}/1024" | bc -l`
                        _n2u_int_value=`echo "${_n2u_curr_value}" | sed 's/^\(.*\)\..*$/\1/'`
                    else
                        break
                    fi

                    # get current unit
                    _n2u_idx=`expr ${_n2u_idx} + 1`
                    _n2u_curr_unit=`echo "${_n2u_default_units}" | cut -d' ' -f${_n2u_idx}`

                done
            else
                _n2u_mode='==MANUAL-MODE=='

                _n2u_idx=1
                _n2u_maxidx=1
                _n2u_unit_found=0
                for STR in ${_n2u_default_units}
                do
                    if [ "${STR}" = "${_n2u_unit}" ]
                    then
                        _n2u_unit_found=1
                        break
                    fi

                    _n2u_maxidx=`expr ${_n2u_maxidx} + 1`
                done

                if [ ${_n2u_unit_found} -eq 0 ]
                then
                    _n2u_maxidx=1
                fi

                while [ ${_n2u_idx} -le ${_n2u_maxidx} ]
                do
                    if [ -z "${_n2u_curr_value}" ]
                    then
                        _n2u_curr_value=${_n2u_value}
                    fi

                    # devide value
                    _n2u_curr_value=`echo "${_n2u_curr_value}/1024" | bc -l`
                    _n2u_int_value=`echo "${_n2u_curr_value}" | sed 's/^\(.*\)\..*$/\1/'`

                    # get current unit
                    _n2u_idx=`expr ${_n2u_idx} + 1`
                    _n2u_curr_unit=`echo "${_n2u_default_units}" | cut -d' ' -f${_n2u_idx}`

                    if [ "${_n2u_unit}" = "${_n2u_curr_unit}" ]
                    then
                        break
                    fi
                done
            fi
        else
            # error
            _n2u_curr_value='empty'
        fi

        if [ "${_n2u_curr_unit}" = '.' ]
        then
            _n2u_unit=''
        fi

        # check decimal value
        echo "${_n2u_curr_value}" | grep -q '\.'

        if [ $? -eq 0 ]
        then
            # decimal separator found, get decimal value
            _n2u_int_decimals=`echo "${_n2u_curr_value}" | sed 's/^.*\.\(.*\)$/\1/'`

            if [ -n "${_n2u_int_decimals}" ]
            then
                # decimal value not empty, go on...
                if [ ${_n2u_decimals} -gt 0 ]
                then
                    # by default a decimal value should be printed, go on...
                    if [ `echo "${_n2u_curr_value} > 0" | bc -l` -eq 1 ]
                    then
                        # decimal value is greater than 0, round it
                        _n2u_zero_string=`printf %${_n2u_decimals}s | tr ' ' '0'`
                        _n2u_curr_value=`echo "${_n2u_curr_value}+.${_n2u_zero_string}5" | bc -l`
                    else
                        # do not print '0' decimal value
                        _n2u_decimals=0
                    fi
                fi
            else
                # do not print '0' decimal value
                _n2u_decimals=0
            fi
        else
            # do not print '0' decimal value
            _n2u_decimals=0
        fi

        # output formatted value
        printf "%.${_n2u_decimals}f ${_n2u_curr_unit}\n" ${_n2u_curr_value}
    }

    # abs_path
    # --------
    #
    # return absolute path to a file
    #
    # Parameters:      $1    path of file
    #
    # Output:          absolute path of file
    #
    abs_path ()
    {
        cd "$(dirname "$1")"
        printf "$(pwd)/$(basename "$1")\n"
        cd "${OLDPWD}"
    }

    # delay_script_exec
    # -----------------
    #
    # Parameters:      $1    name/regexp to identify current process
    #                        e.g. '${pgmname}.*--single'
    #                  $2    delay of next check in seconds, def: 10s
    #
    delay_script_exec ()
    {
        local _dse_delay
        local _dse_first_pid
        local _dse_pid_names
        local _dse_proc_name

        _dse_proc_name="$1"
        _dse_delay="$2"

        if [ -z "${_dse_delay}" ]
        then
            _dse_delay=10
        fi

        if [ -n "${_dse_proc_name}" ]
        then
            _dse_first_pid=''

            until [ "$$" = "${_dse_first_pid}" ]
            do
                # check if current process is the first one on the list.
                # use the ps command with the '-ww' switch to make sure
                # that really all parameters # are shown, independently
                # of the screen width.
                _dse_pid_names=`ps -efww | grep -v "grep " | grep -E "${_dse_proc_name}"`
                _dse_first_pid=`echo "${_dse_pid_names}" | awk -F" " '{print $2}' | head -1`

                if [ "$$" != "${_dse_first_pid}" ]
                then
                    # delay script execution
                    sleep ${_dse_delay}
                fi
            done
        else
            # error
            echo "error: delay_script_exec needs a process name!"
        fi
    }

    # format_version
    # --------------
    #
    # Return a formatted version number
    #
    # Parameters:      $1    count of version fields, or empty
    #                  $2    version number, e.g. 1.2.3
    #
    # Output:          reformated version number, optionally
    #                  enhanced to a given number of fields
    #
    format_version ()
    {
        local _fv_fields
        local _fv_idx
        local _fv_max_idx
        local _fv_new_version
        local _fv_value
        local _fv_version

        _fv_fields="$1"
        _fv_version="$(echo "$2" | tr -d ' ')"

        if [ -n "${_fv_fields}" ]
        then
            # number of version fields
            _fv_max_idx="${_fv_fields}"
        else
            # count number of version fields, e.g. 1.2.3 -> 3 fields
            _fv_max_idx=$(echo "${_fv_version}" | awk -F"." '{print NF}')
        fi

        if [ ${_fv_max_idx} -eq 2 ]
        then
            # make sure that at least one field separator (dot) exists
            _fv_version="$(echo "${_fv_version}." | sed 's/\.\.*$/\./')"
        fi

        _fv_idx=1
        _fv_new_version=''
        while [ ${_fv_idx} -le ${_fv_max_idx} ]
        do
            # loop through each version field, reduce number of zeros in zero-only string to one
            _fv_value=$(echo "${_fv_version}" | cut -d. -f${_fv_idx} | sed -e 's/^00*/0/' -e 's/0\([1-9]\)/\1/')

            if [ -z "${_fv_value}" ]
            then
                # empty field, set to zero
                if [ -z "${_fv_new_version}" ]
                then
                    # first figure
                    _fv_new_version="0"
                else
                    # separate figure by dot
                    _fv_new_version="${_fv_new_version}.0"
                fi
            else
                # version number given
                if [ -z "${_fv_new_version}" ]
                then
                    # first figure
                    _fv_new_version="${_fv_value}"
                else
                    # separate figure by dot
                    _fv_new_version="${_fv_new_version}.${_fv_value}"
                fi
            fi

            _fv_idx=`expr ${_fv_idx} + 1`
        done

        echo "${_fv_new_version}"
    }

    # compare_version
    # ---------------
    #
    # Return the result of a version number comparison
    #
    # Inspired by: https://stackoverflow.com/questions/4023830/how-to-
    #     compare-two-strings-in-dot-separated-version-format-in-bash
    #
    # Switch:          [--text]       - output result in text form
    #
    # Parameters:      $1             - first version number
    #                  $2             - second version number
    #
    # Output:          0 / installed  - version1 = version2
    #                  1 / old        - version1 < version2
    #                  2 / new        - version1 > version2
    #
    compare_version ()
    {
        local _cv_count1
        local _cv_count2
        local _cv_max
        local _cv_pos
        local _cv_retval
        local _cv_rettext
        local _cv_text
        local _cv_version1
        local _cv_version2

        _cv_text=0
        if [ "$1" = '--text' ]
        then
            _cv_text=1
            shift
        fi

        # count number of fields
        _cv_count1=$(echo "$1" | awk -F"." '{print NF}')
        _cv_count2=$(echo "$2" | awk -F"." '{print NF}')

        if [ ${_cv_count1} -gt ${_cv_count2} ]
        then
            _cv_max=${_cv_count1}
        else
            _cv_max=${_cv_count2}
        fi

        # format version number
        _cv_version1=`format_version "${_cv_max}" "$1"`
        _cv_version2=`format_version "${_cv_max}" "$2"`

        if [ "${_cv_version1}" = "${_cv_version2}" ]
        then
            # version1 = version2
          # printf "${_cv_version1}\t${_cv_version2}\t=\n"
            _cv_retval=0
            _cv_rettext='installed'
        else
            # check if version1 is found in first line of sorted output
            _cv_pos=`printf "${_cv_version1}\n${_cv_version2}\n" | sort -V | grep -n "^${_cv_version1}$" | cut -d: -f1`

            if [ ${_cv_pos} -eq 1 ]
            then
                # version1 < version2
              # printf "${_cv_version1}\t${_cv_version2}\t<\n"
                _cv_retval=1
                _cv_rettext='old'
            else
                # version1 > version2
              # printf "${_cv_version1}\t${_cv_version2}\t>\n"
                _cv_retval=2
                _cv_rettext='new'
            fi
        fi

        if [ ${_cv_text} -eq 1 ]
        then
            echo "${_cv_rettext}"
        else
            return ${_cv_retval}
        fi
    }

    # imaputf7_encode
    # ---------------
    #
    # Return IMAP-UTF7 encoded string from normal string
    #
    # Parameters:      $1   normal string
    #
    # Output:          IMAP-UTF7 encoded string
    #
    # Example:         'Müller&Meier-sind-böse' -> 'M&APw-ller&-Meier-sind-b&APY-se'
    #
    imaputf7_encode()
    {
        local _iue_src_str="$1"
        local _iue_separator='/'
        local _iue_max
        local _iue_idx
        local _iue_char=''
        local _iue_hex=''
        local _iue_dest_str=''
        local _iue_tmp_str=''

        local _iue_iconv='/usr/bin/iconv'

        if [ ! -x "${_iue_iconv}" ]
        then
            echo "ERROR: function requires the '${_iue_iconv}' program which couldn't be found!"
            exit 1
        else
            if [ -n "${dovecot_separator}" ]
            then
                _iue_separator="${dovecot_separator}"
            fi

            _iue_max=`expr length "${_iue_src_str}"`

            _iue_idx=1
            while [ ${_iue_idx} -le ${_iue_max} ]
            do
                # get character and hex value
                _iue_char=`echo "${_iue_src_str}" | cut -c ${_iue_idx}`
                _iue_hex=`echo "${_iue_char}" | tr -d '\n' | xxd -i | sed -e 's/ *0x//g' -e 's/,/ /g'`

              # DEBUG="IDX:${_iue_idx} CHAR:${_iue_char} HEX:${_iue_hex}"

                case ${_iue_hex} in
                    2[0-5]|2[7-9a-f]|[3-7][0-9a-e] )
                        # append the following characters (0x20-0x25 and 0x27-0x7e):
                        # 0-9 A-Z a-z ' ' ! " # $ % ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ ` { | } ~
                        if [ -n "${_iue_tmp_str}" ]
                        then
                            # append encoded tmp string and character
                            _iue_dest_str="${_iue_dest_str}`echo "${_iue_tmp_str}${_iue_char}" | \
                                          iconv -f utf-8 -t utf-7 | tr '\+' '\&'`"
                            _iue_tmp_str=''
                        else
                            # append character
                            _iue_dest_str="${_iue_dest_str}${_iue_char}"
                        fi
                        ;;
                    26 )
                        # append '&' (ampersand) (0x26):
                        _iue_dest_str="${_iue_dest_str}&-"
                        ;;
                    5f )
                        # append '_' (underscore) (0x5f):
                        _iue_dest_str="${_iue_dest_str}_"
                        ;;
                    0a )
                        # skip new line character (0x0a):
                        ;;
                    * )
                        # append to tmp string
                        _iue_tmp_str="${_iue_tmp_str}${_iue_char}"
                        ;;
                esac

                _iue_idx=`expr ${_iue_idx} + 1`
            done

            if [ -n "${_iue_tmp_str}" ]
            then
                # append encoded tmp string
                _iue_dest_str="${_iue_dest_str}`echo "${_iue_tmp_str}" | iconv -f utf-8 -t utf-7 | tr '\+' '\&'`-"
                _iue_tmp_str=''
            fi

            # check if source string already contains encoded dots
            echo "${_iue_src_str}" | grep -q '\\2e'

            if [ $? -eq 0 ]
            then
                # 1. make sure that '\2e' entries are output as '\\2e'
                # 2. replace '/' (slash) by '.' (dot)
                _iue_dest_str="`echo "${_iue_dest_str}" | sed -e 's|^\([^\\]*\)\\\2e|\1\\\\\\\\2e|g' -e "s#${_iue_separator}#.#g"`"
            else
                echo "${_iue_src_str}" | grep -q '/'

                if [ $? -eq 0 ]
                then
                    # 1. replace '.' (dot) by '\2e'
                    # 2. replace '/' (slash) by '.' (dot)
                    _iue_dest_str="`echo "${_iue_dest_str}" | sed -e 's|\.|\\\\2e|g' -e "s#${_iue_separator}#.#g"`"
                fi
            fi

            # output result
            echo "${_iue_dest_str}"
        fi
    }

    # imaputf7_decode
    # ---------------
    #
    # Return normal string from IMAP-UTF7 encoded string
    #
    # Parameters:      $1   IMAP-UTF7 encoded string
    #
    # Output:          normal string
    #
    # Example:         'M&APw-ller&-Meier-sind-b&APY-se' -> 'Müller&Meier-sind-böse'
    #
    imaputf7_decode()
    {
        local _iud_src_str="$1"
        local _iud_separator='/'
        local _iud_dest_str=''
        local _iud_left_str=''
        local _iud_exit=0

        local _iud_iconv='/usr/bin/iconv'

        if [ ! -x "${_iud_iconv}" ]
        then
            echo "ERROR: function requires the '${_iud_iconv}' program which couldn't be found!"
            exit 1
        else
            if [ -n "${dovecot_separator}" ]
            then
                _iud_separator="${dovecot_separator}"
            fi

            # 'Ablage.Nachbarn.Heinz\\2eMeier'
            # 1. replace '.' (dot) by '/' (slash)
            # 2. replace '\\\\' by '&&' (placeholder)
            # 3. replace '&&2e' (placeholder) by '.' (dot)
            # 4. replace all '&[^-]' matches by '+' (plus) - don't replace '&-'!
            _iud_src_str=`echo "${_iud_src_str}" | sed -e "s#\.#${_iud_separator}#g" |
                          tr '\\\\' '&' | sed -e 's/&&2e/\./g' -e 's/\&\([^-]\)/\+\1/g'`

            while [ ${_iud_exit} -eq 0 ]
            do
                # check if string contains '&-'
                echo "${_iud_src_str}" | grep -q '&-'

                if [ $? -eq 0 ]
                then
                    # match found
                    # 5. cut of left part of string and convert it from utf-7 to utf-8
                    # 6. preserve right part of string for next loop
                    _iud_left_str=`echo "${_iud_src_str}" | sed 's/^\(.*\)\&\-.*$/\1/' | 
                                   ${_iud_iconv} -f utf-7 -t utf-8`
                    _iud_src_str=`echo "${_iud_src_str}" | sed 's/^.*\&\-\(.*\)$/\1/'`

                    # 7. append '&' to left part of string
                    # 8. append the result to the destination string
                    _iud_dest_str="${_iud_dest_str}${_iud_left_str}&"
                else
                    # no match found
                    #  9. convert remaining string from utf-7 to utf-8
                    # 10. append the result to the destination string
                    _iud_dest_str="${_iud_dest_str}`echo "${_iud_src_str}" |
                                   ${_iud_iconv} -f utf-7 -t utf-8`"
                    _iud_exit=1
                fi
            done

            # output result
            echo "${_iud_dest_str}"
        fi
    }

    # mime_encode
    # -----------
    #
    # Return a MIME encoded string from a normal text string
    #
    # Switches:        $1   Optional: '--b64' - force Base64 encoded string
    #                                 '--qp'  - force Quoted Printable encoded
    #                                           string
    #                  ! Without one of these switches the encoder will decide
    #                  ! on its own, which of the encodings will be used.
    #
    # Parameters:      $1   text string to be encoded
    #
    mime_encode()
    {
        local _men_encoding='MIME-Header'
        local _men_perl='/usr/bin/perl'

        if [ "$1" = '--b64' -o "$1" = '-b64' ]
        then
            _men_encoding='MIME-B'
            shift
        elif [ "$1" = '--qp' -o "$1" = '-qp' ]
        then
            _men_encoding='MIME-Q'
            shift
        fi

        if [ ! -x "${_men_perl}" ]
        then
            echo "ERROR: function requires the '${_men_perl}' program which couldn't be found!"
            exit 1
        else
            # encode string
            echo "$1" | perl -CS -MEncode -ne "print encode(\"${_men_encoding}\", \$_)"
        fi
    }

    # mime_decode
    # -----------
    #
    # Return a normal text string from a MIME encoded input
    #
    # Parameters:      $1   MIME encoded string to be decoded
    #
    mime_decode()
    {
        local _mde_perl='/usr/bin/perl'

        if [ ! -x "${_mde_perl}" ]
        then
            echo "ERROR: function requires the '${_mde_perl}' program which couldn't be found!"
            exit 1
        else
            # decode string and concatenate multiple output lines
            echo "$1" | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | sed -e :a -e '/$/N; s/\n //; ta'
        fi
    }

#============================================================================

    #
    # is_root
    # -------
    #
    # check if root equivalent user
    #
    # Parameters:      $1    username
    #
    # Output:          0 - yes, root user
    #                  1 - no
    #
    is_root ()
    {
        local _ir_ret
        local _ir_user_name
        local _ir_user_uid

        _ir_user_name="$1"
        _ir_ret=1

        # read uid
        _ir_user_uid=`getent passwd ${_ir_user_name} | cut -d: -f3 | tail -n1`

        if [ ${_ir_user_uid} -eq 0 ]
        then
            # equivalent root user
            _ir_ret=0
        fi

        return ${_ir_ret}
    }

    #
    # is_numeric
    # ----------
    #
    # check if numeric value
    #
    # Parameters:      $1    value
    #
    # Output:          0 - yes, numeric value
    #                  1 - no, no numeric value
    #
    is_numeric ()
    {
        if [ -z "$1" ]
        then
            # empty string
            return 1
        else
            echo "$1"|grep -q '^[0-9]*$'
        fi
    }

    #
    # is_date
    # -------
    #
    # check if date value
    #
    # Parameters:      $1 - date string [yyyy-mm-dd]
    #
    # Output:          0     - ok
    #                  bit-1 - invalid year
    #                  bit-2 - invalid month
    #                  bit-3 - invalid day
    #
    is_date ()
    {
        local _id_dd
        local _id_mm
        local _id_yy
        local _id_dd_ok
        local _id_mm_ok
        local _id_yy_ok
        local _id_ret

        _id_yy=`echo ${1} | cut -d- -f1`
        _id_mm=`echo ${1} | cut -d- -f2`
        _id_dd=`echo ${1} | cut -d- -f3`

        # check year
        _id_yy_ok=1
        if [ -n "${_id_yy}" ]
        then
            if is_numeric ${_id_yy}
            then
                if [ ${_id_yy} -ge 2007 -a ${_id_yy} -le 2200 ]
                then
                    _id_yy_ok=0
                fi
            fi
        fi

        # check month
        _id_mm_ok=2
        if [ -n "${_id_mm}" ]
        then
            if is_numeric ${_id_mm}
            then
                if [ ${_id_mm} -ge 1 -a ${_id_mm} -le 12 ]
                then
                    _id_mm_ok=0
                fi
            fi
        fi

        # check day
        _id_dd_ok=4
        if [ -n "${_id_dd}" ]
        then
            if is_numeric ${_id_dd}
            then
                if [ ${_id_dd} -ge 1 -a ${_id_dd} -le 31 ]
                then
                    # check if day is not a leap-day, e.g. 2018-02-29
                    date --date "${1}" >/dev/null 2>&1

                    if [ $? -eq 0 ]
                    then
                        _id_dd_ok=0
                    fi
                fi
            fi
        fi

        _id_ret=`expr ${_id_yy_ok} + ${_id_mm_ok} + ${_id_dd_ok}`

        return ${_id_ret}
    }

    #
    # is_time
    # -------
    #
    # check if time value
    #
    # Parameters:      $1 - time string [HH:MM:SS]
    #
    # Output:          0     - ok
    #                  bit-1 - invalid hour
    #                  bit-2 - invalid minute
    #                  bit-3 - invalid second
    #
    is_time ()
    {
        local _it_hh
        local _it_mm
        local _it_ss
        local _it_hh_ok
        local _it_mm_ok
        local _it_ss_ok
        local _it_ret

        _it_hh=`echo ${1} | cut -d: -f1`
        _it_mm=`echo ${1} | cut -d: -f2`
        _it_ss=`echo ${1} | cut -d: -f3`

        # check hours
        _it_hh_ok=1
        if [ -n "${_it_hh}" ]
        then
            if is_numeric ${_it_hh}
            then
                if [ ${_it_hh} -ge 0 -a ${_it_hh} -le 24 ]
                then
                    _it_hh_ok=0
                fi
            fi
        fi

        # check minutes
        _it_mm_ok=1
        if [ -n "${_it_mm}" ]
        then
            if is_numeric ${_it_mm}
            then
                if [ ${_it_mm} -ge 0 -a ${_it_mm} -le 59 ]
                then
                    _it_mm_ok=0
                fi
            fi
        fi

        # check seconds
        _it_ss_ok=1
        if [ -n "${_it_ss}" ]
        then
            if is_numeric ${_it_ss}
            then
                if [ ${_it_ss} -ge 0 -a ${_it_ss} -le 60 ]
                then
                    _it_ss_ok=0
                fi
            fi
        fi

        _it_ret=`expr ${_it_hh_ok} + ${_it_mm_ok} + ${_it_ss_ok}`

        return ${_it_ret}
    }

    #
    # called_from_install
    # -------------------
    #
    # check if script has been called during the installation process
    #
    # Parameters:      $1/$2 --package <package name>
    #
    # Output:          0 - called during install process
    #                  1 - not called during install process
    #
    called_from_install ()
    {
        local _cfi_debug_output
        local _cfi_package
        local _cfi_parent_cmd
        local _cfi_ret

        _cfi_exit=0
        while [ ${_cfi_exit} -eq 0 ]
        do
            case $1 in
                *-pack|*-package )
                    _cfi_package="$2"
                    shift; shift
                    ;;
                * )
                    _cfi_exit=1
                    ;;
            esac
        done

        _cfi_ret=1
        _cfi_debug_output=/root/.eisfair-debug-output

        # get calling script/program
        # --------------------------
        #
        # during an installation:
        # /tmp/install.sh                          : /bin/bash /usr/share/eisman/eisman_install.sh --auto --url=file:///...
        # /tmp/preinstall.sh                       : /bin/bash /usr/share/eisman/eisman_install.sh --unstable ...
        #                                          : /usr/bin/gawk -v packages= ... -v action=install -v url=file:///...
        # /var/install/config.d/<package>-update.sh: sh /tmp/install.sh file:///...
        # /var/install/config.d/<package>.sh       : sh /tmp/install.sh file:///...
        # /var/install/deinstall/<package>         : /bin/bash /usr/share/eisman/eisman_uninstall.sh --update ...
        #
        # from the command line:
        # /var/install/config.d/<package>.sh       : bash -rcfile .bashrc
        #
        # from the ECE:
        # /var/install/config.d/<package>.sh       : /bin/sh /var/install/bin/edit -apply /etc/config.d/<package>

        _cfi_parent_cmd="$(ps -o args= $PPID)"
        echo "${_cfi_parent_cmd}" | grep -q -E "/install.sh|/eisman_install.sh|/eisman_uninstall.sh *--update|/usr/bin/gawk -v packages="
        _cfi_ret=$?

        if [ -f ${_cfi_debug_output} -a -n "${_cfi_package}" ]
        then
            # check if an override has been set
            grep -q "^[[:space:]]*${_cfi_package}[[:space:]]*$" ${_cfi_debug_output}

            if [ $? -eq 0 ]
            then
                _cfi_ret=2
            fi
        fi

        return ${_cfi_ret}
    }

    #
    # host_exists
    # -----------
    #
    # Parameters:      $1 - url
    #
    # Output:          0  - host exists
    #                  1  - host doesn't exist
    #
    host_exists ()
    {
        local _he_ipaddr
        local _he_retval
        local _he_srvname
        local _he_urlstr

        _he_retval=1
        _he_urlstr="${1}"

        # check if dnsip program exists
        type dnsip >/dev/null 2>/dev/null

        if [ $? -eq 0 ]
        then
            _he_srvname="`echo "${_he_urlstr}" | sed -e 's#^.*[http|ftp].*://##' -e 's#/.*$##'`"
            _he_ipaddr=`dnsip ${_he_srvname}`

            if [ -n "${_he_ipaddr}" ]
            then
                # host found
                _he_retval=0
            fi
        fi

        return ${_he_retval}
    }

    #
    # get_ipaddr_port
    # ---------------
    #
    # Parameters:      $1 - requested data: --type, --addr (default), --port, --all
    #                  $2 - ip address with/without port
    #                  $3 - if --port or --all is used, and optional default porti
    #                       can be defined
    #
    # Output:          result based on data requested using $1
    #                  if '--all' is used, the different options are separated using
    #                  a pipe character: <ip-version (4|6)>|<ip-address>|<ip-port>
    #
    get_ipaddr_port ()
    {
        local _gip_reqtype=`echo "$1" | tr [:upper:] [:lower:]`
        local _gip_ipaddrport=`echo "$2" | sed 's/ *//g'`
        local _gip_def_ipport=`echo "$3" | sed 's/^\([0-9]*\).*$/\1/'`
        local _gip_res_iptype=4
        local _gip_res_ipaddr=''
        local _gip_res_ipport=''
        local _gip_ccount=0
        local _gip_bcount=0

        if [ -n "${_gip_ipaddrport}" ]
        then
            _gip_ccount=`echo "${_gip_ipaddrport}" | awk -F':' '{print NF-1}'`
            _gip_bcount=`echo "${_gip_ipaddrport}" | awk -F"]:" '{print NF-1}'`

            case ${_gip_ccount} in
                0 )
                    # IPv4 - ip address / host name  without port
                    _gip_res_ipaddr="${_gip_ipaddrport}"

                    if [ -n "${_gip_def_ipport}" ]
                    then
                        _gip_res_ipport="${_gip_def_ipport}"
                    fi
                    ;;
                1 )
                    # IPv4 - ip address / host name with port
                    _gip_res_ipaddr=`echo "${_gip_ipaddrport}" | cut -d':' -f1`
                    _gip_res_ipport=`echo "${_gip_ipaddrport}" | cut -d':' -f2`
                    ;;
                * )
                    # IPv6 - ip address
                    _gip_res_iptype=6
                    _gip_res_ipaddr=`echo "${_gip_ipaddrport}" | sed 's/^\[*\([a-f0-9:]*\)\]*\]*.*$/\1/'`

                    if [ ${_gip_bcount} -eq 0 ]
                    then
                        # ip address without port
                        if [ -n "${_gip_def_ipport}" ]
                        then
                            _gip_res_ipport="${_gip_def_ipport}"
                        fi
                    else
                        # ip address with port
                        _gip_res_ipport=`echo "${_gip_ipaddrport}" | sed 's/^\[*[a-f0-9:]*\]*\]:\([0-9]*\)$/\1/'`
                    fi
                    ;;
            esac
        fi

        case ${_gip_reqtype} in
            -*all )
                echo "${_gip_res_iptype}|${_gip_res_ipaddr}|${_gip_res_ipport}"
                ;;
            -*type )
                echo "${_gip_res_iptype}"
                ;;
            -*port )
                echo "${_gip_res_ipport}"
                ;;
            -*addr|* )
                # default: ip address
                echo "${_gip_res_ipaddr}"
                ;;
        esac
    }

fi