#!/bin/bash

#
# Name:         changeseedboxpass
# Version:      1.1.5
#
# (c) 2016-2025, Rapidseedbox, alexey@rapidseedbox.com
#                              boban@rapidseedbox.com

DEBUG="no"

export LANG=en_US

shopt -u checkwinsize

# Fix "bad" terminals
case "${TERM}" in
  "xterm" )
      export TERM="linux"
      ;;
esac


SC_NAME="$( basename "${0}" )"
SC_VER="$( grep -m 1 -E '^#\s*Version:\s+' "${0}" | awk '{print $NF}' )"

LOGFILE="/var/log/changeseedboxpass.log"

MIN_PASSWORD_LENGTH="8"

usage() {
    cat <<EOF
Usage: ${0} [USERNAME [Service Password] ]

Examples:

    Dialog UI:
        ${0}
        ${0} username

    No UI:
        ${0} username deluge PaZZw0rD
        ${0} username all RANDOM

Services are:
        all, user, btsync, deluge, l2tp_ipsec, nzbget, plex,
        qbittorrent, resiliosync, rutorrent, sabnzbd, sickchill, syncthing,
        transmission, utorrent, userdir, vnc, 3proxy, seedboxcp
EOF
}

# -- Quick checks before we allow bad things to happen
_uid="$( id -u 2> /dev/null )"
if [ "${_uid}" != "0" ] ; then
    >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: Sorry."
    >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: root credentials required to run this script !"
    exit 1
fi
if [ -z "${BASH_VERSINFO}" ]; then
    >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: ERROR: You must execute this script with BASH" | tee -a "${LOGFILE}"
    exit 1
fi


# -- Main return code for the script
retcode=0

# -- Define the dialog exit status codes
DIALOG_OK=0
DIALOG_CANCEL=1
#DIALOG_HELP=2
DIALOG_EXTRA=3
#DIALOG_ITEM_HELP=4
DIALOG_ESC=255

#DIALOG_OPTS="--ascii-lines --no-collapse --clear"
#DIALOG_OPTS="--ascii-lines --no-collapse --colors"

DIALOG_OPTS=( \
      "--ascii-lines" \
      "--no-collapse" \
      "--colors" \
            )

# -- Parse command line
PASSWORD_CHECK="yes"
while [ -n "${1}" ] ; do
    case "${1,,}" in
      "-h"|"--help")
          usage
          exit 0
          ;;
      "--no-password-check")
          PASSWORD_CHECK="no"
          shift
          ;;
      -*)
          >&2 echo -ne "\n[$( date -u +"%d-%m-%Y %T %Z" )]: ERROR: Wrong command line switch: ${1}\n\n" \
                  | tee -a "${LOGFILE}"
          exit 1
          ;;
      *)
          break
          ;;
    esac
done

# command -v "cracklib-check" > /dev/null 2>&1 \
#     || PASSWORD_CHECK="no"


USERNAME="${1}"
if [ -z "${USERNAME}" ] ; then
    USERNAME="user"
fi
if ! id "${USERNAME}" > /dev/null 2>&1 ; then
    usage
    >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: Sorry." | tee -a "${LOGFILE}"
    >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: ${USERNAME}: account not found !" | tee -a "${LOGFILE}"
    if [ -e "/rsb-template.id" ] ; then
        >&2 echo -e "\n[$( date -u +"%d-%m-%Y %T %Z" )]: Seedbox template info:" | tee -a "${LOGFILE}"
        >&2 echo -e "[$( date -u +"%d-%m-%Y %T %Z" )]: --------------------------" | tee -a "${LOGFILE}"
        cat "/rsb-template.id"
    fi
    exit 1
fi

SERVICE="${2,,}"
PASSWORD="${3}"
if [ -z "${SERVICE}" ] ; then
    UI="yes"
else
    UI="no"
fi
if [ -n "${SERVICE}" ] && [ -z "${PASSWORD}" ] ; then
    >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: Arguments missing" | tee -a "${LOGFILE}"
    usage
    exit 1
fi
if [ -n "${PASSWORD}" ] && [ "${PASSWORD^^}" = "RANDOM" ] ; then
    if which apg > /dev/null 2>&1 ; then
        PASSWORD="$( apg -n 1 -m ${MIN_PASSWORD_LENGTH} -x ${MIN_PASSWORD_LENGTH} -M NCL 2> /dev/null )"
    elif which pwgen > /dev/null 2>&1 ; then
        PASSWORD="$( pwgen -cn ${MIN_PASSWORD_LENGTH} 1 2> /dev/null )"
    else
        >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: No passowd generator available" | tee -a "${LOGFILE}"
        exit 1
    fi
    if [ -z "${PASSWORD}" ] ; then
        >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: Error generating password" | tee -a "${LOGFILE}"
        exit 1
    fi
fi

# -- Check password complexity/etc
if [ -n "${PASSWORD}" ] && [ "${PASSWORD_CHECK}" = "yes" ] ; then
    _p_len="${#PASSWORD}"
    if [ "${_p_len}" -lt "${MIN_PASSWORD_LENGTH}" ] ; then
        >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: ${PASSWORD}: it is WAY too short - ${_p_len} characters. Use at least 8 alphanumeric characters, mixed case" \
                | tee -a "${LOGFILE}"
        exit 5
    fi

    if [[ ! "$PASSWORD" =~ [0-9] || ! "$PASSWORD" =~ [a-z] || ! "$PASSWORD" =~ [A-Z] ]]; then
        >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: ${PASSWORD}: Password does not meet criteria of having atleast one uppercase, one lowercase and one numeric character in it." \
               | tee -a "${LOGFILE}"
        exit 5
    fi
    
    if [[ "$PASSWORD" =~ [[:space:]\"\'\:\-\\\`\$]  ]]; then
        >&2 echo "[$( date -u +"%d-%m-%Y %T %Z" )]: ${PASSWORD}: Password contains forbidden characters [whitespace OR \" OR ' OR ; OR - OR \` OR \$]" \
               | tee -a "${LOGFILE}"
        exit 5
    fi


    # Boban, commenting out cracklib, too complicated for our application, WHMCS 
    # _out="$( cracklib-check <<< "${PASSWORD}" )"
    # _result="$( awk '{print $2}' <<< "${_out}" )"
    # if [ "${_result}" != "OK" ] ; then
    #     echo "[$( date -u +"%d-%m-%Y %T %Z" )]: ${_out}" | tee -a "${LOGFILE}"
    #     exit 5
    # fi
fi


# -- Store menu options selected by the user
INPUT="/tmp/changeseedboxpass.in.$$"

# -- Storage file for displaying commands output
OUTPUT="/tmp/changeseedboxpass.out.$$"

# -- Storage file for misc data
DATA="/tmp/changeseedboxpass.data.$$"

# -- trap and delete temp files
trap "exit_func" SIGHUP SIGINT SIGTERM

# -- 'lock' file
#echo "Creating lock file" >> "${LOGFILE}"
touch "/var/lock/changeseedboxpass.lock" >> "${LOGFILE}" 2>&1

USERHOME="/home/${USERNAME}"

# -- We'll store passwords in this directory
PASSWORDS_STORE_DIR="/var/local/passwd"
[ -d "${PASSWORDS_STORE_DIR}" ] \
    || mkdir -vp "${PASSWORDS_STORE_DIR}" >> "${LOGFILE}" 2>&1
PASSWORDS_STORE="${PASSWORDS_STORE_DIR}/${USERNAME}"
if [ ! -e "${PASSWORDS_STORE}" ] ; then
    ( \
         touch "${PASSWORDS_STORE}" ; \
         chown -v "${USERNAME}":"${USERNAME}" "${PASSWORDS_STORE}" ; \
         chmod -v 0600 "${PASSWORDS_STORE}" ; \
    ) >> "${LOGFILE}" 2>&1
fi


# -- TERM dimension(s)
if [ ${UI} = "yes" ] ; then
    max_columns="$( tput cols )"
fi


# -------------------------------------------
# -- Logging functions
# -------------------------------------------
ENTRY() {
    [ "${DEBUG}" != "yes" ] && return
    local cfn="${FUNCNAME[1]}"
    local tstamp="$( date -u +"%d-%m-%Y %T %Z" )"
    local msg="> ${cfn} ${FUNCNAME}"
    echo -e "[${tstamp}] [DEBUG]\t${msg}" >> "${LOGFILE}"
}

RETURN() {
    [ "${DEBUG}" != "yes" ] && return
    local cfn="${FUNCNAME[1]}"
    local tstamp="$( date -u +"%d-%m-%Y %T %Z" )"
    local msg="< ${cfn} ${FUNCNAME}"
    echo -e "[${tstamp}] [DEBUG]\t${msg}" >> "${LOGFILE}"
}

INFO() {
    local msg="${1}"
    local tstamp="$( date -u +"%d-%m-%Y %T %Z" )"
    echo -e "[${tstamp}] [INFO]\t${msg}" >> "${LOGFILE}"
}

ERROR() {
    local msg="${1}"
    local tstamp="$( date -u +"%d-%m-%Y %T %Z" )"
    echo -e "[${tstamp}] [ERROR]\t${msg}" >> "${LOGFILE}"
}

DEBUG() {
    local msg="${1}"
    local tstamp="$( date -u +"%d-%m-%Y %T %Z" )"
    echo -e "[${tstamp}] [DEBUG]\t${msg}" >> ${LOGFILE}
}


# -- Initialize output data
init_output() {
    if [ "${UI}" = "yes" ] ; then
        if [ "${all_passwords}" = "0" ] ; then
            echo -n "" > "${OUTPUT}"
        else
            echo "------------------------------------" >> "${OUTPUT}"
        fi
    fi
}

#
# -- Purpose - echo the backtitle string in form 'Backtitle ... spaces ... [SC_VER]'
#
_backtitle() {
    printf "%s%$(( max_columns - ${#1} - ${#SC_VER} - 2 ))s%s" "${1}" " " "${SC_VER}"
}

#
# -- Purpose - display output using msgbox 
#    $1 -> set msgbox height
#    $2 -> set msgbox width
#    $3 -> set msgbox title
#
display_output() {
    ENTRY
    local h=${1:-10}                 # box height default 10
    local w=${2:-41}                 # box width default 41
    local t=${3:-Output}             # box title 

    if [ "${UI}" = "yes" ] ; then
        dialog "${DIALOG_OPTS[@]}" \
               --cr-wrap \
               --backtitle "$( _backtitle "ChangeSeedboxPass for \"${USERNAME}\"" )" \
               --title "  ${t}  " \
               --msgbox "$(<${OUTPUT})" "${h}" "${w}"
    fi
    RETURN
}


#
# -- Generic function - just get password string and store it in $DATA file
#
get_password() {

    ENTRY

    local ret
    local _component
    local _password _p_len _out _result

    _component="${1}" 

    # -- Get password
    while true ; do
        rm -f "${DATA}" >> "${LOGFILE}" 2>&1
        dialog "${DIALOG_OPTS[@]}" \
               --backtitle "$( _backtitle "ChangeSeedboxPass for \"${USERNAME}\"" )" \
               --title "Password" \
               --insecure \
               --extra-button \
               --extra-label "Generate" \
               --passwordbox "Enter new \"${_component}\" password for \"${USERNAME}\"" 9 45 2> "${DATA}"
        ret=$?
        case "${ret}" in
          "${DIALOG_CANCEL}" | "${DIALOG_ESC}")
              break
              ;;
        esac
        # -- Generate random password if requested
        if [ "${ret}" = "${DIALOG_EXTRA}" ] ; then
            if which apg > /dev/null 2>&1 ; then
                apg -n 1 -m ${MIN_PASSWORD_LENGTH} -x ${MIN_PASSWORD_LENGTH} -M NCL > "${DATA}"
                ret=0
            elif which pwgen > /dev/null 2>&1 ; then
                pwgen -cn ${MIN_PASSWORD_LENGTH} 1 > "${DATA}"
                ret=0
            fi
        fi
        # -- Check password complexity/etc
        _password="$( < "${DATA}" )"
        if [ -n "${_password}" ] && [ "${PASSWORD_CHECK}" = "yes" ] ; then
            _p_len="${#_password}"
            if [ "${_p_len}" -lt "${MIN_PASSWORD_LENGTH}" ] ; then
                _out="${_password}: it is WAY too short - ${_p_len} characters.\nUse at least 8 alphanumeric characters, mixed case"
                ERROR "${_password}: it is WAY too short - ${_p_len} characters."
                ERROR "Use at least 8 alphanumeric characters, mixed case"
                _result="ERROR"
            else
                _out="$( cracklib-check <<< "${_password}" )"
                _result="$( awk '{print $2}' <<< "${_out}" )"
            fi
            if [ "${_result}" != "OK" ] ; then
                dialog \
                    "${DIALOG_OPTS[@]}" \
                    --aspect 14 \
                    --title "\Z1\Zb\Zr !!!  ERROR  !!! \Zn" \
                    --backtitle "$( _backtitle "ChangeSeedboxPass for \"${USERNAME}\": ERROR" )" \
                    --scrollbar \
                    --msgbox "\n\n${_out}\n\n" \
                    0 0
                continue
            fi
        fi
        break
    done

    RETURN
    return ${ret}
}


#
# -- _dialog_infobox ( $text )
#
_dialog_infobox () {
    local _text="${1}"
    if [ "${UI}" = "yes" ] ; then
        dialog "${DIALOG_OPTS[@]}" \
               --cr-wrap \
               --aspect 14 \
               --backtitle "$( _backtitle "ChangeSeedboxPass for \"${USERNAME}\"" )" \
	       --infobox "${_text}" \
            0 0
    fi
    return 0
}


#
# -- _svc_command ( $command, $service )
# -- $command: start/stop/restart/enable/disable
#
_svc_command() {
    local _op="${1,,}"
    local _svc="${2}"
    local _msg
    local _op_descr
    if [ "${_op}" = "stop" ] ; then
        _op_descr="Stopping"
    elif [ "${_op}" = "enable" ] ; then
        _op_descr="Enabling"
    elif [ "${_op}" = "disable" ] ; then
        _op_descr="Disabling"
    else
        _op_descr="${_op^}ing"
    fi
    _msg="${_op_descr} ${_svc} service..."
    _dialog_infobox "\n   ${_msg}   \n\n"
    echo "${_msg}" >> "${OUTPUT}"
    INFO "${_msg}"
    service "${_svc}" "${_op}" >> "${OUTPUT}" 2>&1
}


#
# -- Store password in ${PASSWORDS_STORE} file
#
store_password() {
    ENTRY

    local _password="${1}"
    local ret

    if ! grep -q -e "^${STORE_SERVICE}:" "${PASSWORDS_STORE}" ; then
        echo "${STORE_SERVICE}:${_password}" >> "${PASSWORDS_STORE}"
    else
        sed -i -e "s/^${STORE_SERVICE}:.*$/${STORE_SERVICE}:${_password}/g" "${PASSWORDS_STORE}" \
             >> "${LOGFILE}" 2>&1
    fi

    RETURN
    return ${ret}
}


#
# -- Change ruTorrent password
#
rutorrent_func() {

    ENTRY

    local passwd
    local ret
    local rc
    local _htpasswd_flags
    local _htpasswd_flags_1

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "ruTorrent"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing ruTorrent password for \"${USERNAME}\"..." >> "${OUTPUT}"
          _htpasswd_flags=""
          [ ! -e "/var/www/rutorrent/.htpasswd" ] && _htpasswd_flags="-c"
          htpasswd -b ${_htpasswd_flags} \
                   "/var/www/rutorrent/.htpasswd" \
                   "${USERNAME}" "${passwd}" >> "${LOGFILE}" 2>&1
          rc=$?
          if [ ${rc} -eq 0 ] ; then
              if [ -d "/etc/apache2/passwords-enabled" ] ; then
                  [ ! -e "/etc/apache2/passwords-enabled/rtorrentscgi-${USERNAME}.conf" ] \
                      && _htpasswd_flags_1="-c"
                  htpasswd -b ${_htpasswd_flags_1} \
                     "/etc/apache2/passwords-enabled/rtorrentscgi-${USERNAME}.conf" \
                     "${USERNAME}" "${passwd}" >> "${LOGFILE}" 2>&1 
                  rc=$?
              fi
          fi
          if [ "${rc}" = "0" ] ; then
              echo "ruTorrent password has been changed successfully!" >> "${OUTPUT}"
              INFO "ruTorrent password has been changed successfully!"
              if [ "${all_passwords}" = "0" ] ; then
                  echo -n "New password: " >> "${OUTPUT}"
                  echo "${passwd}" >> "${OUTPUT}"
              fi
              store_password "${passwd}"
          else
              echo "!!! Error changing ruTorrenr password !!!" >> "${OUTPUT}"
              ERROR "!!! Error changing ruTorrenr password !!!"
          fi
          [ "${all_passwords}" = "0" ] \
              && display_output 0 0 "ruTorrent"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (ruTorrent): ${passwd}"
    RETURN
}



#
# -- Change Deluge password
#
deluge_func() {

    ENTRY

    local passwd
    local ret
    local rc
    local svc_d
    local svc_w
    local need_restart="no"

    if    [ ! -f "/etc/systemd/system/deluged@.service" ] \
       || [ ! -f "/etc/systemd/system/deluge-web@.service" ]
    then
        ERROR "!!! Error changing Deluge password  for \"${USERNAME}\" -> Deluge service file(s) not found !!!"
        return
    fi

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "Deluge"
        ret=$?
        passwd="$( < "${DATA}" )"
    fi

    init_output

    need_restart="yes"

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          if service "deluge-web@${USERNAME}" status > /dev/null 2>&1 ; then 
              need_restart="yes"
              _svc_command "stop" "deluge-web@${USERNAME}"
          fi
          echo "Changing Deluge password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing Deluge password for \"${USERNAME}\"..."
          "/home/${USERNAME}/.config/deluge/changedelugepass.py" \
                   "/home/${USERNAME}/.config/deluge/" \
                   "${passwd}" >> "${LOGFILE}" 2>&1
          rc=$?
          if [ "${rc}" = "0" ] ; then
              echo "Deluge password  for \"${USERNAME}\" has been changed successfully!" >> "${OUTPUT}"
              INFO "Deluge password  for \"${USERNAME}\" has been changed successfully!"
              if [ "${all_passwords}" = "0" ] ; then
                  echo -n "New password: " >> "${OUTPUT}"
                  echo "${passwd}" >> "${OUTPUT}"
              fi
              if grep -q -e "^${USERNAME}:" "/home/${USERNAME}/.config/deluge/auth" 2> /dev/null ; then
                  sed -i -e "s/^\(${USERNAME}\):[^:]*:\(.*\)$/\1:${passwd}:\2/" \
                                  "/home/${USERNAME}/.config/deluge/auth"
              else
                  echo "${USERNAME}:${passwd}:10" >> "/home/${USERNAME}/.config/deluge/auth"
              fi
              store_password "${passwd}"
          else
              echo  "!!! Error changing Deluge password  for \"${USERNAME}\" !!!" >> "${OUTPUT}"
              ERROR "!!! Error changing Deluge password  for \"${USERNAME}\" !!!"
          fi

          chown -R ${USERNAME}:${USERNAME} "/home/${USERNAME}/.config/deluge"

          if [ "${need_restart}" = "yes" ] ; then
              _svc_command "restart" "deluge-web@${USERNAME}"
              sleep 2
          fi
          [ "${all_passwords}" = "0" ] \
              && display_output 0 0 "Deluge WebUI"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (Deluge): ${passwd}"
    RETURN
}


#
# -- Change uTorrent password for 'user'
#
utorrent_func() {

    ENTRY

    local passwd
    local ret
    local rc
    local i
    local need_restart="no"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "uTorrent"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          if service "utserver@${USERNAME}" status > /dev/null 2>&1 ; then 
              echo "Changing uTorrent password for \"${USERNAME}\"..." >> "${OUTPUT}"
              INFO "Changing uTorrent password for \"${USERNAME}\"..."
              # -- Enable localhost_auth
              sed -e 's|^localhost_authentication:.*$|localhost_authentication: false|g' \
                  -i "/home/${USERNAME}/utorrent/utserver.conf" >> "${OUTPUT}" 2>&1
              # -- Restart utorrent service
              [ "${all_passwords}" = "0" ] \
                  && echo "Re-starting uTorrent service..." >> "${OUTPUT}"
              INFO "Re-starting uTorrent service..."
              if [ "${UI}" = "yes" ] ; then
                  dialog "${DIALOG_OPTS[@]}" --title "Restarting uTorrent Daemon service" \
                     --infobox "$( service utserver@${USERNAME} restart 2>&1 )" \
                     5 50
              else
                  service "utserver@${USERNAME}" restart >> "${LOGFILE}" 2>&1
              fi
              # -- Change password
              rm -fv "/home/${USERNAME}/utorrent/utwhisper/authreuse" >> "${OUTPUT}" 2>&1
              rc=1
              i=0
              while true ; do
                  i=$(( i + 1 ))
                  if [ ${i} -gt 10 ] ; then
                      echo "!!! Failure !!!" >> "${OUTPUT}"
                      ERROR "!!! Failure !!!"
                      break
                  else
                      echo "Try: ${i} ..." >> "${OUTPUT}"
                      INFO "Try: ${i} ..."
                  fi
                  python "/home/${USERNAME}/utorrent/utwhisper/utwhisper.py" \
                             --setsettings webui.username=${USERNAME} >> "${LOGFILE}" 2>&1
                  rc=$?
                  if [ ${rc} -ne 0 ] ; then
                      echo "Failure!" >> "${OUTPUT}"
                      ERROR "Failure!"
                      continue
                  else
                      echo "uTorrent 'webui.username' set: Success!" >> "${OUTPUT}"
                      INFO "uTorrent 'webui.username' set: Success!"
                  fi
                  python "/home/${USERNAME}/utorrent/utwhisper/utwhisper.py" \
                         --setsettings webui.password="${passwd}" >> "${LOGFILE}" 2>&1
                  rc=$?
                  if [ ${rc} -eq 0 ] ; then
                      echo "uTorrent 'webui.password' set: Success!" >> "${OUTPUT}"
                      INFO "uTorrent 'webui.password' set: Success!"
                      break
                  fi
              done
              if [ ${rc} -eq 0 ] ; then
                  [ "${all_passwords}" = "0" ] \
                      && echo "uTorrent password for \"${USERNAME}\" has been changed successfully!" \
                             >> "${OUTPUT}"
                  INFO "uTorrent password for \"${USERNAME}\" has been changed successfully!"
                  if [ "${all_passwords}" = "0" ] ; then
                       echo -n "New password: " >> "${OUTPUT}"
                       echo "${passwd}" >> "${OUTPUT}"
                  fi
                  store_password "${passwd}"
              else
                  echo "!!! Error changing uTorrent password for \"${USERNAME}\" !!!" >> "${OUTPUT}"
                  ERROR "!!! Error changing uTorrent password for \"${USERNAME}\" !!!"
              fi
              # Disable localhost_auth
              sed -e 's|^localhost_authentication:.*$|localhost_authentication: true|g' \
                  -i "/home/${USERNAME}/utorrent/utserver.conf" >> "${OUTPUT}" 2>&1

              # Restart utorrent service
              [ "${all_passwords}" = "0" ] \
                  && echo "Re-starting uTorrent service..." >> "${OUTPUT}"
              INFO "Re-starting uTorrent service..."
              if [ "${UI}" = "yes" ] ; then
                  dialog \
                     "${DIALOG_OPTS[@]}" \
                     --title "Restarting uTorrent Daemon service" \
                     --infobox "$( service utserver@${USERNAME} restart 2>&1 )" \
                     5 50
              else
                  service "utserver@${USERNAME}" restart >> "${LOGFILE}" 2>&1
              fi
              [ "${all_passwords}" = "0" ] \
                  && display_output 0 0 "uTorrent password"
          fi
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    [ -f "authreuse" ] \
        && rm -vf "authreuse" >> "${LOGFILE}" 2>&1

    INFO "New password for \"${USERNAME}\" (uTorrent): ${passwd}"
    RETURN
}


#
# -- Change L2TP/IPsec password for 'user'
#
l2tp_ipsec_func() {

    ENTRY

    local passwd
    local ret
    local rc

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "L2TP/IPsec"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing L2TP/IPsec password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing L2TP/IPsec password for \"${USERNAME}\"..."
          # -- Set L2TP/IPsec user's password
          echo "s/^${USERNAME}\s*l2tpd\s*.*$/${USERNAME} l2tpd ${passwd} */" \
                 | sed -i -f - "/etc/ppp/chap-secrets" > /dev/null 2>&1
          if [ $? -eq 0 ] ; then
              echo "L2TP/IPsec password for \"${USERNAME}\" has been changed successfully!" >> "${OUTPUT}"
              INFO "L2TP/IPsec password for \"${USERNAME}\" has been changed successfully!"
              if [ "${all_passwords}" = "0" ] ; then
                  echo -n "New password: " >> "${OUTPUT}"
                  echo "${passwd}" >> "${OUTPUT}"
              fi
              store_password "${passwd}"
          else
              echo "!!! Error changing L2TP/IPsec password for \"${USERNAME}\" !!!" >> "${OUTPUT}"
              ERROR "!!! Error changing L2TP/IPsec password for \"${USERNAME}\" !!!"
          fi
          [ "${all_passwords}" = "0" ] \
              && display_output 0 0 "Unix password"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (L2TP/IPsec): ${passwd}"
    RETURN
}


#
# -- Change Apache2 NZBGet WebUI password for 'user'
#
nzbget_func() {

    ENTRY

    local passwd_file
    local pline
    local passwd
    local ret
    local rc

    passwd_file="/etc/apache2/nzbget.users.password"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "NZBGet WebUI access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          pline=`(echo -n "${USERNAME}:NZBGet:" && echo -n "${USERNAME}:NZBGet:${passwd}" | md5sum | awk '{print $1}')`
          grep -e "^${USERNAME}:NZBGet:" "${passwd_file}" >> "${LOGFILE}" 2>&1
          if [ $? -eq 0 ] ; then
              echo "s#^${USERNAME}:NZBGet:.*#${pline}#" \
                  | sed -f - -i "${passwd_file}"
          else
              echo "${pline}" >> "${passwd_file}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "NZBGet Web UI access"
          else
              echo "NZBGet WebUI access password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "NZBGet WebUI access password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (NZBGet): ${passwd}"
    RETURN
}


#
# -- Change Unix password for 'user'
#
user_func() {

    ENTRY

    local passwd
    local ret
    local rc

    passwd="${1}"
    ret=0

    # Disable dictionary check.
    sed -i 's/^#\? *dictcheck *= *1/dictcheck = 0/' /etc/security/pwquality.conf > /dev/null 2>&1

    if [ -z "${passwd}" ] ; then
        get_password "Unix"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing Unix password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing Unix password for \"${USERNAME}\"..."
          # -- Set user's password
          if echo "${USERNAME}:${passwd}" | chpasswd >> "${LOGFILE}" 2>&1 ; then
              # -- Also set passwords for some services
              # -- Cuberite
              if [ -e "${USERHOME}/.config/Cuberite/webadmin.ini" ]; then
                  if command -v "crudini" > /dev/null 2>&1 ; then
                      crudini \
                          --set "${USERHOME}/.config/Cuberite/webadmin.ini" \
                              "User:admin" "Password" "${passwd}" > /dev/null 2>&1
                      sed -i -re 's/\s+=\s+/=/' \
                          "${USERHOME}/.config/Cuberite/webadmin.ini" > /dev/null 2>&1
                      systemctl is-active "cuberite@${USERNAME}" > /dev/null 2>&1 \
                          && systemctl restart "cuberite@${USERNAME}" > /dev/null 2>&1
                  fi
              fi
              # --
              echo "Unix password for \"${USERNAME}\" has been changed successfully!" >> "${OUTPUT}"
              INFO "Unix password for \"${USERNAME}\" has been changed successfully!"
              if [ "${all_passwords}" = "0" ] ; then
                  echo -n "New password: " >> "${OUTPUT}"
                  echo "${passwd}" >> "${OUTPUT}"
              fi
              store_password "${passwd}"
          else
              echo "!!! Error changing Unix password for \"${USERNAME}\" !!!" >> "${OUTPUT}"
              ERROR "!!! Error changing Unix password for \"${USERNAME}\" !!!"
          fi
          [ "${all_passwords}" = "0" ] \
              && display_output 0 0 "Unix password"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (user account): ${passwd}"
    RETURN
}


#
# -- Change Apache2 SABnzbd WebUI password for 'user'
#
sabnzbd_func() {

    ENTRY

    local passwd_file
    local pline
    local passwd
    local ret
    local rc

    passwd_file="/etc/apache2/sabnzbd.users.password"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "SABnzbd WebUI access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          pline=`(echo -n "${USERNAME}:SABnzbd:" && echo -n "${USERNAME}:SABnzbd:${passwd}" | md5sum | awk '{print $1}')`
          grep -e "^${USERNAME}:SABnzbd:" "${passwd_file}" >> "${LOGFILE}" 2>&1
          if [ $? -eq 0 ] ; then
              echo "s#^${USERNAME}:SABnzbd:.*#${pline}#" \
                 | sed -f - -i "${passwd_file}"
          else
              echo "${pline}" >> "${passwd_file}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "SABnzbd Web UI access"
          else
              echo "SABnzbd WebUI access password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "SABnzbd WebUI access password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (SABnzbd): ${passwd}"
    RETURN
}


#
# -- Change Apache2 Transmission WebUI password for 'user'
#
transmission_func() {

    ENTRY

    local passwd_file
    local pline
    local passwd
    local ret
    local rc

    passwd_file="/etc/apache2/transmission.users.password"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "Transmission WebUI access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # make decision
    case ${ret} in
      ${DIALOG_OK})
          pline=`(echo -n "${USERNAME}:Transmission:" && echo -n "${USERNAME}:Transmission:${passwd}" | md5sum | awk '{print $1}')`
          grep -e "^${USERNAME}:Transmission:" "${passwd_file}" >> "${LOGFILE}" 2>&1
          if [ $? -eq 0 ] ; then
              echo "s#^${USERNAME}:Transmission:.*#${pline}#" \
                 | sed -f - -i "${passwd_file}"
          else
              echo "${pline}" >> "${passwd_file}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "Transmission Web UI access"
          else
              echo "Transmission WebUI access password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "Transmission WebUI access password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (Transmission): ${passwd}"
    RETURN
}


#
# -- Change Apache2 UserDir password for 'user'
#
userdir_func() {

    ENTRY

    local passwd_file passwd_basic_file
    local pline
    local passwd
    local ret
    local rc

    passwd_file="/etc/apache2/users.password"
    passwd_basic_file="/etc/apache2/users.basic.password"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "Web access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          pline=`(echo -n "${USERNAME}:apache2:" && echo -n "${USERNAME}:apache2:${passwd}" | md5sum | awk '{print $1}')`
          if grep -q -e "^${USERNAME}:apache2:" "${passwd_file}" >> "${LOGFILE}" 2>&1
          then
              echo "s#^${USERNAME}:apache2:.*#${pline}#" \
                  | sed -f - -i "${passwd_file}"
          else
              echo "${pline}" >> "${passwd_file}"
          fi
          if [ -s "${passwd_basic_file}" ] ; then
              htpasswd -b "${passwd_basic_file}" "${USERNAME}" "${passwd}" >> "${OUTPUT}" 2>&1
          else
              htpasswd -c -b "${passwd_basic_file}" "${USERNAME}" "${passwd}" >> "${OUTPUT}" 2>&1
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "User Web access"
          else
              echo "Web Access password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "Web Access password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (UserDir): ${passwd}"
    RETURN
}


#
# -- Change Apache2 Plex Configurator password for 'user'
#
plex_func() {

    ENTRY

    local passwd_file
    local pline
    local passwd
    local ret
    local rc

    passwd_file="/etc/apache2/plex.users.password"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "Plex Configurator"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # make decision
    case ${ret} in
      ${DIALOG_OK})
          pline=`(echo -n "${USERNAME}:apache2:" && echo -n "${USERNAME}:apache2:${passwd}" | md5sum | awk '{print $1}')`
          if [ -e "${passwd_file}" ] ; then
              if grep -e "^${USERNAME}:apache2:" "${passwd_file}" >> "${LOGFILE}" 2>&1 ; then 
                  echo "s#^${USERNAME}:apache2:.*#${pline}#" \
                      | sed -f - -i "${passwd_file}"
              else
                  echo "${pline}" >> "${passwd_file}"
              fi
          else
              echo "${pline}" >> "${passwd_file}"
          fi

          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "Plex Configurator access"
          else
              echo "Plex Configurator password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "Plex Configurator password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (Plex configurator): ${passwd}"
    RETURN
}



#
# -- Change VNC password for 'user'
#
vnc_func() {

    ENTRY

    local passwd
    local ret
    local rc

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "VNC"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing VNC password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing VNC password for \"${USERNAME}\"..."
          su ${USERNAME} -c "echo -n -e \"${passwd}\n${passwd}\n\" | vncpasswd > /dev/null 2>&1"
          if service "vncserver-${USERNAME}@${USERNAME}" status > /dev/null 2>&1 ; then 
              _svc_command "restart" "vncserver-${USERNAME}@${USERNAME}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "VNC"
          else
              echo "VNC password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "VNC password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (VNC): ${passwd}"
    RETURN
}


#
# -- Change BTSync password
#
btsync_func() {

    ENTRY

    local passwd
    local passwd_hash
    local ret
    local rc

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "BTSync"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing BTSync password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing BTSync password for \"${USERNAME}\"..."
          passwd_hash=$( openssl passwd -crypt "${passwd}" 2>/dev/null )
          echo "s|\"password_hash\"\s*:\s*\".*\",|\"password_hash\" : \"${passwd_hash}\",|" \
              | sed -i -f - /home/${USERNAME}/.config/btsync/config.json >> "${LOGFILE}" 2>&1
          if service "btsync@${USERNAME}" status > /dev/null 2>&1 ; then 
              _svc_command "restart" "btsync@${USERNAME}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "BTSync"
          else
              echo "BTSync password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "BTSync password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (BTSync): ${passwd}"
    RETURN
}


#
# -- Change ResilioSync password
#
resiliosync_func() {

    ENTRY

    local passwd
    local passwd_hash
    local ret
    local rc

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "ResilioSync"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing ResilioSync password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing ResilioSync password for \"${USERNAME}\"..."
          passwd_hash="$( openssl passwd -crypt "${passwd}" 2>/dev/null )"
          if [ -z "${passwd_hash}" ] ; then
              passwd_hash="$( mkpasswd -m des  "${passwd}" 2>/dev/null )"
          fi
          echo "s|\"password_hash\"\s*:\s*\".*\",|\"password_hash\" : \"${passwd_hash}\",|" \
              | sed -i -f - /home/${USERNAME}/.config/resilio-sync/config.json >> "${LOGFILE}" 2>&1
          if service "resilio-sync@${USERNAME}" status > /dev/null 2>&1 ; then 
              _svc_command "restart" "resilio-sync@${USERNAME}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "ResilioSync"
          else
              echo "ResilioSync password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "ResilioSync password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (ResilioSync): ${passwd}"
    RETURN
}


#
# -- Change SickChill password
#
sickchill_func() {

    ENTRY

    local passwd
    local passwd_hash
    local ret
    local rc
    local need_restart="no"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "SickChill"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing SickChill password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing SickChill password for \"${USERNAME}\"..."
          # --
          if service "sickchill@${USERNAME}" status > /dev/null 2>&1 ; then 
              need_restart="yes"
              _svc_command "stop" "sickchill@${USERNAME}"
          fi
          sed -i "s/web_username.*/web_username = \"${USERNAME}\"/g" \
              "/home/${USERNAME}/.config/sickchill/config.ini" \
                  >> "${OUTPUT}" 2>&1
          sed -i "s/web_password.*/web_password = \"${passwd}\"/g" \
              "/home/${USERNAME}/.config/sickchill/config.ini" \
                  >> "${OUTPUT}" 2>&1
          # --
          if [ "${need_restart}" = "yes" ] ; then
              _svc_command "restart" "sickchill@${USERNAME}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "SickChill"
          else
              echo "SickChill password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "SickChill password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (SickChill): ${passwd}"
    RETURN
}


#
# -- Change Syncthing password
#
syncthing_func() {

    ENTRY

    local passwd
    local ret
    local need_restart="no"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "Syncthing"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          echo "Changing Syncthing password for \"${USERNAME}\"..." >> "${OUTPUT}"
          INFO "Changing Syncthing password for \"${USERNAME}\"..."
          # --
          if service "syncthing@${USERNAME}" status > /dev/null 2>&1 ; then 
              need_restart="yes"
              _svc_command "stop" "syncthing@${USERNAME}"
          fi
          # --
          echo "------------------------------------" >> "${OUTPUT}"
          su "${USERNAME}" user \
             -c "syncthing generate --gui-user='${USERNAME}' --gui-password='${passwd}'" >> "${OUTPUT}" 2>&1
          echo "------------------------------------" >> "${OUTPUT}"
          #
          if [ "${need_restart}" = "yes" ] ; then
              _svc_command "restart" "syncthing@${USERNAME}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "Syncthing"
          else
              echo "Syncthing password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "Syncthing password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (Syncthing): ${passwd}"
    RETURN
}


#
# -- Change Apache2 qBittorrent WebUI password for 'user'
#
qbittorrent_func() {

    ENTRY

    local passwd_file
    local pline
    local passwd
    local ret
    local rc

    passwd_file="/etc/apache2/qbittorrent.users.password"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "qBittorrent WebUI access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          pline=`(echo -n "${USERNAME}:qBittorrent:" && echo -n "${USERNAME}:qBittorrent:${passwd}" | md5sum | awk '{print $1}')`
          if grep -q -e "^${USERNAME}:qBittorrent:" "${passwd_file}" >> "${LOGFILE}" 2>&1 ; then
              echo "s#^${USERNAME}:qBittorrent:.*#${pline}#" \
                  | sed -f - -i "${passwd_file}"
          else
              echo "${pline}" >> "${passwd_file}"
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "qBittorrent Web UI access"
          else
              echo "qBittorrent WebUI access password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "qBittorrent WebUI access password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (qBittorrent): ${passwd}"
    RETURN
}



#
# -- Change 3proxy password for 'user'
#
_3proxy_func() {

    ENTRY

    local passwd_file
    local pline
    local passwd
    local ret
    local rc
    local need_restart="no"

    passwd_file="/usr/local/etc/3proxy/passwd"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "3proxy access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    init_output

    # -- Make decision
    case ${ret} in
      ${DIALOG_OK})
          pline="$( echo -n "${USERNAME}:CL:${passwd}" )"
          if grep -q -e "^${USERNAME}:CL:" "${passwd_file}" >> "${LOGFILE}" 2>&1 ; then
              echo "s#^${USERNAME}:CL:.*#${pline}#" \
                  | sed -f - -i "${passwd_file}"
          else
              echo "${pline}" >> "${passwd_file}"
          fi
          if service "3proxy" status > /dev/null 2>&1 ; then 
              echo "Reloading 3proxy service..." >> "${OUTPUT}"
              INFO "Reloading 3proxy service..."
              killall -s SIGUSR1 3proxy 2>&1 >> "${OUTPUT}" 2>&1
          fi
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "3proxy access"
          else
              echo "3proxy access password for \"${USERNAME}\" changed succesfully!" >> "${OUTPUT}"
              INFO "3proxy access password for \"${USERNAME}\" changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for \"${USERNAME}\" (3proxy): ${passwd}"
    RETURN
}



#
# -- Change SeedboxCP WebUI password
#
seedboxcp_func() {

    ENTRY

    local config_file
    local pline
    local passwd
    local hashed_password
    local ret
    local rc

    config_file="/var/www/html/seedboxcp/config.php"

    passwd="${1}"
    ret=0
    if [ -z "${passwd}" ] ; then
        get_password "SeedboxCP WebUI access"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    hashed_password="$( php -r "echo password_hash('${passwd}', PASSWORD_BCRYPT);" )"

    init_output

    # -- Make decision
    case ${ret} in
        ${DIALOG_OK})
          sed -i -e "s|^\$password.*$|\$password = '${hashed_password}';|g" "${config_file}"
          if [ "${all_passwords}" = "0" ] ; then
              echo -n "New password: ${passwd}" >> "${OUTPUT}"
              display_output 0 0 "SeedboxCP WebUI access"
          else
              echo "SeedboxCP WebUI access password for user changed succesfully!" >> "${OUTPUT}"
              INFO "SeedboxCP WebUI access password for user changed succesfully!"
          fi
          store_password "${passwd}"
          ;;
      ${DIALOG_CANCEL}|${DIALOG_ESC})
          INFO "Cancel/Esc pressed."
          RETURN ; return
          ;;
    esac

    INFO "New password for user (SeedboxCP WebUI): ${passwd}"
    RETURN
}



#
# -- Perform cleanup and exit
#
exit_func () {

    ENTRY

    # -- If temp files found, delete them
    [ -f "${OUTPUT}" ] && rm -f "${OUTPUT}" >> "${LOGFILE}" 2>&1
    [ -f "${INPUT}"  ] && rm -f "${INPUT}"  >> "${LOGFILE}" 2>&1
    [ -f "${DATA}"   ] && rm -f "${DATA}"   >> "${LOGFILE}" 2>&1

    [ "${UI}" = "yes" ] && clear

    [ ! -z "${PASSWORD}" ] && echo "${PASSWORD}"

    INFO "==========================================================="
    INFO "== ${SC_NAME} ${SC_VER}: Finished. RC: ${retcode}"
    INFO "==========================================================="
    INFO ""

    RETURN

    rm -f "/var/lock/changeseedboxpass.lock" >> "${LOGFILE}" 2>&1
    exit ${retcode}
}


#
# -- Change password for all defined modules
#
all_func () {

    ENTRY

    local i
    local n
    local item
    local passwd

    all_passwords=1
    echo -n "" > "${OUTPUT}"

    # -- Number of entries in main menu
    n=${#ar[@]}

    passwd="${1}"
    ret="${DIALOG_OK}"
    if [ -z "${passwd}" ] ; then
        get_password "All"
        ret=$?
        passwd="$( cat "${DATA}" )"
    fi

    if [ "${ret}" = "${DIALOG_OK}" ] && [ -n "${passwd}" ] ; then
        i=2
        while [ ${i} -lt ${n} ] ; do
            item="$( tr '[:upper:]' '[:lower:]' <<< "${ar[${i}]}" )"
            if declare -f ${item}_func > /dev/null ; then
                if [ "${item}" != "exit" ] ; then
                    STORE_SERVICE="${item}"
                    "${item}_func" "${passwd}"
                fi
                i="$(( i + 2 ))"
            fi
        done

        echo "------------------------------------" >> "${OUTPUT}"
        echo -n "New password for \"${USERNAME}\": ${passwd}" >> "${OUTPUT}"
        display_output \
            0 0 \
            "All user's passwords change results"
        INFO "New password for \"${USERNAME}\" (all services): ${passwd}"
    fi
    RETURN
}


INFO ""
INFO "==========================================================="
INFO "== ${SC_NAME} ${SC_VER}: Starting"
INFO "==========================================================="

#
# -- Set infinite loop
#
while true ; do

    # -- Return code for get_password function
    ret=1

    # -- All passwords flag
    all_passwords=0

    # -- Menu array
    ar=()

    # -- Mandatory menu elements
    ar+=("All" "Change all passwords at once")
    ar+=("User" "Unix user password")

    # -- Let's define optional menu elements
    if [ -f "/var/www/html/seedboxcp/config.php" ] ; then
        ar+=("SeedboxCP" "SeedboxCP WebUI access password")
    fi
    if [ -d "/var/www/rutorrent" ] ; then
        ar+=("ruTorrent" "ruTorrent WebUI password")
    fi
    if [ -d "/home/${USERNAME}/.config/deluge" ] ; then
        if service "deluge-web@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("Deluge" "Deluge WebUI password")
        fi
    fi
    if [ -d "/home/${USERNAME}/utorrent" -a -f "/home/${USERNAME}/utorrent/utwhisper/utwhisper.py" ] ; then
        if service "utserver@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("uTorrent" "uTorrent WebUI password")
        fi
    fi
    if [ -e "/etc/ppp/chap-secrets" ] ; then
        if grep -e "^${USERNAME}\s*l2tpd\s*.*$" "/etc/ppp/chap-secrets" > /dev/null 2>&1 ; then
            ar+=("L2TP_IPsec" "L2TP/IPsec password")
        fi
    fi
    if [ -d "/home/${USERNAME}/.config/nzbget" ] ; then
        if service "nzbget@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("NZBGet" "NZBGet WebUI password")
        fi
    fi
    if [ -d "/home/${USERNAME}/.config/btsync" ] ; then
        if service "btsync@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("BTSync" "BTSync password")
        fi
    fi
    if [ -d "/home/${USERNAME}/.config/qBittorrent" ] ; then
        if service "qbittorrent@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("qBittorrent" "qBittorrent WebUI password")
        fi
    fi
    if [ -d "/home/${USERNAME}/.config/resilio-sync" ] ; then
        if service "resilio-sync@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("ResilioSync" "ResilioSync password")
        fi
    fi
    if [ -d "/opt/sabnzbd" ] ; then
        if [ -e "/etc/apache2/sabnzbd.users.password" ] ; then
            ar+=("SABnzbd" "SABnzbd WebUI password")
        fi
    fi
    if [ -d "/home/${USERNAME}/.config/sickchill" ] ; then
        if service "sickchill@${USERNAME}" status > /dev/null 2>&1 ; then 
            ar+=("SickChill" "SickChill WebUI password")
        fi
    fi
    if    command -v "syncthing" > /dev/null 2>&1 \
       && [ -e "${USERHOME}/.config/syncthing/config.xml" ]
    then
        ar+=("Syncthing" "Syncthing password")
    fi
    if [ -d "/home/${USERNAME}/.config/transmission-daemon" ] ; then
        ar+=("Transmission" "Transmission WebUI password")
    fi
    if [ -e "/etc/apache2" ] ; then
        ar+=("UserDir" "User Web access password")
    fi
    if [ "${USERNAME}" = "user" ] ; then
        if [ -L "/etc/apache2/sites-enabled/plex.conf" ] ; then
            ar+=("Plex" "Plex Configurator password")
        fi
    fi
    if [ -f "/home/${USERNAME}/.vnc/passwd" ] ; then
        if service "vncserver-${USERNAME}" status > /dev/null 2>&1 ; then 
            if which vncpasswd > /dev/null 2>&1 ; then
                ar+=("VNC" "VNC password")
            fi
        fi
    fi
    if [ -f "/usr/local/etc/3proxy/passwd" ] ; then
        if service "3proxy" status > /dev/null 2>&1 ; then 
            ar+=("_3proxy" "_3proxy access password")
        fi
    fi

    # -- Final menu elements
    ar+=("Exit" "Exit to the shell")

    # -- Count additional menu lines
    num="${#ar[@]}"
    num="$(( num / 2))"

    if [ "${UI}" = "yes" ] ; then
        # -- Display main menu
        dialog "${DIALOG_OPTS[@]}" \
               --cancel-label "Exit" \
               --backtitle "$( _backtitle "ChangeSeedboxPass for '${USERNAME}'" )" \
               --title "[ M A I N - M E N U ]" \
               --menu "You can use the UP/DOWN arrow keys, the first \n\
letter of the choice as a hot key, or the \n\
number keys 1-9 to choose an option.\n\
Choose the TASK" $((num+12)) 0 ${num} \
            "${ar[@]}" 2>"${INPUT}"
        ret=$?
        [ "${ret}" = "${DIALOG_CANCEL}" ] || [ "${ret}" = "${DIALOG_ESC}" ] && break
        menuitem="$( < "${INPUT}" )"
    else
        menuitem="${SERVICE}"
    fi
    menuitem="${menuitem,,}"

    # -- Call module function
    if declare -f ${menuitem}_func > /dev/null ; then
        STORE_SERVICE="${menuitem}"
        "${menuitem}_func" "${PASSWORD}"
        [ "${UI}" != "yes" ] && break
    else
        retcode=1
        break
    fi

done

exit_func
