#----------------------------------------------------------------------------
# /var/install/include/jedlib - library for eisfair scripts
#
# Copyright (c) 2001-2007 The Eisfair Team, c/o Frank Meyer, frank(at)eisfair(dot)org
#
# Creation:     2006-03-10  jed
# Last Update:  $Id: jedlib 11504 2007-07-16 14:42:29Z jed $
#
# 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_passwdfile=/etc/passwd
_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.
#
# Routines:
#   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
#
# Functions:
#   is_root()               check if root equivalent user
#   is_numeric()            check if numeric value
#
#----------------------------------------------------------------------------

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

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

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

    # 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()
    {
        _w2cl_label='Info:'
        _w2cl_fup=0
        _w2cl_opt=''

        while [ 1 ]
        do
            case "$1"
            in
                -header) _w2cl_opt='-e'; _w2cl_label="\nDate: `date`\n"; shift;;
                -info)   _w2cl_label='  Info:';    shift;;
                -warn)   _w2cl_label='  Warning:'; shift;;
                -error)  _w2cl_label='  Error:';   shift;;
                -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
        _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
                    echo -e "\nDate: `date`\n"
                fi

                echo ${_w2cl_opt} "${_w2cl_label} $*"
            fi
        } >> ${configlog_file}.tmp
    }

    #
    # 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()
    {
        _ccl_idxmax=$1

        if [ "${_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 doesn´t contain log entries
                rm -f ${configlog_file}
            fi
        fi

        #
        # append new log entries if some entries exist.
        #
        if [ -f ${configlog_file}.tmp ]
        then
            # add newly created logfile to default logfile
            cat ${configlog_file}.tmp >> ${configlog_file}
            rm ${configlog_file}.tmp

            # create newline marker file
            echo "new loglines added" > ${configlog_file}.newlines
        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()
    {
        if [ -f ${configlog_file} -a -f ${configlog_file}.newlines ]
        then
            sleep 5
            clrhome
            mecho -info "Configuration messages appeared, please check configuration"
            mecho
            /var/install/bin/doc ${configlog_file}
            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()
    {
        _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()
    {
        _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()
    {
        _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 ()
    {
        _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 ()
    {
        _gfa_name="$1"

        if [ -f ${_gfa_name} -o -d ${_gfa_name} ]
        then
            # 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
            _gfa_str=`ls -ld ${_gfa_name} | tr -s ' ' ':'`

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

            # file ownership data, owner, group
            _gfa_access=`echo ${_gfa_str} | cut -d: -f1`
            _gfa_owner=`echo ${_gfa_str}  | cut -d: -f3`
            _gfa_group=`echo ${_gfa_str}  | cut -d: -f4`

            # change IFS
            IFS=${_gfa_oldifs}

            # extract text strings
            _gfa_txt2=`echo ${_gfa_access} | cut -c2-4`
            _gfa_txt3=`echo ${_gfa_access} | cut -c5-7`
            _gfa_txt4=`echo ${_gfa_access} | cut -c8-10`

            # convert to binary values
            _gfa_bin2=`echo ${_gfa_txt2} | tr '\-rwxsS' '011110'`
            _gfa_bin3=`echo ${_gfa_txt3} | tr '\-rwxsS' '011110'`
            _gfa_bin4=`echo ${_gfa_txt4} | tr '\-rwxtT' '011110'`
        
            # check if setuid bit has been set
            _gfa_dec1=0
            echo "${_gfa_txt2}" | grep -E -q "s|S"
            if [ $? -eq 0 ]
            then
                _gfa_dec1=`expr ${_gfa_dec1} + 4`
            fi

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

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

            # convert to decimal values
            _gfa_dec2=`echo "ibase=2;${_gfa_bin2}" | bc`
            _gfa_dec3=`echo "ibase=2;${_gfa_bin3}" | bc`
            _gfa_dec4=`echo "ibase=2;${_gfa_bin4}" | bc`

            # output: ownership data, owner, group
            echo "${_gfa_dec1}${_gfa_dec2}${_gfa_dec3}${_gfa_dec4}:${_gfa_owner}:${_gfa_group}"
        fi
    }

    #
    # set_accessrights
    # ----------------
    # set file/directory ownership and access rights
    #
    # Parameters:      $1    filename/directory
    #                  $2    string which contains access rights, owner and group
    #                        in the following format: 'mask:owner:group'
    #
    set_accessrights ()
    {
        _sfa_name="$1"
        _sfa_data="$2"

        if [ -f ${_sfa_name} -o -d ${_sfa_name} ]
        then
            # change IFS
            _gfa_oldifs=${IFS}
            IFS=' '

            # file ownership data, owner, group
            _sfa_access=`echo ${_sfa_data} | cut -d: -f1`
            _sfa_owner=`echo ${_sfa_data}  | cut -d: -f2`
            _sfa_group=`echo ${_sfa_data}  | cut -d: -f3`

            # change IFS
            IFS=${_gfa_oldifs}

            # set access rights
            chmod ${_sfa_access} ${_sfa_name}
            chown ${_sfa_owner}  ${_sfa_name}
            chgrp ${_sfa_group}  ${_sfa_name}
        fi
    }

    #
    # rand_char
    # ---------
    # return random char
    #
    # Output:          string which contains a random char
    #
    rand_char ()
    {
        # array of allowed characters
        # first character is a placebo and will never be used
        _rc_max=64
        _rc_chars=(a a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 \. \-)

        # initialize random number
        RANDOM=$$$(date +%s)

        _rc_nbr=$[ ( ${RANDOM} % ${_rc_max} ) + 1 ]

        echo ${_rc_chars[${_rc_nbr}]}
    }

    #
    # rand_string
    # -------------
    # return random string
    #
    # Parameters:      $1    length of string
    #
    # Output:          string which contains a random string
    #
    rand_string ()
    {
        _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}"
    }

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

    #
    # is_root
    # -------
    #
    # check if root equivalent user
    #
    # Parameters:      $1    username
    #
    # Output:          0 - yes, root user
    #                  1 - no
    #

    function is_root()
    {
        _ir_user_name="$1"
        _ir_ret=1

        # read uid
        _ir_user_uid=`grep "^${_ir_user_name}:" ${_jedlib_passwdfile} | cut -d: -f3`

        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
    #

    function is_numeric()
    {
        echo "$1"|grep -q '^[0-9]*$'
    }

fi