#!/bin/bash

## Copyright (c) 2025 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -o errexit
set -o nounset
set -o errtrace
set -o pipefail

# shellcheck source=../libexec/helper-scripts/get_colors.sh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/get_colors.sh
# shellcheck source=../libexec/helper-scripts/accountctl.sh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/accountctl.sh

do_rebuild_greetd_config='false'

get_all_config_section_contents() {
  local file_name section in_section line
  file_name="$1"
  section="$2"
  in_section='false'

  while read -r -- line; do
    if [[ "${line}" =~ ^[[:space:]]*\["${section}"\][[:space:]]*$ ]]; then
      in_section='true'
      continue
    elif [[ "${line}" =~ ^[[:space:]]*\[.*\][[:space:]]*$ ]]; then
      in_section='false'
      continue
    fi
    if [ "${in_section}" = 'true' ]; then
      printf '%s\n' "${line}"
    fi
  done < "${file_name}"

  true "INFO: Extracted contents of all '$section' sections from file '$file_name'."
}

remove_from_config_section() {
  local file_name section remove_entity filter_stage line lines output \
    line_was_removed remove_entity_key remove_entity_val
  file_name="$1"
  section="$2"
  remove_entity="$3"
  filter_stage='1'
  line_was_removed=''
  remove_entity_key="${remove_entity%%=*}"
  remove_entity_val="${remove_entity#*=}"

  mapfile -t lines < "$file_name"

  output=()
  for line in "${lines[@]}"; do
    if [ "${filter_stage}" = '1' ]; then
      output+=( "${line}" )
      if [[ "${line}" =~ ^[[:space:]]*\["${section}"\][[:space:]]*$ ]]; then
        filter_stage='2'
      fi
    elif [ "${filter_stage}" = '2' ]; then
      ## 'remove_entity' is treated as a key/value pair separated by an =
      ## sign, both the key and value are treated literally. The key, equals
      ## sign, and value may be surrounded by spaces.
      if [[ "${line}" \
        =~ ^([[:space:]]*)"${remove_entity_key}"[[:space:]]*=[[:space:]]*"${remove_entity_val}"[[:space:]]*(#.*)?$ ]]; then
        line_was_removed="true"
        if [ -n "${BASH_REMATCH[2]}" ]; then
          ## BASH_REMATCH[1] = leading whitespace
          ## BASH_REMATCH[2] = comment
          output+=( "${BASH_REMATCH[1]}${BASH_REMATCH[2]}" )
        fi
        continue
      fi
      output+=( "${line}" )
      if [[ "${line}" =~ ^[[:space:]]*\[.*\][[:space:]]*$ ]] \
        && ! [[ "${line}" =~ ^[[:space:]]*\["${section}"\][[:space:]]*$ ]]; then
        filter_stage='1'
      fi
    else
      printf '%s\n' "ERROR: Unreachable code hit in remove_from_config_section!" >&2
      return 1
    fi
  done

  printf '%s\n' "${output[@]}" | sponge -- "$file_name"

  if [ "$line_was_removed" = "true" ]; then
    printf '%s\n' "INFO: Removed lines matching '$remove_entity' from section '$section' of file '$file_name'." >&2
    return 0
  fi
  return 1
}

neutralize_greetd_initial_session_section() {
  local config_section_lines output line

  config_section_lines=( "$@" )
  output=()

  for line in "${config_section_lines[@]}"; do
    if [[ "${line}" =~ ^([[:space:]]*)command[[:space:]]*=[[:space:]]*\"[^\"]+\"[[:space:]]*(#.*)?$ ]]; then
      if [ -n "${BASH_REMATCH[2]}" ]; then
        ## BASH_REMATCH[1] = leading whitespace
        ## BASH_REMATCH[2] = comment
        output+=( "${BASH_REMATCH[1]}${BASH_REMATCH[2]}" )
      fi
    elif [[ "${line}" =~ ^[[:space:]]*# ]]; then
      output+=( "${line}" )
    else
      ## greetd will crash if it encounters an 'initial_session' section with
      ## no command keys, so we must comment out anything in the section that
      ## isn't commented out.
      output+=( "#${line}" )
    fi
  done

  printf '%s\n' "${output[@]}"
}

remove_user_from_greetd_autologin() {
  local file_name target_user lines output initial_session_buffer \
    do_remove_section in_initial_session_section line_was_removed \
    filter_out_command_keys

  ## greetd has both "user" and "command" configuration keys in its
  ## initial_session config sections (which are used to configure autologin).
  ## We can't just go through and remove all command keys from all
  ## initial_session sections, since that would break autologin for any other
  ## user accounts with autologin enabled. We also can't delete config
  ## sections that happen to include
  ## "user=the_user_were_disabling_autologin_for" in them, since it's entirely
  ## possible someone will have multiple user accounts configured in the same
  ## section. The algorithm we use is therefore as follows:
  ##
  ## * If all user keys in an initial_session section match the user account
  ##   we are disabling autologin for, we delete the entire section.
  ## * If there are user keys present in the section that do not match the
  ##   user account we are disabling autologin for, we delete only the
  ##   matching user keys and leave the section otherwise unmodified.
  ##   Importantly, we do not attempt to delete any command lines, since
  ##   greetd's configuration file has no way of specifying which command is
  ##   bound to which user.

  file_name="$1"
  target_user="$2"

  mapfile -t lines < "$file_name"

  output=()
  initial_session_buffer=()
  do_remove_section='true'
  in_initial_session_section='false'
  line_was_removed='false'
  filter_out_command_keys='false'

  for line in "${lines[@]}"; do
    if [ "${in_initial_session_section}" = 'false' ]; then
      if [[ "${line}" =~ ^[[:space:]]*\[initial_session\][[:space:]]*$ ]]; then
        initial_session_buffer+=( "${line}" )
        in_initial_session_section='true'
        do_remove_section='true'
        filter_out_command_keys='false'
        continue
      fi
      output+=( "${line}" )
    else
      if [[ "${line}" =~ ^[[:space:]]*\[.*\][[:space:]]*$ ]]; then
        if [ "${do_remove_section}" = 'false' ]; then
          if [ "${filter_out_command_keys}" = 'true' ]; then
            mapfile -t initial_session_buffer < <(
              neutralize_greetd_initial_session_section \
                "${initial_session_buffer[@]}"
            )
          fi
          output+=( "${initial_session_buffer[@]}" )
        fi
        initial_session_buffer=()
        if [[ "${line}" =~ ^[[:space:]]*\[initial_session\][[:space:]]*$ ]]; then
          ## Prime state for next loop iteration
          do_remove_section='true'
          filter_out_command_keys='false'
          initial_session_buffer+=( "${line}" )
        else
          ## Switch back to the out-of-section handling code, it will prime
          ## the state later if needed
          in_initial_session_section='false'

          ## Append the header we just read
          output+=( "${line}" )
        fi
        continue
      fi

      if [[ "${line}" =~ ^([[:space:]]*)user[[:space:]]*=[[:space:]]*\""${target_user}"\"[[:space:]]*(#.*)?$ ]]; then
        line_was_removed='true'
        if [ -n "${BASH_REMATCH[2]}" ]; then
          ## BASH_REMATCH[1] = leading whitespace
          ## BASH_REMATCH[2] = comment
          initial_session_buffer+=( "${BASH_REMATCH[1]}${BASH_REMATCH[2]}" );
          if [ "${do_remove_section}" = 'true' ]; then
            ## We only set filter_out_command_keys if do_remove_config_section
            ## isn't already toggled to false, so that we don't
            ## unintentionally enable command key stripping in situations
            ## where there are user keys that don't match the target user.
            filter_out_command_keys='true'
            do_remove_section='false'
          fi
        fi
      elif [[ "${line}" =~ ^[[:space:]]*user[[:space:]]*= ]]; then
        do_remove_section='false'
        filter_out_command_keys='false'
        initial_session_buffer+=( "${line}" )
      elif [[ "${line}" =~ ^[[:space:]]*# ]]; then
        if [ "${do_remove_section}" = 'true' ]; then
          filter_out_command_keys='true'
          do_remove_section='false'
        fi
        initial_session_buffer+=( "${line}" )
      else
        initial_session_buffer+=( "${line}" )
      fi
    fi
  done

  if (( ${#initial_session_buffer[@]} != 0 )) \
    && [ "${do_remove_section}" = 'false' ]; then
    if [ "${filter_out_command_keys}" = 'true' ]; then
      mapfile -t initial_session_buffer < <(
        neutralize_greetd_initial_session_section "${initial_session_buffer[@]}"
      )
    fi
    output+=( "${initial_session_buffer[@]}" )
  fi

  if [ "${line_was_removed}" = 'true' ]; then
    printf '%s\n' "${output[@]}" | sponge -- "${file_name}"
    printf '%s\n' "INFO: Removed greetd autologin config for user '${target_user}' from file '${file_name}'." >&2
    return 0
  fi
  return 1
}

check_file_for_meaningful_config() {
  local file_name line

  file_name="$1"

  while read -r line; do
    if ! [[ "${line}" =~ ^[[:space:]]*$ ]] \
      && ! [[ "${line}" =~ ^[[:space:]]*\[.*\][[:space:]]*$ ]]; then
      return 0
    fi
  done < "${file_name}"

  return 1
}

enable_autologin() {
  local user
  user="$1"

  mkdir --parents -- /etc/lightdm/lightdm.conf.d
  printf '%s\n' "[Seat:*]
autologin-user=${user}" | sponge -- '/etc/lightdm/lightdm.conf.d/40_autologin.conf'
  printf '%s\n' "INFO: Wrote file '/etc/lightdm/lightdm.conf.d/40_autologin.conf' to enable autologin for account '$user'." >&2
  printf '%s\n' "$delimiter" >&2
  cat -- '/etc/lightdm/lightdm.conf.d/40_autologin.conf' >&2
  printf '%s\n' "$delimiter" >&2

  mkdir --parents -- /etc/sddm.conf.d
  printf '%s\n' "[Autologin]
User=${user}" | sponge -- '/etc/sddm.conf.d/z-autologin.conf'
  printf '%s\n' "INFO: Wrote file '/etc/sddm.conf.d/z-autologin.conf' to enable autologin for account '$user'." >&2
  printf '%s\n' "$delimiter" >&2
  cat -- '/etc/sddm.conf.d/z-autologin.conf' >&2
  printf '%s\n' "$delimiter" >&2

  mkdir --parents -- /etc/greetd/config.toml.d
  printf '%s\n' "[initial_session]
command = \"/usr/libexec/desktop-config-dist/start-lxqt-session\"
user = \"${user}\"" | sponge -- '/etc/greetd/config.toml.d/40_autologin.conf'
  printf '%s\n' "INFO: Wrote file '/etc/greetd/config.toml.d/40_autologin.conf' to enable autologin for account '$user'." >&2
  printf '%s\n' "$delimiter" >&2
  cat -- '/etc/greetd/config.toml.d/40_autologin.conf' >&2
  printf '%s\n' "$delimiter" >&2
  do_rebuild_greetd_config='true'
}

disable_autologin() {
  local user lightdm_config_file_list file_name
  user="$1"

  readarray -t lightdm_config_file_list < <(find /etc/lightdm -type f)
  for file_name in "${lightdm_config_file_list[@]}"; do
    remove_from_config_section "${file_name}" 'Seat:*' "autologin-user=${user}" || true
    true "INFO: Processed autologin configuration removal for account '$user' from file '$file_name'."
    if ! check_file_for_meaningful_config "${file_name}"; then
      printf '%s\n' "INFO: File '$file_name' contains no meaningful configuration data, removing." >&2
      safe-rm --verbose -- "${file_name}"
    fi
  done

  for file_name in /etc/sddm.conf /etc/sddm.conf.d/*; do
    if ! [ -f "${file_name}" ]; then
      continue
    fi
    remove_from_config_section "${file_name}" 'Autologin' "User=${user}" || true
    true "INFO: Processed autologin configuration removal for account '$user' from file '$file_name'."
    if ! check_file_for_meaningful_config "${file_name}"; then
      printf '%s\n' "INFO: File '$file_name' contains no meaningful configuration data, removing." >&2
      safe-rm --verbose -- "${file_name}"
    fi
  done

  for file_name in /etc/greetd/config.toml.d/*; do
    if ! [ -f "${file_name}" ]; then
      continue
    fi
    remove_user_from_greetd_autologin "${file_name}" "${user}" || true
    true "INFO: Processed autologin configuration removal for account '$user' from file '$file_name'."
    if ! check_file_for_meaningful_config "${file_name}"; then
      printf '%s\n' "INFO: File '$file_name' contains no meaningful configuration data, removing." >&2
      safe-rm --verbose -- "${file_name}"
    fi
  done
  do_rebuild_greetd_config='true'
}

enable_sysmaint_autologin() {
  mkdir --parents -- /etc/user-sysmaint-split.conf.d
  printf '%s\n' 'sysmaint-autologin=yes' | sponge -a -- /etc/user-sysmaint-split.conf.d/40_autologin.conf
  printf '%s\n' "INFO: Wrote autologin configuration for account 'sysmaint' to file '/etc/user-sysmaint-split.conf.d/40_autologin.conf'." >&2
  printf '%s\n' "$delimiter" >&2
  cat -- /etc/user-sysmaint-split.conf.d/40_autologin.conf >&2
  printf '%s\n' "$delimiter" >&2
}

disable_sysmaint_autologin() {
  local file_name file_contents
  for file_name in /etc/user-sysmaint-split.conf.d/*; do
    if ! [ -f "${file_name}" ]; then
      continue
    fi
    ## user-sysmaint-split does not currently support trailing comments or
    ## extra spaces in these config files, so we don't need to take them into
    ## account.
    sed -i '/^sysmaint-autologin=/d' -- "${file_name}"
    printf '%s\n' "INFO: Removed autologin configuration for account 'sysmaint' from file '${file_name}'." >&2
    file_contents="$(cat -- "${file_name}")"
    if [ -z "${file_contents}" ]; then
      printf '%s\n' "INFO: File '$file_name' contains no meaningful configuration data, removing." >&2
      safe-rm --verbose -- "${file_name}"
    fi
  done
}

validate_username() {
  local user found_user user_entry

  user="${1:-}"
  if [ -z "${user}" ]; then
    printf '%s\n' "ERROR: No username provided. Please specify a username." >&2
    return 1
  fi

  if ! id "${user}" &>/dev/null ; then
    printf '%s\n' "ERROR: Account '$user' does not exist. Please check the username and try again." >&2
    return 1
  fi

  found_user='n'
  for user_entry in "${user_list[@]}"; do
    if [ "${user}" = "${user_entry}" ]; then
      found_user='y'
      break
    fi
  done

  if [ "${found_user}" = 'n' ]; then
    printf '%s\n' "ERROR: Account '$user' is not a normal user account. Please check the username and try again." >&2
    return 1
  fi
}

filter_out_sysmaint_maybe() {
  ## This function expects to have data piped to in on standard input.
  if [ "${special_sysmaint_handling}" = 'yes' ]; then
    grep --invert-match --extended-regexp -- \
      '(^|[[:space:]]|"|=)[[:space:]]*sysmaint[[:space:]]*($|[[:space:]]|"|#)'
  else
    cat
  fi
}

check_autologin() {
  local user
  user="${1:-}"
  ## Don't run check_root, this might need to be used as a normal user by
  ## systemcheck

  ## NOTE: Exit code is important here because pwchange uses
  ##       'autologinchange -c "$user"' and relies on the exit code.
  # shellcheck disable=SC2076
  if [[ " ${autologin_users[*]} " =~ " ${user} " ]]; then
    return 0
  else
    return 1
  fi
}

cli_enable_autologin() {
  local user

  check_root
  create_dm_config_dirs

  user="${1:-}"
  validate_username "${user}"

  if [ "${user}" = 'sysmaint' ] && [ "${special_sysmaint_handling}" = 'yes' ]; then
    ## Account 'sysmaint' requires special handling.
    if [ "${sysmaint_autologin}" = 'yes' ]; then
      printf '%s\n' "INFO: Autologin already enabled for account 'sysmaint', exiting." >&2
      return 0
    fi
    enable_sysmaint_autologin
    return 0
  fi

  # shellcheck disable=SC2076
  if [[ " ${autologin_users[*]} " =~ " ${user} " ]]; then
    printf '%s\n' "INFO: Autologin already enabled for account '$user', exiting." >&2
    return 0
  fi

  enable_autologin "${user}"
}

cli_disable_autologin() {
  local user

  check_root
  create_dm_config_dirs

  user="${1:-}"
  validate_username "${user}"

  if [ "${user}" = 'sysmaint' ] && [ "${special_sysmaint_handling}" = 'yes' ]; then
    ## Account 'sysmaint' requires special handling.
    if [ "${sysmaint_autologin}" = 'no' ]; then
      printf '%s\n' "INFO: Autologin already disabled for account 'sysmaint', exiting." >&2
      return 0
    fi
    disable_sysmaint_autologin
    warn_on_unusable_password 'sysmaint'
    return 0
  fi

  # shellcheck disable=SC2076
  if ! [[ " ${autologin_users[*]} " =~ " ${user} " ]]; then
    printf '%s\n' "INFO: Autologin already disabled for account '$user', exiting." >&2
    return 0
  fi

  disable_autologin "${user}"
  warn_on_unusable_password "${user}"
}

warn_on_unusable_password() {
  local user
  user="$1"
  if is_pass_locked "${user}" || is_pass_disabled "${user}"; then
    printf '%s\n' "${red}WARNING:${nocolor} Account '${user}' has a locked or disabled password." >&2
    printf '%s\n' "You will NOT be able to log in manually to this account." >&2
    printf '%s\n' "You can use the 'pwchange' utility to set a password." >&2
    printf '%s\n' "See https://www.kicksecure.com/wiki/User#Locking_a_Password for more information." >&2
  elif [ -z "$(get_clean_pass "${user}")" ]; then
    printf '%s\n' "${red}WARNING:${nocolor} Account '${user}' has no password set." >&2
    printf '%s\n' "Anyone can log into this account knowing only the username." >&2
    printf '%s\n' "You can use the 'pwchange' utility to set a password." >&2
    printf '%s\n' "See https://www.kicksecure.com/wiki/Login for more information." >&2
  fi
}

autologinchange() {
  local user user_entry autologin_user enable_yn disable_yn

  check_root
  create_dm_config_dirs

  printf '%s\n' "[${green}INFO${nocolor}]: This tool enables or disables GUI autologin only." >&2
  printf '%s\n' "Users present on the system:" >&2
  for user_entry in "${user_list[@]}"; do
    printf '%s\n' "   ${user_entry}" >&2
  done

  read -r -p "Enter the username you would like to toggle autologin for: " -- user

  validate_username "${user}"

  # shellcheck disable=SC2076
  if [[ " ${autologin_users[*]} " =~ " ${user} " ]]; then
    printf '%s\n' "Account '$user' is currently configured to automatically log in." >&2
    read -r -p "Would you like to disable autologin? [Y/N] " -- disable_yn

    if [ "${disable_yn,,}" = 'y' ]; then
      disable_autologin "${user}"
      printf '%s\n' "SUCCESS: Autologin for account '$user' disabled." >&2
      warn_on_unusable_password "${user}"
    else
      printf '%s\n' "CANCELLED disabling autologin for account '$user'." >&2
    fi
    return 0
  elif [ "${user}" = 'sysmaint' ] && [ "${special_sysmaint_handling}" = 'yes' ]; then
    if [ "${sysmaint_autologin}" = 'yes' ]; then
      printf '%s\n' "Account 'sysmaint' is currently configured to automatically log in." >&2
      read -r -p "Would you like to disable autologin for sysmaint session? [Y/N] " -- disable_yn

      if [ "${disable_yn,,}" = 'y' ]; then
        disable_sysmaint_autologin
        printf '%s\n' "SUCCESS: Autologin for account 'sysmaint' disabled." >&2
        warn_on_unusable_password 'sysmaint'
      else
        printf '%s\n' "CANCELLED disabling autologin for account 'sysmaint'." >&2
      fi
      return 0
    else
      printf '%s\n' "Account 'sysmaint' is currently NOT configured to automatically log in." >&2
      read -r -p "Would you like to enable autologin for sysmaint session? [Y/N] " -- enable_yn

      if [ "${enable_yn,,}" = 'y' ]; then
        ## Disable sysmaint autologin first, then re-enable it, to make
        ## sure other configuration lying around doesn't override the
        ## user's choice.
        disable_sysmaint_autologin
        enable_sysmaint_autologin
        printf '%s\n' "SUCCESS: Autologin for account 'sysmaint' enabled." >&2
      else
        printf '%s\n' "CANCELLED enabling autologin for account 'sysmaint'." >&2
      fi
      return 0
    fi
  else
    printf '%s\n' "Account '$user' is currently NOT configured to automatically log in." >&2
    read -r -p "Are you sure you want to enable autologin for account '$user'? [Y/N] " -- enable_yn

    if [ "${enable_yn,,}" = 'y' ]; then
      if [ "${#autologin_users[@]}" != '0' ]; then
        for autologin_user in "${autologin_users[@]}"; do
          disable_autologin "${autologin_user}"
        done
      fi
      enable_autologin "${user}"
      printf '%s\n' "SUCCESS: Autologin for account '$user' enabled." >&2
    else
      printf '%s\n' "CANCELLED enabling autologin for account '$user'." >&2
    fi
    return 0
  fi
}

check_root() {
  if [ "$(id -u)" != "0" ]; then
    printf '%s\n' "ERROR: This must be run as root (sudo)!" >&2
    return 1
  fi
}

create_dm_config_dirs() {
  mkdir --parents -- /etc/lightdm
  mkdir --parents -- /etc/sddm.conf.d
  mkdir --parents -- /etc/greetd/config.toml.d
}

if [ -f '/usr/share/qubes/marker-vm' ]; then
  printf '%s\n' "INFO: GUI autologin is not applicable to Qubes OS." >&2
  exit 0
fi

delimiter="####################"
autologin_users_lightdm=()
autologin_users_sddm=()
autologin_users=()

special_sysmaint_handling='no'
sysmaint_autologin='no'
if [ -x /usr/libexec/user-sysmaint-split/sysmaint-boot ]; then
  special_sysmaint_handling='yes'
  if [ "$(/usr/libexec/user-sysmaint-split/sysmaint-boot query-sysmaint-autologin 2>/dev/null)" = 'yes' ]; then
    sysmaint_autologin='yes'
  fi
fi

autologinchange_mode=''
while true; do
  case "${1:-}" in
    '-c')
      shift
      autologinchange_mode='check_autologin'
      ;;
    '-e')
      shift
      autologinchange_mode='cli_enable_autologin'
      ;;
    '-d')
      shift
      autologinchange_mode='cli_disable_autologin'
      ;;
    '-r')
      ## -r = raw, don't use special handling on sysmaint account even if
      ## user-sysmaint-split is installed
      shift
      special_sysmaint_handling='no'
      ;;
    '--')
      shift
      break
      ;;
    *)
      break
      ;;
  esac
done
if [ -z "${autologinchange_mode}" ]; then
  autologinchange_mode='autologinchange'
fi

## Ensure that lightdm doesn't have a multi-seat configuration, we can't
## safely manage those
if [ -d /etc/lightdm ]; then
  if grep --quiet --recursive --ignore-case -- '^[[:space:]]*\[Seat:[^*]' /etc/lightdm; then
    printf '%s\n' "ERROR: Multi-seat lightdm configuration detected, cannot proceed!" >&2
    exit 1
  fi
fi

autologin_users_lightdm=()
if [ -d /etc/lightdm ]; then
  readarray -t autologin_users_lightdm < <(
    readarray -t lightdm_file_list < <(find /etc/lightdm -type f)
    for file_name in "${lightdm_file_list[@]}"; do
      get_all_config_section_contents "${file_name}" 'Seat:*' \
        | grep --extended-regexp -- '^[[:space:]]*autologin-user[[:space:]]*=[[:space:]]*[^ ]+[[:space:]]*(#.*)?$' \
        | filter_out_sysmaint_maybe \
        | sed -nE 's/^.*=[[:space:]]*([^ #]+).*$/\1/p' || true
    done
  ) || true
fi
true "INFO: Collected list of users with lightdm autologin enabled."

readarray -t autologin_users_sddm < <(
  for file_name in /etc/sddm.conf /etc/sddm.conf.d/*; do
    if ! [ -f "${file_name}" ]; then
      continue
    fi
    get_all_config_section_contents "${file_name}" 'Autologin' \
      | grep --extended-regexp -- '^[[:space:]]*User[[:space:]]*=[[:space:]]*[^ ]+[[:space:]]*(#.*)?$' \
      | filter_out_sysmaint_maybe \
      | sed -nE 's/^.*=[[:space:]]*([^ #]+).*$/\1/p' || true
  done
) || true
true "INFO: Collected list of users with sddm autologin enabled."

readarray -t autologin_users_greetd < <(
  for file_name in /etc/greetd/config.toml.d/*; do
    if ! [ -f "${file_name}" ]; then
      continue
    fi
    get_all_config_section_contents "${file_name}" 'initial_session' \
      | grep --extended-regexp -- '^[[:space:]]*user[[:space:]]*=[[:space:]]*"[^"]+"[[:space:]]*(#.*)?$' \
      | filter_out_sysmaint_maybe \
      | sed -nE 's/^.*"([^"]*)".*$/\1/p' || true
  done
) || true

readarray -t autologin_users < <(
  printf '%s\n' \
    "${autologin_users_lightdm[@]}" \
    "${autologin_users_sddm[@]}" \
    "${autologin_users_greetd[@]}" \
    | sed '/^$/d' \
    | sort -u
)

if ! user_list_str="$(/usr/libexec/helper-scripts/get-user-list)"; then
  printf '%s\n' "ERROR: Failed to get user list!" >&2
  exit 1
fi
readarray -t user_list <<< "$user_list_str"

"${autologinchange_mode}" "$@"
if [ "${do_rebuild_greetd_config}" = 'true' ]; then
  printf '%s\n' "INFO: Rebuilding greetd config." >&2
  build-config-file /etc/greetd/config.toml.d /etc/greetd/config.toml
fi
