# -*- mode: sh -*-
###
### config hook
###

dbc_go(){
    local f db host newhost port oldhosts do_config _preconf_list _s _t STATE iformat ifile install_question migrating userdb_prio _dbc_dbadmin_set_to_default _dbc_dbuser_set_to_default _dbc_basepath_set_to_default
    . /usr/share/dbconfig-common/dpkg/common
    _dbc_debug "(config) dbc_go() $@"

    ## With dbconfig-no-thanks installed we don't need to do anything.
    if dbc_no_thanks ; then
        return 0
    fi

    dbc_config "$@"

    db_capb backup

    # only do this on install/reconfigure
    if [ "$dbc_command" != "configure" ] && [ "$dbc_command" != "reconfigure" ];
    then
        return 0
    fi

    ##
    ## register all the dbconfig-common questions
    ##
    ## note that this can fail in the case that dbconfig-common is being
    ## installed at the same time as the dependant package and the latter
    ## is preconfigured before we are (no way to avoid this without being
    ## in base).  in this case we gracefully exit and defer to the second
    ## time the config script is run by dpkg in the postinst.   note if that
    ## "hack" in dpkg ever goes away we can still work around the issue so
    ## i think it's fair to avoid over-complicating things in the dependency
    ## chain.
    ##
    if ! dbc_register_debconf; then
        _dbc_debug "dbconfig-common not yet setup, deferring configuration."
        return 0
    fi

    # make sure debconf is up to date with on-disk configuration
    dbc_read_package_config
    dbc_preseed_package_debconf

    if [ "$dbc_dbtype" = "pgsql" ] ; then
        db_get $dbc_package/pgsql/method
        if [ "$RET" = "unix socket" ] ; then
            db_set $dbc_package/pgsql/method "Unix socket"
        elif [ "$RET" = "tcp/ip" ] ; then
            db_set $dbc_package/pgsql/method "TCP/IP"
        elif [ "$RET" = "tcp/ip + ssl" ] ; then
            db_set $dbc_package/pgsql/method "TCP/IP + SSL"
        fi
    fi

    # Find out whether the database has been purged on a previous occasion. If
    # so, we'll have to give the user a chance to re-install it.
    #
    # We need some check if the package is removed, but not purged.
    # An alternative over using this is to add a new internal template.
    # The drawback of this solution is that preseeding the answer to
    # the purge question is ignored (reset) during package installation
    # so if required this needs to be preseeded when removing the package.
    db_get $dbc_package/purge
    if [ "$RET" = true ]; then
        dbc_command=reconfigure
    fi

    # if we are here due to an error, raising question priorities
    if [ "$dbc_retry_after_error" ] ;then
        dbc_remote_questions_priority="$dbc_prio_high"
        dbc_prio_low="$dbc_prio_high"
        dbc_prio_medium="$dbc_prio_high"
        dbc_prio_high="$dbc_prio_critical"
        # And make sure that whatever the package that calls us sets it to,
        # after one iteration we should be high enough for something to happen,
        # else we may be caught in a loop.
        dbc_prio_critical="critical"
    fi

    # check out if they're migrating from a non-dbc version
    if [ "$dbc_oldversion" ] && [ "$dbc_first_version" ] && \
           dpkg --compare-versions "$dbc_first_version" gt "$dbc_oldversion"; then
        migrating="yes"
    fi

    # if this is a frontend app, then the user/db type questions get
    # a raised priority
    if [ "$dbc_frontend" ]; then
        userdb_prio="$dbc_prio_medium"
    else
        userdb_prio="$dbc_prio_low"
    fi

    # the first question we ask will differ depending on how we're invoked
    if [ "$migrating" ] || [ "$dbc_retry_after_error" = "upgrade" ] ; then
        install_question="$dbc_package/dbconfig-upgrade"
    elif [ "$dbc_command" = "configure" ]; then
        install_question="$dbc_package/dbconfig-install"
    else
        install_question="$dbc_package/dbconfig-reinstall"
        # if we are reconfiguring (via dpkg-reconfigure), also leave a hint
        # for our future postinst selves so we know we *should* run the code
        # that would otherwise think we were upgrading
        db_set $dbc_package/internal/reconfiguring true
    fi

    ##
    ## start new dbc upgrade section
    ##
    # if there is a previously existing version already installed
    # *and* the maintainer has provided the first version that used
    # dbconfig-common *and*  this version is newer than the
    # previously installed version... do the dbc import stuff.
    if [ "$migrating" ]; then
        dbc_migrate
    fi

    # and start our beautiful state-machine
    # we start in STATE=1 (install_question) in all but one situation:
    #   - we're installing a frontend/readonly app
    if [ ! "$dbc_frontend" ]; then
        STATE=1
    else
        STATE=2
    fi
    dbc_statefull=true # Make sure that we can also backup from password questions
    while true; do
        case "$STATE" in
            # state 1 - ask if they want our help at all
            1)
                db_input $dbc_prio_high $install_question || true
                ;;
            # state 2 - check to see if they do.
            #         - see if this is an upgrade newly supporting dbc
            #         - multidb support step 1
            2)
                db_get $install_question
                if [ "$RET" != "true" ]; then
                    db_set $dbc_package/internal/skip-preseed true
                    return 0;
                fi
                db_set $dbc_package/dbconfig-install true

                ##
                ## start multidb section
                ##
                # if the dbtype is hardcoded (using config.mysql, etc), use that
                if [ "$dbc_hardcoded_dbtype" ]; then
                    dbc_dbtype=$dbc_hardcoded_dbtype
                    # else if the package supports multiple dbtypes, help them pick one
                elif [ "$dbc_dbtypes" ]; then
                    # If $dbc_dbtypes only contains one element, we don't really need
                    # to choose But let's inform the administrator with updated
                    # template text.

                    # If dbc_dbtype isn't already set (from conf file) then use the
                    # default as our first guess.
                    if [ ! "$dbc_dbtype" ]; then
                        dbc_dbtype="$dbc_default_dbtype"
                    else
                        # If $dbc_dbtype not in $dbc_dbtypes we have a weird
                        # situation. This can happen during dpkg-reconfigure or
                        # upgrades where the original cmd-line $dbc_dbtype package got
                        # removed in the mean time (let's hope it is on purpose). This
                        # could also happen when a package dropped support (it should
                        # handle that itself) for the previously selected dbtype.
                        # Note: if this happens during reconfigure, we warned the user
                        # already. Idea: we check if we are reconfiguring, then just
                        # continue if not, we raise an error. But if we are recovering
                        # from the error in the "retry" mode, we should just
                        # continue. Hmm, there is no other error raised during config.
                        if ! echo "$dbc_dbtypes" | grep -q "$dbc_dbtype"; then
                            dbc_logline "The originally selected database type is currently not installed, assuming this is on purpose."
                            dbc_dbtype="$dbc_default_dbtype"
                        fi
                    fi
                    db_set $dbc_package/database-type "$dbc_dbtype"
                    db_input $dbc_prio_high $dbc_package/database-type || true
                fi
                ;;
            # state 3 - multidb support part 2, pre-seeding, get conn. method
            3)
                if [ "$dbc_dbtypes" ]; then
                    db_get $dbc_package/database-type && dbc_dbtype="$RET"
                    # now that we have a dbtype, reload common to set other defaults
                    dbc_config "$@"
                    # Also re-register the templates, as otherwise $dbvendor will
                    # not be replaced in the following questions
                    dbc_register_debconf
                fi

                # there's a bit more to do with rdbms that support authentication
                if echo "$dbc_authenticated_dbtypes" | grep -q "$dbc_dbtype"; then
                    # If these haven't been specified, use defaults. Track that
                    # we did that, so we can do it again when the admin backed
                    # up the debconf questions and choose an other dbtype.
                    # See bts #663234
                    if [ ! "$dbc_dbadmin" ] || [ "$_dbc_dbadmin_set_to_default" = true ]; then
                        _dbc_dbadmin_set_to_default=true
                        dbc_dbadmin="$dbc_default_admin"
                    fi
                    if [ ! "$dbc_dbuser" ] || [ "$_dbc_dbuser_set_to_default" = true ]; then
                        _dbc_dbuser_set_to_default=true
                        dbc_dbuser="$dbc_default_dbuser"
                    fi
                fi

                if echo "$dbc_fs_dbtypes" | grep -q "$dbc_dbtype"; then
                    # if these haven't been specified, use defaults
                    if [ ! "$dbc_basepath" ] || [ "$_dbc_basepath_set_to_default" = true ]; then
                        _dbc_basepath_set_to_default=true
                        dbc_basepath="$dbc_default_basepath";
                    fi
                fi

                # same code in dpkg/common
                if [ ! "$dbc_dbname" ]; then
                    dbc_dbname=$(echo $dbc_package | tr -d +-.);
                fi

                # pre-seed any already defined values into debconf as defaults
                db_set $dbc_package/db/dbname "$dbc_dbname"
                if [ "$dbc_upgrade" ]; then
                    db_set $dbc_package/dbconfig-upgrade "$dbc_upgrade"
                fi
                if [ "$dbc_remove" ]; then
                    db_set $dbc_package/dbconfig-remove "$dbc_remove"
                fi
                if echo "$dbc_authenticated_dbtypes" | grep -q "$dbc_dbtype"; then
                    db_set $dbc_package/db/app-user "$dbc_dbuser""@""$dbc_dballow"
                    if [ "$dbc_dbpass" ]; then
                        db_set $dbc_package/$dbc_dbtype/app-pass "$dbc_dbpass"
                        db_set $dbc_package/app-password-confirm "$dbc_dbpass"
                        # Not sure if the above actually has any effect if the
                        # passwords aren't "seen", but during error handling
                        # and reconfiguring we need to allow changing the
                        # password.
                        if [ "$dbc_command" != "reconfigure" ] && [ ! "$dbc_retry_after_error" ]; then
                            db_fset $dbc_package/$dbc_dbtype/app-pass seen true
                            db_fset $dbc_package/app-password-confirm seen true
                        fi
                    fi
                    # This "if" itself should be redundant, as it is filled above.
                    if [ "$dbc_dbadmin" ]; then
                        # This may be overruled by MySQL/MariaDB localhost settings
                        db_set $dbc_package/$dbc_dbtype/admin-user "$dbc_dbadmin"
                    fi
                fi
                if echo "$dbc_remote_dbtypes" | grep -q "$dbc_dbtype"; then
                    if [ "$dbc_dbserver" ]; then
                        db_set $dbc_package/remote/host "$dbc_dbserver"
                    fi
                    if [ "$dbc_dbport" ]; then
                        db_set $dbc_package/remote/port "$dbc_dbport"
                    fi
                    if [ "$dbc_ssl" = "true" ] && [ "$dbc_dbtype" = "pgsql" ]; then
                        db_set $dbc_package/pgsql/method "TCP/IP + SSL"
                    fi
                    db_input $dbc_remote_questions_priority $dbc_package/$dbc_dbtype/method || true
                fi
                if echo "$dbc_fs_dbtypes" | grep -q "$dbc_dbtype"; then
                    # if these haven't been specified, use defaults
                    if [ "$dbc_basepath" ]; then
                        db_set $dbc_package/db/basepath "$dbc_basepath"
                    fi
                fi

                ;;
            # state 4 - do stuff based on the connection method
            4)
                db_get $dbc_package/$dbc_dbtype/method && dbc_method="$RET"

                if echo "$dbc_remote_dbtypes" | grep -q "$dbc_dbtype"; then
                    # if package/method == tcp/ip or tcp/ip + ssl
                    if [ "$dbc_method" != "Unix socket" ]; then
                        # look at the hosts used in any other dbconfig-using
                        # package, and create a list of hosts.
                        _preconf_list=$( (
                                           for f in /etc/dbconfig-common/*.conf; do
                                               test -f $f || continue
                                               eval $(dbconfig-generate-include --dbserver=_s $f | grep -v '^#')
                                               [ "$_s" ] && echo $_s
                                           done
                                           echo localhost
                                       ) | sort | uniq)
                        # turn the list into a comma separated list if it exists
                        # and then substitute it into the list of available hosts
                        _preconf_list=$(echo $_preconf_list | sed -e 's/ /, /g')
                        _preconf_list="new host, $_preconf_list"
                        db_subst $dbc_package/remote/host hosts "$_preconf_list"
                        # and then ask them for one
                        db_input $dbc_prio_high $dbc_package/remote/host || true
                        # but if it is unix socket, forget all the host stuff
                    else
                        db_reset $dbc_package/remote/host || true
                        db_reset $dbc_package/remote/newhost || true
                        db_reset $dbc_package/remote/port || true
                    fi
                fi
                ;;
            # state 5 - get host / port info if necessary
            5)
                if echo "$dbc_remote_dbtypes" | grep -q "$dbc_dbtype"; then
                    if [ "$dbc_method" != "Unix socket" ]; then
                        if [ "$_preconf_list" ]; then
                            db_get $dbc_package/remote/host
                            host=$RET
                        fi

                        # if they've chosen "new host" or the host list was empty
                        if [ ! "$host" ] || [ "$host" = "new host" ]; then
                            # prompt them for a new hostname
                            db_input $dbc_prio_high $dbc_package/remote/newhost || true
                        fi
                    fi
                fi
                ;;
            # state 6 - do stuff based on host/port selection
            6)
                if echo "$dbc_remote_dbtypes" | grep -q "$dbc_dbtype"; then
                    if [ "$dbc_method" != "Unix socket" ]; then
                        if [ ! "$host" ] || [ "$host" = "new host" ]; then
                            db_get $dbc_package/remote/newhost
                            newhost="$RET"

                            # add the new host to the existing list of hosts
                            db_metaget $dbc_package/remote/host choices
                            oldhosts="$RET"
                            db_subst $dbc_package/remote/host hosts "$oldhosts, $newhost"
                            db_set $dbc_package/remote/host "$newhost"
                            db_fset $dbc_package/remote/host seen true
                            dbc_dbserver="$newhost"
                        else
                            # set the "newhost" to the selected host, because
                            # the second time through the configure script we'll
                            # need this set
                            db_set $dbc_package/remote/newhost "$host"
                            dbc_dbserver="$host"
                        fi

                        # on what port?
                        db_input $dbc_remote_questions_priority $dbc_package/remote/port || true
                    fi
                fi
                ;;
            # state 7 - pgsql & mysql specific auth stuff, part 1
            7)
                if [ "$dbc_dbtype" = "pgsql" ] && [ ! "$dbc_frontend" ]; then
                    # postgresql provides multiple auth types, and ssl
                    # get the admin auth method
                    db_input $dbc_prio_low $dbc_package/pgsql/authmethod-admin || true
                fi
                if [ "$dbc_dbtype" = "mysql" ] && [ ! "$dbc_frontend" ]; then
                    # variable to specify a different mysql authentication plugin
                    # to be used for users created - by the dbconfig-common consumer -
                    # through dbconfig-common. dbc_authplugin="default" won't specify
                    # any authentication plugin to MySQL, allowing it to use its default,
                    # which might change from version to version.
                    if [ "$dbc_authplugin" ]; then
                        db_set $dbc_package/mysql/authplugin "$dbc_authplugin"
                    fi
                    # allows authplugin to be queried/changed in low priority mode
                    db_input $dbc_prio_low $dbc_package/mysql/authplugin || true
                fi
                ;;
            # state 8 - pgsql auth stuff, part 2
            8)
                if [ "$dbc_dbtype" = "pgsql" ] && [ ! "$dbc_frontend" ]; then
                    db_get $dbc_package/pgsql/authmethod-admin && authmethod_admin="$RET"
                    db_input $dbc_prio_medium $dbc_package/pgsql/authmethod-user || true
                fi
                ;;
            # state 9 - admin/app user/pass, dbname
            9)
                # get the name of the database to use
                db_input $userdb_prio $dbc_package/db/dbname || true

                if echo "$dbc_fs_dbtypes" | grep -q "$dbc_dbtype"; then
                    # check the path / permissions to install to
                    db_input $dbc_prio_low $dbc_package/db/basepath || true
                fi

                if echo "$dbc_authenticated_dbtypes" | grep -q "$dbc_dbtype"; then

                    db_input $userdb_prio $dbc_package/db/app-user || true
                    if ! dbc_get_app_pass ; then
                        # Make sure that we can also backup from password questions
                        STATE=$(($STATE - 1))
                        continue
                    fi

                    # who's the admin user
                    if [ ! "$dbc_frontend" ]; then
                        # Note: dpkg/prerm has the same code
                        if [ "$dbc_dbtype" = mysql ] && _dbc_mysql_get_debian_sys_maint ; then
                            db_set $dbc_package/$dbc_dbtype/admin-user "$dbc_dbadmin"
                            db_fset $dbc_package/$dbc_dbtype/admin-user seen true
                            db_set $dbc_package/$dbc_dbtype/admin-pass "$dbc_dbadmpass"
                            db_fset $dbc_package/$dbc_dbtype/admin-pass seen true
                        fi
                        db_input $userdb_prio $dbc_package/$dbc_dbtype/admin-user || true
                    fi
                fi
                ;;
            # * - end state
            *)
                break
                ;;
        esac
        if db_go; then
            STATE=$(($STATE + 1))
        else
            STATE=$(($STATE - 1))
        fi

        if [ $STATE -lt 1 ]; then
            if [ "$dbc_config_allow_backup" ]; then
                return 30
            fi
            exit 10
        fi
    done

    dbc_statefull=""
    db_set $dbc_package/internal/skip-preseed true
}

dbc_migrate() {

    # if dbc_load_include is set, determine the format
    # and location of the old config file
    if [ "$dbc_load_include" ]; then
        iformat=$(echo $dbc_load_include | cut -d: -f1)
        ifile=$(echo $dbc_load_include | cut -d: -f2-)
    fi

    ##
    ## if they want to import settings from a previous
    ## non-dbc version, do that and mark the questions
    ## skipped
    ##
    if [ -z "$ifile" ] || [ ! -f "$ifile" ]; then
        return
    fi

    dbc_logpart "migrating old settings into dbconfig-common: "
    if [ "$dbc_debug" ]; then
        _dbc_debug "dbconfig-load-include $dbc_load_include_args -f $iformat $ifile"
        dbconfig-load-include $dbc_load_include_args -f $iformat $ifile
    fi
    eval $(dbconfig-load-include $dbc_load_include_args -f $iformat $ifile)
    if [ "$?" != "0" ]; then
        dbc_logline "failed"
        return
    fi

    # the load script needs to return at least a database type, if it's
    # not a single-dbtype package
    dbc_dbtype=${dbc_dbtype:-${dbc_hardcoded_dbtype:-}}
    if [ -z "$dbc_dbtype" ]; then
        dbc_logline "failed"
        return
    fi

    # if the dbtype is hardcoded, reset it no matter what
    # dbconfig-load-include tells us
    if [ "$dbc_hardcoded_dbtype" ]; then
        dbc_dbtype="$dbc_hardcoded_dbtype"
    fi

    for f in database-type $dbc_dbtype/method db/dbname; do
        db_fset $dbc_package/$f seen true || true
    done
    if echo "$dbc_authenticated_dbtypes" | grep -q "$dbc_dbtype"; then
        for f in pgsql/authmethod-admin pgsql/authmethod-user $dbc_dbtype/admin-user db/app-user; do
            db_fset $dbc_package/$f seen true || true
        done
        db_set $dbc_package/db/app-user "$dbc_dbuser"
        db_set $dbc_package/$dbc_dbtype/app-pass "$dbc_dbpass"
        db_set $dbc_package/app-password-confirm "$dbc_dbpass"
    fi
    if echo "$dbc_remote_dbtypes" | grep -q "$dbc_dbtype"; then
        for f in remote/host remote/newhost remote/port ; do
            db_fset $dbc_package/$f seen true || true
        done
        db_set $dbc_package/remote/host "$dbc_dbserver"
        db_set $dbc_package/remote/newhost "$dbc_dbserver"
        db_set $dbc_package/remote/port "$dbc_dbport"
        if [ "$dbc_dbserver" ]; then
            if [ "$dbc_ssl" ]; then
                db_set $dbc_package/$dbc_dbtype/method "TCP/IP + SSL"
            else
                db_set $dbc_package/$dbc_dbtype/method "TCP/IP"
            fi
        fi
    fi

    db_set $dbc_package/database-type $dbc_dbtype
    db_set $dbc_package/db/dbname "$dbc_dbname"

    dbc_logline "done"
}
