#!/bin/bash
#  _____               _           _
# |   __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# |   __|  _| -_| -_| . | . |     | . | . |   | -_|
# |__|  |_| |___|___|___|___|_|_|_|___|___|_|_|___|
#
#                              Freedom in the Cloud
#
# Install daemon for the web admin system
# See also freedombone-utils-webadmin
#
# License
# =======
#
# Copyright (C) 2018-2019 Bob Mottram <bob@freedombone.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

PROJECT_NAME='freedombone'

export TEXTDOMAIN=${PROJECT_NAME}-installer
export TEXTDOMAINDIR="/usr/share/locale"

# for outgoing smtp relay
source "/usr/share/${PROJECT_NAME}/base/${PROJECT_NAME}-base-email"

SSH_PORT=2222

INSTALL_STATE_FIRST_BOOT=0
INSTALL_STATE_WEBADMIN_PASSWORD_CTEATED=1
INSTALL_STATE_RUNNING_COMMAND=2
INSTALL_STATE_COMMAND_FAIL=3
INSTALL_STATE_COMMAND_SUCCESS=4

# Timeouts for various operations to ensure the system doesn't hang
APP_INSTALL_TIMEOUT_SEC=3600
BACKUP_TIMEOUT_SEC=7200
FORMAT_TIMEOUT_SEC=600

# file containing new password
IMAGE_PASSWORD_FILE=/root/login.txt

# Stores a list of drives when the system was first installed.
# This is used to detect drives later connected
DRIVES_BASELINE_FILE=/root/.drives_baseline

install_state=$INSTALL_STATE_FIRST_BOOT

CONFIGURATION_FILE="/root/${PROJECT_NAME}.cfg"
COMPLETION_FILE="/root/${PROJECT_NAME}-completed.txt"

# file containing a list of removed apps
REMOVED_APPS_FILE=/root/removed

# name of the app currently being installed
APP_BEING_INSTALLED=

# contains the blocked users and domains
FIREWALL_DOMAINS=/root/${PROJECT_NAME}-firewall-domains.cfg

# contains words or phrases to be blocked
MUTED_WORDS=/root/${PROJECT_NAME}-firewall-words.cfg

local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local

webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
default_domain_file="$webadmin_install_dir/.default_domain.txt"
scuttlebot_file="$webadmin_install_dir/.scuttlebot_invite.txt"
email_proxy_file="$webadmin_install_dir/.emailproxy.txt"
theme_file="$webadmin_install_dir/.theme.txt"
translations_import_file="$webadmin_install_dir/.translations_import.txt"
icecast_file="$webadmin_install_dir/.icecast.txt"
koel_file="$webadmin_install_dir/.koel.txt"
dlna_file="$webadmin_install_dir/.dlna.txt"
datlinks_file="$webadmin_install_dir/.datlinks.txt"
settings_updates_file="$webadmin_install_dir/.settingsupdates.txt"
ssh_file="$webadmin_install_dir/.ssh.txt"
smolrss_file="$webadmin_install_dir/.rssfeeds.txt"
syncthing_file="$webadmin_install_dir/.syncthing.txt"
appsettings_file="$webadmin_install_dir/.appsettings.txt"
factoryreset_file="$webadmin_install_dir/.factoryreset.txt"
upgrade_file="$webadmin_install_dir/.upgrade.txt"
language_file="$webadmin_install_dir/.language.txt"
system_monitor_file="$webadmin_install_dir/.system_monitor.txt"
dynamic_dns_file="$webadmin_install_dir/.dynamicdns.txt"
reset_file="$webadmin_install_dir/.reset.txt"
shutdown_file="$webadmin_install_dir/.shutdown.txt"
setup_file="$webadmin_install_dir/setup.txt"
domain_file="$webadmin_install_dir/.temp_domain.txt"
pending_removes="$webadmin_install_dir/pending_removes.txt"
pending_installs="$webadmin_install_dir/pending_installs.txt"
new_user_file="$webadmin_install_dir/.new_user.txt"
remove_user_file="$webadmin_install_dir/.remove_user.txt"
change_password_file="$webadmin_install_dir/changepassword.dat"
install_state_file="/root/.install_state.txt"
blocklist_file="$webadmin_install_dir/.blocklist.txt"
muted_words_file="$webadmin_install_dir/.blocklistwords.txt"
bridgeslist_file="$webadmin_install_dir/.bridgeslist.txt"
INSTALL_DIR=/root/build
webadmin_user='admin'
webadmin_temp_password_file=/root/.temp_webadmin_password
installer_script=/root/.fbone_installer.sh

# Used to initiate automatic backups
webadmin_prev_hour=99

# temporary backup and restore scripts
factoryreset_script=/root/.webadmin_factory_reset.sh
upgrade_script=/root/.webadmin_upgrade.sh
backup_script=/root/.webadmin_backup.sh
backup_keys_script=/root/.webadmin_backup_keys.sh
restore_script=/root/.webadmin_restore.sh
restore_keys_script=/root/.webadmin_restore_keys.sh
format_script=/root/.webadmin_format.sh
new_user_script=/root/.webadmin_new_user.sh
remove_user_script=/root/.webadmin_remove_user.sh
appsettings_script=/root/.webadmin_appsettings.sh

# Files used to initiate backup or restore manually from the web UI
backup_file="$webadmin_install_dir/.start_backup"
backup_keys_file="$webadmin_install_dir/.start_backup_keys"
restore_file="$webadmin_install_dir/.start_restore"
restore_keys_file="$webadmin_install_dir/.start_restore_keys"
format_file="$webadmin_install_dir/.start_format"

# These files contain the percentage progress
backup_progress_file=/root/.backup_progress.txt
restore_progress_file=/root/.restore_progress.txt
format_progress_file=/root/.format_progress.txt

# whether an automatically scheduled backup is running
running_auto_backup=
backup_drive_mounted=
USB_MOUNT=/mnt/usb

ICECAST_PORT=8005
ICECAST_DIR=/icestream
ICECAST_JINGLES=/jingles
liquidsoap_script=/etc/liquidsoapuser/radio.liq

webadmin_ipv4_address=
webadmin_monitor_ip_ctr=1


function homepage_create_qr_code {
    webadmin_onion_domain="$1"

    if [ ! -f /usr/local/bin/myqr ]; then
        echo -n "http://${webadmin_onion_domain}/home" | qrencode -t PNG -o "$homepage_install_dir/images/homepage_qrcode.png"
    else
        myqr "http://${webadmin_onion_domain}/home" -p "/root/${PROJECT_NAME}/img/onion.png" -c -v 8 -n "$homepage_install_dir/images/homepage_qrcode.png"
    fi
}

function web_create_homepage {
    homepage_install_dir="/var/www/${local_hostname}/htdocs/home"

    homepage_filename="$homepage_install_dir/index.html"
    homepage_about_filename="$homepage_install_dir/about.html"

    homepage_template_filename="$webadmin_install_dir/homepage_template.html"
    icons_dir="$homepage_install_dir/icons"

    if [ ! -d "$homepage_install_dir" ]; then
        mkdir -p "$homepage_install_dir"
    fi

    if [ ! -d "$icons_dir" ]; then
        mkdir -p "$icons_dir"
    fi

    # NOTE: Here we don't use the icons from the admin directory
    # because that is password controlled. So that any user on the system
    # can use the homepage the icons are copied over to the home directory

    # copy the icons
    cp -r "$webadmin_install_dir/icons"/*.png "$icons_dir"

    # copy the logo
    if [ ! -d "$homepage_install_dir/images" ]; then
        mkdir -p "$homepage_install_dir/images"
    fi
    cp "$webadmin_install_dir/images/logo.png" "$homepage_install_dir/images"

    # copy the script used for search
    cp "$webadmin_install_dir/search.php" "$homepage_install_dir"

    if [ ! -f "$homepage_template_filename" ]; then
        return
    fi
    cp "$homepage_template_filename" "$homepage_filename"

    # copy the about screen for homepage
    cp "$webadmin_install_dir/homepage_about.html" "$homepage_about_filename"

    # show onion address for homepage
    webadmin_onion_domain=$(cat /var/lib/tor/hidden_service_webadmin/hostname)
    sed -i "s|WEBADMINONIONADDRESS|${webadmin_onion_domain}|g" "$homepage_about_filename"
    homepage_create_qr_code "$webadmin_onion_domain"
}

function get_external_ipv4_address {
    ipv4_result=$(curl -s ipinfo.io/ip)
    if [[ "$ipv4_result" != *'<'* ]]; then
        echo "$ipv4_result"
    else
        echo ''
    fi
}

function web_admin_background_color {
    if ! grep -q 'WEBADMIN_BACKGROUND_COLOR=' "/root/${PROJECT_NAME}.cfg"; then
        echo 'WEBADMIN_BACKGROUND_COLOR=white' >> "/root/${PROJECT_NAME}.cfg"
    fi
    if ! grep -q 'WEBADMIN_FOREGROUND_COLOR=' "/root/${PROJECT_NAME}.cfg"; then
        echo 'WEBADMIN_FOREGROUND_COLOR=black' >> "/root/${PROJECT_NAME}.cfg"
    fi
    bg_color=$(grep "WEBADMIN_BACKGROUND_COLOR=" "/root/${PROJECT_NAME}.cfg" | awk -F '=' '{print $2}')
    fg_color=$(grep "WEBADMIN_FOREGROUND_COLOR=" "/root/${PROJECT_NAME}.cfg" | awk -F '=' '{print $2}')
    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local

    for webfile in "/var/www/${local_hostname}/htdocs/admin"/*.html; do
        if ! grep -q "background-color: ${bg_color};" "$webfile"; then
            sed -i "0,/background-color:.*/s//background-color: ${bg_color};/" "$webfile"
            sed -i "0,/ color:.*/s// color: ${fg_color};/" "$webfile"
        fi
        sed -i "s|color: blue|color: ${fg_color}|g" "$webfile"
        sed -i "s|color: darkblue|color: ${fg_color}|g" "$webfile"
    done

    # colors of the border around app categories
    apps_border_light=cfdde7
    apps_border_dark=1f5177

    search_background_light=5499ca
    search_background_dark=f9f3f3
    search_background_light2=fdfdfd
    search_background_dark2=144163

    # change colors on home screen
    sed -i "0,/background-color:.*/s//background-color: ${bg_color};/" "/var/www/${local_hostname}/htdocs/home/index.html"
    sed -i "0,/ color:.*/s// color: ${fg_color};/" "/var/www/${local_hostname}/htdocs/home/index.html"

    # change the search background
    if [[ "$bg_color" == 'white' ]]; then
        cp "/root/${PROJECT_NAME}/img/backgrounds/searx_light.png" "/etc/searx/searx/static/themes/courgette/img/bg-body-index.jpg"
        sed -i "s|$search_background_dark|$search_background_light|g" "/var/www/${local_hostname}/htdocs/admin/index.html"
        sed -i "s|$search_background_dark2|$search_background_light2|g" "/var/www/${local_hostname}/htdocs/admin/index.html"
        sed -i "s|$search_background_dark|$search_background_light|g" "/var/www/${local_hostname}/htdocs/home/index.html"
        sed -i "s|$search_background_dark2|$search_background_light2|g" "/var/www/${local_hostname}/htdocs/home/index.html"
        sed -i "s|$apps_border_dark|$apps_border_light|g" "/var/www/${local_hostname}/htdocs/admin/apps.html"
        sed -i "s|$apps_border_dark|$apps_border_light|g" "/var/www/${local_hostname}/htdocs/admin/apps_add.html"
    else
        cp "/root/${PROJECT_NAME}/img/backgrounds/searx_dark.png" "/etc/searx/searx/static/themes/courgette/img/bg-body-index.jpg"
        sed -i "s|$search_background_light|$search_background_dark|g" "/var/www/${local_hostname}/htdocs/admin/index.html"
        sed -i "s|$search_background_light2|$search_background_dark2|g" "/var/www/${local_hostname}/htdocs/admin/index.html"
        sed -i "s|$search_background_light|$search_background_dark|g" "/var/www/${local_hostname}/htdocs/home/index.html"
        sed -i "s|$search_background_light2|$search_background_dark2|g" "/var/www/${local_hostname}/htdocs/home/index.html"
        sed -i "s|$apps_border_light|$apps_border_dark|g" "/var/www/${local_hostname}/htdocs/admin/apps.html"
        sed -i "s|$apps_border_light|$apps_border_dark|g" "/var/www/${local_hostname}/htdocs/admin/apps_add.html"
    fi

    # change webmail theme
    if [ -f "/var/www/${local_hostname}/htdocs/mail/config/config.php" ]; then
        if [[ "$bg_color" == 'white' ]]; then
            sed -i 's|theme_default.*|theme_default = 54;|g' "/var/www/${local_hostname}/htdocs/mail/config/config.php"
        else
            sed -i 's|theme_default.*|theme_default = 55;|g' "/var/www/${local_hostname}/htdocs/mail/config/config.php"
        fi

        # remove the chosen theme parameter
        for filename in /var/local/squirrelmail/data/*.pref; do
            if grep -q 'chosen_theme' "$filename"; then
                sed -i '/chosen_theme/d' "$filename"
            fi
        done
    fi
}

function web_admin_create_app_descriptions {
    # this obtains the descriptions from each app and puts
    # them into a file which can then be used for translations
    FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"

    app_descriptions_file="$webadmin_install_dir/app_descriptions.txt"
    if [ -f "$app_descriptions_file" ]; then
        rm "$app_descriptions_file"
    fi
    touch "$app_descriptions_file"

    for filename in $FILES
    do
        app_name=$(echo "${filename}" | awk -F '-app-' '{print $2}')
        app_name_upper=$(echo "$app_name" | awk '{print toupper($0)}')

        if grep -q "${app_name_upper}_SHORT_DESCRIPTION=" "${filename}"; then
            app_short_description=$(grep "${app_name_upper}_SHORT_DESCRIPTION=" "${filename}" | head -n 1 | awk -F '=' '{print $2}' | sed 's/\$//g' | sed 's/"//g' | sed "s/'//g")
            if [ "$app_short_description" ]; then
                if ! grep -Fxq "$app_short_description" "$app_descriptions_file"; then
                    echo "$app_short_description" >> "$app_descriptions_file"
                fi
            fi
        fi

        if grep -q "${app_name_upper}_DESCRIPTION=" "${filename}"; then
            app_description=$(grep "${app_name_upper}_DESCRIPTION=" "${filename}" | head -n 1 | awk -F '=' '{print $2}' | sed 's/\$//g' | sed 's/"//g' | sed "s/'//g")
            if [ "$app_description" ]; then
                if ! grep -Fxq "$app_description" "$app_descriptions_file"; then
                    echo "$app_description" >> "$app_descriptions_file"
                fi
            fi
        fi
    done

    if [ -f "$app_descriptions_file" ]; then
        chown www-data:www-data "$app_descriptions_file"
    fi
}

function web_admin_translate_text {
    text="$1"
    DEFAULT_LANGUAGE=$(grep "DEFAULT_LANGUAGE=" "/root/${PROJECT_NAME}.cfg" | awk -F '=' '{print $2}')
    if [[ "$DEFAULT_LANGUAGE" == "en_GB"* ]]; then
        echo "$text"
        return
    fi
    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    translations_file="/var/www/${local_hostname}/htdocs/admin/translations/${DEFAULT_LANGUAGE}.txt"
    if [ -f "$translations_file" ]; then
        if grep -q "${text}|" "$translations_file"; then
            grep "${text}|" "$translations_file" | head -n 1 | awk -F '|' '{print $2}'
            return
        fi
    fi
    echo "$text"
}

function web_admin_translate {
    if ! grep -q 'DEFAULT_LANGUAGE=' "$CONFIGURATION_FILE"; then
        return
    fi
    language=$(grep 'DEFAULT_LANGUAGE=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
    if [ ! "$language" ]; then
        return
    fi

    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
    webadmin_homepage_dir="/var/www/${local_hostname}/htdocs/home"

    translations_file="$webadmin_install_dir/translations/${language}.txt"
    if [ ! -f "$translations_file" ]; then
        return
    fi

    declare -a translations_array
    readarray translations_array < "$translations_file"

    echo "Starting translations"
    i=0
    while (( ${#translations_array[@]} > i )); do
        translated_text=
        english_text=$(echo "${translations_array[i]}" | awk -F '|' '{print $1}')
        translated_text=$(echo "${translations_array[i]}" | awk -F '|' '{print $2}')
        if [ "$translated_text" ]; then

            # get the files containing this text
            # shellcheck disable=SC2207
            webfiles=($(grep -l ">$english_text<" "$webadmin_install_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "/translate=\"yes\"/s|>$english_text<|>$translated_text<|g" "${webfiles[j]}"
                j=$((j+1))
            done

            # get the files containing this button text
            # shellcheck disable=SC2207
            webfiles=($(grep -l "value=\"$english_text\"" "$webadmin_install_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "/translate=\"yes\"/s|value=\"$english_text\"|value=\"$translated_text\"|g" "${webfiles[j]}"
                j=$((j+1))
            done

            # get the alt text
            # shellcheck disable=SC2207
            webfiles=($(grep -l " alt=\"$english_text\"" "$webadmin_install_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "s| alt=\"$english_text\"| alt=\"$translated_text\"|g" "${webfiles[j]}"
                j=$((j+1))
            done

            # get titles
            # shellcheck disable=SC2207
            webfiles=($(grep -l " title=\"$english_text\">" "$webadmin_install_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "s| title=\"$english_text\">| title=\"$translated_text\">|g" "${webfiles[j]}"
                j=$((j+1))
            done

            # homepage -----------------------------------------------------------------------------
            # shellcheck disable=SC2207
            webfiles=($(grep -l ">$english_text<" "$webadmin_homepage_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "/translate=\"yes\"/s|>$english_text<|>$translated_text<|g" "${webfiles[j]}"
                j=$((j+1))
            done

            # shellcheck disable=SC2207
            webfiles=($(grep -l "value=\"$english_text\"" "$webadmin_homepage_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "/translate=\"yes\"/s|value=\"$english_text\"|value=\"$translated_text\"|g" "${webfiles[j]}"
                j=$((j+1))
            done

            # shellcheck disable=SC2207
            webfiles=($(grep -l " alt=\"$english_text\"" "$webadmin_homepage_dir"/*.html))

            # translate each file
            j=0
            while (( ${#webfiles[@]} > j )); do
                sed -i "s| alt=\"$english_text\"| alt=\"$translated_text\"|g" "${webfiles[j]}"
                j=$((j+1))
            done
        fi
        i=$((i+1))
        echo -n '.'
    done

    echo ''
    echo "Changing lang headers"
    langstr="${language:0:2}"
    for filename in "$webadmin_install_dir"/*.html; do
        sed -i 's|"yes" lang="en">||g' "$filename"
    done
    for filename in "$webadmin_install_dir"/*.html; do
        sed -i "s|<html>|<html lang=\"$langstr\">|g" "$filename"
        sed -i "s|<html lang=\"en\">|<html lang=\"$langstr\">|g" "$filename"
    done

    chown www-data:www-data "$webadmin_install_dir"/*.html
    echo "Translations complete"
}

function backup_mount_drive {
    backup_drive_mounted=
    if [ "$1" ]; then
        if [[ "$1" == "/dev/"* ]]; then
            USB_DRIVE="$1"
        else
            USB_DRIVE=/dev/${1}1
        fi
    fi

    # check that the backup destination is available
    if [ ! -b "$USB_DRIVE" ]; then
        return
    fi

    # unmount if already mounted
    umount -f "$USB_MOUNT"
    if [ ! -d "$USB_MOUNT" ]; then
        mkdir "$USB_MOUNT"
    fi
    if [ -f /dev/mapper/encrypted_usb ]; then
        rm -rf /dev/mapper/encrypted_usb
    fi
    cryptsetup close encrypted_usb

    if ! mount "$USB_DRIVE" "$USB_MOUNT"; then
        rm -rf "$USB_MOUNT"
        return
    fi
    backup_drive_mounted=1
}

function backup_unmount_drive {
    if ! umount "$USB_MOUNT"; then
        echo $"Unable to unmount the drive."
        rm -rf "$USB_MOUNT"
        return
    fi
    rm -rf "$USB_MOUNT"
    if [[ "$USB_DRIVE" == /dev/mapper/encrypted_usb ]]; then
        echo $"Unmount encrypted USB"
        cryptsetup close encrypted_usb
    fi
    if [ -f /dev/mapper/encrypted_usb ]; then
        rm -rf /dev/mapper/encrypted_usb
    fi
    backup_drive_mounted=
}

function detect_connected_drives {
    if [ ! -f $DRIVES_BASELINE_FILE ]; then
        # shellcheck disable=SC2012
        ls -gA /dev/sd* | awk -F '/dev/' '{print $2}' > $DRIVES_BASELINE_FILE
        return
    fi
    # shellcheck disable=SC2012
    ls -gA /dev/sd* | awk -F '/dev/' '{print $2}' > /tmp/.drives_current

    diff /tmp/.drives_current ${DRIVES_BASELINE_FILE} | awk -F '< ' '{print $2}'  | sed '/^$/d'  | sed 's/[0-9]*//g' | uniq | head -n 1
}

function app_not_on_onion_only {
    app_name="$1"

    if [[ "$ONION_ONLY" != 'no' ]]; then
        if grep -q "NOT_ON_ONION=1" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
            echo "0"
            return
        fi
    fi
    echo "1"
}

function app_not_on_arm {
    app_name="$1"

    if grep -q "NOT_ON_ARM=1" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
        archtype=$(uname -m)
        if [[ "$archtype" == 'arm'* ]]; then
            echo "0"
            return
        fi
    fi
    echo "1"
}

function app_not_in_webadmin {
    app_name="$1"

    if grep -q "NOT_IN_WEBADMIN=1" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
        echo "0"
        return
    fi
    echo "1"
}

function enough_ram_for_app {
    app_name="$1"

    if ! grep -q "MINIMUM_RAM_MB=" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
        echo "0"
        return
    fi

    minimum_ram_MB=$(grep "MINIMUM_RAM_MB=" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}" | head -n 1 | awk -F '=' '{print $2}')
    minimum_ram_bytes=$((minimum_ram_MB * 1024))

    ram_available=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    if [ "$ram_available" -lt "$minimum_ram_bytes" ]; then
        echo "1"
        return
    fi
    echo "0"
}

function webadmin_update_version {
    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
    if [ -f "$webadmin_install_dir/about.html" ]; then
        VERSION=$(grep "VERSION=" "/usr/local/bin/${PROJECT_NAME}-vars" | grep -v DEBIAN | awk -F '"' '{print $2}')
        sed -i "s|\"versiontext\".*|\"versiontext\">$VERSION</p>|g" "$webadmin_install_dir/about.html"
    fi
}

function web_admin_onion_only {
    # In onion only mode domain names or ddns codes
    # don't need to be provided

    if ! grep -q 'ONION_ONLY=' "$CONFIGURATION_FILE"; then
        return
    fi

    ONION_ONLY=$(grep 'ONION_ONLY=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')

    if [ ! "$ONION_ONLY" ]; then
        ONION_ONLY='no'
    fi

    if [[ "$ONION_ONLY" == 'no' ]]; then
        return
    fi

    # shellcheck disable=SC2154
    sed -i '/freedns_code/d' "$webadmin_install_dir/app_add_template.html"
    # shellcheck disable=SC2154
    sed -i '/freedns_code/d' "$webadmin_install_dir/add_app_confirm_template.html"

    sed -i '/install_domain/d' "$webadmin_install_dir/app_add_template.html"
    sed -i '/install_domain/d' "$webadmin_install_dir/add_app_confirm_template.html"

    sed -i 's|onion_only=false;|onion_only=true;|g' "$webadmin_install_dir/installapp.php"
    sed -i 's|onion_only=false;|onion_only=true;|g' "$webadmin_install_dir/installappconfirm.php"

    sed -i 's|setup_domain.html|setup_installing.html|g' "$webadmin_install_dir/setupconfirm.php"
}

function get_app_categories {
    APP_CATEGORY=()
    APP_CATEGORY+=("chat")
    APP_CATEGORY+=("media")
    APP_CATEGORY+=("office")
    APP_CATEGORY+=("social")
    APP_CATEGORY+=("sync")
    APP_CATEGORY+=("publishing")
    APP_CATEGORY+=("other")
}

function web_admin_create_add_apps_category {
    # number of apps added
    add_apps_ctr=0

    # This counter is used to enforce 4 icon rows
    available_apps_ctr=0

    # Index within the array of all apps
    app_index=0

    # shellcheck disable=SC2086
    category_str="$(tr '[:lower:]' '[:upper:]' <<< ${category:0:1})${category:1}"
    translated_category=$(web_admin_translate_text "$category_str")

    apps_header_str="<fieldset class=\"field_set\"><legend translate=\"yes\" class=\"category\">$translated_category</legend>"
    echo "    $apps_header_str" >> "$appslist_add_filename"

    for filename in $FILES
    do
        app_name=$(echo "${filename}" | awk -F '-app-' '{print $2}')

        if [[ $(enough_ram_for_app "$app_name") == "0" ]]; then
            if [[ $(app_not_on_onion_only "$app_name") != "0" ]]; then
                if [[ $(app_not_on_arm "$app_name") != "0" ]]; then
                    if [[ $(app_not_in_webadmin "$app_name") != "0" ]]; then

                        app_is_installed=

                        # check if the app is pending installation
                        app_pending_install=
                        if [ -f "$pending_installs" ]; then
                            if grep -q "install_${app_name}" "$pending_installs"; then
                                app_is_installed=1
                                app_pending_install=1
                            fi
                        fi

                        if [ ! $app_is_installed ]; then
                            app_filename="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"
                            if [ -f "$app_filename" ]; then
                                # does this app have a category?
                                if ! grep -q 'APP_CATEGORY=' "$app_filename"; then
                                    if [[ "$category" != 'other' ]]; then
                                        app_index=$((app_index+1))
                                        continue
                                    fi
                                fi

                                # Does this app belong in the current category?
                                if ! grep -q "APP_CATEGORY=$category" "$app_filename"; then
                                    app_index=$((app_index+1))
                                    continue
                                fi

                                if grep -q "VARIANTS=''" "$app_filename"; then
                                    continue
                                fi
                                if grep -q 'VARIANTS=""' "$app_filename"; then
                                    continue
                                fi
                                # get the icon for the app
                                icon_filename="/usr/share/${PROJECT_NAME}/android-app/${app_name}.png"
                                if [ -f "$icon_filename" ]; then
                                    cp "$icon_filename" "$webadmin_install_dir/icons/${app_name}.png"
                                else
                                    continue
                                fi

                                app_name_upper=$(echo "$app_name" | awk '{print toupper($0)}')
                                DESCRIPTION=

                                if ! grep -q "${app_name_upper}_SHORT_DESCRIPTION=" "$app_filename"; then
                                    continue
                                fi
                                if grep -q "#${app_name_upper}_SHORT_DESCRIPTION=" "$app_filename"; then
                                    continue
                                fi

                                SHORT_DESCRIPTION="$(grep "${app_name_upper}_SHORT_DESCRIPTION=" "$app_filename" | head -n 1 | sed 's|\$||g' | sed "s|'||g" | sed 's|\"||g' | awk -F '=' '{print $2}')"
                                translated_short_description=$(web_admin_translate_text "$SHORT_DESCRIPTION")
                                SHORT_DESCRIPTION="$translated_short_description"
                                app_title="${SHORT_DESCRIPTION}"

                                if grep -q "${app_name_upper}_DESCRIPTION=" "$app_filename"; then
                                    DESCRIPTION="$(grep "${app_name_upper}_DESCRIPTION=" "$app_filename" | head -n 1 | sed 's|\$||g' | sed "s|'||g" | sed 's|\"||g' | awk -F '=' '{print $2}')"

                                    translated_description=$(web_admin_translate_text "$DESCRIPTION")
                                    DESCRIPTION="$translated_description"
                                    app_title="${DESCRIPTION}"
                                fi

                                if [ $available_apps_ctr -eq 0 ]; then
                                    echo '    <div class="row">' >> "$appslist_add_filename"
                                fi

                                filename_app="$webadmin_install_dir/app_${app_name}.html"
                                if [ -f "$filename_app" ]; then
                                    rm "$filename_app"
                                fi

                                filename_app="$webadmin_install_dir/app_add_${app_name}.html"

                                if [ ! $app_pending_install ]; then
                                    { echo '      <div class="column">';
                                      echo '        <div>';
                                      echo "          <a href=\"app_add_${app_name}.html\" title=\"${app_title}\">";
                                      echo "            <img src=\"icons/${app_name}.png\" style=\"width:40%\">";
                                      echo "            <center>${app_name}</center>";
                                      echo '          </a>';
                                      echo '        </div>';
                                      echo '      </div>'; } >> "$appslist_add_filename"
                                else
                                    { echo '      <div class="column">';
                                      echo '        <div>';
                                      echo "        <img src=\"icons/${app_name}.png\" style=\"width:40%\">";
                                      echo "        <center class=\"installing\">${app_name}</center>";
                                      echo '        </div>';
                                      echo '      </div>'; } >> "$appslist_add_filename"
                                fi

                                cp "$app_add_template_filename" "$filename_app"

                                # Replace app variables
                                sed -i "s|HOSTNAME|$(hostname)|g" "$filename_app"
                                sed -i "s|APPNAME|${app_name}|g" "$filename_app"
                                sed -i "s|APPDESCRIPTION|${DESCRIPTION}|g" "$filename_app"

                                app_add_remove_domain=
                                if [[ "$ONION_ONLY" != 'no' ]]; then
                                    app_add_remove_domain=1
                                fi
                                if grep -q 'SHOW_DOMAIN_IN_WEBADMIN=0' "$filename"; then
                                    app_add_remove_domain=1
                                    sed -i '/freedns_code/d' "$filename_app"
                                    sed -i 's|"no_domain".*|"no_domain" value="1">|g' "$filename_app"
                                fi

                                # remove domain if necessary
                                if [ $app_add_remove_domain ]; then
                                    if grep -q 'install_domain' "$filename_app"; then
                                        sed -i '/install_domain/d' "$filename_app"
                                    fi
                                    sed -i "/installappconfirm.php/a <input type=\"hidden\" name=\"install_domain\" value=\"${app_name}.$(hostname)\">" "$filename_app"
                                fi

                                if grep -q 'freedns_code' "$filename_app"; then
                                    sed -i '/freedns_code/d' "$filename_app"
                                fi

                                available_apps_ctr=$((available_apps_ctr+1))
                                add_apps_ctr=$((add_apps_ctr+1))

                                # four columns per row
                                if [ $available_apps_ctr -eq 4 ]; then
                                    echo '    </div>' >> "$appslist_add_filename"
                                    available_apps_ctr=0
                                fi
                            fi
                        fi
                    fi
                fi
            fi
        fi
    done

    if [ ${available_apps_ctr} -gt 0 ]; then
        # Complete the rest of the four column row
        # shellcheck disable=SC2034
        for i in $(seq ${available_apps_ctr} 3)
        do
            { echo '      <div class="column">';
              echo '        <div>';
              echo '        </div>';
              echo '      </div>'; } >> "$appslist_add_filename"
        done
        echo '    </div>' >> "$appslist_add_filename"
    fi

    if [ ${add_apps_ctr} -gt 0 ]; then
        echo '    </fieldset>' >> "$appslist_add_filename"
    else
        # remove the header for this category
        sed -i "/>$translated_category</d" "$appslist_add_filename"
    fi
}

function web_admin_create_add_apps {
    if grep -q 'ONION_ONLY=' "$CONFIGURATION_FILE"; then
        ONION_ONLY=$(grep 'ONION_ONLY=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
    else
        ONION_ONLY='no'
    fi

    appslist_add_filename="$webadmin_install_dir/apps_add.html"

    apps_add_template_filename="$webadmin_install_dir/apps_add_template.html"
    pending_installs="$webadmin_install_dir/pending_installs.txt"
    icons_dir="$webadmin_install_dir/icons"
    app_add_template_filename="$webadmin_install_dir/app_add_template.html"
    FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"

    if [ ! -d "$icons_dir" ]; then
        mkdir -p "$icons_dir"
    fi

    if [ ! -f "$apps_add_template_filename" ]; then
        return
    fi
    cp "$apps_add_template_filename" "$appslist_add_filename"
    sed -i '/<\/div>/d' "$appslist_add_filename"
    sed -i '/<\/body>/d' "$appslist_add_filename"
    sed -i '/<\/html>/d' "$appslist_add_filename"

    get_app_categories

    # shellcheck disable=SC2068,SC2034
    for category in ${APP_CATEGORY[@]}
    do
        web_admin_create_add_apps_category
    done

    { echo '    </div>';
      echo '    <br><br>';
      echo '  </body>';
      echo '</html>'; } >> "$appslist_add_filename"

    chown -R www-data:www-data "$webadmin_install_dir"
}

function web_admin_create_installed_apps {
    appslist_filename="$webadmin_install_dir/apps.html"

    appslist_template_filename="$webadmin_install_dir/apps_template.html"
    icons_dir="$webadmin_install_dir/icons"
    pending_removes="$webadmin_install_dir/pending_removes.txt"

    if [ ! -d "$icons_dir" ]; then
        mkdir -p "$icons_dir"
    fi

    if [ ! -f "$appslist_template_filename" ]; then
        return
    fi
    cp "$appslist_template_filename" "$appslist_filename"
    sed -i '/<\/div> <!-- header -->/d' "$appslist_filename"
    sed -i '/<\/body>/d' "$appslist_filename"
    sed -i '/<\/html>/d' "$appslist_filename"

    installed_apps_ctr=0

    # Complete the rest of the four column row
    # shellcheck disable=SC2034
    for i in $(seq ${installed_apps_ctr} 3)
    do
        { echo '      <div class="column">';
          echo '        <div>';
          echo '        </div>';
          echo '      </div>'; } >> "$appslist_filename"
    done

    { echo '  </div>';
      echo '  </body>';
      echo '</html>'; } >> "$appslist_filename"

    chown -R www-data:www-data "$webadmin_install_dir"
}

function web_admin_create_users {
    if [ ! -d "/home/$webadmin_user" ]; then
        return
    fi

    users_file="$webadmin_install_dir/users.html"

    cp "$webadmin_install_dir"/users_template.html "$users_file"
    sed -i '/users list/,/end of users/d' "$users_file"
    sed -i '/<\/body>/d' "$users_file"
    sed -i '/<\/html>/d' "$users_file"

    echo "    <div class=\"row\">" >> "$users_file"
    echo "      <div class=\"column\">" >> "$users_file"

    rm "$webadmin_install_dir/userprofile_"*

    USERNAME="$webadmin_user"
    userfile="$webadmin_install_dir/userprofile_${USERNAME}.html"
    useremail=${USERNAME}@${HOSTNAME}
    GPG_ID=$(su -c "gpg --list-keys '$useremail'" - "$USERNAME" | sed -n '2p' | sed 's/^[ \t]*//')
    if [ -f "/home/$USERNAME/.gnupg/gpg.conf" ]; then
        if grep -q "default-key" "/home/$USERNAME/.gnupg/gpg.conf"; then
            default_gpg_key=$(grep "default-key" "/home/$USERNAME/.gnupg/gpg.conf")
            if [[ "$default_gpg_key" != *'#'* ]]; then
                default_gpg_key=$(grep "default-key" "/home/$USERNAME/.gnupg/gpg.conf" | awk -F ' ' '{print $2}')
                if [ ${#default_gpg_key} -gt 3 ]; then
                    GPG_ID=$(su -c "gpg --list-keys '$default_gpg_key'" - "$USERNAME" | sed -n '2p' | sed 's/^[ \t]*//')
                fi
            fi
        fi
    fi
    #pubkey_qrcode="$webadmin_install_dir/images/userprofile_${USERNAME}.png"
    #su -c "gpg --armor --export \"$GPG_ID\"" - "$USERNAME" | qrencode -t PNG -o "$pubkey_qrcode"

    { echo '        <div class="chip">';
      echo "          <a href=\"userprofile_${USERNAME}.html\" title=\"${USERNAME}\">";
      echo '            <img src="images/user_admin.png" alt="Person" width="96" height="96">';
      echo "            $USERNAME";
      echo '          </a>';
      echo '        </div>'; } >> "$users_file"

    cp "$webadmin_install_dir"/userprofile.html "$userfile"
    sed -i "s|USERNAME|${USERNAME}|g" "$userfile"
    if [[ "$USERNAME" == "$webadmin_user" ]]; then
        sed -i "s|USERTYPE|Admin|g" "$userfile"
        sed -i '/remove user button/,/end of remove/d' "$userfile"
    else
        sed -i "s|USERTYPE|User|g" "$userfile"
    fi

    if [[ "$useremail" != *'.onion' ]]; then
        useronionemail=${USERNAME}@$(cat /var/lib/tor/hidden_service_email/hostname)
        sed -i "s|USEREMAIL|${useremail}<br><br>${useronionemail}|g" "$userfile"
    else
        sed -i "s|USEREMAIL|${useremail}|g" "$userfile"
    fi

    sed -i "s|USERGPG|${GPG_ID}|g" "$userfile"

    chown www-data:www-data "$userfile"
    #chown www-data:www-data "$pubkey_qrcode"

    translated_add_user=$(web_admin_translate_text "Add a new member")

    { echo '        <div class="chip">';
      echo "          <a href=\"new_user.html\" title=\"${translated_add_user}\">";
      echo '            <img src="images/user.png" alt="Person" width="96" height="96">';
      echo '            <div class="adduser">+</div>';
      echo '          </a>';
      echo '        </div>';
      echo '      </div>';
      echo '    </div>';
      echo '  </body>';
      echo '</html>'; } >> "$users_file"

    chown www-data:www-data "$users_file"
}

function wait_for_enough_entropy {
    # Wait indefinitely until enough entropy is available to
    # generate the webadmin login password
    while true
    do
        ENTROPY=$(cat /proc/sys/kernel/random/entropy_avail)
        # shellcheck disable=SC2086
        if [ $ENTROPY -gt 500 ]; then
            break
        fi
        sleep 2
    done
}

function create_random_string {
    wait_for_enough_entropy
    openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c "${1}" ; echo -n ''
}

function web_admin_create_user {
    username="$1"
    password="$2"

    if [ ! "$username" ]; then
        return
    fi

    chmod 600 /etc/shadow
    chmod 600 /etc/gshadow
    if [ ! -d "/home/$username" ]; then
        useradd -m -p "$password" -s /bin/bash "$username"
        groupadd "$username"
    fi
    echo -n "${username}:${password}" | /usr/sbin/chpasswd
    chmod 0000 /etc/shadow
    chmod 0000 /etc/gshadow
}

function web_admin_setup_login {
    if [ $install_state -ne $INSTALL_STATE_FIRST_BOOT ]; then
        return
    fi

    # if an nginx password file has not been created for web admin
    if [ -f /etc/nginx/.webadminpasswd ]; then
        return
    fi

    # remove master password for the password manager
    if [ -f /root/.passwords/root/master ]; then
        rm /root/.passwords/root/master
    fi

    # remove detected drives file used by backup system
    if [ -f $DRIVES_BASELINE_FILE ]; then
        rm $DRIVES_BASELINE_FILE
    fi

    # this file indicates that the setup screen is active
    # and gets removed by freedombone-installer
    if [ ! -f "$webadmin_install_dir/.setupscreenactive" ]; then
        touch "$webadmin_install_dir/.setupscreenactive"
    fi

    if [ ! -f $webadmin_temp_password_file ]; then
        wait_for_enough_entropy
        if [ -f /usr/share/dict/words ]; then
            webadmin_password=$(diceware)
            if [ ! "$webadmin_password" ]; then
                webadmin_password="$(openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c 10 ; echo -n '')"
            fi
        else
            webadmin_password="$(openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c 10 ; echo -n '')"
        fi
        echo -n "$webadmin_password" > $webadmin_temp_password_file
    else
        webadmin_password=$(cat $webadmin_temp_password_file)
    fi

    web_admin_create_user "$webadmin_user" "$webadmin_password"

    # ensure that username is set
    if ! grep "MY_USERNAME=$webadmin_user" "$CONFIGURATION_FILE"; then
        echo "MY_USERNAME=$webadmin_user" >> "$CONFIGURATION_FILE"
    else
        sed -i "s|MY_USERNAME=.*|MY_USERNAME=$webadmin_user|g" "$CONFIGURATION_FILE"
    fi

    # create a password for users
    if [ ! -f /etc/nginx/.webadminpasswd ]; then
        touch /etc/nginx/.webadminpasswd
    fi

    # create a password file used by nginx
    echo -n "$webadmin_password" | htpasswd -i -s -c /etc/nginx/.webadminpasswd "$webadmin_user"
    if ! grep -q "${webadmin_user}:" /etc/nginx/.webadminpasswd; then
        echo $"/etc/nginx/.webadminpasswd password not created for $webadmin_user"
        if [ -f /etc/nginx/.webadminpasswd ]; then
            rm /etc/nginx/.webadminpasswd
        fi
        return
    fi

    # create a setup page with the initial password inserted
    # and copy it to the index
    cp "$webadmin_install_dir"/setup.html "$webadmin_install_dir"/setup.prev
    cp "$webadmin_install_dir"/setup_confirm_template.html "$webadmin_install_dir"/setup_confirm.html
    sed -i "s|WEBADMINPASSWORD|${webadmin_password}|g" "$webadmin_install_dir/setup.prev"
    sed -i "s|WEBADMINPASSWORD|${webadmin_password}|g" "$webadmin_install_dir/setup_confirm.html"
    cp "$webadmin_install_dir"/setup.prev "$webadmin_install_dir"/index.html

    # if initial setup has not yet happened then create
    # a password file
    if ! grep -q 'install_final' "$COMPLETION_FILE"; then
        echo -n "$webadmin_password" > ${IMAGE_PASSWORD_FILE}
    fi

    web_admin_background_color
    web_admin_create_app_descriptions
    web_admin_translate

    echo -n "$INSTALL_STATE_WEBADMIN_PASSWORD_CTEATED" > "$install_state_file"
    install_state=$INSTALL_STATE_WEBADMIN_PASSWORD_CTEATED
}

function enable_webadmin_login {
    # switch on nginx authentication for freedombone.local
    if grep -q "#auth_basic" "/etc/nginx/sites-available/${local_hostname}"; then
        sed -i 's|#auth_basic|auth_basic|g' "/etc/nginx/sites-available/${local_hostname}"
    fi
}

function remove_initial_setup_page {
    if [ -f "$webadmin_install_dir/index.prev" ]; then
        # Replace the installing screen with the main index page when done
        # It should reload by itself
        if [ -f "$webadmin_install_dir/setup_installing.html" ]; then
            cp "$webadmin_install_dir/EN/index.html" "$webadmin_install_dir/setup_installing.html"
        fi

        # Replace the setup confirm screen with the main index
        if [ -f "$webadmin_install_dir/setup_confirm.html" ]; then
            cp "$webadmin_install_dir/EN/index.html" "$webadmin_install_dir/setup_confirm.html"
        fi

        # Replace the setup domain screen with the main index
        if [ -f "$webadmin_install_dir/setup_domain.html" ]; then
            cp "$webadmin_install_dir/EN/index.html" "$webadmin_install_dir/setup_domain.html"
        fi

        # Show the web admin index page (not the initial setup page)
        cp "$webadmin_install_dir/EN/index.html" "$webadmin_install_dir/index.html"
        rm "$webadmin_install_dir/index.prev"
    fi

    # Remove the initial setup page
    if [ -f "$webadmin_install_dir/setup.prev" ]; then
        rm "$webadmin_install_dir/setup.prev"
    fi
}

function remove_temporary_setup_files {
    # remove the file which indicates that the setup screen is active
    if [ -f "$webadmin_install_dir/.setupscreenactive" ]; then
        rm "$webadmin_install_dir/.setupscreenactive"
    fi

    # remove the setup file created by setup.php
    if [ -f "$setup_file" ]; then
        rm "$setup_file"
    fi

    # remove the file containing the domain name
    if [ -f "$domain_file" ]; then
        rm "$domain_file"
    fi
}

function restore_webadmin_files {
    # restore files which were removed for the initial setup
    if [ -d "$INSTALL_DIR/tempwebadmin" ]; then
        mv "$INSTALL_DIR/tempwebadmin"/* "$webadmin_install_dir"
        rm -rf "$INSTALL_DIR/tempwebadmin"
    fi
}

function set_webadmin_permissions {
    # set permissions for web admin site at freedombone.local
    chown www-data:www-data "$webadmin_install_dir/*.html"
}

function check_for_existing_processes {
    script_name="$1"

    { echo '#!/bin/bash';
      echo '';
      echo 'function exit_if_process_is_running {';
      echo "    process_name=\"\$1\"";
      echo "    process_exists=\$(ps a | grep \"\$process_name\" | grep -v 'grep')";
      echo "    if [ \"\$process_exists\" ]; then";
      echo "        if [[ \"\$process_exists\" != *'grep'* ]]; then";
      echo "            process_id=\$(echo \"\$process_exists\" | awk -F ' ' '{print \$1}')";
      echo "            if [ \"\$process_id\" ]; then";
      echo "                if [[ \"$script_name\" != *\"\$process_name\" ]]; then";
      echo "                    echo \"\$process_name is running\"";
      echo "                    exit 0";
      echo '                fi';
      echo '            fi';
      echo '        fi';
      echo '    fi';
      echo '}';
      echo '';
      echo 'exit_if_process_is_running fbone_installer.sh';
      echo 'exit_if_process_is_running webadmin_factory_reset.sh';
      echo 'exit_if_process_is_running webadmin_appsettings.sh';
      echo 'exit_if_process_is_running webadmin_upgrade.sh';
      echo 'exit_if_process_is_running webadmin_format.sh';
      echo 'exit_if_process_is_running backup-local';
      echo 'exit_if_process_is_running addremove';
      echo 'exit_if_process_is_running webadmin_backup.sh';
      echo 'exit_if_process_is_running webadmin_backup_keys.sh';
      echo 'exit_if_process_is_running restore-local';
      echo 'exit_if_process_is_running webadmin_restore.sh';
      echo 'exit_if_process_is_running webadmin_restore_keys.sh';
      echo 'exit_if_process_is_running webadmin_new_user.sh';
      echo 'exit_if_process_is_running webadmin_remove_user.sh';
      echo ''; } > "$script_name"
}

function run_setup_command {
    if [ $install_state -ne $INSTALL_STATE_WEBADMIN_PASSWORD_CTEATED ]; then
        return
    fi

    check_for_existing_processes $installer_script

    { echo "echo \"Beginning install \$(date)\" > $webadmin_install_dir/log.txt";
      echo "chown www-data:www-data $webadmin_install_dir/log.txt";
      echo '';
      echo "/usr/local/bin/freedombone -c \"$CONFIGURATION_FILE\" >> $webadmin_install_dir/log.txt;";

      echo "if ! grep -q 'install_final' \"$COMPLETION_FILE\"; then";
      echo "    chown www-data:www-data $webadmin_install_dir/log.txt";
      echo "    echo '$INSTALL_STATE_COMMAND_FAIL' > $install_state_file";
      echo '    exit 36';
      echo 'fi';
      echo '';
      echo "chown www-data:www-data $webadmin_install_dir/log.txt";
      echo '';
      echo "exit 0"; } >> $installer_script
    chmod +x $installer_script

    echo -n "$INSTALL_STATE_RUNNING_COMMAND" > "$install_state_file"
    install_state=$INSTALL_STATE_RUNNING_COMMAND

    # run in a separate process
    ./$installer_script &
}

function check_install_command_state {
    if [ $install_state -ne $INSTALL_STATE_RUNNING_COMMAND ]; then
        return
    fi
    reset_install_state=
    if [ ! -f "$install_state_file" ]; then
        reset_install_state=1
    else
        curr_state=$(cat "$install_state_file")

        # shellcheck disable=SC2086
        if [ $curr_state -eq $INSTALL_STATE_COMMAND_FAIL ]; then
            reset_install_state=1
        fi

        install_has_finished=

        # shellcheck disable=SC2086
        if [ $curr_state -eq $INSTALL_STATE_COMMAND_SUCCESS ]; then
            install_has_finished=1
        else
            # Also check the install log for a message
            # indicating completion has happened
            if [ -f "$webadmin_install_dir/log.txt" ]; then
                end_of_log=$(tail -n 10 "$webadmin_install_dir/log.txt" | grep ${PROJECT_NAME})
                end_of_log_message=$'installation is complete'
                if [[ "$end_of_log" == *"$end_of_log_message"* ]]; then
                    install_has_finished=1
                fi
            fi
        fi

        if [ $install_has_finished ]; then
            echo -n "$INSTALL_STATE_COMMAND_SUCCESS" > "$install_state_file"
            install_state=$INSTALL_STATE_COMMAND_SUCCESS
            restore_webadmin_files
        fi
    fi

    if [ $reset_install_state ]; then
        chown www-data:www-data "$webadmin_install_dir/log.txt"
        # remove the setup file containing login details
        if [ -f "$setup_file" ]; then
            rm "$setup_file"
        fi
        # remove the webadmin password file
        if [ -f /etc/nginx/.webadminpasswd ]; then
            rm /etc/nginx/.webadminpasswd
        fi
        echo -n "$INSTALL_STATE_FIRST_BOOT" > "$install_state_file"
        install_state=$INSTALL_STATE_FIRST_BOOT
    fi
}

function before_setup_runs {
    if [ $install_state -ne $INSTALL_STATE_WEBADMIN_PASSWORD_CTEATED ]; then
        return
    fi

    if [ ! -f /etc/nginx/.webadminpasswd ]; then
        return
    fi

    if grep -q 'install_final' "$COMPLETION_FILE"; then
        return
    fi

    if [ ! -f "/usr/share/${PROJECT_NAME}/webadmin/EN/setup_installing.html" ]; then
        return
    fi

    cp "/usr/share/${PROJECT_NAME}/webadmin/EN/setup_installing.html" "$webadmin_install_dir/index.html"

    # get the username and domain from the .temp_setup.txt file
    # created by setup.php
    MY_USERNAME=$(cat "$setup_file")
    if [ ! "$MY_USERNAME" ]; then
        MY_USERNAME="$webadmin_user"
    else
        if [[ "$MY_USERNAME" != "$webadmin_user" ]]; then
            temp_webadmin_password=$(cat $webadmin_temp_password_file)
            web_admin_create_user "$webadmin_user" "$temp_webadmin_password"
            webadmin_user="$MY_USERNAME"
        fi
    fi
    DEFAULT_DOMAIN_NAME=${local_hostname}

    if [ -f "$domain_file" ]; then
        DEFAULT_DOMAIN_NAME=$(cat "$domain_file")
    fi

    # change the username in the config file
    if grep -q 'MY_USERNAME=' "$CONFIGURATION_FILE"; then
        if ! grep -Fxq "MY_USERNAME=$MY_USERNAME" "$CONFIGURATION_FILE"; then
            sed -i "s|MY_USERNAME=.*|MY_USERNAME=$MY_USERNAME|g" "$CONFIGURATION_FILE"
        fi
    else
        echo "MY_USERNAME=$MY_USERNAME" >> "$CONFIGURATION_FILE"
    fi

    # change the full name in the config file
    if grep -q 'MY_NAME=' "$CONFIGURATION_FILE"; then
        if ! grep -Fxq "MY_NAME=$MY_USERNAME" "$CONFIGURATION_FILE"; then
            sed -i "s|MY_NAME=.*|MY_USERNAME=$MY_USERNAME|g" "$CONFIGURATION_FILE"
        fi
    else
        echo "MY_NAME=$MY_USERNAME" >> "$CONFIGURATION_FILE"
    fi

    # change the default domain in the config file
    if grep -q 'DEFAULT_DOMAIN_NAME=' "$CONFIGURATION_FILE"; then
        if ! grep -Fxq "DEFAULT_DOMAIN_NAME=$DEFAULT_DOMAIN_NAME" "$CONFIGURATION_FILE"; then
            sed -i "s|DEFAULT_DOMAIN_NAME=.*|DEFAULT_DOMAIN_NAME=$DEFAULT_DOMAIN_NAME|g" "$CONFIGURATION_FILE"
        fi
    else
        echo "DEFAULT_DOMAIN_NAME=$DEFAULT_DOMAIN_NAME" >> "$CONFIGURATION_FILE"
    fi

    # ensure that minimal install is set
    if grep -q 'MINIMAL_INSTALL=' "$CONFIGURATION_FILE"; then
        if ! grep -Fxq "MINIMAL_INSTALL=yes" "$CONFIGURATION_FILE"; then
            sed -i 's|MINIMAL_INSTALL=.*|MINIMAL_INSTALL=yes|g' "$CONFIGURATION_FILE"
        fi
    else
        echo 'MINIMAL_INSTALL=yes' >> "$CONFIGURATION_FILE"
    fi

    # ensure that no DDNS provider is specified
    if grep -q 'DDNS_PROVIDER=' "$CONFIGURATION_FILE"; then
        if ! grep -Fxq "DDNS_PROVIDER=none" "$CONFIGURATION_FILE"; then
            sed -i 's|DDNS_PROVIDER=.*|DDNS_PROVIDER=none|g' "$CONFIGURATION_FILE"
        fi
    else
        echo 'DDNS_PROVIDER=none' >> "$CONFIGURATION_FILE"
    fi

    run_setup_command
}

function after_setup_has_finished {
    if [ $install_state -ne $INSTALL_STATE_COMMAND_SUCCESS ]; then
        return
    fi
    if [ -f /root/.initial_setup ]; then
        rm /root/.initial_setup
    fi

    if [ -f $webadmin_temp_password_file ]; then
        rm $webadmin_temp_password_file
    fi

    increment_install_progress

    web_admin_onion_only

    increment_install_progress

    web_admin_create_users

    increment_install_progress

    web_admin_create_installed_apps

    increment_install_progress

    web_admin_create_add_apps

    increment_install_progress

    webadmin_update_version

    increment_install_progress

    if [ -d /etc/searx ]; then
        # new searx secret
        if [ -f "/etc/searx/searx/settings.yml" ]; then
            sed -i "s|secret_key :.*|secret_key : \"$(create_random_string 30)\"|g" "/etc/searx/searx/settings.yml"
        fi

        # update searx
        #cd /etc/searx || return
        #./manage.sh update_packages
        chown -R searx:searx /etc/searx
        systemctl restart searx
    fi

    increment_install_progress

    # remove default user
    if [ -d /home/fbone ]; then
        userdel -r fbone
        if [ -d /home/fbone ]; then
            rm -rf /home/fbone
        fi
    fi

    increment_install_progress

    systemctl restart nginx
    if [ -f $installer_script ]; then
        rm $installer_script
    fi

    increment_install_progress

    regenerate_blocklist
    regenerate_blocklist_muted_words

    increment_install_progress

    web_create_homepage

    increment_install_progress

    chown -R www-data:www-data "$webadmin_install_dir"

    enable_webadmin_login
    remove_initial_setup_page
    set_webadmin_permissions
    remove_temporary_setup_files

    systemctl reboot -i
}

function install_apps_from_webadmin {
    if [ -f "$pending_installs" ]; then
        linestr=$(head -n 1 "$pending_installs")
        if [[ "$linestr" == "install_"* && "$linestr" != *'_running'* ]]; then
            app_name=$(echo "$linestr" | awk -F '_' '{print $2}' | awk -F ',' '{print $1}')
            if [ -f "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}" ]; then
                app_domain=$(echo "$linestr" | awk -F ',' '{print $2}')
                if [ ! "$app_domain" ]; then
                    app_domain=${app_name}.local
                fi
                app_name_upper=$(echo "$app_name" | awk '{print toupper($0)}')

                # indicate that we are installing
                sed -i "s|${app_name}|${app_name}_running|g" "$pending_installs"

                # Add domain name to the config
                if ! grep -q "${app_name_upper}_DOMAIN_NAME=" "$CONFIGURATION_FILE"; then
                    echo "${app_name_upper}_DOMAIN_NAME=${app_domain}" >> "$CONFIGURATION_FILE"
                else
                    sed -i "s|${app_name_upper}_DOMAIN_NAME=.*|${app_name_upper}_DOMAIN_NAME=${app_domain}|g" "$CONFIGURATION_FILE"
                fi

                # remove app from the removed file
                if grep -Fxq "_${app_name}_" "$REMOVED_APPS_FILE"; then
                    sed -i "/_${app_name}_/d" "$REMOVED_APPS_FILE"
                fi

                # remove the qrcode for the app if it exists
                if [ -f "$webadmin_install_dir/app_qrcode_${app_name}.png" ]; then
                    rm "$webadmin_install_dir/app_qrcode_${app_name}.png"
                fi

                # remove from pending list so that if the install gets stuck
                # it won't repeatedly try to install a bad app
                sed -i "/$linestr/d" "$pending_installs"

                if ! /usr/bin/timeout $APP_INSTALL_TIMEOUT_SEC /usr/local/bin/${PROJECT_NAME}-addremove add "${app_name}" > "$webadmin_install_dir/applog.txt"; then
                    sed -i "/$linestr/d" "$pending_installs"
                    notification_str="Failed to install. For details see admin/applog.txt"
                else
                    notification_str="Installed successfully"
                fi
                translated_notification_str=$(web_admin_translate_text "$notification_str")
                /usr/local/bin/${PROJECT_NAME}-notification -s "[${PROJECT_NAME}] ${app_name} ${translated_notification_str}" -m "${app_name} ${translated_notification_str}" &

                chown www-data:www-data "$webadmin_install_dir/applog.txt"
            else
                # remove from pending list
                sed -i "/$linestr/d" "$pending_installs"
            fi
        else
            # if any unusual line is found then remove the file
            rm "$pending_installs"
        fi
    fi
}

function remove_apps_from_webadmin {
    if [ -f "$pending_removes" ]; then
        linestr=$(head -n 1 "$pending_removes")
        if [[ "$linestr" == "remove_"* ]]; then
            app_name=$(echo "$linestr" | awk -F '_' '{print $2}')
            if [ -f "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}" ]; then
                # indicate that we are removing
                if [[ "$linestr" != *'_running'* ]]; then
                    sed -i "s|${app_name}|${app_name}_running|g" "$pending_removes"
                fi

                /usr/bin/timeout $APP_INSTALL_TIMEOUT_SEC /usr/local/bin/${PROJECT_NAME}-addremove remove "${app_name}" > "$webadmin_install_dir/applog.txt"
                chown www-data:www-data "$webadmin_install_dir/applog.txt"
                if [ -f "$webadmin_install_dir/app_qrcode_${app_name}.png" ]; then
                    rm "$webadmin_install_dir/app_qrcode_${app_name}.png"
                fi

                notification_str="removed"
                translated_notification_str=$(web_admin_translate_text "$notification_str")
                /usr/local/bin/${PROJECT_NAME}-notification -s "[${PROJECT_NAME}] ${app_name}" -m "${app_name} ${translated_notification_str}" &

                # NOTE: we don't need to run web_admin_create_add_apps
                # because that happens anyway as part of addremove
            fi
            # remove the line
            sed -i "/$linestr/d" "$pending_removes"
        else
            # if any unusual line is found then remove the file
            rm "$pending_removes"
        fi
    fi
}

function update_progress_bar {
    if [ ! -f "$setup_file" ]; then
        return
    fi
    # shellcheck disable=SC2086
    if [ $install_state -gt $INSTALL_STATE_RUNNING_COMMAND ]; then
        return
    fi
    if [ ! -f /root/.install_counter ]; then
        echo -n '1' > /root/.install_counter
    fi
    max_counter=286
    installing_page="$webadmin_install_dir/setup_installing.html"
    progress_counter=$(cat /root/.install_counter)
    progress_percent=$((progress_counter * 100 / max_counter))
    if [ $progress_percent -gt 100 ]; then
        progress_percent=100
    fi
    sed -i "s|<div class=\"w3-container.*|<div class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${progress_percent}%\">${progress_percent}%</div>|g" "$installing_page"
    if ! grep -q 'w3-container w3-blue' "$webadmin_install_dir/index.html"; then
        cp "$webadmin_install_dir/setup_installing.html" "$webadmin_install_dir/index.html"
    fi
    sed -i "s|<div class=\"w3-container.*|<div class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${progress_percent}%\">${progress_percent}%</div>|g" "$webadmin_install_dir/index.html"
}

function increment_install_progress {
    install_comment=$"1"

    if [ -f /root/.install_counter ]; then
        install_counter=$(cat /root/.install_counter)
    else
        install_counter=0
    fi

    if [ "$install_comment" ]; then
        echo "$install_comment" > /root/.install_comment
    fi

    install_counter=$((install_counter + 1))
    echo -n "$install_counter" > /root/.install_counter
    update_progress_bar
}

function initiate_automatic_backup {
    backup_hour=3
    if grep -q "BACKUP_HOUR=" "$CONFIGURATION_FILE"; then
        backup_hour=$(grep "BACKUP_HOUR=" "$CONFIGURATION_FILE" | awk -F '=' '{print $2}')
    else
        echo "BACKUP_HOUR=$backup_hour" >> "$CONFIGURATION_FILE"
    fi

    curr_hour=$(date +%H)
    if [ "$curr_hour" -eq "$backup_hour" ]; then
        if [ "$webadmin_prev_hour" -ne "$backup_hour" ]; then
            # check that backup drive is plugged in
            backup_device=$(detect_connected_drives)
            if [[ "$backup_device" == 'sd'* ]]; then
                touch "$backup_file"
                autobackup_log_file="$webadmin_install_dir/autobackup.txt"
                if [ -f "$autobackup_log_file" ]; then
                    # keep the number of lines in the autobackup log small
                    # we don't need to check things from ancient history
                    backup_file_lines=$(wc -l < "$autobackup_log_file")
                    # shellcheck disable=SC2086
                    if [ $backup_file_lines -gt 14 ]; then
                        tail -n +2 "$autobackup_log_file" > /tmp/autobackup_file
                        mv /tmp/autobackup_file "$autobackup_log_file"
                    fi
                fi
                echo $"Backup initiated $(date)" >> "$autobackup_log_file"
                chown www-data:www-data "$autobackup_log_file"
                running_auto_backup=1
            fi
        fi
    fi
    webadmin_prev_hour=$curr_hour
}

function update_backup_progress_bar {
    if [ ! -f "$backup_progress_file" ]; then
        return
    fi

    backup_process_exists=
    backup_process=$(pgrep 'webadmin_backup.sh' | grep -v 'grep')
    if [ "$backup_process" ]; then
        if [[ "$backup_process" != *'grep'* ]]; then
            backup_pid=$(echo "$backup_process" | awk -F ' ' '{print $1}')
            if [ "$backup_pid" ]; then
                backup_process_exists=1
            fi
        fi
    fi

    if [ ! $backup_process_exists ]; then
        return
    fi

    max_counter=23
    progress_page="$webadmin_install_dir/backup_progress.html"
    progress_counter=$(cat $backup_progress_file)
    progress_percent=$((progress_counter * 100 / max_counter))
    if [ $progress_percent -gt 100 ]; then
        progress_percent=$((progress_percent - 100))
    fi
    sed -i "s|<div class=\"w3-container.*|<div class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${progress_percent}%\">${progress_percent}%</div>|g" "$progress_page"
}

function update_restore_progress_bar {
    if [ ! -f "$restore_progress_file" ]; then
        return
    fi
    restore_process_exists=
    restore_process=$(pgrep 'webadmin_restore.sh' | grep -v 'grep')
    if [ "$restore_process" ]; then
        if [[ "$restore_process" != *'grep'* ]]; then
            restore_pid=$(echo "$restore_process" | awk -F ' ' '{print $1}')
            if [ "$restore_pid" ]; then
                restore_process_exists=1
            fi
        fi
    fi

    if [ ! $restore_process_exists ]; then
        return
    fi

    max_counter=23
    progress_page="$webadmin_install_dir/restore_progress.html"
    progress_counter=$(cat $restore_progress_file)
    progress_percent=$((progress_counter * 100 / max_counter))
    if [ $progress_percent -gt 100 ]; then
        progress_percent=$((progress_percent -  100))
    fi
    sed -i "s|<div class=\"w3-container.*|<div class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${progress_percent}%\">${progress_percent}%</div>|g" "$progress_page"
}

function update_format_progress_bar {
    if [ ! -f "$format_progress_file" ]; then
        return
    fi
    format_process_exists=
    format_process=$(pgrep 'webadmin_format.sh' | grep -v 'grep')
    if [ "$format_process" ]; then
        if [[ "$format_process" != *'grep'* ]]; then
            format_pid=$(echo "$format_process" | awk -F ' ' '{print $1}')
            if [ "$format_pid" ]; then
                format_process_exists=1
            fi
        fi
    fi

    if [ ! $format_process_exists ]; then
        return
    fi

    max_counter=5
    progress_page="$webadmin_install_dir/format_progress.html"
    progress_counter=$(cat $format_progress_file)
    progress_percent=$((progress_counter * 100 / max_counter))
    if [ $progress_percent -gt 100 ]; then
        progress_percent=100
    fi
    sed -i "s|<div class=\"w3-container.*|<div class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${progress_percent}%\">${progress_percent}%</div>|g" "$progress_page"
}

function backup_and_restore {
    update_backup_progress_bar
    update_restore_progress_bar
    update_format_progress_bar

    initiate_automatic_backup

    if [ -f "$restore_file" ]; then
        rm "$restore_file"

        ADMIN_USERNAME=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | awk -F '=' '{print $2}')

        webadmin_onion_address=$(cat /var/lib/tor/hidden_service_webadmin/hostname)
        restore_title=$'Restore status'
        restore_failed_message=$"Restore failed. See http://${webadmin_onion_address}/admin/restore.txt for details"
        restore_success_message=$"Restore succeeded"

        check_for_existing_processes $restore_script
        { echo "echo \"Beginning webadmin restore \$(date)\" > $webadmin_install_dir/restore.txt";
          echo "chown www-data:www-data $webadmin_install_dir/restore.txt";
          echo '';
          echo "cp $webadmin_install_dir/restore_progress_template.html $webadmin_install_dir/restore_progress.html";
          echo "chown www-data:www-data $webadmin_install_dir/restore_progress.html";
          echo '';
          echo 'backup_password=';
          echo 'if [ -f /tmp/backup_password.txt ]; then';
          echo "    backup_password=\$(cat /tmp/backup_password.txt)";
          echo "    ${PROJECT_NAME}-pass -u \"$ADMIN_USERNAME\" -a simplebackup -p \"\$backup_password\"";
          echo '    rm /tmp/backup_password.txt';
          echo 'else';
          echo "    backup_password=\$(${PROJECT_NAME}-pass -u \"$ADMIN_USERNAME\" -a simplebackup)";
          echo 'fi';
          echo '';
          echo "if /usr/bin/timeout $BACKUP_TIMEOUT_SEC /usr/local/bin/${PROJECT_NAME}-restore-local simple \"\$backup_password\" >> $webadmin_install_dir/restore.txt; then";
          echo "    echo \"Completed \$(date)\" >> $webadmin_install_dir/restore.txt";
          echo "    cp $webadmin_install_dir/restore_complete.html $webadmin_install_dir/restore_progress.html";
          echo "    /usr/local/bin/${PROJECT_NAME}-notification -m \"$restore_success_message\" -s \"[${PROJECT_NAME}] $restore_title\" &";
          echo 'else';
          echo "    cp $webadmin_install_dir/restore_failed.html $webadmin_install_dir/restore_progress.html";
          echo "    /usr/local/bin/${PROJECT_NAME}-notification -m \"$restore_failed_message\" -s \"[${PROJECT_NAME}] $restore_title\" &";
          echo 'fi';
          echo '';
          echo "chown www-data:www-data $webadmin_install_dir/restore.txt";
          echo "chown www-data:www-data $webadmin_install_dir/restore_progress.html";
          echo '';
          echo "rm $restore_progress_file";
          echo '';
          echo "exit 0"; } >> $restore_script
        chmod +x $restore_script

        # run in a separate process
        ./$restore_script &
    else
        if [ -f "$backup_file" ]; then
            rm "$backup_file"

            ADMIN_USERNAME=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | awk -F '=' '{print $2}')

            webadmin_onion_address=$(cat /var/lib/tor/hidden_service_webadmin/hostname)
            backup_title=$'Backup status'
            backup_failed_message=$"Backup failed. See http://${webadmin_onion_address}/admin/backup.txt for details"
            backup_success_message=$"Backup succeeded"

            backup_name='webadmin'
            if [ $running_auto_backup ]; then
                backup_name=$'scheduled'
                date >> "$webadmin_install_dir/autobackup.log"
                chown www-data:www-data "$webadmin_install_dir/autobackup.log"
                running_auto_backup=
            fi

            check_for_existing_processes $backup_script
            { echo "echo \"Beginning $backup_name backup \$(date)\" > $webadmin_install_dir/backup.txt";
              echo "chown www-data:www-data $webadmin_install_dir/backup.txt";
              echo '';
              echo "cp $webadmin_install_dir/backup_progress_template.html $webadmin_install_dir/backup_progress.html";
              echo "chown www-data:www-data $webadmin_install_dir/backup_progress.html";
              echo '';
              echo 'backup_password=';
              echo 'if [ -f /tmp/backup_password.txt ]; then';
              echo "    backup_password=\$(cat /tmp/backup_password.txt)";
              echo "    ${PROJECT_NAME}-pass -u \"$ADMIN_USERNAME\" -a simplebackup -p \"\$backup_password\"";
              echo '    rm /tmp/backup_password.txt';
              echo "    sed -i \"s|\\\"backup_password\\\".*|\\\"backup_password\\\" value=\\\"\$backup_password\\\"></p>|g\" $webadmin_install_dir/backup_password.html";
              echo "    sed -i \"s|\\\"backup_password_confirm\\\".*|\\\"backup_password_confirm\\\" value=\\\"\$backup_password\\\"></p>|g\" $webadmin_install_dir/backup_password.html";
              echo "    chown www-data:www-data $webadmin_install_dir/backup_password.html";
              echo "    sed -i \"s|\\\"backup_password\\\".*|\\\"backup_password\\\" value=\\\"\$backup_password\\\"></p>|g\" $webadmin_install_dir/restore_password.html";
              echo "    chown www-data:www-data $webadmin_install_dir/restore_password.html";
              echo 'else';
              echo "    backup_password=\$(${PROJECT_NAME}-pass -u \"$ADMIN_USERNAME\" -a simplebackup)";
              echo 'fi';
              echo '';
              echo "if /usr/bin/timeout $BACKUP_TIMEOUT_SEC /usr/local/bin/${PROJECT_NAME}-backup-local simple \"\$backup_password\" >> $webadmin_install_dir/backup.txt; then";
              echo "    echo \"Completed \$(date)\" >> $webadmin_install_dir/backup.txt";
              echo "    cp $webadmin_install_dir/backup_complete.html $webadmin_install_dir/backup_progress.html";
              echo "    /usr/local/bin/${PROJECT_NAME}-notification -m \"$backup_success_message\" -s \"[${PROJECT_NAME}] $backup_title\" &";
              echo 'else';
              echo "    cp $webadmin_install_dir/backup_failed.html $webadmin_install_dir/backup_progress.html";
              echo "    /usr/local/bin/${PROJECT_NAME}-notification -m \"$backup_failed_message\" -s \"[${PROJECT_NAME}] $backup_title\" &";
              echo 'fi';
              echo '';
              echo "chown www-data:www-data $webadmin_install_dir/backup.txt";
              echo "chown www-data:www-data $webadmin_install_dir/backup_progress.html";
              echo '';
              echo "rm $backup_progress_file";
              echo '';
              echo "exit 0"; } >> $backup_script
            chmod +x $backup_script

            # run in a separate process
            ./$backup_script &
        else
            if [ -f "$format_file" ]; then
                rm "$format_file"

                webadmin_onion_address=$(cat /var/lib/tor/hidden_service_webadmin/hostname)
                format_title=$'USB format status'
                format_failed_message=$"USB format failed. See http://${webadmin_onion_address}/admin/format.txt for details"
                format_success_message=$"USB format succeeded"

                check_for_existing_processes $format_script
                { echo "if /usr/bin/timeout $FORMAT_TIMEOUT_SEC /usr/local/bin/${PROJECT_NAME}-format simple > $webadmin_install_dir/format.txt; then";
                  echo "    cp $webadmin_install_dir/format_complete.html $webadmin_install_dir/format_progress.html";
                  echo "    /usr/local/bin/${PROJECT_NAME}-notification -m \"$format_success_message\" -s \"[${PROJECT_NAME}] $format_title\" &";
                  echo 'else';
                  echo "    cp $webadmin_install_dir/format_failed.html $webadmin_install_dir/format_progress.html";
                  echo "    /usr/local/bin/${PROJECT_NAME}-notification -m \"$format_failed_message\" -s \"[${PROJECT_NAME}] $format_title\" &";
                  echo 'fi';
                  echo "chown www-data:www-data $webadmin_install_dir/format_progress.html";
                  echo '';
                  echo "rm $format_progress_file";
                  echo '';
                  echo "exit 0"; } >> $format_script
                chmod +x $format_script

                # run in a separate process
                ./$format_script &
            fi
        fi
    fi
}

function backup_and_restore_keys {
    if [ -f "$restore_keys_file" ]; then
        rm "$restore_keys_file"
        admin_username=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
        # check_for_existing_processes $restore_keys_script
        { echo "echo \"Beginning webadmin restore keys \$(date)\" > $webadmin_install_dir/restore.txt";
          echo "chown www-data:www-data $webadmin_install_dir/restore.txt";
          echo '';
          echo "cp $webadmin_install_dir/restore_keys_progress_template.html $webadmin_install_dir/restore_keys_progress.html";
          echo "chown www-data:www-data $webadmin_install_dir/restore_keys_progress.html";
          echo '';
          echo "if /usr/local/bin/${PROJECT_NAME}-recoverkey -u \"$admin_username\" -d \"simple\" >> $webadmin_install_dir/restore.txt; then";
          echo "    echo \"Completed \$(date)\" >> $webadmin_install_dir/restore.txt";
          echo "    cp $webadmin_install_dir/restore_keys_complete.html $webadmin_install_dir/restore_keys_progress.html";
          echo 'else';
          echo "    cp $webadmin_install_dir/restore_keys_failed.html $webadmin_install_dir/restore_keys_progress.html";
          echo 'fi';
          echo '';
          echo "chown www-data:www-data $webadmin_install_dir/restore.txt";
          echo "chown www-data:www-data $webadmin_install_dir/restore_keys_progress.html";
          echo '';
          echo "exit 0"; } >> $restore_keys_script
        chmod +x $restore_keys_script

        # run in a separate process
        ./$restore_keys_script &
    else
        if [ -f "$backup_keys_file" ]; then
            rm "$backup_keys_file"
            admin_username=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
            check_for_existing_processes $backup_keys_script
            { echo "echo \"Beginning webadmin backup keys \$(date)\" > $webadmin_install_dir/backup.txt";
              echo "chown www-data:www-data $webadmin_install_dir/backup.txt";
              echo '';
              echo "cp $webadmin_install_dir/backup_keys_progress_template.html $webadmin_install_dir/backup_keys_progress.html";
              echo "chown www-data:www-data $webadmin_install_dir/backup_keys_progress.html";
              echo '';
              echo "if /usr/local/bin/${PROJECT_NAME}-keydrive -u \"$admin_username\" --master 'yes' -d \"simple\" >> $webadmin_install_dir/backup.txt; then";
              echo "    echo \"Completed \$(date)\" >> $webadmin_install_dir/backup.txt";
              echo "    cp $webadmin_install_dir/backup_keys_complete.html $webadmin_install_dir/backup_keys_progress.html";
              echo 'else';
              echo "    cp $webadmin_install_dir/backup_keys_failed.html $webadmin_install_dir/backup_keys_progress.html";
              echo 'fi';
              echo '';
              echo "chown www-data:www-data $webadmin_install_dir/backup.txt";
              echo "chown www-data:www-data $webadmin_install_dir/backup_keys_progress.html";
              echo '';
              echo "exit 0"; } >> $backup_keys_script
            chmod +x $backup_keys_script

            # run in a separate process
            ./$backup_keys_script &
        fi
    fi
}

function is_valid_user {
    USRNAME="$1"
    if [[ "$USRNAME" != "turtl" && "$USRNAME" != "znc" && "$USRNAME" != "pihole" && "$USRNAME" != "fbone" && "$USRNAME" != "go" && "$USRNAME" != "gogs" && "$USRNAME" != "git" && "$USRNAME" != "sync" && "$USRNAME" != "tahoelafs" ]]; then
        echo "1"
    else
        echo "0"
    fi
}

function valid_username_characters {
  local re='^[[:lower:]_][[:lower:][:digit:]_-]{2,15}$'
  (( ${#1} > 16 )) && return 1
  [[ $1 =~ $re ]] # return value of this comparison is used for the function
}

function add_remove_users {
    if [ -f "$new_user_file" ]; then
        new_username=$(awk -F ',' '{print $1}' < "$new_user_file")

        if [ ${#new_username} -ge 3 ]; then
            if [ ${#new_username} -le 32 ]; then
                if valid_username_characters "$new_username"; then
                    if [ ! -d "/home/$new_username" ]; then
                        if [[ $(is_valid_user "$new_username") == "1" ]]; then
                            new_password=$(awk -F ',' '{print $2}' < "$new_user_file")

                            check_for_existing_processes $new_user_script
                            { echo "/usr/local/bin/${PROJECT_NAME}-adduser $new_username password=$new_password > $webadmin_install_dir/log.txt";
                              echo "exit 0"; } >> $new_user_script
                            chmod +x $new_user_script

                            # run in a separate process
                            ./$new_user_script &

                            new_password=
                        fi
                    fi
                fi
            fi
        fi

        rm "$new_user_file"
    fi

    if [ -f "$remove_user_file" ]; then
        remove_username=$(cat "$remove_user_file")

        if [ ${#remove_username} -ge 3 ]; then
            if [ ${#remove_username} -le 32 ]; then
                if valid_username_characters "$remove_username"; then
                    if [ -d "/home/$remove_username" ]; then
                        if [[ $(is_valid_user "$remove_username") == "1" ]]; then
                            admin_username=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
                            if [[ "$remove_username" != "$admin_username" ]]; then
                                check_for_existing_processes $remove_user_script
                                { echo "/usr/local/bin/${PROJECT_NAME}-rmuser $remove_username -f > $webadmin_install_dir/log.txt";
                                  echo "exit 0"; } >> $remove_user_script
                                chmod +x $remove_user_script

                                # run in a separate process
                                ./$remove_user_script &
                            fi
                        fi
                    fi
                fi
            fi
        fi

        rm "$remove_user_file"
    fi
}

function webadmin_change_password {
    if [ ! -f "$change_password_file" ]; then
        return
    fi

    temp_password_file=$(cat "$change_password_file")
    if [ -f "$temp_password_file" ]; then
        curr_username=$(awk -F ',' '{print $1}' < "$temp_password_file")
        if [ ${#curr_username} -ge 3 ]; then
            if [[ $(is_valid_user "$curr_username") == "1" ]]; then
                if [ -d "/home/$curr_username" ]; then
                    new_password=$(awk -F ',' '{print $2}' < "$temp_password_file")

                    admin_username=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')

                    # change the webadmin login
                    if [[ "$curr_username" == "$admin_username" ]]; then
                        if [ -f /etc/nginx/.webadminpasswd ]; then
                            sed -i "/${curr_username}:/d" /etc/nginx/.webadminpasswd
                        fi
                        echo -n "$new_password" | htpasswd -i -s -c /etc/nginx/.webadminpasswd "$curr_username"
                        echo -n "$new_password" > ${IMAGE_PASSWORD_FILE}
                    fi

                    # change the login for the user
                    echo -n "${curr_username}:${new_password}" | /usr/sbin/chpasswd

                    # change passwords for each installed app
                    /usr/local/bin/${PROJECT_NAME}-chpasswd "$curr_username" "$new_password"

                    # change the backup password
                    ${PROJECT_NAME}-pass -u admin -a simplebackup -p "$new_password"

                    new_password=
                fi
            fi
        fi
        rm "$temp_password_file"
    fi
    rm "$change_password_file"
}

function webadmin_upgrade {
    if [ -f "$upgrade_file" ]; then
        rm "$upgrade_file"

        check_for_existing_processes $upgrade_script
        { echo "echo \"Beginning webadmin upgrade \$(date)\" > $webadmin_install_dir/upgrade.txt";
          echo "chown www-data:www-data $webadmin_install_dir/upgrade.txt";
          echo '';
          echo "/usr/local/bin/${PROJECT_NAME}-upgrade >> $webadmin_install_dir/upgrade.txt";
          echo '';
          echo "chown www-data:www-data $webadmin_install_dir/upgrade.txt";
          echo '';
          echo "exit 0"; } >> $upgrade_script
        chmod +x $upgrade_script

        # run in a separate process
        ./$upgrade_script &
    fi
}

function webadmin_factory_reset {
    if [ -f "$factoryreset_file" ]; then
        rm "$factoryreset_file"

        check_for_existing_processes $factoryreset_script
        { echo "echo \"Beginning webadmin factory reset \$(date)\" > $webadmin_install_dir/factoryreset.txt";
          echo "chown www-data:www-data $webadmin_install_dir/factoryreset.txt";
          echo '';
          echo "/usr/local/bin/${PROJECT_NAME}-factory-reset -f >> $webadmin_install_dir/factoryreset.txt";
          echo '';
          echo "chown www-data:www-data $webadmin_install_dir/factoryreset.txt";
          echo '';
          echo "exit 0"; } >> $factoryreset_script
        chmod +x $factoryreset_script

        # run in a separate process
        ./$factoryreset_script &
    fi
}

function reset_shutdown {
    if [ -f "$shutdown_file" ]; then
        rm "$shutdown_file"
        if [ -f "$reset_file" ]; then
            rm "$reset_file"
        fi
        sleep 2
        systemctl poweroff
    fi

    if [ -f "$reset_file" ]; then
        rm "$reset_file"
        if [ -f "$shutdown_file" ]; then
            rm "$shutdown_file"
        fi
        sleep 2
        systemctl reboot -i
    fi
}

function regenerate_blocklist {
    if [ ! -f "$FIREWALL_DOMAINS" ]; then
        touch "$FIREWALL_DOMAINS"
    fi
    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
    if [ -f "$webadmin_install_dir/blocking_template.html" ]; then
        cp "$webadmin_install_dir/blocking_template.html" "$webadmin_install_dir/blocking.html"
        blockedlist=$(sed 's@[/\&]@\\&@g;s/$/\\/' "$FIREWALL_DOMAINS"; echo .)
        blockedlist=${blockedlist%.}
        sed -i "s|BLOCKEDLIST|$blockedlist|g" "$webadmin_install_dir/blocking.html"
        chown www-data:www-data "$webadmin_install_dir/blocking.html"
    fi
}

function regenerate_blocklist_muted_words {
    if [ ! -f "$MUTED_WORDS" ]; then
        touch "$MUTED_WORDS"
    fi
    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
    if [ -f "$webadmin_install_dir/blocking_words_template.html" ]; then
        cp "$webadmin_install_dir/blocking_words_template.html" "$webadmin_install_dir/blocking_words.html"
        blockedlistwords=$(sed 's@[/\&]@\\&@g;s/$/\\/' "$MUTED_WORDS"; echo .)
        blockedlistwords=${blockedlistwords%.}
        sed -i "s|BLOCKEDWORDSLIST|$blockedlistwords|g" "$webadmin_install_dir/blocking_words.html"
        chown www-data:www-data "$webadmin_install_dir/blocking_words.html"
    fi
}

function regenerate_bridges {
    if [ ! -f "/root/.webadmin_torbridges" ]; then
        touch "/root/.webadmin_torbridges"
    fi
    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
    if [ -f "$webadmin_install_dir/bridges_template.html" ]; then
        cp "$webadmin_install_dir/bridges_template.html" "$webadmin_install_dir/bridges.html"
        bridgeslist=$(sed 's@[/\&]@\\&@g;s/$/\\/' /root/.webadmin_torbridges; echo .)
        bridgeslist=${bridgeslist%.}
        sed -i "s|TORBRIDGES|$bridgeslist|g" "$webadmin_install_dir/bridges.html"
        chown www-data:www-data "$webadmin_install_dir/bridges.html"
    fi
}

function regenerate_dynamic_dns {
    ddns="$1"
    ddns_username="$2"
    ddns_password="$3"
    ddns_code="$4"

    local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
    webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
    if [ -f "$webadmin_install_dir/dynamicdns_template.html" ]; then
        cp "$webadmin_install_dir/dynamicdns_template.html" "$webadmin_install_dir/dynamicdns.html"
        if [[ "$ddns" == 'default@freedns.afraid.org' ]]; then
            ddns='freedns'
        fi
        if [[ "$ddns" == 'dyn.com' ]]; then
            ddns='dyn'
        fi
        sed -i "s|\"$ddns\"|\"$ddns\" selected|g" "$webadmin_install_dir/dynamicdns.html"
        sed -i "s|DDNS_USERNAME|$ddns_username|g" "$webadmin_install_dir/dynamicdns.html"
        sed -i "s|DDNS_CODE|$ddns_code|g" "$webadmin_install_dir/dynamicdns.html"
        sed -i "s|CURRENT_IP_ADDRESS|$(get_external_ipv4_address)|g" "$webadmin_install_dir/dynamicdns.html"
        chown www-data:www-data "$webadmin_install_dir/dynamicdns.html"
    fi
}

function syncthing_update_settings_template {
    # Creates the syncthing settings screen within webadmin
    # shellcheck disable=SC2154
    app_settings_screen_template="$webadmin_install_dir/settings_syncthing_template.html"
    app_settings_screen="$webadmin_install_dir/settings_syncthing.html"
    cp "$app_settings_screen_template" "$app_settings_screen"
    syncthinglist=$(sed 's@[/\&]@\\&@g;s/$/\\/' "/home/$MY_USERNAME/.syncthingids"; echo .)
    syncthinglist=${syncthinglist%.}
    sed -i "s|SYNCTHINGIDS|$syncthinglist|g" "$app_settings_screen"
    chown www-data:www-data "$app_settings_screen"
}

function smolrss_update_settings_template {
    # Creates rss feeds list within the web UI
    # shellcheck disable=SC2154
    app_settings_screen_template="$webadmin_install_dir/settings_smolrss_template.html"
    app_settings_screen="$webadmin_install_dir/settings_smolrss.html"
    cp "$app_settings_screen_template" "$app_settings_screen"
    feedslist=$(sed 's@[/\&]@\\&@g;s/$/\\/' "/var/www/$SMOLRSS_DOMAIN_NAME/htdocs/feeds.txt"; echo .)
    feedslist=${feedslist%.}
    sed -i "s|RSSFEEDS|$feedslist|g" "$app_settings_screen"
    chown www-data:www-data "$app_settings_screen"
}

function datserver_update_settings_template {
    # Creates dat links list within the web UI
    # shellcheck disable=SC2154
    app_settings_screen_template="$webadmin_install_dir/settings_datserver_template.html"
    app_settings_screen="$webadmin_install_dir/settings_datserver.html"
    cp "$app_settings_screen_template" "$app_settings_screen"
    datlinks=$(sed 's@[/\&]@\\&@g;s/$/\\/' "/etc/datserver/feeds"; echo .)
    datlinks=${datlinks%.}
    sed -i "s|DATLINKS|$datlinks|g" "$app_settings_screen"
    chown www-data:www-data "$app_settings_screen"
}

function update_syncthing {
    if [ -f "$syncthing_file" ]; then

        MY_USERNAME=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | awk -F '=' '{print $2}')

        syncthingids_new="/home/$MY_USERNAME/.syncthingids.webadmin"

        if [ -f "$syncthingids_new" ]; then
            rm "$syncthingids_new"
        fi
        touch "$syncthingids_new"

        # add an extra line, otherwise the last line may not parse
        echo "" >> "$syncthing_file"

        syncthing_lines_ctr=0
        while read -r line; do
            if [ $syncthing_lines_ctr -gt 1024 ]; then
                # This prevents someone copy-pasting a giant amount of text
                # into the syncthing ids.
                break
            fi
            syncthing_lines_ctr=$((syncthing_lines_ctr + 1))

            if [ "$line" ]; then
                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                echo "$newline" >> "$syncthingids_new"
            fi
        done < "$syncthing_file"

        mv "/home/$MY_USERNAME/.syncthingids" "/home/$MY_USERNAME/.syncthingids.backup"
        mv "$syncthingids_new" "/home/$MY_USERNAME/.syncthingids"
        chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.syncthingids"
        rm "$syncthing_file"
        syncthing_update_settings_template
        touch "/home/$MY_USERNAME/.syncthing-update"
        chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.syncthing-update"
    fi
}

function update_icecast {
    if [ -f "$icecast_file" ]; then
        if [ -d /etc/icecast2 ]; then
            ICECAST_TITLE=$(awk -F ',' '{print $1}' < "$icecast_file")
            ICECAST_DESCRIPTION=$(awk -F ',' '{print $2}' < "$icecast_file")
            icecast_genre=$(awk -F ',' '{print $3}' < "$icecast_file")

            if [[ "$ICECAST_TITLE" != '' && "$ICECAST_DESCRIPTION" != '' && "$icecast_genre" != '' ]]; then
                ADMIN_USERNAME=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | awk -F '=' '{print $2}')
                ICECAST_SOURCE_PASSWORD=$("${PROJECT_NAME}-pass" -u "$ADMIN_USERNAME" -a icecastsource)
                ICECAST_USER_PASSWORD=$("${PROJECT_NAME}-pass" -u "$ADMIN_USERNAME" -a icecastuser)

                ICECAST_TITLE_MAIN="$ICECAST_DESCRIPTION"

                { echo '#Settings';
                  echo '';
                  echo 'set("log.file.path", "/dev/null")';
                  echo 'set("server.telnet", false)';
                  echo 'set("harbor.bind_addr","0.0.0.0")';
                  echo '';
                  echo '# Music playlists';
                  echo "music1 = nrj(playlist.safe(\"$ICECAST_DIR\"))";
                  echo '';
                  echo '# Some jingles';
                  echo "jingles = nrj(playlist.safe(\"$ICECAST_JINGLES\"))";
                  echo '';
                  echo '# If something goes wrong, well play this';
                  echo 'security = single("/etc/icecast2/default.ogg")';
                  echo '';
                  echo '# Start building the feed with music';
                  echo 'radio = random([music1])';
                  echo '';
                  echo '# Add the security, requests and smart crossfade';
                  echo 'radio = fallback(track_sensitive = false,[smart_crossfade(fallback([request.queue(id="request"),radio])), security])';
                  echo '';
                  echo '# Now add some jingles';
                  echo 'radio = random(weights=[1,2],[jingles,radio])';
                  echo '';
                  echo '# Add a skip command for the music stream';
                  echo '#server.register(';
                  echo '#usage="skip",';
                  echo '#description="Skip the current song.",';
                  echo '#"skip",';
                  echo '#fun(_) -> begin source.skip(radio) "Done!" end';
                  echo '';
                  echo '# Talk over stream using microphone mount.';
                  echo "#mic = input.harbor(\"mic\",port=8080,password=\"$ICECAST_USER_PASSWORD\",buffer=15.0,max=30.0)";
                  echo '#radio = smooth_add(delay=0.8, p=0.15, normal=radio, special=mic)';
                  echo '';
                  echo '#Add support for live streams.';
                  echo "#live = audio_to_stereo(input.harbor(\"live\", port=8080, password=\"$ICECAST_USER_PASSWORD\", buffer=15.0, max=30.0))";
                  echo '#full = fallback(track_sensitive=false, [live,radio])';
                  echo '';
                  echo '# Stream it out';
                  echo '#output.icecast(%mp3.vbr,';
                  echo "#host = \"localhost\", port = $ICECAST_PORT, password = \"$ICECAST_SOURCE_PASSWORD\", mount = \"music.mp3\", name=\"$ICECAST_TITLE\", description=\"$ICECAST_DESCRIPTION\",radio)";
                  echo '';
                  echo '#output.icecast(%vorbis,';
                  echo "#host = \"localhost\", port = $ICECAST_PORT,";
                  echo "#password = \"$ICECAST_SOURCE_PASSWORD\", mount = \"music.ogg\",";
                  echo "#name=\"$ICECAST_TITLE\", description=\"$ICECAST_DESCRIPTION\",radio)";
                  echo '';
                  echo '#output.icecast(%opus(vbr="unconstrained",bitrate=5),';
                  echo "#host = \"localhost\", port = $ICECAST_PORT,";
                  echo "#password = \"$ICECAST_SOURCE_PASSWORD\", mount = \"music.opus\",";
                  echo "#name=\"$ICECAST_TITLE\", description=\"$ICECAST_DESCRIPTION\",radio)";
                  echo '';
                  echo "#output.icecast(%mp3.vbr, host = \"localhost\", port = $ICECAST_PORT, password = \"$ICECAST_SOURCE_PASSWORD\", mount = \"stream.mp3\", name=\"$ICECAST_TITLE_MAIN\", description=\"$ICECAST_TITLE_MAIN\", full)";
                  echo '';
                  echo "#output.icecast(%vorbis(samplerate=8000, channels=2, quality=0.1), host=\"localhost\", port=$ICECAST_PORT, password=\"$ICECAST_SOURCE_PASSWORD\", mount=\"stream.ogg\", name=\"$ICECAST_TITLE_MAIN\", description=\"$ICECAST_TITLE_MAIN\",full)";
                  echo '';
                  echo "output.icecast(%opus(vbr=\"unconstrained\",bitrate=20), description=\"$ICECAST_TITLE_MAIN\", host=\"localhost\", port=$ICECAST_PORT, password=\"$ICECAST_SOURCE_PASSWORD\", mount=\"stream.opus\", radio)"; } > "$liquidsoap_script"
                chown liquidsoapuser:icecast "$liquidsoap_script"

                sed -i "s|\"icecast_name\".*|\"icecast_name\" value=\"$ICECAST_TITLE\">|g" "$webadmin_install_dir/settings_icecast.html"
                sed -i "s|\"icecast_description\".*|\"icecast_description\" value=\"$ICECAST_DESCRIPTION\">|g" "$webadmin_install_dir/settings_icecast.html"
                sed -i "s|\"icecast_genre\".*|\"icecast_genre\" value=\"$icecast_genre\">|g" "$webadmin_install_dir/settings_icecast.html"

                icecast_usb_drive=$(detect_connected_drives)
                if [ "$icecast_usb_drive" ]; then
                    icecast_playlist_updated=
                    backup_mount_drive "$icecast_usb_drive"
                    if [ $backup_drive_mounted ]; then
                        icecast_import_dir="$USB_MOUNT/playlist"
                        # search some common directory names
                        if [ ! -d "$icecast_import_dir" ]; then
                            icecast_import_dir="$USB_MOUNT/icecast"
                        fi
                        if [ ! -d "$icecast_import_dir" ]; then
                            icecast_import_dir="$USB_MOUNT/radio"
                        fi
                        if [ ! -d "$icecast_import_dir" ]; then
                            icecast_import_dir="$USB_MOUNT/stream"
                        fi
                        if [ ! -d "$icecast_import_dir" ]; then
                            icecast_import_dir="$USB_MOUNT/music"
                        fi
                        if [ -d "$icecast_import_dir" ]; then
                            if [ -d "$ICECAST_DIR" ]; then
                                stop_icecast
                                # remove any existing playlist
                                # shellcheck disable=SC2115
                                rm -rf $ICECAST_DIR/*
                                # shellcheck disable=SC2115
                                rm -rf $ICECAST_JINGLES/*
                                # copy the new files
                                cp -ru "$icecast_import_dir/"* "$ICECAST_DIR"
                                cd "$ICECAST_DIR" || return
                                for name in *; do mv "$name" "${name// /_}"; done
                                icecast_playlist_updated=1
                            fi
                        fi
                    fi
                    backup_unmount_drive
                    if [ $icecast_playlist_updated ]; then
                        # move default file
                        if [ -f $ICECAST_DIR/default.ogg ]; then
                            mv $ICECAST_DIR/default.ogg /etc/icecast2/default.ogg
                            chown icecast2:icecast /etc/icecast2/default.ogg
                        fi

                        # move jingles
                        mv $ICECAST_DIR/jingle* $ICECAST_JINGLES
                        mv $ICECAST_DIR/Jingle* $ICECAST_JINGLES

                        chown -R liquidsoapuser:icecast $ICECAST_DIR
                        chown -R liquidsoapuser:icecast $ICECAST_JINGLES

                        icecast_import_subject=$'[Freedombone] Playlist imported'
                        icecast_import_msg=$'Playlist was imported from USB drive'

                        start_icecast

                        icecast_notification_file=/root/.icecast_import_msg.sh
                        { echo '#!/bin/bash';
                          echo "/usr/local/bin/${PROJECT_NAME}-notification -s '$icecast_import_subject' -m '$icecast_import_msg'"; } > "$icecast_notification_file"
                        chmod +x "$icecast_notification_file"
                        ./$icecast_notification_file &

                        rm "$icecast_file"
                        return
                    fi
                fi

                stop_icecast
                start_icecast
            fi
        fi

        rm "$icecast_file"
    fi
}

function update_koel {
    if [ -f "$koel_file" ]; then
        if [ -d /music ]; then
            koel_usb_drive=$(detect_connected_drives)
            if [ "$koel_usb_drive" ]; then
                backup_mount_drive "$koel_usb_drive"
                if [ $backup_drive_mounted ]; then
                    koel_import_dir="$USB_MOUNT/Music"
                    # search some common directory names
                    if [ ! -d "$koel_import_dir" ]; then
                        koel_import_dir="$USB_MOUNT/music"
                    fi
                    if [ -d "$koel_import_dir" ]; then
                        # copy the new files
                        cp -ru "$koel_import_dir/"* /music
                    fi
                    backup_unmount_drive
                fi
            fi
        fi

        rm "$koel_file"
    fi
}

function update_dlna {
    if [ -f "$dlna_file" ]; then
        if [ ! -f /etc/minidlna.conf ]; then
            dlna_usb_drive=$(detect_connected_drives)
            if [ "$dlna_usb_drive" ]; then
                backup_mount_drive "$dlna_usb_drive"
                if [ $backup_drive_mounted ]; then

                    # music
                    dlna_import_dir="$USB_MOUNT/Music"
                    if [ ! -d "$dlna_import_dir" ]; then
                        dlna_import_dir="$USB_MOUNT/music"
                    fi
                    if [ -d "$dlna_import_dir" ]; then
                        cp -ru "$dlna_import_dir/"* /music
                        chown -R minidlna:minidlna /music
                    fi

                    # pictures
                    dlna_import_dir="$USB_MOUNT/Pictures"
                    if [ ! -d "$dlna_import_dir" ]; then
                        dlna_import_dir="$USB_MOUNT/pictures"
                    fi
                    if [ ! -d "$dlna_import_dir" ]; then
                        dlna_import_dir="$USB_MOUNT/Photos"
                    fi
                    if [ ! -d "$dlna_import_dir" ]; then
                        dlna_import_dir="$USB_MOUNT/photos"
                    fi
                    if [ ! -d "$dlna_import_dir" ]; then
                        dlna_import_dir="$USB_MOUNT/DCIM"
                    fi
                    if [ -d "$dlna_import_dir" ]; then
                        cp -ru "$dlna_import_dir/"* /pictures
                        chown -R minidlna:minidlna /pictures
                    fi

                    # videos
                    dlna_import_dir="$USB_MOUNT/Videos"
                    if [ ! -d "$dlna_import_dir" ]; then
                        dlna_import_dir="$USB_MOUNT/videos"
                    fi
                    if [ -d "$dlna_import_dir" ]; then
                        cp -ru "$dlna_import_dir/"* /videos
                        chown -R minidlna:minidlna /videos
                    fi

                    backup_unmount_drive

                    systemctl restart minidlna
                    minidlnad -R
                fi
            fi
        fi

        rm "$dlna_file"
    fi
}

function update_smolrss {
    if [ -f "$smolrss_file" ]; then

        SMOLRSS_DOMAIN_NAME=$(grep 'SMOLRSS_DOMAIN_NAME=' "$CONFIGURATION_FILE" | awk -F '=' '{print $2}')

        cd "/var/www/$SMOLRSS_DOMAIN_NAME/htdocs" || return

        if [ -f "feeds.new" ]; then
            rm "feeds.new"
        fi
        touch "feeds.new"

        # add an extra line, otherwise the last line may not parse
        echo "" >> "$smolrss_file"

        feeds_lines_ctr=0
        while read -r line; do
            if [ $feeds_lines_ctr -gt 1024 ]; then
                # This prevents someone copy-pasting a giant amount of text
                # into the rss feeds
                break
            fi
            feeds_lines_ctr=$((feeds_lines_ctr + 1))

            if [ "$line" ]; then
                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                echo "$newline" >> "feeds.new"
            fi
        done < "$smolrss_file"

        mv "feeds.new" feeds.txt
        ./create_feeds feeds.txt > feeds.xml
        chown www-data:www-data feeds.txt

        rm "$smolrss_file"
        smolrss_update_settings_template
    fi
}

function update_dat_links {
    if [ -f "$datlinks_file" ]; then

        cd "/etc/datserver" || return

        if [ -f "feeds.new" ]; then
            rm "feeds.new"
        fi
        touch "feeds.new"

        # add an extra line, otherwise the last line may not parse
        echo "" >> "$datlinks_file"

        datlinks_lines_ctr=0
        while read -r line; do
            if [ $datlinks_lines_ctr -gt 1024 ]; then
                # This prevents someone copy-pasting a giant amount of text
                # into the dat links
                break
            fi
            datlinks_lines_ctr=$((datlinks_lines_ctr + 1))

            if [ "$line" ]; then
                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                if [[ "$newline" == 'dat://'* ]]; then
                    echo "$newline" >> "feeds.new"
                fi
            fi
        done < "$datlinks_file"

        mv "feeds.new" feeds

        rm "$datlinks_file"
        datserver_update_settings_template

        chown -R datserver:datserver /etc/datserver/feeds
        systemctl restart datserver
    fi
}

function change_updates_settings {
    if [ -f "$settings_updates_file" ]; then
        updates_enabled=$(awk -F ',' '{print $1}' < "$settings_updates_file")
        if [[ "$updates_enabled" != '0' && "$updates_enabled" != '1' ]]; then
            rm "$settings_updates_file"
            return
        fi

        updates_repo=$(awk -F ',' '{print $2}' < "$settings_updates_file")
        if [[ "$updates_repo" != *'.'* || "$updates_repo" != 'http'* || "$updates_repo" == *' '* || "$updates_repo" == *'$'* || "$updates_repo" == *'`'* ]]; then
            rm "$settings_updates_file"
            return
        fi

        updates_branch=$(awk -F ',' '{print $3}' < "$settings_updates_file")
        if [[ "$updates_branch" == 'http'* || "$updates_branch" == *' '* || "$updates_branch" == *'$'* || "$updates_branch" == *'`'* ]]; then
            rm "$settings_updates_file"
            return
        fi

        PROJECT_REPO='none'
        if [ "$updates_repo" ]; then
            PROJECT_REPO="$updates_repo"
        fi
        if grep -q 'PROJECT_REPO=' "$CONFIGURATION_FILE"; then
            sed -i "s|PROJECT_REPO=.*|PROJECT_REPO=$PROJECT_REPO|g" "$CONFIGURATION_FILE"
        else
            echo "PROJECT_REPO=$PROJECT_REPO" >> "$CONFIGURATION_FILE"
        fi

        STABLE_BRANCH=
        if [ "$updates_branch" ]; then
            STABLE_BRANCH="$updates_branch"
        fi
        if grep -q 'STABLE_BRANCH=' "$CONFIGURATION_FILE"; then
            sed -i "s|STABLE_BRANCH=.*|STABLE_BRANCH=$STABLE_BRANCH|g" "$CONFIGURATION_FILE"
        else
            echo "STABLE_BRANCH=$STABLE_BRANCH" >> "$CONFIGURATION_FILE"
        fi

        # change default checked state for radio button
        if [[ "$updates_enabled" == '1' ]]; then
            sed -i "s|value=\"1\">|value=\"1\" checked>|g" "$webadmin_install_dir/settings_updates.html"
            sed -i "s|value=\"0\" checked>|value=\"0\">|g" "$webadmin_install_dir/settings_updates.html"
        else
            sed -i "s|value=\"0\">|value=\"0\" checked>|g" "$webadmin_install_dir/settings_updates.html"
            sed -i "s|value=\"1\" checked>|value=\"1\">|g" "$webadmin_install_dir/settings_updates.html"
        fi

        # update variables within updates settings screen
        sed -i "s|name=\"updates_repo\".*|name=\"updates_repo\" value=\"$PROJECT_REPO\">|g" "$webadmin_install_dir/settings_updates.html"
        sed -i "s|name=\"updates_branch\".*|name=\"updates_branch\" value=\"$STABLE_BRANCH\">|g" "$webadmin_install_dir/settings_updates.html"

        # if we are updating from the web UI then disable any development branch
        if grep -q 'DEVELOPMENT_BRANCH=' "$CONFIGURATION_FILE"; then
            sed '/DEVELOPMENT_BRANCH=/d' "$CONFIGURATION_FILE"
        fi

        rm "$settings_updates_file"
    fi
}

function update_enable_ssh {
    if [ -f "$ssh_file" ]; then
        SSH_CONFIG='/etc/ssh/sshd_config'
        if ! grep -q 'PasswordAuthentication' $SSH_CONFIG; then
            echo 'PasswordAuthentication no' >> $SSH_CONFIG
        fi
        if grep -q '#PasswordAuthentication' $SSH_CONFIG; then
            sed -i "s|#PasswordAuthentication|PasswordAuthentication|g" $SSH_CONFIG
        fi
        if ! grep -q 'PasswordAuthentication no' $SSH_CONFIG; then
            sed -i "s|PasswordAuthentication.*|PasswordAuthentication no|g" $SSH_CONFIG
        fi

        ssh_active=$(awk -F ',' '{print $1}' < "$ssh_file")
        ADMIN_USERNAME=$(grep 'MY_USERNAME=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
        if [[ "$ssh_active" != '1' ]]; then
            # disable ssh access
            if [ -f "/home/$ADMIN_USERNAME/.ssh/authorized_keys" ]; then
                rm "/home/$ADMIN_USERNAME/.ssh/authorized_keys"
            fi
            iptables -D INPUT -p udp --dport "${SSH_PORT}" -j ACCEPT
            iptables -D INPUT -p tcp --dport "${SSH_PORT}" -j ACCEPT
        else
            # enable ssh access
            ssh_public_key=$(awk -F ',' '{print $2}' < "$ssh_file")

            if [ ${#ssh_public_key} -gt 20 ]; then
                if [[ "$ssh_public_key" == 'ssh-'* ]]; then
                    if [ ! -d "/home/$ADMIN_USERNAME/.ssh" ]; then
                        mkdir "/home/$ADMIN_USERNAME/.ssh"
                    fi
                    echo "$ssh_public_key" > "/home/$ADMIN_USERNAME/.ssh/authorized_keys"
                    echo "" >> "/home/$ADMIN_USERNAME/.ssh/authorized_keys"
                    chown -R "$ADMIN_USERNAME":"$ADMIN_USERNAME" "/home/$ADMIN_USERNAME/.ssh"
                    iptables -A INPUT -p udp --dport "${SSH_PORT}" -j ACCEPT
                    iptables -A INPUT -p tcp --dport "${SSH_PORT}" -j ACCEPT
                fi
            fi
        fi
        iptables-save > /etc/firewall.conf
        ip6tables-save > /etc/firewall6.conf
        systemctl restart ssh
        rm "$ssh_file"
    fi
}

function update_email_blocklists {
    FIREWALL_DOMAINS_OLD="$1"
    FIREWALL_DOMAINS_NEW="${1}.new"

    if [ -f "$FIREWALL_DOMAINS_OLD" ]; then
        # remove email blocks
        for d in /home/*/ ; do
            USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
            if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
                while read -r block_line; do
                    if [ "$block_line" ]; then
                        if [[ "$block_line" != *'@'* ]]; then
                            # line is a domain name
                            new_block_line="@${block_line}"
                            block_line="${new_block_line}"
                        fi

                        # does not exist in the new version
                        if ! grep -q "$block_line" "$FIREWALL_DOMAINS_NEW"; then
                            "${PROJECT_NAME}-unignore" -u "$USERNAME" -e "$block_line"
                        fi
                    fi
                done < "$FIREWALL_DOMAINS_OLD"
            fi
        done
    fi

    # add email blocks
    for d in /home/*/ ; do
        USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
        if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
            while read -r block_line; do
                if [ "$block_line" ]; then
                    if [[ "$block_line" != *'@'* ]]; then
                        # line is a domain name
                        new_block_line="@${block_line}"
                        block_line="${new_block_line}"
                    fi

                    if [ -f "$FIREWALL_DOMAINS_OLD" ]; then
                        # does not exist in the old version
                        if ! grep -q "$block_line" "$FIREWALL_DOMAINS_OLD"; then
                            "${PROJECT_NAME}-ignore" -u "$USERNAME" -e "$block_line"
                        fi
                    else
                        "${PROJECT_NAME}-ignore" -u "$USERNAME" -e "$block_line"
                    fi
                fi
            done < "$FIREWALL_DOMAINS_NEW"
        fi
    done
}

function update_email_muted_words {
    MUTED_WORDS_OLD="$1"
    MUTED_WORDS_NEW="${1}.new"
    muted_words_changed=

    if [ -f "$MUTED_WORDS_OLD" ]; then
        # remove email blocks
        for d in /home/*/ ; do
            USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
            if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
                while read -r block_line; do
                    if [ "$block_line" ]; then
                        # does not exist in the new version
                        if ! grep -q "$block_line" "$MUTED_WORDS_NEW"; then
                            "${PROJECT_NAME}-unignore" -u "$USERNAME" -a "$block_line"
                            muted_words_changed=1
                        fi
                    fi
                done < "$MUTED_WORDS_OLD"
            fi
        done
    fi

    # add email blocks
    for d in /home/*/ ; do
        USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
        if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
            while read -r block_line; do
                if [ "$block_line" ]; then
                    if [ -f "$MUTED_WORDS_OLD" ]; then
                        # does not exist in the old version
                        if ! grep -q "$block_line" "$MUTED_WORDS_OLD"; then
                            "${PROJECT_NAME}-ignore" -u "$USERNAME" -a "$block_line"
                            muted_words_changed=1
                        fi
                    else
                        "${PROJECT_NAME}-ignore" -u "$USERNAME" -a "$block_line"
                        muted_words_changed=1
                    fi
                fi
            done < "$MUTED_WORDS_NEW"
        fi
    done

    if [ $muted_words_changed ]; then
        if [ -f /etc/prosody/prosody.cfg.lua ]; then
            systemctl restart prosody
        fi
    fi
}

function update_blocklist {
    if [ -f "$blocklist_file" ]; then

        if [ -f "${FIREWALL_DOMAINS}.new" ]; then
            rm "${FIREWALL_DOMAINS}.new"
        fi
        touch "${FIREWALL_DOMAINS}.new"

        # create the prosody firewall file
        if [ -d /var/lib/prosody ]; then
            blacklisted_addresses_filename=/var/lib/prosody/blocked_addresses.txt
            if [ -f "${blacklisted_addresses_filename}.new" ]; then
                rm "${blacklisted_addresses_filename}.new"
            fi
        fi

        # add an extra line, otherwise the last line may not parse
        echo "" >> "$blocklist_file"

        blocked_lines_ctr=0
        while read -r line; do
            if [ $blocked_lines_ctr -gt 1024 ]; then
                # This prevents someone copy-pasting a giant amount of text
                # into the blocklist. If you're legitimately blocking more
                # than this number then you probably have other problems to
                # think about and should consider whitelisting instead
                break
            fi
            blocked_lines_ctr=$((blocked_lines_ctr + 1))

            if [ "$line" ]; then
                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                line="$newline"
                if [[ "$line" == *'@'* ]]; then
                    # blocked user
                    # remove leading @
                    if [[ "$line" == '@'* ]]; then
                        newline=${line:1}
                        line="$newline"
                    fi
                    blocked_username=$(echo "$line" | awk -F '@' '{print $1}')
                    if valid_username_characters "$blocked_username"; then
                        blocked_domain=$(echo "$line" | awk -F '@' '{print $2}')
                        if [[ "$blocked_domain" == *'.'* ]]; then
                            if [ ${#blocked_domain} -gt 3 ]; then
                                test_domain=$(echo "$blocked_domain" | tr -dc a-z0-9.-)
                                if [[ "$blocked_domain" == "$test_domain" ]]; then
                                    blocked_address="${blocked_username}@${blocked_domain}"
                                    if ! grep -q "$blocked_address" "${FIREWALL_DOMAINS}.new"; then
                                        echo "${blocked_username}@${blocked_domain}" >> "${FIREWALL_DOMAINS}.new"
                                        # update the prosody firewall
                                        if [ -d /var/lib/prosody ]; then
                                            if ! grep -q "${blocked_username}@${blocked_domain}" "${blacklisted_addresses_filename}.new"; then
                                                echo "${blocked_username}@${blocked_domain}" >> "${blacklisted_addresses_filename}.new"
                                            fi
                                        fi
                                    fi
                                fi
                            fi
                        fi
                    fi
                else
                    # blocked domain
                    if [[ "$line" == *'.'* ]]; then
                        blocked_domain="$line"
                        test_domain=$(echo "$blocked_domain" | tr -dc a-z0-9.-)
                        if [[ "$blocked_domain" == "$test_domain" ]]; then
                            if [ ${#blocked_domain} -gt 3 ]; then
                                if ! grep -q "$blocked_domain" "${FIREWALL_DOMAINS}.new"; then
                                    echo "$blocked_domain" >> "${FIREWALL_DOMAINS}.new"
                                fi
                            fi
                        fi
                    fi
                fi
            fi
        done < "$blocklist_file"

        # update the prosody firewall
        if [ -d /var/lib/prosody ]; then
            if [ -f "${blacklisted_addresses_filename}.new" ]; then
                cp "${blacklisted_addresses_filename}.new" "${blacklisted_addresses_filename}"
                rm "${blacklisted_addresses_filename}.new"
            else
                echo -n '' > "${blacklisted_addresses_filename}"
            fi
            chown prosody:prosody "${blacklisted_addresses_filename}"
            systemctl restart prosody
        fi

        update_email_blocklists "${FIREWALL_DOMAINS}"

        mv "${FIREWALL_DOMAINS}" "${FIREWALL_DOMAINS}.backup"
        mv "${FIREWALL_DOMAINS}.new" "${FIREWALL_DOMAINS}"
        rm "$blocklist_file"
        regenerate_blocklist
    fi
}

function update_muted_words {
    if [ -f "$muted_words_file" ]; then

        if [ -f "${MUTED_WORDS}.new" ]; then
            rm "${MUTED_WORDS}.new"
        fi
        touch "${MUTED_WORDS}.new"

        # add an extra line, otherwise the last line may not parse
        echo "" >> "$muted_words_file"

        blocked_lines_ctr=0
        while read -r line; do
            if [ $blocked_lines_ctr -gt 1024 ]; then
                # This prevents someone copy-pasting a giant amount of text
                # into the blocklist. If you're legitimately blocking more
                # than this number then you probably have other problems to
                # think about and should consider whitelisting instead
                break
            fi
            blocked_lines_ctr=$((blocked_lines_ctr + 1))

            if [ "$line" ]; then
                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                line="$newline"

                if [ ${#line} -gt 1 ]; then
                    blocked_words_str="$line"
                    if ! grep -q "$blocked_words_str" "${MUTED_WORDS}.new"; then
                        echo "$blocked_words_str" >> "${MUTED_WORDS}.new"
                    fi
                fi
            fi
        done < "$muted_words_file"

        update_email_muted_words "${MUTED_WORDS}"

        mv "${MUTED_WORDS}" "${MUTED_WORDS}.backup"
        mv "${MUTED_WORDS}.new" "${MUTED_WORDS}"
        rm "$muted_words_file"
        regenerate_blocklist_muted_words
    fi
}

function import_translations {
    if [ -f "$translations_import_file" ]; then
        translations_language=

        if [ -f "translations_import.new" ]; then
            rm "translations_import.new"
        fi
        touch "translations_import.new"

        # add an extra line, otherwise the last line may not parse
        echo "" >> "$translations_import_file"

        import_lines_ctr=0
        translation_lines_ctr=0
        while read -r line; do
            if [ $import_lines_ctr -gt 2048 ]; then
                # This prevents someone copy-pasting a giant amount of text
                break
            fi

            if [ "$line" ]; then
                import_lines_ctr=$((import_lines_ctr + 1))

                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                line="$newline"

                if [ $import_lines_ctr -eq 1 ]; then
                    translations_language="$line"
                fi

                if [ "$translations_language" ]; then
                    if [[ "$line" == *'|'* ]]; then
                        no_of_separators=$(echo "${line}" | awk -F '|' '{print NF-1}')
                        # shellcheck disable=SC2086
                        if [ $no_of_separators -eq 1 ]; then
                            echo "$line" >> "translations_import.new"
                            translation_lines_ctr=$((translation_lines_ctr + 1))
                        fi
                    fi
                fi
            fi
        done < "$translations_import_file"

        if [ "$translations_language" ]; then
            if [ $translation_lines_ctr -gt 100 ]; then
                local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
                webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"

                if [ ! -d "$webadmin_install_dir/translations" ]; then
                    mkdir "$webadmin_install_dir/translations"
                fi
                mv "translations_import.new" "$webadmin_install_dir/translations/${translations_language}.txt"
                chown -R www-data:www-data "$webadmin_install_dir/translations"

                # keep the imported translations
                if [ ! -f "$webadmin_install_dir/.keep_translations.txt" ]; then
                    touch "$webadmin_install_dir/.keep_translations.txt"
                    chown www-data:www-data "$webadmin_install_dir/.keep_translations.txt"
                fi
            fi
        fi
        if [ -f "translations_import.new" ]; then
            rm "translations_import.new"
        fi
        rm "$translations_import_file"
    fi
}

function change_default_domain {
    if [ -f "$default_domain_file" ]; then
        new_default_domain_name=$(cat "$default_domain_file")
        rm "$default_domain_file"

        # only applies to the standard server install, not onion
        ONION_ONLY=$(grep 'ONION_ONLY=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
        if [[ "$ONION_ONLY" == 'no' ]]; then
            if [ "$new_default_domain_name" ]; then
                if [ ${#new_default_domain_name} -gt 5 ]; then
                    if [[ "$new_default_domain_name" == *'.'* ]]; then

                        # has the default domain changed ?
                        DEFAULT_DOMAIN_NAME=$(grep 'DEFAULT_DOMAIN_NAME=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
                        if [[ "$DEFAULT_DOMAIN_NAME" != "$new_default_domain_name" ]]; then
                            # set the new default domain within the config file
                            if ! grep -q "NEW_DEFAULT_DOMAIN_NAME=" $CONFIGURATION_FILE; then
                                echo "NEW_DEFAULT_DOMAIN_NAME=$new_default_domain_name" >> $CONFIGURATION_FILE
                            else
                                sed -i "s|NEW_DEFAULT_DOMAIN_NAME=.*|NEW_DEFAULT_DOMAIN_NAME=$new_default_domain_name|g" $CONFIGURATION_FILE
                            fi

                            # initiate an upgrade
                            touch "$upgrade_file"
                        fi

                    fi
                fi
            fi
        fi
    fi
}

function create_scuttlebot_invite {
    if [ -f "$scuttlebot_file" ]; then
        if [ -d /etc/scuttlebot ]; then
            invite_string=$(su -c "/etc/scuttlebot/node_modules/.bin/sbot invite.create 1" - scuttlebot | sed 's/"//g')
            if [ ! "$invite_string" ]; then
                echo $'Unable to create scuttlebot invite'
                exit 36
            fi
            current_invite=$(grep 'SCUTTLEBOT_INVITE=' "/root/${PROJECT_NAME}.cfg" | head -n 1 | sed 's|SCUTTLEBOT_INVITE=||g')
            sed -i "s|SCUTTLEBOT_INVITE=.*|SCUTTLEBOT_INVITE=${invite_string}|g" "/root/${PROJECT_NAME}.cfg"
            sed -i "s|$current_invite|$invite_string|g" "$webadmin_install_dir/app_scuttlebot.html"

            if [ ! -f /usr/local/bin/myqr ]; then
                echo -n "$invite_string" | qrencode -t PNG -o "$webadmin_install_dir/app_qrcode_scuttlebot.png"
            else
                myqr "$invite_string" -p /root/freedombone/img/android-app/scuttlebot.png -c -n "$webadmin_install_dir/app_qrcode_scuttlebot.png"
            fi
            echo -n "$invite_string" > /etc/scuttlebot/.current_invite.txt
        fi

        rm "$scuttlebot_file"
    fi
}

function update_bridges {
    if [ -f "$bridgeslist_file" ]; then

        if [ -f "/root/.webadmin_torbridges" ]; then
            rm "/root/.webadmin_torbridges"
        fi
        touch "/root/.webadmin_torbridges"

        if [ ! -f /usr/bin/obfs4proxy ]; then
            apt-get -yq install obfs4proxy
        fi

        bridge_type='obfs4'
        { echo 'ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed';
          echo 'UseBridges 1'; } > /etc/torrc.d/bridges

        bridges_lines_ctr=0
        while read -r line; do
            if [ $bridges_lines_ctr -gt 1024 ]; then
                # This prevents someone copy-pasting a giant amount of text
                # into the bridges list.
                break
            fi
            bridges_lines_ctr=$((bridges_lines_ctr + 1))

            if [ "$line" ]; then
                # remove leading and trailing spaces
                newline="$(echo -e "${line}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
                line="$newline"
                if [ ${#line} -gt 10 ]; then
                    if [[ "$line" == '#'* ]]; then
                        echo "$line" >> "/root/.webadmin_torbridges"
                    else
                        bridge_ip_address=$(echo "$line" | awk -F ':' '{print $1}')
                        bridge_port=$(echo "$line" | awk -F ':' '{print $2}' | awk -F ' ' '{print $1}')
                        bridge_key=$(echo "$line" | awk -F ' ' '{print $2}')
                        if [[ "${bridge_ip_address}" == *"."* ]]; then
                            if ! grep -q "Bridge $bridge_type ${bridge_ip_address}:${bridge_port} ${bridge_key}" /etc/torrc.d/bridges; then
                                echo "Bridge $bridge_type ${bridge_ip_address}:${bridge_port} ${bridge_key}" >> /etc/torrc.d/bridges
                                echo "${bridge_ip_address}:${bridge_port} ${bridge_key}" >> "/root/.webadmin_torbridges"
                            fi
                        fi
                    fi
               fi
            fi
        done < "$bridgeslist_file"

        rm "$bridgeslist_file"
        regenerate_bridges

        systemctl restart tor
    fi
}

function update_email_proxy {
    # This allows outgoing email to be proxied through your ISP or another SMTP server
    if [ -f "$email_proxy_file" ]; then
        isp_smtp_domain=$(awk -F ',' '{print $1}' < "$email_proxy_file")
        isp_smtp_port=$(awk -F ',' '{print $2}' < "$email_proxy_file")
        isp_smtp_username=$(awk -F ',' '{print $3}' < "$email_proxy_file")
        isp_smtp_password=$(awk -F ',' '{print $4}' < "$email_proxy_file")

        rm "$email_proxy_file"

        email_smtp_proxy_through_isp "$isp_smtp_domain" "$isp_smtp_port" "$isp_smtp_username" "$isp_smtp_password"
    fi
}

function update_dynamic_dns {
    if [ -f "$dynamic_dns_file" ]; then
        ddns=$(awk -F ',' '{print $1}' < "$dynamic_dns_file")
        ddns_username=$(awk -F ',' '{print $2}' < "$dynamic_dns_file")
        ddns_password=$(awk -F ',' '{print $3}' < "$dynamic_dns_file")
        ddns_code=$(awk -F ',' '{print $4}' < "$dynamic_dns_file")

        ddns_is_valid=
        if [ "$ddns_username" ]; then
            if [ "$ddns_password" ]; then
                if [ ${#ddns_username} -gt 2 ]; then
                    if [ ${#ddns_username} -lt 512 ]; then
                        if [ ${#ddns_password} -gt 2 ]; then
                            if [ ${#ddns_password} -lt 512 ]; then
                                ddns_is_valid=1
                            fi
                        fi
                    fi
                fi
            fi
        fi

        if [ $ddns_is_valid ]; then
            /usr/local/bin/${PROJECT_NAME}-ddns "$ddns" "$ddns_username" "$ddns_password"

            if [ "$ddns_code" ]; then
                if [ ${#ddns_code} -gt 30 ]; then
                    # if the whole cron line was pasted then parse that
                    if [[ "$ddns_code" == *'freedns'* ]]; then
                        if [[ "$ddns_code" == *'?'* && "$ddns_code" == *'='* ]]; then
                            ddns_code=$(echo "$ddns_code" | awk -F '?' '{print $2}' | awk -F '=' '{print $1}')
                        fi
                    fi
                    if grep -q "DEFAULT_DOMAIN_CODE=" "$CONFIGURATION_FILE"; then
                        sed -i "s|DEFAULT_DOMAIN_CODE=.*|DEFAULT_DOMAIN_CODE=${ddns_code}|g" "$CONFIGURATION_FILE"
                    else
                        echo "DEFAULT_DOMAIN_CODE=${ddns_code}" >> "$CONFIGURATION_FILE"
                    fi
                else
                    ddns_code=
                fi
            fi

            regenerate_dynamic_dns "$ddns" "$ddns_username" "$ddns_password" "$ddns_code"
        fi

        rm "$dynamic_dns_file"
    fi
}

function webadmin_monitor_ip_changes {
    if [ -f "$webadmin_install_dir/dynamicdns.html" ]; then
        ONION_ONLY=$(grep 'ONION_ONLY=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
        if [[ "$ONION_ONLY" == 'no' ]]; then
            webadmin_monitor_ip_ctr=$((webadmin_monitor_ip_ctr-1))
            if [ $webadmin_monitor_ip_ctr -le 0 ]; then
                webadmin_monitor_ip_ctr=300
                curr_ipv4=$(get_external_ipv4_address)
                if [ "$curr_ipv4" ]; then
                    if [[ "$curr_ipv4" != "$webadmin_ipv4_address" ]]; then
                        if [ "$webadmin_ipv4_address" ]; then

                            # update dynamic dns
                            if grep -q 'freedns' /etc/crontab; then
                                DEFAULT_DOMAIN_CODE=$(grep 'DEFAULT_DOMAIN_CODE=' "$CONFIGURATION_FILE" | head -n 1 | awk -F '=' '{print $2}')
                                if [ "$DEFAULT_DOMAIN_CODE" ]; then
                                    # shellcheck disable=SC2086
                                    wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?$DEFAULT_DOMAIN_CODE= >> /var/log/freedns_@_update.log 2>&1 &
                                fi
                            fi

                            /usr/local/bin/${PROJECT_NAME}-notification -s "[${PROJECT_NAME}] Dynamic DNS" -m "IP address changed from $webadmin_ipv4_address to $curr_ipv4" &
                        fi
                        webadmin_ipv4_address="$curr_ipv4"
                        sed -i "s|<p class=\"ipaddress\".*|<p class=\"ipaddress\" translate=\"no\">${curr_ipv4}</p>|g" "$webadmin_install_dir/dynamicdns.html"
                    fi
                fi
            fi
        fi
    fi
}

function change_theme {
    if [ -f "$theme_file" ]; then
        bg_color=$(awk -F ',' '{print $1}' < "$theme_file")
        fg_color=$(awk -F ',' '{print $2}' < "$theme_file")

        if ! grep -q 'WEBADMIN_BACKGROUND_COLOR=' "/root/${PROJECT_NAME}.cfg"; then
            echo "WEBADMIN_BACKGROUND_COLOR=${bg_color}" >> "/root/${PROJECT_NAME}.cfg"
        else
            sed -i "s|WEBADMIN_BACKGROUND_COLOR=.*|WEBADMIN_BACKGROUND_COLOR=${bg_color}|g" "/root/${PROJECT_NAME}.cfg"
        fi

        if ! grep -q 'WEBADMIN_FOREGROUND_COLOR=' "/root/${PROJECT_NAME}.cfg"; then
            echo "WEBADMIN_FOREGROUND_COLOR=${fg_color}" >> "/root/${PROJECT_NAME}.cfg"
        else
            sed -i "s|WEBADMIN_FOREGROUND_COLOR=.*|WEBADMIN_FOREGROUND_COLOR=${fg_color}|g" "/root/${PROJECT_NAME}.cfg"
        fi

        web_admin_background_color
        rm "$theme_file"
    fi
}

function change_language {
    if [ -f "$language_file" ]; then
        language=$(cat "$language_file")
        local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
        webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"
        if [ -f "$webadmin_install_dir/language_template.html" ]; then
            if grep -q "\"$language\"" "$webadmin_install_dir/language_template.html"; then

                if ! grep -q "DEFAULT_LANGUAGE=" "$CONFIGURATION_FILE"; then
                    echo "DEFAULT_LANGUAGE=$language" >> "$CONFIGURATION_FILE"
                else
                    sed -i "s|DEFAULT_LANGUAGE=.*|DEFAULT_LANGUAGE=$language|g" "$CONFIGURATION_FILE"
                fi

                /usr/bin/timeout $APP_INSTALL_TIMEOUT_SEC /usr/local/bin/${PROJECT_NAME}-language "${language}" > "$webadmin_install_dir/log.txt"

                # change the selected language
                cp "$webadmin_install_dir/language_template.html" "$webadmin_install_dir/language.html"
                sed -i "s|\"$language\" translate=\"yes\"|\"$language\" translate=\"yes\" selected|g" "$webadmin_install_dir/language.html"
                chown www-data:www-data "$webadmin_install_dir/language.html"
            fi
        fi

        rm "$language_file"
    fi
}

function update_system_monitor {
    if [ -f "$system_monitor_file" ]; then
        rm "$system_monitor_file"

        drives_list=$(df -h | grep "/dev/")
        test_drive=/dev/sda2
        if [[ "$drives_list" != *"$test_drive"* ]]; then
            test_drive=/dev/sda1
            if [[ "$drives_list" != *"$test_drive"* ]]; then
                test_drive=/dev/mmcblk0p2
                if [[ "$drives_list" != *"$test_drive"* ]]; then
                    test_drive=/dev/mmcblk0p1
                fi
            fi
        fi

        cpu_usage=$(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}' | awk -F '.' '{print $1}')

        disk_use=$(df -h | grep $test_drive)
        disk_use_percent='0%'
        disk_use_gb='0'
        disk_size_gb='0'
        if [[ "$disk_use" == *"$test_drive"* ]]; then
            disk_use_percent=$(df -h | grep $test_drive | tail -n 1 | awk -F ' ' '{print $5}')
            disk_use_gb=$(df -h | grep $test_drive | tail -n 1 | awk -F ' ' '{print $3}' | sed 's|G||g')
            disk_size_gb=$(df -h | grep $test_drive | tail -n 1 | awk -F ' ' '{print $2}' | sed 's|G||g')
        fi

        backup_disk_use_percent=
        backup_disk_use_gb=
        if [ -f "$DRIVES_BASELINE_FILE" ]; then
            backup_device=$(detect_connected_drives)
            if [ "$backup_device" ]; then
                backup_mount_drive "$backup_device"
                if [ $backup_drive_mounted ]; then
                    backup_disk_use=$(df -h | grep "$backup_device")
                    backup_disk_use_percent='0%'
                    backup_disk_use_gb='0'
                    backup_disk_size_gb='0'
                    if [[ "$backup_disk_use" == *"$backup_device"* ]]; then
                        backup_disk_use_percent=$(df -h | grep "$backup_device" | tail -n 1 | awk -F ' ' '{print $5}')
                        backup_disk_use_gb=$(df -h | grep "$backup_device" | tail -n 1 | awk -F ' ' '{print $3}' | sed 's|G||g')
                        backup_disk_size_gb=$(df -h | grep "$backup_device" | tail -n 1 | awk -F ' ' '{print $2}' | sed 's|G||g')
                    fi
                fi
                backup_unmount_drive
            fi
        fi

        total_memory=$(free -m | grep "Mem:" | awk -F ' ' '{print $2}')
        total_memory_gb_integer=$((total_memory/100))
        total_memory_gb='0'
        if [ ${#total_memory_gb_integer} -gt 1 ]; then
            #shellcheck disable=SC2001
            total_memory_gb=$(echo "$total_memory_gb_integer" | sed 's/.$/.&/')
        else
            #shellcheck disable=SC2001
            total_memory_gb=0$(echo "$total_memory_gb_integer" | sed 's/.$/.&/')
        fi

        used_memory=$(free -m | grep "Mem:" | awk -F ' ' '{print $3}')
        used_memory_percent=$((used_memory * 100 / total_memory))
        used_memory_gb_integer=$((used_memory/100))
        used_memory_gb='0'
        if [ ${#used_memory_gb_integer} -gt 1 ]; then
            #shellcheck disable=SC2001
            used_memory_gb=$(echo "$used_memory_gb_integer" | sed 's/.$/.&/')
        else
            #shellcheck disable=SC2001
            used_memory_gb=0$(echo "$used_memory_gb_integer" | sed 's/.$/.&/')
        fi

        cpu_temperature=0
        if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
            cpu_temp=$(cat /sys/class/thermal/thermal_zone*/temp | head -n 1)
            if [ "$cpu_temp" ]; then
                cpu_temperature=$((cpu_temp / 1000))
            fi
        fi

        disk_io_speed=20
        disk_io_speed_percent=10
        if [ "$test_drive" ]; then
            disk_io_speed=$(hdparm -t $test_drive | awk -F '= ' '{print $2}' | awk -F ' ' '{print $1}' | tail -n 1 | awk -F '.' '{print $1}')
            if [ "$disk_io_speed" ]; then
                disk_io_speed_percent=$((disk_io_speed * 100 / 500))
                if [ $disk_io_speed_percent -gt 100 ]; then
                    disk_io_speed_percent=100
                fi
            fi
        fi

        local_hostname=$(grep 'host-name' /etc/avahi/avahi-daemon.conf | awk -F '=' '{print $2}').local
        webadmin_install_dir="/var/www/${local_hostname}/htdocs/admin"

        #spectre-meltdown-checker --no-color > "$webadmin_install_dir/spectre.txt"
        #if [ -f "$webadmin_install_dir/spectre.txt" ]; then
        #    spectre_vulnerabilities=$(grep "VULNERABLE" "$webadmin_install_dir/spectre.txt" | grep -vc "NOT ")
        #else
        spectre_vulnerabilities=0
        #fi

        if [ -f "$webadmin_install_dir/system_monitor_template.html" ]; then
            cp "$webadmin_install_dir/system_monitor_template.html" "$webadmin_install_dir/system_monitor.html"

            # remove spectre warning
            # shellcheck disable=SC2086
            if [ $spectre_vulnerabilities -eq 0 ]; then
                sed -i 's|images/spectre.png||g' "$webadmin_install_dir/system_monitor.html"
                if [ -f "$webadmin_install_dir/spectre.txt" ]; then
                    rm "$webadmin_install_dir/spectre.txt"
                fi
            fi

            if [ "$cpu_usage" ]; then
                sed -i "s|<div name=\"cpuusage\" class=\"w3-container.*|<div name=\"cpuusage\" class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${cpu_usage}%\">${cpu_usage}%</div>|g" "$webadmin_install_dir/system_monitor.html"
            fi

            if [ "$disk_use_percent" ]; then
                sed -i "s|<div name=\"diskspace\" class=\"w3-container.*|<div name=\"diskspace\" class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:$disk_use_percent\">${disk_use_gb} / ${disk_size_gb}GB</div>|g" "$webadmin_install_dir/system_monitor.html"
            fi

            if [ "$backup_disk_use_gb" ]; then
                sed -i "s|<div name=\"backupspace\" class=\"w3-container.*|<div name=\"backupspace\" class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:$backup_disk_use_percent\">${backup_disk_use_gb} / ${backup_disk_size_gb}GB</div>|g" "$webadmin_install_dir/system_monitor.html"
            else
                sed -i "/\"backupspace\"/d" "$webadmin_install_dir/system_monitor.html"
                sed -i '/titletextbackupspace/d' "$webadmin_install_dir/system_monitor.html"
            fi

            sed -i "s|<div name=\"memory\" class=\"w3-container.*|<div name=\"memory\" class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${used_memory_percent}%\">${used_memory_gb} / ${total_memory_gb}GB</div>|g" "$webadmin_install_dir/system_monitor.html"

            if [ $cpu_temperature -gt 0 ]; then
                sed -i "s|<div name=\"cputemp\" class=\"w3-container.*|<div name=\"cputemp\" class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${cpu_temperature}%\">${cpu_temperature}C</div>|g" "$webadmin_install_dir/system_monitor.html"
            else
                sed -i "/\"cputemp\"/d" "$webadmin_install_dir/system_monitor.html"
                sed -i '/titletextcputemp/d' "$webadmin_install_dir/system_monitor.html"
            fi

            sed -i "s|<div name=\"diskio\" class=\"w3-container.*|<div name=\"diskio\" class=\"w3-container w3-blue w3-round-xlarge\" style=\"width:${disk_io_speed_percent}%\">${disk_io_speed} MB/s</div>|g" "$webadmin_install_dir/system_monitor.html"

            chown www-data:www-data "$webadmin_install_dir/system_monitor.html"
        fi
    fi
}

function update_app_settings {
    if [ ! -f "$appsettings_file" ]; then
        return
    fi
    settings_data=$(cat "$appsettings_file")
    rm "$appsettings_file"

    echo "$settings_data" > "$webadmin_install_dir/settingschange.txt"
    echo '' >> "$webadmin_install_dir/settingschange.txt"
    echo 'update_app_settings' >> "$webadmin_install_dir/settingschange.txt"
    if [[ "$settings_data" == *','* ]]; then
        app_name=$(echo "$settings_data" | awk -F ',' '{print $1}')
        echo "app_name: ${app_name}" >> "$webadmin_install_dir/settingschange.txt"
        if [ "$app_name" ]; then
            app_filename="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"
            echo "app_filename: ${app_filename}" >> "$webadmin_install_dir/settingschange.txt"
            if [ -f "$app_filename" ]; then
                app_function=$(echo "$settings_data" | awk -F ',' '{print $2}')
                echo "app_function: ${app_function}" >> "$webadmin_install_dir/settingschange.txt"
                if [ "$app_function" ]; then
                    if grep -q "function ${app_name}_setting_${app_function} {" "$app_filename"; then
                        app_value=$(echo "$settings_data" | awk -F ',' '{print $3}')

                        echo "app_value: ${app_value}" >> "$webadmin_install_dir/settingschange.txt"
                        echo "script: $appsettings_script" >> "$webadmin_install_dir/settingschange.txt"

                        check_for_existing_processes $appsettings_script

                        { echo "echo \"Beginning webadmin ${app_name} app settings change \$(date)\" >> $webadmin_install_dir/settingschange.txt";
                          echo "PROJECT_NAME=$PROJECT_NAME";
                          echo "source $app_filename";
                          echo "${app_name}_setting_${app_function} $app_value";
                          echo "chown www-data:www-data $webadmin_install_dir/settingschange.txt";
                          echo "exit 0"; } >> $appsettings_script
                        chmod +x $appsettings_script

                        # run in a separate process
                        ./$appsettings_script &
                    fi
                fi
            fi
        fi
    else
        echo 'No settings specified' >> "$webadmin_install_dir/settingschange.txt"
        chown www-data:www-data "$webadmin_install_dir/settingschange.txt"
    fi
}

# If the freedombone command is already running then kill its process
#shellcheck disable=SC2009
install_process=$(ps a | grep '/usr/local/bin/freedombone -c' | grep -v 'grep')
if [ "$install_process" ]; then
    if [[ "$install_process" != *'grep'* ]]; then
        install_pid=$(echo "$install_process" | awk -F ' ' '{print $1}')
        if [ "$install_pid" ]; then
            pkill -9 "$install_pid"
        fi
    fi
fi

# get the current install state
if [ -f "$install_state_file" ]; then
    install_state=$(cat "$install_state_file")
    # shellcheck disable=SC2086
    if [ $install_state -ne $INSTALL_STATE_COMMAND_SUCCESS ]; then
        if grep -q 'install_final' "$COMPLETION_FILE"; then
            install_state=$INSTALL_STATE_COMMAND_SUCCESS
        else
            chown www-data:www-data "$webadmin_install_dir/log.txt"
            # remove the setup file containing login details
            if [ -f "$setup_file" ]; then
                rm "$setup_file"
            fi
            if [ -f /etc/nginx/.webadminpasswd ]; then
                rm /etc/nginx/.webadminpasswd
            fi
            install_state=$INSTALL_STATE_FIRST_BOOT
        fi
        echo -n "$install_state" > "$install_state_file"
    fi
else
    if grep -q 'install_final' "$COMPLETION_FILE"; then
        install_state=$INSTALL_STATE_COMMAND_SUCCESS
    else
        install_state=$INSTALL_STATE_FIRST_BOOT
    fi
    echo -n "$install_state" > "$install_state_file"
fi

while true
do
    if [ -f /tmp/.upgrading ]; then
        sleep 2
    else
        web_admin_setup_login
        if [ -d "$webadmin_install_dir" ]; then
            if [ -f "$setup_file" ]; then
                update_progress_bar
                before_setup_runs
                check_install_command_state
                after_setup_has_finished
                sleep 1
            else
                if [ $install_state -eq $INSTALL_STATE_COMMAND_SUCCESS ]; then
                    reset_shutdown
                    change_updates_settings
                    update_enable_ssh
                    webadmin_factory_reset
                    webadmin_change_password
                    update_blocklist
                    update_muted_words
                    update_dynamic_dns
                    webadmin_monitor_ip_changes
                    update_system_monitor
                    change_language
                    change_theme
                    backup_and_restore
                    backup_and_restore_keys
                    add_remove_users
                    update_app_settings
                    update_syncthing
                    update_smolrss
                    update_icecast
                    update_koel
                    update_dlna
                    update_dat_links
                    update_email_proxy
                    import_translations
                    webadmin_upgrade
                    create_scuttlebot_invite
                    install_apps_from_webadmin
                    change_default_domain
                    sleep 1
                    remove_apps_from_webadmin
                fi
            fi
        fi
        sleep 1
    fi
done

exit 0