#!/bin/bash
#  _____               _           _
# |   __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# |   __|  _| -_| -_| . | . |     | . | . |   | -_|
# |__|  |_| |___|___|___|___|_|_|_|___|___|_|_|___|
#
#                              Freedom in the Cloud
#
# XMPP server
#
# Try to minimize the number of daemon restarts, since that causes
# PEP to break within client apps.
#
# The two directories for prosody modules seem necessary.
# Trying to remove /usr/lib/prosody/modules causes problems, and that's
# part of the package install.
#
# License
# =======
#
# Copyright (C) 2014-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/>.

VARIANTS='full full-vim chat'

APP_CATEGORY=chat

IN_DEFAULT_INSTALL=0
INSTALLED_ON_DEFAULT_DOMAIN=1
SHOW_ON_ABOUT=1
NOT_ON_HOMEPAGE=1
REQUIRES_APP=

# Whether to strictly enforce end-to-end security for one-to-one chat
XMPP_E2EE=no

# Directory where XMPP settings are stored
XMPP_DIRECTORY="/var/lib/prosody"
XMPP_PASSWORD=

XMPP_CIPHERS='"EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA"'
XMPP_ECC_CURVE='"secp384r1"'

prosody_latest_version='0.11'
prosody_nightly=30
prosody_nightly_directory=build11
prosody_nightly_hash='f3944afdd8ff3f47bcb5a870f834e4cac4d2d8f755e5da0e39c44f6f580b3440'
prosody_filename=prosody-${prosody_latest_version}-1nightly${prosody_nightly}
prosody_nightly_url="https://prosody.im/nightly/${prosody_latest_version}/${prosody_nightly_directory}/${prosody_filename}.tar.gz"

# From https://hg.prosody.im/prosody-modules
prosody_modules_filename='prosody-modules-20190127.tar.gz'
prosody_modules_hash='47aa1caea5ef411bc86620ff6c386c132d77fb255d42f5d2923d86a361b91c92'
xmpp_encryption_warning=$"For security reasons, OMEMO or PGP encryption is required for conversations on this server."

XMPP_SHORT_DESCRIPTION=$'Chat system'
XMPP_DESCRIPTION=$'Chat system'
XMPP_MOBILE_APP_URL='https://f-droid.org/packages/eu.siacs.conversations'

# commandline utility for notifications
XMPPSEND_REPO="https://code.freedombone.net/bashrc/xmppsend"
XMPPSEND_COMMIT='9401665f40723df779f828d01cc1fa6df28b14c9'

# used to disable TLS on onion only installs
xmpp_tls_enabled=''

xmpp_variables=(ONION_ONLY
                INSTALLED_WITHIN_DOCKER
                XMPP_CIPHERS
                XMPP_ECC_CURVE
                XMPP_ECC_CURVE
                XMPP_E2EE
                MY_USERNAME
                MY_EMAIL_ADDRESS
                DEFAULT_DOMAIN_NAME
                XMPP_DOMAIN_CODE)

function xmpp_setting_stricttls {
    # switching strict TLS on or off, which requires authentication with a letsencrypt cert
    strict_tls="$1"
    strict_tls_update=

    if [[ "$strict_tls" == '1' ]]; then
        if ! grep -q 's2s_secure_auth = true' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_secure_auth = .*|s2s_secure_auth = true|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
        if ! grep -q 's2s_require_encryption = true' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_require_encryption = .*|s2s_require_encryption = true|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
    fi

    if [[ "$strict_tls" == '0' ]]; then
        if ! grep -q 's2s_secure_auth = false' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_secure_auth = .*|s2s_secure_auth = false|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
        if ! grep -q 's2s_require_encryption = false' /etc/prosody/prosody.cfg.lua; then
            sed -i 's|s2s_require_encryption = .*|s2s_require_encryption = false|g' /etc/prosody/prosody.cfg.lua
            strict_tls_update=1
        fi
    fi

    if [ $strict_tls_update ]; then
        systemctl restart prosody
    fi
}

function prosody_update_onion_certs {
    if [[ "$ONION_ONLY" == 'no' ]]; then
        return
    fi
    if [ ! -f /var/lib/prosody/xmpp.crt ]; then
        if [ -f /etc/ssl/certs/xmpp.crt ]; then
            cp /etc/ssl/certs/xmpp.crt /var/lib/prosody/xmpp.crt
            chown prosody:prosody /var/lib/prosody/xmpp.crt
            sed -i 's|/etc/ssl/certs/xmpp.crt|/var/lib/prosody/xmpp.crt|g' /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi
    if [ ! -f /var/lib/prosody/xmpp.key ]; then
        if [ -f /etc/ssl/private/xmpp.key ]; then
            cp /etc/ssl/private/xmpp.key /var/lib/prosody/xmpp.key
            chown prosody:prosody /var/lib/prosody/xmpp.key
            sed -i 's|/etc/ssl/private/xmpp.key|/var/lib/prosody/xmpp.key|g' /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi
    if ! grep -q 'dhparam = "/etc/prosody/xmpp.dhparam";' /etc/prosody/conf.d/xmpp.cfg.lua; then
        sed -i 's|dhparam = .*|dhparam = "/etc/prosody/xmpp.dhparam";|g' /etc/prosody/conf.d/xmpp.cfg.lua
        xmpp_restart=1
    fi
}

function prosody_default_security_labels {
    prosody_config_file="$1"

    if grep -q 'security_labels = {' "$prosody_config_file"; then
        return
    fi

    { echo '';
      echo 'security_labels = {';
      echo '  { -- This label will come first';
      echo '    name = "Public",';
      echo '    label = true,';
      echo '      default = true -- The default label.';
      echo '  },';
      echo '  {';
      echo '    name = "Private",';
      echo '    label = "PRIVATE",';
      echo '    color = "white",';
      echo '    bgcolor = "blue"';
      echo '  },';
      echo '  Sensitive = {';
      echo '    SECRET = {';
      echo '      label = true';
      echo '    },';
      echo '    TOPSECRET = {';
      echo '      color = "red",';
      echo '      bgcolor = "black",';
      echo '    }';
      echo '  }';
      echo '}'; } >> "$prosody_config_file"

    xmpp_restart=1
}

function change_default_domain_name_xmpp {
    new_default_domain_name="$1"

    read_config_param DEFAULT_DOMAIN_NAME
    sed -i "s|$DEFAULT_DOMAIN_NAME|$new_default_domain_name|g" /etc/prosody/prosody.cfg.lua
    sed -i "s|$DEFAULT_DOMAIN_NAME|$new_default_domain_name|g" /etc/prosody/conf.avail/xmpp.cfg.lua

    systemctl restart prosody
}

function prosody_remove_module_from_config {
    remove_prosody_module_name="$1"
    prosody_config_file="$2"

    if [ ! "${remove_prosody_module_name}" ]; then
        return
    fi

    if [ ! -f "${prosody_config_file}" ]; then
        echo "Config file ${prosody_config_file} not found when removing module $remove_prosody_module_name"
        return
    fi

    if grep -q "\"${remove_prosody_module_name}\"" "${prosody_config_file}"; then
        sed -i "/\"${remove_prosody_module_name}\"/d" "${prosody_config_file}"
        xmpp_restart=1
    fi
}

function prosody_remove_module {
    remove_prosody_module_name="$1"
    prosody_remove_module_from_config "${remove_prosody_module_name}" /etc/prosody/prosody.cfg.lua
    prosody_remove_module_from_config "${remove_prosody_module_name}" /etc/prosody/conf.avail/xmpp.cfg.lua
}

function prosody_add_module_to_config {
    new_prosody_module_name="$1"
    prosody_config_file="$2"
    add_to_muc="$3"

    if [ ! "${new_prosody_module_name}" ]; then
        return
    fi

    if [ ! -f "${prosody_config_file}" ]; then
        echo "Config file ${prosody_config_file} not found when adding module $new_prosody_module_name"
        return
    fi

    if ! grep -q "\"${new_prosody_module_name}\"" "$prosody_config_file"; then
        sed -i "/\"pep\"/a \"${new_prosody_module_name}\";" "$prosody_config_file"

        if [ "$add_to_muc" ]; then
            if grep -q "\"muc_limits\"" "$prosody_config_file"; then
                sed -i "/\"muc_limits\"/a \"${new_prosody_module_name}\";" "$prosody_config_file"
            fi
        fi

        sed -i "s|\"${new_prosody_module_name}\"|        \"${new_prosody_module_name}\"|g" "$prosody_config_file"
        xmpp_restart=1
    fi
}

function prosody_add_module {
    new_prosody_module_name="$1"
    add_to_muc="$2"
    prosody_add_module_to_config "${new_prosody_module_name}" /etc/prosody/prosody.cfg.lua "$add_to_muc"
    prosody_add_module_to_config "${new_prosody_module_name}" /etc/prosody/conf.avail/xmpp.cfg.lua "$add_to_muc"
}

function xmpp_fix_exists {
    if ! grep -q "CREATE INDEX IF NOT EXISTS" plugins/mod_storage_sql1.lua; then
        sed -i 's|CREATE INDEX|CREATE INDEX IF NOT EXISTS|g' plugins/mod_storage_sql1.lua
    fi
    if ! grep -q "CREATE INDEX IF NOT EXISTS" util/sql.lua; then
        sed -i 's|CREATE INDEX|CREATE INDEX IF NOT EXISTS|g' util/sql.lua
    fi
    if ! grep -q "CREATE TABLE IF NOT EXISTS" plugins/mod_storage_sql1.lua; then
        sed -i 's|CREATE TABLE|CREATE TABLE IF NOT EXISTS|g' plugins/mod_storage_sql1.lua
    fi
    if ! grep -q "CREATE TABLE IF NOT EXISTS" util/sql.lua; then
        sed -i 's|CREATE TABLE|CREATE TABLE IF NOT EXISTS|g' util/sql.lua
    fi
}

function xmpp_update_e2e_policy {
    filename="$1"

    read_config_param DEFAULT_DOMAIN_NAME
    read_config_param ONION_ONLY

    if ! grep -q "e2e_policy_muc" "$filename"; then
        echo "e2e_policy_muc = \"none\"" >> "$filename"
        xmpp_restart=1
    else
        if ! grep -q 'e2e_policy_muc = "none"' "$filename"; then
            sed -i 's|e2e_policy_muc.*|e2e_policy_muc = "none"|g' "$filename"
            xmpp_restart=1
        fi
    fi
    if ! grep -q "e2e_policy_chat" "$filename"; then
        if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
            echo "e2e_policy_chat = \"required\"" >> "$filename"
            xmpp_restart=1
        else
            echo "e2e_policy_chat = \"optional\"" >> "$filename"
            xmpp_restart=1
        fi
    else
        if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
            if ! grep -q 'e2e_policy_chat = "required"' "$filename"; then
                sed -i 's|e2e_policy_chat.*|e2e_policy_chat = "required"|g' "$filename"
                xmpp_restart=1
            fi
        else
            if ! grep -q 'e2e_policy_chat = "optional"' "$filename"; then
                sed -i 's|e2e_policy_chat.*|e2e_policy_chat = "optional"|g' "$filename"
                xmpp_restart=1
            fi
        fi
    fi
    if ! grep -q "e2e_policy_message_required_chat" "$filename"; then
        echo "e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"" >> "$filename"
        xmpp_restart=1
    else
        if ! grep -q "e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"" "$filename"; then
            sed -i "s|e2e_policy_message_required_chat.*|e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"|g" "$filename"
            xmpp_restart=1
        fi
    fi
    if ! grep -q "e2e_policy_whitelist" "$filename"; then
        echo "e2e_policy_whitelist = { \"notification@$HOSTNAME\" };" >> "$filename"
        xmpp_restart=1
    else
        if ! grep -q "e2e_policy_whitelist = { \"notification@$HOSTNAME\" };" "$filename"; then
            sed -i "s|e2e_policy_whitelist.*|e2e_policy_whitelist = { \"notification@$HOSTNAME\" };|g" "$filename"
            xmpp_restart=1
        fi
    fi

    if [[ "$ONION_ONLY" != 'no' ]]; then
        XMPP_ONION_HOSTNAME=$(cat /var/lib/tor/hidden_service_email/hostname)
        sed -i "s|VirtualHost \".*.onion.*|VirtualHost \"${XMPP_ONION_HOSTNAME}\"|g" "$filename"
        # TLS is not strictly needed for onion transport security
        if ! grep -q 'c2s_require_encryption = false' "$filename"; then
            sed -i 's|c2s_require_encryption =.*|c2s_require_encryption = false|g' "$filename"
            xmpp_restart=1
        fi
        if ! grep -q 's2s_require_encryption = false' "$filename"; then
            sed -i 's|s2s_require_encryption =.*|s2s_require_encryption = false|g' "$filename"
            xmpp_restart=1
        fi
    fi
}

function logging_on_xmpp {
    if [ ! -d /etc/prosody ]; then
        return
    fi

    if ! grep -q 'info = "/var/log/prosody/prosody.log";' /etc/prosody/prosody.cfg.lua; then
        if [ -d /etc/prosody ]; then
            if [ ! -d /var/log/prosody ]; then
                mkdir /var/log/prosody
                chown root:adm /var/log/prosody
            fi
            if ! grep -q "/var/log/prosody/prosody.log" /etc/prosody/prosody.cfg.lua; then
                sed -i 's|info = "/dev/null";|info = "/var/log/prosody/prosody.log";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|error = "/dev/null";|error = "/var/log/prosody/prosody.err";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|levels = { "error" }; to = "/dev/null";|levels = { "info" }; to = "syslog";|g' /etc/prosody/prosody.cfg.lua
                touch /var/log/prosody/prosody.log
                chown prosody:prosody /var/log/prosody/prosody.log
                touch /var/log/prosody/prosody.err
                chown prosody:prosody /var/log/prosody/prosody.err
            fi
        fi
        systemctl restart prosody
    fi
}

function logging_off_xmpp {
    if [ ! -d /etc/prosody ]; then
        return
    fi

    logging_restart_prosody=

    # remove any chat log
    read_config_param DEFAULT_DOMAIN_NAME
    prosody_chat_domain="chat.${DEFAULT_DOMAIN_NAME}"
    # shellcheck disable=SC2001
    prosody_chat_domain_str=$(echo "$prosody_chat_domain" | sed 's|\.|%2e|g')
    if [ -d "${XMPP_DIRECTORY}/${prosody_chat_domain_str}/muc_log" ]; then
        # shellcheck disable=SC2086
        rm -rf ${XMPP_DIRECTORY}/${prosody_chat_domain_str}/muc_log*
        logging_restart_prosody=1
    fi

    if ! grep -q 'muc_log_by_default = false;' /etc/prosody/prosody.cfg.lua; then
        sed -i 's|muc_log_by_default.*|muc_log_by_default = false;|g' /etc/prosody/prosody.cfg.lua
        logging_restart_prosody=1
    fi

    if ! grep -q 'muc_log_all_rooms = false;' /etc/prosody/prosody.cfg.lua; then
        sed -i 's|muc_log_all_rooms.*|muc_log_all_rooms = false;|g' /etc/prosody/prosody.cfg.lua
        logging_restart_prosody=1
    fi

    if ! grep -q '/dev/null' /etc/prosody/prosody.cfg.lua; then
        if [ -d /etc/prosody ]; then
            if grep -q "/var/log/prosody/prosody.log" /etc/prosody/prosody.cfg.lua; then
                sed -i 's|info = "/var/log/prosody/prosody.log";|info = "/dev/null";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|error = "/var/log/prosody/prosody.err";|error = "/dev/null";|g' /etc/prosody/prosody.cfg.lua
                sed -i 's|levels = { "info" }; to = "syslog";|levels = { "error" }; to = "/dev/null";|g' /etc/prosody/prosody.cfg.lua
                $REMOVE_FILES_COMMAND /var/log/prosody/*
                rm -rf /var/log/prosody
            fi
        fi
        logging_restart_prosody=1
    fi

    if [ $logging_restart_prosody ]; then
        systemctl restart prosody
    fi
}

function xmpp_add_onion_address {
    domain_name="$1"
    onion_address="$2"
    if [ ${#domain_name} -eq 0 ]; then
        return
    fi
    if [ ${#onion_address} -eq 0 ]; then
        return
    fi
    if ! grep "${onion_address}" /etc/prosody/prosody.cfg.lua; then
        if grep -q "[\"${domain_name}\"]" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|[\"${domain_name}\"].*|[\"${domain_name}\"] = \"${onion_address}\";|g" /etc/prosody/prosody.cfg.lua
        else
            sed -i "/onions_map = {/a  [\"${domain_name}\"] = \"${onion_address}\";" /etc/prosody/prosody.cfg.lua
        fi
        systemctl restart prosody
    fi
}

function xmpp_add_onion_address_interactive {
    data=$(mktemp 2>/dev/null)
    dialog --backtitle $"Freedombone Control Panel" \
           --title $"Add a clearnet to Onion domain mapping" \
           --form $"Sepecify a clearnet domain name and its equivalent onion address\\n" 9 50 2 \
           $"Domain:" 1 1 "" 1 18 26 25 \
           $"Onion address:" 2 1 "" 2 18 26 25 \
           2> "$data"
    sel=$?
    case $sel in
        1) rm -f "$data"
           return;;
        255) rm -f "$data"
             return;;
    esac
    domain_name=$(sed -n 1p < "$data")
    onion_address=$(sed -n 2p < "$data")
    rm -f "$data"
    if [[ "$onion_address" != *".onion" ]]; then
        return
    fi
    if [[ "$domain_name" != *"."* ]]; then
        return
    fi

    xmpp_add_onion_address "$domain_name" "$onion_address"

    dialog --title $"Add a clearnet to Onion domain mapping" \
           --msgbox $"${domain_name} -> ${onion_address} added" 6 70
}

function xmpp_remove_onion_address {
    domain_name="$1"
    if [ ${#domain_name} -eq 0 ]; then
        return
    fi
    xmpp_changed=
    if grep -q "[\"${domain_name}\"]" /etc/prosody/prosody.cfg.lua; then
        sed -i "/[\"${domain_name}\"]/d" /etc/prosody/prosody.cfg.lua
        xmpp_changed=1
    fi

    if grep -q "= \"${domain_name}\";" /etc/prosody/prosody.cfg.lua; then
        sed -i "/= \"${domain_name}\";/d" /etc/prosody/prosody.cfg.lua
        xmpp_changed=1
    fi
    if [ $xmpp_changed ]; then
        systemctl restart prosody
    fi
}

function xmpp_remove_onion_address_interactive {
    data=$(mktemp 2>/dev/null)
    dialog --title $"Remove clearnet to Onion domain mapping" \
           --backtitle $"Freedombone Control Panel" \
           --inputbox $'Enter the domain name or onion address to be removed' 8 60 2>"$data"
    sel=$?
    case $sel in
        0) domain_name=$(<"$data")
           if [[ "$domain_name" != *"."* ]]; then
               rm -f "$data"
               return
           fi
           xmpp_remove_onion_address "$domain_name"
           dialog --title $"Remove a clearnet to Onion domain mapping" \
                  --msgbox $"${domain_name} removed" 6 70
           ;;
    esac
    rm -f "$data"
}

function configure_interactive_xmpp {
    read_config_param XMPP_E2EE

    while true
    do
        e2ee_policy=$'optional'
        if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
            e2ee_policy=$'required'
        fi

        W=(1 $"End-to-end security policy: $e2ee_policy"
           2 $"Add a clearnet to onion domain mapping"
           3 $"Remove a clearnet to onion domain mapping")

        # shellcheck disable=SC2068
        selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"XMPP" --menu $"Choose an operation, or ESC to exit:" 11 60 3 "${W[@]}" 3>&2 2>&1 1>&3)

        if [ ! "$selection" ]; then
            break
        fi

        case $selection in
            1) if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
                   XMPP_E2EE='no'
               else
                   XMPP_E2EE='yes'
               fi
               write_config_param 'XMPP_E2EE' "$XMPP_E2EE"
               xmpp_update_e2e_policy /etc/prosody/conf.avail/xmpp.cfg.lua
               xmpp_update_e2e_policy /etc/prosody/prosody.cfg.lua
               systemctl restart prosody

               e2ee_policy=$'optional'
               if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
                   e2ee_policy=$'required'
               fi

               dialog --title $"xmpp end-to-end security policy" \
                      --msgbox $"The security policy has been changed to $e2ee_policy" 6 70
               ;;
            2) xmpp_add_onion_address_interactive;;
            3) xmpp_remove_onion_address_interactive;;
        esac
    done
}

function remove_user_xmpp {
    remove_username="$1"

    "${PROJECT_NAME}-pass" -u "$remove_username" --rmapp xmpp
    if [[ "$ONION_ONLY" != "no" ]]; then
        DOMAIN=$(cat /var/lib/tor/hidden_service_email/hostname)
    else
        DOMAIN=${HOSTNAME}
    fi
    prosodyctl deluser "${remove_username}@${DOMAIN}"
}

function add_user_xmpp_client {
    new_username="$1"
    new_user_password="$2"

    if [ -f /usr/local/bin/profanity ]; then
        XMPP_CLIENT_DIR=/home/$new_username/.local/share/profanity
        XMPP_CLIENT_ACCOUNTS=$XMPP_CLIENT_DIR/accounts
        if [ ! -d "$XMPP_CLIENT_DIR" ]; then
            mkdir -p "$XMPP_CLIENT_DIR"
        fi
        if [ ! -d "/home/$new_username/.config/profanity" ]; then
            mkdir -p "/home/$new_username/.config/profanity"
        fi
        MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$new_username" "$new_username@$HOSTNAME")
        { echo "[${new_username}@${HOSTNAME}]";
          echo 'enabled=true';
          echo "jid=${new_username}@${HOSTNAME}";
          echo "server=$XMPP_ONION_HOSTNAME";
          echo "pgp.keyid=$MY_GPG_PUBLIC_KEY_ID";
          echo 'resource=profanity';
          echo "muc.service=conference.${HOSTNAME}";
          echo "muc.nick=${new_username}";
          echo 'presence.last=online';
          echo 'presence.login=online';
          echo 'priority.online=0';
          echo 'priority.chat=0';
          echo 'priority.away=0';
          echo 'priority.xa=0';
          echo 'priority.dnd=0'; } > "$XMPP_CLIENT_ACCOUNTS"

        echo '[connection]' > "/home/$new_username/.config/profanity/profrc"
        if [[ $ONION_ONLY != "no" ]]; then
            echo "account=${new_username}@${XMPP_ONION_HOSTNAME}" >> "/home/$new_username/.config/profanity/profrc"
        else
            echo "account=${new_username}@${HOSTNAME}" >> "/home/$new_username/.config/profanity/profrc"
        fi
        { echo '';
          echo '[plugins]';
          echo 'load=prof_omemo_plugin.py;';
          echo '';
          echo '[otr]';
          echo 'policy=opportunistic';
          echo 'log=off';
          echo '';
          echo '[pgp]';
          echo 'log=off';
          echo '';
          echo '[ui]';
          echo 'enc.warn=true'; } >> "/home/$new_username/.config/profanity/profrc"

        chown -R "$new_username":"$new_username" "/home/$new_username/.local"
        chown -R "$new_username":"$new_username" "/home/$new_username/.config"
    fi
}

function add_user_xmpp {
    new_username="$1"
    new_user_password="$2"

    XMPP_ONION_HOSTNAME=$(cat /var/lib/tor/hidden_service_email/hostname)
    "${PROJECT_NAME}-pass" -u "$new_username" -a xmpp -p "$new_user_password"

    if [[ "$ONION_ONLY" != "no" ]]; then
        DOMAIN_NAME=$XMPP_ONION_HOSTNAME
    else
        DOMAIN_NAME=$HOSTNAME
    fi
    EMAIL_ADDRESS="$new_username@$DOMAIN_NAME"

    if [ ${#new_user_password} -eq 0 ]; then
        prosodyctl adduser "$EMAIL_ADDRESS"
    else
        if ! prosodyctl register "$new_username" "$DOMAIN_NAME" "$new_user_password"; then
            exit 65
        fi
    fi

    add_user_xmpp_client "$new_username" "$new_user_password"
    echo '0'
}

function install_interactive_xmpp {
    echo -n ''
    APP_INSTALLED=1
}

function change_password_xmpp {
    curr_username="$1"
    new_user_password="$2"

    read_config_param DEFAULT_DOMAIN_NAME

    "${PROJECT_NAME}-pass" -u "$curr_username" -a xmpp -p "$new_user_password"

    # TODO: this is currently interactive. Really there needs to be a
    # non-interactive password change option for prosodyctl
    clear
    echo ''
    echo $'Currently Prosody requires password changes to be done interactively'
    prosodyctl passwd "${curr_username}@${DEFAULT_DOMAIN_NAME}"

    if [ -f /usr/local/bin/profanity ]; then
        XMPP_CLIENT_DIR=/home/$curr_username/.local/share/profanity
        XMPP_CLIENT_ACCOUNTS=$XMPP_CLIENT_DIR/accounts
        if [ -f "$XMPP_CLIENT_ACCOUNTS" ]; then
            sed -i "s|password=.*|password=$new_user_password|g" "$XMPP_CLIENT_ACCOUNTS"
        fi
    fi
}

function reconfigure_xmpp {
    echo -n ''
}

function update_prosody_modules {
    if [ ! "$1" ]; then
        if [ ! -d ${XMPP_DIRECTORY}/prosody-modules ]; then
            return
        fi
    fi
    if [ ! -d /usr/lib/prosody ]; then
        return
    fi

    if [ ! -f "$INSTALL_DIR/$prosody_modules_filename" ]; then
        xmpp_restart=1

        # Obtain the modules
        if [ -f "$HOME/${PROJECT_NAME}/image_build/$prosody_modules_filename" ]; then
            cp "$HOME/${PROJECT_NAME}/image_build/$prosody_modules_filename" "$INSTALL_DIR"
        else
            if [ -f "/home/$MY_USERNAME/${PROJECT_NAME}/image_build/$prosody_modules_filename" ]; then
                cp "/home/$MY_USERNAME/${PROJECT_NAME}/image_build/$prosody_modules_filename" "$INSTALL_DIR"
            fi
        fi

        if [ -f "$INSTALL_DIR/$prosody_modules_filename" ]; then
            cd "$INSTALL_DIR" || exit 24

            # Check the hash
            curr_hash=$(sha256sum "$INSTALL_DIR/$prosody_modules_filename" | awk -F ' ' '{print $1}')
            if [[ "$curr_hash" != "$prosody_modules_hash" ]]; then
                echo $'Prosody modules hash does not match'
                exit 83
            else
                # Extract the modules
                if [ -d "$INSTALL_DIR/prosody-modules" ]; then
                    rm -rf "$INSTALL_DIR/prosody-modules"
                fi
                tar -xzvf $prosody_modules_filename
                if [ -d "$INSTALL_DIR/prosody-modules" ]; then
                    systemctl stop prosody
                    if [ ! -d ${XMPP_DIRECTORY}/prosody-modules ]; then
                        mkdir -p ${XMPP_DIRECTORY}/prosody-modules
                    fi
                    cp -r "$INSTALL_DIR/prosody-modules/"* ${XMPP_DIRECTORY}/prosody-modules/
                    cp -r "$INSTALL_DIR/prosody-modules/"* /usr/lib/prosody/modules/
                    chown -R prosody:prosody ${XMPP_DIRECTORY}/prosody-modules
                    chown -R prosody:prosody /usr/lib/prosody/modules
                    systemctl start prosody
                else
                    echo $'Prosody modules not extracted'
                    exit 72
                fi
            fi
        fi
    fi

    prosody_add_module 's2s_blacklist' muc
    prosody_add_module 'firewall'
    prosody_add_module 'block_strangers'

    xmpp_server_blacklist /etc/prosody/prosody.cfg.lua

    if grep -q '"mam_muc";' /etc/prosody/prosody.cfg.lua; then
        sed -i '/"mam_muc";/d' /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    fi
}

function prosody_daemon_restart_script {
    # On rare occasions the daemon appears to get stuck
    # i.e. still active, but not accepting connections
    # This ensures that it will unstick itself at least once per day
    if [ -f /etc/cron.daily/prosody ]; then
        rm /etc/cron.daily/prosody
    fi
    if [ ! -f /etc/cron.hourly/prosody ]; then
        { echo '#!/bin/bash';
          echo "is_active=\$(systemctl is-active prosody)";
          echo "if [[ \"\$is_active\" != 'active' ]]; then";
          echo '  systemctl restart prosody'
          echo 'fi'; } > /etc/cron.hourly/prosody
        chmod +x /etc/cron.hourly/prosody
    fi
}

function configure_xmppsend {
    $INSTALL_PACKAGES libstrophe-dev

    if [ ! -d "$INSTALL_DIR" ]; then
        mkdir -p "$INSTALL_DIR"
    fi
    cd "$INSTALL_DIR" || return
    git clone $XMPPSEND_REPO "$INSTALL_DIR/xmppsend"
    cd "$INSTALL_DIR/xmppsend" || return
    git checkout "$XMPPSEND_COMMIT" -b "$XMPPSEND_COMMIT"
    if ! make; then
        echo $'Unable to build xmppsend'
        return
    fi
    make install

    set_completion_param "xmppsend commit" "$XMPPSEND_COMMIT"
}

function upgrade_xmppsend {
    CURR_XMPPSEND_COMMIT=$(get_completion_param "xmppsend commit")
    if [[ "$CURR_XMPPSEND_COMMIT" == "$XMPPSEND_COMMIT" ]]; then
        return
    fi

    if [ ! -d "$INSTALL_DIR/xmppsend" ]; then
        configure_xmppsend
    else
        cd "$INSTALL_DIR/xmppsend" || return
        git stash
        git checkout master
        git pull
        git checkout "$XMPPSEND_COMMIT" -b "$XMPPSEND_COMMIT"
        if ! make; then
            return
        fi
        make install

        set_completion_param "xmppsend commit" "$XMPPSEND_COMMIT"
    fi

}

function prosody_set_parameter {
    prosody_param_name="$1"
    prosody_param_value="$2"

    if ! grep -q "${prosody_param_name} " /etc/prosody/prosody.cfg.lua; then
        echo "${prosody_param_name} = ${prosody_param_value};" >> /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    else
        if ! grep -q "${prosody_param_name} = ${prosody_param_value};" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|${prosody_param_name} .*|${prosody_param_name} = ${prosody_param_value};|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
       fi
    fi
}

function upgrade_xmpp {
    xmpp_restart=

    if [ -d /etc/letsencrypt ]; then
        prosody_groups=$(groups prosody)
        if [[ "$prosody_groups" != *'ssl-cert'* ]]; then
            usermod -a -G ssl-cert prosody
        fi
    fi

    read_config_param ONION_ONLY
    prosody_update_onion_certs

    if [[ "$ONION_ONLY" != 'no' ]]; then
        # Disable TLS for onion only versions
        # this makes the user experience a lot slicker
        # because there are no prompts to accept
        # self-signed certs
        xmpp_tls_enabled='-- '
        xmpp_str="\-\- \"tls\""
        if ! grep -q "$xmpp_str" /etc/prosody/conf.avail/xmpp.cfg.lua; then
            sed -i "s|\"tls\"|${xmpp_tls_enabled}\"tls\"|g" /etc/prosody/conf.avail/xmpp.cfg.lua
            xmpp_restart=1
        fi
        if ! grep -q "$xmpp_str" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|\"tls\"|${xmpp_tls_enabled}\"tls\"|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi

    read_config_param XMPP_E2EE
    xmpp_update_e2e_policy /etc/prosody/conf.avail/xmpp.cfg.lua
    xmpp_update_e2e_policy /etc/prosody/prosody.cfg.lua

    prosody_daemon_restart_script
    function_check update_prosody_modules
    update_prosody_modules
    xmpp_onion_addresses /etc/prosody/prosody.cfg.lua
    xmpp_contact_info /etc/prosody/prosody.cfg.lua
    xmpp_server_blacklist /etc/prosody/prosody.cfg.lua

    # add word filter to muc
    prosody_add_module "filter_words"
    if ! grep -q 'filter_words =' /etc/prosody/prosody.cfg.lua; then
        echo 'filter_words = {}' >> /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    fi

    prosody_set_parameter 'http_upload_file_size_limit' '25165824'
    prosody_set_parameter 'muc_room_default_members_only' 'false'
    prosody_set_parameter 'muc_tombstones' 'false'

    # security labels
    prosody_add_module "seclabels"
    prosody_default_security_labels /etc/prosody/prosody.cfg.lua

    # extra battery saving
    prosody_add_module "csi_compat"
    prosody_add_module "csi_battery_saver"

    # remove omemo_all_access
    # This isn't needed with prosody 0.11+
    prosody_remove_module "omemo_all_access"

    # remove muc logging
    prosody_remove_module "muc_log"
    prosody_remove_module "muc_log_http"

    # remove any broadcast settings
    prosody_remove_module "broadcast"

    # handling avatars
    prosody_remove_module "pep_vcard_avatar"
    prosody_remove_module "vcard"
    prosody_add_module "profile"

    if grep -q "/etc/ssl/certs/xmpp.dhparam" /etc/prosody/prosody.cfg.lua; then
        cp /etc/ssl/certs/xmpp.dhparam /etc/prosody/xmpp.dhparam
        chown prosody:prosody /etc/prosody/xmpp.dhparam
        sed -i 's|/etc/ssl/certs/xmpp.dhparam|/etc/prosody/xmpp.dhparam|g' /etc/prosody/prosody.cfg.lua
        sed -i 's|/etc/ssl/certs/xmpp.dhparam|/etc/prosody/xmpp.dhparam|g' /etc/prosody/conf.avail/xmpp.cfg.lua
        xmpp_restart=1
    fi

    if grep -q "/etc/ssl/private/xmpp.key" /etc/prosody/prosody.cfg.lua; then
        if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem" ]; then
            sed -i "s|/etc/ssl/private/xmpp.key|/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi

    if grep -q "/etc/ssl/certs/xmpp.crt" /etc/prosody/prosody.cfg.lua; then
        if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem" ]; then
            sed -i "s|/etc/ssl/certs/xmpp.crt|/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi

    curr_prosody_filename=$(grep "prosody_filename" "$COMPLETION_FILE" | awk -F ':' '{print $2}')
    if [[ "$curr_prosody_filename" != "$prosody_filename" ]]; then
        if [ -d "${INSTALL_DIR}/${prosody_filename}" ]; then
            # ensure that the binaries have not been overwritten
            # by an operating system upgrade
            cd "${INSTALL_DIR}/${prosody_filename}" || exit 46
            xmpp_fix_exists
            make prefix=/usr install
        else
            cd "$INSTALL_DIR" || exit 23
            # Try to get the source from the project repo
            if [ -f "/root/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" ]; then
                cp "/root/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" .
            else
                if [ -f "/home/${MY_USERNAME}/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" ]; then
                    cp "/home/${MY_USERNAME}/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" .
                else
                    wget $prosody_nightly_url
                fi
            fi
            if [ ! -f "${INSTALL_DIR}/${prosody_filename}.tar.gz" ]; then
                echo $"Failed to download prosody nightly $prosody_nightly_url"
                return
            fi

            hash_value=$(sha256sum "${INSTALL_DIR}/${prosody_filename}.tar.gz" | awk -F ' ' '{print $1}')
            if [[ "$hash_value" != "$prosody_nightly_hash" ]]; then
                rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"
                echo $'Unexpected hash value for prosody nightly download'
                return
            fi

            tar -xzvf "${INSTALL_DIR}/${prosody_filename}.tar.gz"
            cd "${INSTALL_DIR}/${prosody_filename}" || exit 24
            xmpp_fix_exists
            ./configure --ostype=debian --prefix=/usr
            make prefix=/usr
            make prefix=/usr install
            if [ -f /usr/local/bin/prosody ]; then
                echo $'Failed to build prosody nightly to /usr/bin'
                rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"
                rm -rf "${INSTALL_DIR:?}/${prosody_filename}"
                return
            fi
            rm "${INSTALL_DIR:?}/${prosody_filename}.tar.gz"
        fi

        # add onion addresses for known servers
        if ! grep -q "onions_map =" /etc/prosody/prosody.cfg.lua; then
            echo '' >> /etc/prosody/prosody.cfg.lua
            xmpp_onion_addresses /etc/prosody/prosody.cfg.lua
        fi

        set_completion_param "prosody_filename" "${prosody_filename}"

        xmpp_restart=1
    fi

    if [ $xmpp_restart ]; then
        cp -r "$INSTALL_DIR/prosody-modules/"* ${XMPP_DIRECTORY}/prosody-modules/
        chown -R prosody:prosody ${XMPP_DIRECTORY}/prosody-modules

        echo $'Restarting prosody'
        systemctl restart prosody
    fi
}

function backup_local_xmpp {
    source_directory=${XMPP_DIRECTORY}
    if [ -d $source_directory ]; then
        dest_directory=xmpp
        function_check backup_directory_to_usb
        backup_directory_to_usb $source_directory $dest_directory
    fi
}

function restore_local_xmpp {
    if [ -d ${XMPP_DIRECTORY} ]; then
        echo $"Restoring xmpp settings"
        temp_restore_dir=/root/tempxmpp
        function_check restore_directory_from_usb
        restore_directory_from_usb $temp_restore_dir xmpp
        if [ -d $temp_restore_dir${XMPP_DIRECTORY} ]; then
            cp -r $temp_restore_dir${XMPP_DIRECTORY}/* ${XMPP_DIRECTORY}
        else
            cp -r $temp_restore_dir/* ${XMPP_DIRECTORY}/
        fi
        # shellcheck disable=SC2181
        if [ ! "$?" = "0" ]; then
            function_check set_user_permissions
            set_user_permissions
            function_check backup_unmount_drive
            backup_unmount_drive
            exit 72
        fi
        rm -rf $temp_restore_dir
        systemctl restart prosody
        chown -R prosody:prosody ${XMPP_DIRECTORY}/*
        echo $"Restore of xmpp settings complete"
    fi
}

function backup_remote_xmpp {
    echo -n ''
}

function restore_remote_xmpp {
    echo -n ''
}

function configure_firewall_for_xmpp {
    if [ ! -d /etc/prosody ]; then
        return
    fi
    if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
        return
    fi
    if [[ $INSTALLED_WITHIN_DOCKER == "yes" ]]; then
        # docker does its own firewalling
        return
    fi
    if [[ $ONION_ONLY != "no" ]]; then
        return
    fi
    firewall_add XMPP 5222 tcp
    firewall_add XMPP 5223 tcp
    firewall_add XMPP 5269 tcp
    firewall_add XMPP 5280 tcp
    firewall_add XMPP 5281 tcp
    mark_completed "${FUNCNAME[0]}"
}

function remove_xmpp {
    remove_profanity
    remove_movim
    firewall_remove 5222 tcp
    firewall_remove 5223 tcp
    firewall_remove 5269 tcp
    firewall_remove 5280 tcp
    firewall_remove 5281 tcp

    $PACKAGE_UNHOLD prosody
    $REMOVE_PACKAGES_PURGE prosody
    rm /etc/cron.daily/prosody
    if [ -f "$INSTALL_DIR/$prosody_modules_filename" ]; then
        rm "$INSTALL_DIR/$prosody_modules_filename"
    fi
    if [ -d "$INSTALL_DIR/prosody-modules" ]; then
        rm -rf "$INSTALL_DIR/prosody-modules"
    fi
    if [ -d /etc/prosody ]; then
        rm -rf /etc/prosody
    fi
    if [ -d ${XMPP_DIRECTORY} ]; then
        rm -rf ${XMPP_DIRECTORY}
    fi
    if [ -d /usr/lib/prosody ]; then
        rm -rf /usr/lib/prosody
    fi
    if [ -f /usr/local/bin/prosody ]; then
        rm /usr/local/bin/prosody
    fi
    if [ -f /usr/local/bin/prosodyctl ]; then
        rm /usr/local/bin/prosodyctl
    fi
    groupdel prosody

    remove_completion_param install_xmpp
    sed -i '/xmpp/d' "$COMPLETION_FILE"
    sed -i '/prosody/d' "$COMPLETION_FILE"

    rm /etc/avahi/services/xmpp.service
    rm /etc/avahi/services/xmpp-server.service
    systemctl restart avahi-daemon
}

function xmpp_contact_info {
    filename="$1"

    if grep -q "contact_info =" "$filename"; then
        return
    fi

    { echo 'contact_info = {';
      echo "abuse = { \"mailto:${MY_EMAIL_ADDRESS}\", \"xmpp:${MY_USERNAME}@${HOSTNAME}\" };";
      echo "admin = { \"mailto:${MY_EMAIL_ADDRESS}\", \"xmpp:${MY_USERNAME}@${HOSTNAME}\" };";
      echo "feedback = { \"mailto:${MY_EMAIL_ADDRESS}\", \"xmpp:${MY_USERNAME}@${HOSTNAME}\" };";
      echo "security = { \"xmpp:${MY_USERNAME}@${HOSTNAME}\" };";
      echo "support = { \"xmpp:${MY_USERNAME}@${HOSTNAME}\" };";
      echo '};'; } >> "$filename"
}

function xmpp_modules {
    filename="$1"

    { echo 'modules_enabled = {';
      echo '  "server_contact_info";';
      echo '  "pubsub";';
      echo '  "pubsub_hub";';
      echo '  "dialback"; -- s2s dialback support';
      echo '  "disco"; -- Service discovery';
      echo '  "private"; -- Private XML storage (for room bookmarks, etc.)';
      echo '  "version"; -- Replies to server version requests';
      echo '  "uptime"; -- Report how long server has been running';
      echo '  "time"; -- Let others know the time here on this server';
      echo '  "ping"; -- Replies to XMPP pings with pongs';
      echo '  "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands';
      echo '  "posix"; -- POSIX functionality, sends server to background, enables syslog, etc.';
      echo '  "bosh"; -- Enable mod_bosh';
      echo "  ${xmpp_tls_enabled}\"tls\"; -- Enable mod_tls";
      echo '  "saslauth"; -- Enable mod_saslauth';
      echo '  "onions"; -- Enable chat via onion service';
      echo '  "mam"; -- Message archive management';
      echo '  "seclabels"; -- Security level indicators';
      echo '  "csi"; -- Client state indication (CSI)';
      echo '  "csi_compat"; -- CSI for older clients';
      echo '  "csi_battery_saver"; -- Extra CSI battery saving';
      echo '  "carbons"; -- Message carbons';
      echo '  "carbons_adhoc"; -- Message carbons';
      echo '  "carbons_copies"; -- Message carbons';
      echo '  "smacks"; -- Stream management';
      echo '  "smacks_offline"; -- Stream management';
      echo '  "pep"; -- Personal Eventing Protocol (to support OMEMO)';
      echo '  "firewall"; -- Block addresses';
      echo '  "profile"; -- Avatars';
      echo '  "e2e_policy"; -- To support OMEMO';
      echo '  "blocklist"; -- Privacy lists';
      echo '  "s2s_blacklist"; -- Blacklist particular servers';
      echo '  "privacy_lists"; -- Privacy lists';
      echo '  "blocking"; -- Blocking command';
      echo '  "block_strangers"; -- Dont allow messages from strangers';
      echo '  "roster"; -- Roster versioning';
      echo '  "offline_email"; -- If offline send to email';
      echo '  "offline"; -- Store offline messages';
      echo '  "http";';
      echo '  "http_upload";';
      echo '  "websocket";';
      echo '  "throttle_presence"; -- Reduce battery and bandwidth usage';
      echo '  "filter_chatstates"; -- Reduce battery and bandwidth usage';
      echo '};'; } >> "$filename"
}

function xmpp_onion_addresses {
    filename="$1"

    { echo 'onions_map = {';
      echo '  ["anonymitaet-im-inter.net"] = "rwf5skuv5vqzcdit.onion";';
      echo '  ["autistici.org"] = "wi7qkxyrdpu5cmvr.onion";';
      echo '  ["jabber.calyxinstitute.org"] = "ijeeynrc6x2uy5ob.onion";';
      echo '  ["jabber.ccc.de"] = "okj7xc6j2szr2y75.onion";';
      echo '  ["cloak.dk"] = "m2dsl4banuimpm6c.onion";';
      echo '  ["jabber.cryptoparty.is"] = "cryjabkbdljzohnp.onion";';
      echo '  ["daemons.cf"] = "daemon4jidu2oig6.onion";';
      echo '  ["dukgo.com"] = "wlcpmruglhxp6quz.onion";';
      echo '  ["evil.im"] = "evilxro6nvjuvxqo.onion";';
      echo '  ["xmpp.evil.im"] = "evilxro6nvjuvxqo.onion";';
      echo '  ["inventati.org"] = "wi7qkxyrdpu5cmvr.onion";';
      echo '  ["jabber.ipredator.se"] = "3iffdebkzzkpgipa.onion";';
      echo '  ["jabber-germany.de"] = "dbbrphko5tqcpar3.onion";';
      echo '  ["kode.im"] = "ihkw7qy3tok45dun.onion";';
      echo '  ["im.koderoot.net"] = "ihkw7qy3tok45dun.onion";';
      echo '  ["adb-centralen.se"] = "qai7jjjnhbrdiexf.onion";';
      echo '  ["joelpurra.se"] = "37x6i3wgr2jyublb.onion";';
      echo '  ["nordberg.se"] = "qai7jjjnhbrdiexf.onion";';
      echo '  ["jabber.lqdn.fr"] = "jabber63t4r2qi57.onion";';
      echo '  ["jabber.otr.im"] = "5rgdtlawqkcplz75.onion";';
      echo '  ["otromundo.cf"] = "arauemwe2utqqzye.onion";';
      echo '  ["patchcord.be"] = "xsydhi3dnbjuatpz.onion";';
      echo '  ["riseup.net"] = "4cjw6cwpeaeppfqz.onion";';
      echo '  ["xmpp.riseup.net"] = "4cjw6cwpeaeppfqz.onion";';
      echo '  ["rows.io"] = "yz6yiv2hxyagvwy6.onion";';
      echo '  ["xmpp.rows.io"] = "yz6yiv2hxyagvwy6.onion";';
      echo '  ["securejabber.me"] = "giyvshdnojeivkom.onion";';
      echo '  ["so36.net"] = "s4fgy24e2b5weqdb.onion";';
      echo '  ["jabber.so36.net"] = "s4fgy24e2b5weqdb.onion";';
      echo '  ["jabber.systemli.org"] = "x5tno6mwkncu5m3h.onion";';
      echo '  ["taolo.ga"] = "l3ybpw4vs6ie5rv2.onion";';
      echo '  ["tchncs.de"] = "duvfmyqmdlyvc3mi.onion";';
      echo '  ["wtfismyip.com"] = "ofkztxcohimx34la.onion";';
      echo '  ["prosody.xmpp.is"] = "y2qmqomqpszzryei.onion";';
      echo '  ["xndr.de"] = "trcubpttd6zkc3tf.onion";';
      echo '  ["jabber.cat"] = "sybzodlxacch7st7.onion";';
      echo '  ["trashserver.net"] = "m4c722bvc2r7brnn.onion";';
      echo '};'; } > /tmp/xmpp_onions_map.txt

    if [ ! -f ${XMPP_DIRECTORY}/onions_map.txt ]; then
       touch ${XMPP_DIRECTORY}/onions_map.txt
       chown prosody:prosody ${XMPP_DIRECTORY}/onions_map.txt
    fi

    if ! cmp --silent /tmp/xmpp_onions_map.txt ${XMPP_DIRECTORY}/onions_map.txt; then
        onions_map_str=$(cat /tmp/xmpp_onions_map.txt)

        # remove existing onions map
        sed -i '/onions_map = {/,/};/d' "$filename"

        # append new onions map
        echo "$onions_map_str" >> "$filename"

        cp /tmp/xmpp_onions_map.txt ${XMPP_DIRECTORY}/onions_map.txt
        chown prosody:prosody ${XMPP_DIRECTORY}/onions_map.txt

        xmpp_restart=1
    fi

    rm /tmp/xmpp_onions_map.txt
}

function xmpp_server_blacklist {
    filename="$1"

    prosody_firewall_rules=${XMPP_DIRECTORY}/firewall.txt
    blacklisted_addresses_filename=${XMPP_DIRECTORY}/blocked_addresses.txt
    blacklisted_addresses_filename_new=/tmp/xmpp_blocked_addresses.txt
    blacklisted_domains=

    if [ -f "${blacklisted_addresses_filename_new}" ]; then
        rm "${blacklisted_addresses_filename_new}"
    fi

    while read -r blocked; do
        if [ ${#blocked} -gt 4 ]; then
            if [[ "$blocked" == *"."* ]]; then
                if [[ "$blocked" != *"@"* ]]; then
                    if [ "$blacklisted_domains" ]; then
                        blacklisted_domains="${blacklisted_domains}, \"$blocked\""
                    else
                        blacklisted_domains="\"$blocked\""
                    fi
                else
                    echo "$blocked" >> "${blacklisted_addresses_filename_new}"
                fi
            fi
        fi
    done <"$FIREWALL_DOMAINS"

    if ! grep -q "s2s_blacklist =" "$filename"; then
        echo "s2s_blacklist = { $blacklisted_domains }" >> "$filename"
        xmpp_restart=1
    else
        if ! grep -q "s2s_blacklist = { $blacklisted_domains }" "$filename"; then
            sed -i "s|s2s_blacklist =.*|s2s_blacklist = { $blacklisted_domains }|g" "$filename"
            xmpp_restart=1
        fi
    fi

    # create blacklisted addresses file
    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

    if [ ! -f "$prosody_firewall_rules" ]; then
        # create firewall rules
        { echo "%LIST blacklist: file:${blacklisted_addresses_filename}";
          echo '';
          echo 'KIND: presence';
          echo 'TYPE: subscribe';
          echo 'CHECK LIST: blacklist contains $<@from>';
          echo 'BOUNCE=policy-violation (Blocked)';
          echo '';
          echo 'KIND: message';
          echo 'TYPE: chat';
          echo 'CHECK LIST: blacklist contains $<@from>';
          echo 'BOUNCE=policy-violation (Blocked)';
          echo '';
          echo 'KIND: message';
          echo 'TYPE: groupchat';
          echo 'CHECK LIST: blacklist contains $<@from>';
          echo 'BOUNCE=policy-violation (Blocked)';
          echo '';
          echo '%RATE normal: 2 (burst 3)';
          echo 'KIND: message';
          echo 'LIMIT: normal';
          echo 'BOUNCE=policy-violation (Sending too fast!)'; } > "$prosody_firewall_rules"
        xmpp_restart=1
    fi
    chown prosody:prosody "$prosody_firewall_rules"
    chown prosody:prosody "$blacklisted_addresses_filename"

    # ensure firewall rules file is linked
    if ! grep -q "firewall_scripts =" /etc/prosody/prosody.cfg.lua; then
        echo "firewall_scripts = { \"$prosody_firewall_rules\" }" >> /etc/prosody/prosody.cfg.lua
        xmpp_restart=1
    else
        if ! grep -q "firewall_scripts = { \"$prosody_firewall_rules\" }" /etc/prosody/prosody.cfg.lua; then
            sed -i "s|firewall_scripts =.*|firewall_scripts = { \"$prosody_firewall_rules\" }|g" /etc/prosody/prosody.cfg.lua
            xmpp_restart=1
        fi
    fi
    if ! grep -q "firewall_scripts =" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        echo "firewall_scripts = { \"$prosody_firewall_rules\" }" >> /etc/prosody/conf.avail/xmpp.cfg.lua
        xmpp_restart=1
    else
        if ! grep -q "firewall_scripts = { \"$prosody_firewall_rules\" }" /etc/prosody/conf.avail/xmpp.cfg.lua; then
            sed -i "s|firewall_scripts =.*|firewall_scripts = { \"$prosody_firewall_rules\" }|g" /etc/prosody/conf.avail/xmpp.cfg.lua
            xmpp_restart=1
        fi
    fi
}

function xmpp_create_config {
    echo "admins = { \"$MY_USERNAME@$DEFAULT_DOMAIN_NAME\", \"notification@$DEFAULT_DOMAIN_NAME\" }" > /etc/prosody/prosody.cfg.lua
    echo 'plugin_paths = { "/var/lib/prosody/prosody-modules" }' >> /etc/prosody/prosody.cfg.lua
    echo '' >> /etc/prosody/prosody.cfg.lua
    xmpp_modules /etc/prosody/prosody.cfg.lua
    echo '' >> /etc/prosody/prosody.cfg.lua
    xmpp_onion_addresses /etc/prosody/prosody.cfg.lua
    xmpp_contact_info /etc/prosody/prosody.cfg.lua
    xmpp_server_blacklist /etc/prosody/prosody.cfg.lua
    { echo '';
      echo 'allow_registration = false;';
      echo '';
      echo 'daemonize = true;';
      echo '';
      echo 'pidfile = "/var/run/prosody/prosody.pid";';
      echo '';
      echo 'https_ports = { 5281 }';
      echo 'https_interfaces = { "*" }';
      echo 'https_ssl = {'; } >> /etc/prosody/prosody.cfg.lua
    if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem" ]; then
        echo "    certificate = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem\";" >> /etc/prosody/prosody.cfg.lua
        echo "    key = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem\";" >> /etc/prosody/prosody.cfg.lua
    else
        echo "    certificate = \"/etc/ssl/certs/xmpp.crt\";" >> /etc/prosody/prosody.cfg.lua
        echo "    key = \"/etc/ssl/private/xmpp.key\";" >> /etc/prosody/prosody.cfg.lua
    fi
    { echo "    curve = $XMPP_ECC_CURVE;";
      echo "    ciphers = $XMPP_CIPHERS;";
      echo '    options = {"no_sslv2", "no_sslv3" };'; } >> /etc/prosody/prosody.cfg.lua
    if [ -f "/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem" ]; then
        echo "    dhparam = \"/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.dhparam\";" >> /etc/prosody/prosody.cfg.lua
    else
        echo "    dhparam = \"/etc/ssl/certs/xmpp.dhparam\";" >> /etc/prosody/prosody.cfg.lua
    fi
    { echo "}";
      echo '';
      echo 'ssl = {'; } >> /etc/prosody/prosody.cfg.lua
    if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem" ]; then
        echo "    certificate = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem\";" >> /etc/prosody/prosody.cfg.lua
        echo "    key = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem\";" >> /etc/prosody/prosody.cfg.lua
    else
        echo "    certificate = \"/etc/ssl/certs/xmpp.crt\";" >> /etc/prosody/prosody.cfg.lua
        echo "    key = \"/etc/ssl/private/xmpp.key\";" >> /etc/prosody/prosody.cfg.lua
    fi
    { echo "    curve = $XMPP_ECC_CURVE;";
      echo '    depth = "2";';
      echo "    ciphers = $XMPP_CIPHERS;";
      echo '    options = {"no_sslv2", "no_sslv3" };'; } >> /etc/prosody/prosody.cfg.lua
    if [ -f "/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem" ]; then
        echo "    dhparam = \"/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.dhparam\";" >> /etc/prosody/prosody.cfg.lua
    else
        echo "    dhparam = \"/etc/ssl/certs/xmpp.dhparam\";" >> /etc/prosody/prosody.cfg.lua
    fi

    e2ee_policy='optional'
    if [[ "$XMPP_E2EE" == 'y'* || "$XMPP_E2EE" == 't'* ]]; then
        e2ee_policy='required'
    fi

    { echo '}';
      echo '';
      echo 'c2s_require_encryption = false';
      echo 's2s_require_encryption = false';
      echo '';
      echo 'e2e_policy_muc = "none"';
      echo "e2e_policy_chat = \"$e2ee_policy\"";
      echo "e2e_policy_message_required_chat = \"$xmpp_encryption_warning\"";
      echo "e2e_policy_whitelist = { \"notification@${HOSTNAME}\" };";
      echo '';
      echo '# This may need to be set to true in some cases when the other server requires TLS';
      echo 's2s_secure_auth = false';
      echo '';
      echo 'authentication = "internal_hashed"';
      echo '';
      echo 'storage = "sql"';
      echo 'sql = { driver = "SQLite3", database = "prosody.sqlite" }';
      echo '';
      echo 'log = {';
      echo '    info = "/dev/null";';
      echo '    error = "/dev/null";';
      echo '    { levels = { "error" }; to = "/dev/null";  };';
      echo '}';
      echo ''; } >> /etc/prosody/prosody.cfg.lua
    if [[ "$ONION_ONLY" != 'no' ]]; then
        echo "VirtualHost \"${XMPP_ONION_HOSTNAME}\"" >> /etc/prosody/prosody.cfg.lua
        # TLS is not needed for onion transport security
        sed -i 's|s2s_require_encryption =.*|s2s_require_encryption = false|g' /etc/prosody/prosody.cfg.lua
        sed -i 's|c2s_require_encryption =.*|c2s_require_encryption = false|g' /etc/prosody/prosody.cfg.lua
    else
        echo "VirtualHost \"${DEFAULT_DOMAIN_NAME}\"" >> /etc/prosody/prosody.cfg.lua
    fi
    echo '    ssl = {' >> /etc/prosody/prosody.cfg.lua
    if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem" ]; then
        echo "        certificate = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem\";" >> /etc/prosody/prosody.cfg.lua
        echo "        key = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem\";" >> /etc/prosody/prosody.cfg.lua
    else
        echo "        certificate = \"/etc/ssl/certs/xmpp.crt\";" >> /etc/prosody/prosody.cfg.lua
        echo "        key = \"/etc/ssl/private/xmpp.key\";" >> /etc/prosody/prosody.cfg.lua
    fi
    { echo "        curve = $XMPP_ECC_CURVE;";
      echo '        depth = "2";';
      echo "        ciphers = $XMPP_CIPHERS;";
      echo '        options = {"no_sslv2", "no_sslv3" };'; } >> /etc/prosody/prosody.cfg.lua
    if [ -f "/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem" ]; then
        echo "        dhparam = \"/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.dhparam\";" >> /etc/prosody/prosody.cfg.lua
    else
        echo "        dhparam = \"/etc/ssl/certs/xmpp.dhparam\";" >> /etc/prosody/prosody.cfg.lua
    fi
    { echo '    }';
      echo '';
      echo 'Include "conf.d/*.cfg.lua"';
      echo 'http_upload_path = "/var/lib/prosody/http_uploads"';
      echo 'http_upload_file_size_limit = 25165824';
      echo '';
      echo "Component \"chat.${DEFAULT_DOMAIN_NAME}\" \"muc\"";
      echo '    name = "Chatrooms"';
      echo '    modules_enabled = {';
      echo '        "muc_limits";';
      echo '        "filter_words";';
      echo '        "muc_block_pm";';
      echo "        ${xmpp_tls_enabled}\"tls\";";
      echo '        "vcard_muc";';
      echo '        "s2s_blacklist";';
      echo '    }'; } >> /etc/prosody/prosody.cfg.lua

    if [[ "$ONION_ONLY" == 'no' ]]; then
        { echo '    ssl = {';

          echo "        certificate = \"/etc/letsencrypt/live/chat.${DEFAULT_DOMAIN_NAME}/fullchain.pem\";";
          echo "        key = \"/etc/letsencrypt/live/chat.${DEFAULT_DOMAIN_NAME}/privkey.pem\";";
          echo "        curve = \"$XMPP_ECC_CURVE\";";
          echo "        depth = \"2\";";
          echo "        ciphers = \"$XMPP_CIPHERS\";";
          echo "        options = { \"no_sslv2\", \"no_sslv3\" };";
          echo "        dhparam = \"/etc/prosody/xmpp.dhparam\";";
          echo "    }"; } >> /etc/prosody/prosody.cfg.lua
    fi
    { echo 'storage = { muc_log = "sql"; }';
      echo 'filter_words = {}';
      echo 'sql = { driver = "SQLite3", database = "prosody.sqlite" }';
      echo 'muc_event_rate = 0.5;';
      echo 'muc_burst_factor = 10;';
      echo 'muc_log_by_default = false;';
      echo 'muc_log_all_rooms = false;';
      echo 'max_archive_query_results = 10;';
      echo 'max_history_messages = 10;';
      echo 'muc_room_default_public = true;';
      echo 'muc_room_default_persistent = false;';
      echo 'muc_room_default_members_only = false;';
      echo 'muc_room_default_moderated = true;';
      echo 'muc_room_default_public_jids = false;';
      echo 'muc_room_default_change_subject = false;';
      echo 'muc_room_default_history_length = 20;';
      echo 'muc_room_default_language = "en";';
      echo 'muc_room_locking = false;';
      echo 'muc_room_lock_timeout = 300;';
      echo 'muc_tombstones = false;';
      echo 'restrict_room_creation = "local";'; } >> /etc/prosody/prosody.cfg.lua
}

function install_xmpp_nightly {
    if [ ! -d "$INSTALL_DIR" ]; then
        mkdir -p "$INSTALL_DIR"
    fi

    cd "$INSTALL_DIR" || exit 24

    # Try to get the source from the project repo
    if [ -f "/root/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" ]; then
        cp "/root/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" .
    else
        if [ -f "/home/${MY_USERNAME}/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" ]; then
            cp "/home/${MY_USERNAME}/${PROJECT_NAME}/image_build/${prosody_filename}.tar.gz" .
        else
            wget "$prosody_nightly_url"
        fi
    fi

    if [ ! -f "${INSTALL_DIR}/${prosody_filename}.tar.gz" ]; then
        echo $"Failed to download prosody nightly $prosody_nightly_url"
        exit 78
    fi

    hash_value=$(sha256sum "${INSTALL_DIR}/${prosody_filename}.tar.gz" | awk -F ' ' '{print $1}')
    if [[ "$hash_value" != "$prosody_nightly_hash" ]]; then
        rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"
        echo $'Unexpected hash value for prosody nightly download'
        exit 68
    fi

    tar -xzvf "${INSTALL_DIR}/${prosody_filename}.tar.gz"
    cd "${INSTALL_DIR}/${prosody_filename}" || exit 72
    xmpp_fix_exists
    ./configure --ostype=debian --prefix=/usr
    make prefix=/usr
    make prefix=/usr install
    if [ -f /usr/local/bin/prosody ]; then
        echo $'Failed to build prosody nightly to /usr/bin'
        rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"
        rm -rf "${INSTALL_DIR:?}/${prosody_filename}"
        exit 62
    fi
    rm "${INSTALL_DIR}/${prosody_filename}.tar.gz"

    set_completion_param "prosody_filename" "${prosody_filename}"
}

function add_xmpp_onion_http_upload {
    if grep -q 'HiddenServicePort 5281 127.0.0.1:5281' "/etc/torrc.d/${PROJECT_NAME}"; then
        return
    fi
    sed -i '/ 5269 /a HiddenServicePort 5281 127.0.0.1:5281' "/etc/torrc.d/${PROJECT_NAME}"
    systemctl restart tor
}

function add_xmpp_onion_to_email {
    if ! grep -q 'hidden_service_xmpp' "/etc/torrc.d/${PROJECT_NAME}"; then
        return
    fi

    # remove xmpp hidden service
    sed -i "/hidden_service_xmpp/,+1 d" "/etc/torrc.d/${PROJECT_NAME}"
    sed -i '/5222/d' "/etc/torrc.d/${PROJECT_NAME}"
    sed -i '/5269/d' "/etc/torrc.d/${PROJECT_NAME}"

    # add xmpp ports to email
    sed -i '/ 465 /a HiddenServicePort 5269 127.0.0.1:5269' "/etc/torrc.d/${PROJECT_NAME}"
    sed -i '/ 465 /a HiddenServicePort 5222 127.0.0.1:5222' "/etc/torrc.d/${PROJECT_NAME}"

    systemctl restart tor
}

function install_xmpp {
    increment_app_install_progress

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

    # remove any existing install attempt
    if [ -f "$INSTALL_DIR/$prosody_modules_filename" ]; then
        rm "$INSTALL_DIR/$prosody_modules_filename"
    fi
    if [ -d "$INSTALL_DIR/prosody-modules" ]; then
        rm -rf "$INSTALL_DIR/prosody-modules"
    fi

    if [[ "$ONION_ONLY" != 'no' ]]; then
        # Disable TLS for onion only versions
        # this makes the user experience a lot slicker
        # because there are no prompts to accept
        # self-signed certs
        xmpp_tls_enabled='-- '
    fi

    increment_app_install_progress

    update_prosody_modules

    increment_app_install_progress

    # obtain a cert for the default domain
    if [[ "$(cert_exists "${DEFAULT_DOMAIN_NAME}" pem)" == "0" ]]; then
        create_site_certificate "${DEFAULT_DOMAIN_NAME}" 'yes'
        if [[ "$ONION_ONLY" == 'no' ]]; then
            if [[ "$(cert_exists "${DEFAULT_DOMAIN_NAME}" pem)" == "0" ]]; then
                echo $'LetsEncrypt cert could not be obtained for xmpp'
                exit 72
            fi
        fi
    fi

    increment_app_install_progress

    if [[ "$(cert_exists "chat.${DEFAULT_DOMAIN_NAME}" pem)" == "0" ]]; then
        create_site_certificate "chat.${DEFAULT_DOMAIN_NAME}" 'yes'
        if [[ "$ONION_ONLY" == 'no' ]]; then
            if [[ "$(cert_exists "chat.${DEFAULT_DOMAIN_NAME}" pem)" == "0" ]]; then
                echo $'LetsEncrypt cert could not be obtained for xmpp muc'
                exit 56
            fi
        fi
    fi

    increment_app_install_progress

    $INSTALL_PACKAGES lua-sec lua-bitop lua5.1 liblua5.1-dev

    increment_app_install_progress

    $INSTALL_PACKAGES libidn11-dev libssl-dev lua-dbi-sqlite3

    increment_app_install_progress

    $INSTALL_PACKAGES mercurial curl python-xmpp

    increment_app_install_progress

    $INSTALL_PACKAGES prosody

    increment_app_install_progress

    if [ ! -f /usr/bin/hg ]; then
        echo $"Couldn't install mercurial"
        exit 52
    fi

    if [ ! -d /etc/prosody ]; then
        echo $"ERROR: prosody does not appear to have installed. $CHECK_MESSAGE"
        exit 52
    fi

    groupadd prosody

    if [ ! -d ${XMPP_DIRECTORY}/http_uploads ]; then
        mkdir -p ${XMPP_DIRECTORY}/http_uploads
    fi
    if [ ! -d /etc/prosody/conf.d ]; then
        mkdir -p /etc/prosody/conf.d
    fi

    chmod -R 700 /etc/prosody/conf.d
    chown -R prosody ${XMPP_DIRECTORY}
    chown -R prosody /etc/prosody/conf.d

    # install modules
    update_prosody_modules initial
    if [ ! -d ${XMPP_DIRECTORY}/prosody-modules ]; then
        echo $'No prosody modules available'
        exit 82
    fi

    increment_app_install_progress

    # create a certificate
    if [ ! -f "/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.pem" ]; then
        if [ ! -f /etc/ssl/certs/xmpp.crt ]; then
            "${PROJECT_NAME}-addcert" -h xmpp --dhkey "${DH_KEYLENGTH}"
            # shellcheck disable=SC2034
            CHECK_HOSTNAME=xmpp
            check_certificates xmpp
            if [ ! -f /etc/ssl/certs/xmpp.crt ]; then
                echo $'Failed to create xmpp certificate'
                exit 72
            fi
            if [ ! -f /etc/ssl/private/xmpp.key ]; then
                echo $'Failed to create xmpp private certificate'
                exit 36
            fi
            chmod g=rX /etc/ssl/private/xmpp.key
            chmod g=rX /etc/ssl/certs/xmpp.*
        fi
    fi

    increment_app_install_progress

    groupadd default
    chmod 600 /etc/shadow
    chmod 600 /etc/gshadow
    usermod -g default prosody
    chmod 0000 /etc/shadow
    chmod 0000 /etc/gshadow

    chown root:default /etc/ssl/private/xmpp.*
    chown root:default /etc/ssl/certs/xmpp.*
    chown root:default "/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.*"
    chown root:default "/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.*"

    cp -a /etc/prosody/conf.avail/example.com.cfg.lua /etc/prosody/conf.avail/xmpp.cfg.lua

    if [ -f "/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem" ]; then
        sed -i "s|key =.*|key = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/privkey.pem\";|g" /etc/prosody/conf.avail/xmpp.cfg.lua
        sed -i "s|certificate =.*|certificate = \"/etc/letsencrypt/live/${DEFAULT_DOMAIN_NAME}/fullchain.pem\";|g" /etc/prosody/conf.avail/xmpp.cfg.lua
    else
        sed -i "s|key =.*|key = \"/etc/ssl/private/xmpp.key\";|g" /etc/prosody/conf.avail/xmpp.cfg.lua
        sed -i "s|certificate =.*|certificate = \"/etc/ssl/certs/xmpp.crt\";|g" /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    if ! grep -q "xmpp.dhparam" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        if [[ "$(cert_exists "${DEFAULT_DOMAIN_NAME}")" == "1" ]]; then
            sed -i "/certificate =/a\\        dhparam = \"/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.dhparam\";" /etc/prosody/conf.avail/xmpp.cfg.lua
        else
            sed -i '/certificate =/a\\        dhparam = "/etc/ssl/certs/xmpp.dhparam";' /etc/prosody/conf.avail/xmpp.cfg.lua
        fi
    fi
    if ! grep -q 'options = {"no_sslv2", "no_sslv3" }' /etc/prosody/conf.avail/xmpp.cfg.lua; then
        sed -i '/certificate =/a\        options = {"no_sslv2", "no_sslv3" };' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    if ! grep -q 'ciphers =' /etc/prosody/conf.avail/xmpp.cfg.lua; then
        sed -i "/certificate =/a\\        ciphers = $XMPP_CIPHERS;" /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    if ! grep -q 'depth = "2";' /etc/prosody/conf.avail/xmpp.cfg.lua; then
        sed -i '/certificate =/a\        depth = "2";' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    if ! grep -q 'curve =' /etc/prosody/conf.avail/xmpp.cfg.lua; then
        sed -i "/certificate =/a\\        curve = $XMPP_ECC_CURVE;" /etc/prosody/conf.avail/xmpp.cfg.lua
    fi

    sed -i "s/example.com/$DEFAULT_DOMAIN_NAME/g" /etc/prosody/conf.avail/xmpp.cfg.lua
    sed -i 's/enabled = false -- Remove this line to enable this host//g' /etc/prosody/conf.avail/xmpp.cfg.lua

    if ! grep -q "modules_enabled" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        echo '' >> /etc/prosody/conf.avail/xmpp.cfg.lua
        xmpp_modules /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    echo '' >> /etc/prosody/conf.avail/xmpp.cfg.lua
    if ! grep -q "c2s_require_encryption" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        echo 'c2s_require_encryption = false' >> /etc/prosody/conf.avail/xmpp.cfg.lua
    else
        sed -i 's|c2s_require_encryption.*|c2s_require_encryption = false|g' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    if ! grep -q "s2s_require_encryption" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        echo 's2s_require_encryption = false' >> /etc/prosody/conf.avail/xmpp.cfg.lua
    else
        sed -i 's|s2s_require_encryption.*|s2s_require_encryption = false|g' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi

    if [[ "$ONION_ONLY" != 'no' ]]; then
        sed -i 's|c2s_require_encryption.*|c2s_require_encryption = false|g' /etc/prosody/conf.avail/xmpp.cfg.lua
        sed -i 's|s2s_require_encryption.*|s2s_require_encryption = false|g' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi

    increment_app_install_progress

    xmpp_update_e2e_policy /etc/prosody/conf.avail/xmpp.cfg.lua

    if ! grep -q "allow_unencrypted_plain_auth" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        echo 'allow_unencrypted_plain_auth = true' >> /etc/prosody/conf.avail/xmpp.cfg.lua
    else
        sed -i 's|allow_unencrypted_plain_auth.*|allow_unencrypted_plain_auth = true|g' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    ln -sf /etc/prosody/conf.avail/xmpp.cfg.lua /etc/prosody/conf.d/xmpp.cfg.lua

    if [ ! -d /var/lib/tor ]; then
        echo $'No Tor installation found. xmpp onion site cannot be configured.'
        exit 87
    fi

    increment_app_install_progress

    if [ ! -f /var/lib/tor/hidden_service_email/hostname ]; then
        echo $'xmpp onion site hostname not found'
        exit 65
    fi
    XMPP_ONION_HOSTNAME=$(cat /var/lib/tor/hidden_service_email/hostname)
    if ! grep -q "${XMPP_ONION_HOSTNAME}" /etc/prosody/conf.avail/xmpp.cfg.lua; then
        { echo '';
          echo "VirtualHost \"${XMPP_ONION_HOSTNAME}\"";
          echo '    modules_enabled = { "onions" };'; } >> /etc/prosody/conf.avail/xmpp.cfg.lua
    fi
    set_completion_param "xmpp onion domain" "${XMPP_ONION_HOSTNAME}"

    increment_app_install_progress

    if [ -f "$IMAGE_PASSWORD_FILE" ]; then
        XMPP_PASSWORD="$(printf "%s" "$(cat "$IMAGE_PASSWORD_FILE")")"
    else
        if [ ${#XMPP_PASSWORD} -lt 8 ]; then
            XMPP_PASSWORD="$(create_password "${MINIMUM_PASSWORD_LENGTH}")"
        fi
    fi

    function_check configure_firewall_for_xmpp
    configure_firewall_for_xmpp

    increment_app_install_progress

    update_default_domain

    xmpp_create_config

    increment_app_install_progress

    # TODO comment this out after debian supports prosody 0.10 or later
    install_xmpp_nightly

    increment_app_install_progress

    chown -R prosody /etc/prosody
    chown -R prosody ${XMPP_DIRECTORY}
    chown -R prosody /usr/lib/prosody
    chmod -R 700 /etc/prosody/conf.d
    usermod -a -G www-data prosody

    # Avoid STIG failures
    if [ -f /usr/lib/ssl/private/xmpp.key ]; then
        chown root:root /usr/lib/ssl/private/xmpp.key
    fi
    if [ -f /usr/lib/ssl/certs/xmpp.crt ]; then
        chown root:root /usr/lib/ssl/certs/xmpp.crt
    fi
    if [ -f /usr/lib/ssl/certs/xmpp.dhparam ]; then
        chown root:root /usr/lib/ssl/certs/xmpp.dhparam
    fi

    if [ -d /etc/letsencrypt ]; then
        usermod -a -G ssl-cert prosody
    fi

    if [ -f /etc/ssl/certs/xmpp.dhparam ]; then
        cp /etc/ssl/certs/xmpp.dhparam /etc/prosody/xmpp.dhparam
        chown prosody:prosody /etc/prosody/xmpp.dhparam
        sed -i 's|/etc/ssl/certs/xmpp.dhparam|/etc/prosody/xmpp.dhparam|g' /etc/prosody/prosody.cfg.lua
        sed -i 's|/etc/ssl/certs/xmpp.dhparam|/etc/prosody/xmpp.dhparam|g' /etc/prosody/conf.avail/xmpp.cfg.lua
    fi

    increment_app_install_progress

    $PACKAGE_HOLD prosody

    increment_app_install_progress

    add_xmpp_onion_to_email

    increment_app_install_progress

    add_xmpp_onion_http_upload

    increment_app_install_progress

    prosody_default_security_labels /etc/prosody/prosody.cfg.lua

    prosody_update_onion_certs

    systemctl restart prosody

    configure_xmppsend

    increment_app_install_progress

    if [[ $ONION_ONLY != 'no' ]]; then
        prosodyctl register "$MY_USERNAME" "$XMPP_ONION_HOSTNAME" "$XMPP_PASSWORD"
    else
        prosodyctl register "$MY_USERNAME" "$DEFAULT_DOMAIN_NAME" "$XMPP_PASSWORD"
    fi
    # shellcheck disable=SC2181
    if [ ! "$?" = "0" ]; then
        echo ''
        echo ''
        systemctl status prosody -l
        echo ''
        echo ''
        cat /etc/prosody/prosody.cfg.lua
        echo ''
        echo ''
        cat /etc/prosody/conf.avail/xmpp.cfg.lua
        echo ''
        echo ''
        #remove_xmpp
        echo $'Unable to register prosody user'
        exit 34
    fi

    increment_app_install_progress

    prosody_daemon_restart_script

    "${PROJECT_NAME}-pass" -u "$MY_USERNAME" -a xmpp -p "$XMPP_PASSWORD"

    # Add avahi services
    { echo '<?xml version="1.0" standalone="no"?><!--*-nxml-*-->';
      echo '<!DOCTYPE service-group SYSTEM "avahi-service.dtd">';
      echo '<service-group>';
      echo '  <name replace-wildcards="yes">%h XMPP</name>';
      echo '  <service>';
      echo '    <type>_xmpp._tcp</type>';
      echo "    <port>5222</port>";
      echo '  </service>';
      echo '  <service>';
      echo '    <type>_xmpp-server._tcp</type>';
      echo "    <port>5269</port>";
      echo '  </service>';
      echo '</service-group>'; } > /etc/avahi/services/xmpp.service

    increment_app_install_progress

    systemctl restart avahi-daemon

    APP_INSTALLED=1
}

# NOTE: deliberately no exit 0