#!/bin/bash

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

## Usage:
## dummy-dependency [--remove|--purge] [-y|--yes] 'package-name'

#set -x
set -e
set -o errtrace
set -o pipefail
set -o nounset

true "$0: INFO: START"

show_usage() {
   printf '%s\n' "Usage: $0 [--remove|--purge] [--cached|--cache-only] [-y|--yes] 'package-name'" >&2
   exit 1
}

cleanup() {
   trap '' EXIT
   if [ -n "${TMPDIR_NEW:-}" ] && [ -d "${TMPDIR_NEW}" ]; then
      safe-rm -r -f -- "${TMPDIR_NEW}"
   fi
}

root_check() {
   if [ "$(id -u)" -ne 0 ]; then
      printf '%s\n' "$0: ERROR: This script must be run as root." >&2
      exit 1
   fi
}

trap cleanup EXIT

dummy_dependency() {
   local equivs_file deb_file_original deb_file_copy equivs_content equivs_build_log

   root_check

   create_dummy_dependency() {
      equivs_content="Package: dummy-${package_to_replace}
Version: 99:99
Maintainer: dummy-dependency script <dummy-dependency@dummy-dependency.invalid>
Conflicts: ${package_to_replace}
Provides: ${package_to_replace}
Architecture: all
Description: dummy-package for '${package_to_replace}'
 A metapackage that replaces '${package_to_replace}'."

      printf '%s\n' "${equivs_content}" | sponge -- "${equivs_file}"

      if ! equivs_build_log="$(equivs-build -- "${equivs_file}" 2>&1)" ; then
         printf '%s\n' "$0: ERROR: 'equivs-build -- \"${equivs_file}\"' command failed!" >&2
         printf '%s\n' "$0: Logs:" >&2
         printf '%s\n' "${equivs_build_log}" >&2
         exit 1
      fi

      ## Sanity test.
      test -r "${deb_file_original}"

      mkdir --parents -- /var/lib/dummy-dependency
      ## Avoid APT warning:
      ## N: Download is performed unsandboxed as root as file '/tmp/user/0/tmp.8O7ET4e1Bx/dummy-user-sysmaint-split_99_all.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
      cp --verbose -- "${deb_file_original}" "${deb_file_copy}"

      printf '%s\n' "$0: INFO: Dummy package created."

      if [ "${cache_only_option}" = "true" ]; then
         printf '%s\n' "$0: INFO: Stopping because using '--cache-only'."
         exit 0
      fi
   }

   ## Validate package name, see
   ## https://www.debian.org/doc/debian-policy/ch-controlfields.html#source
   if ! grep --quiet '^[a-z0-9]\+[a-z0-9+-.]\+$' -- <<< "${package_to_replace}" ; then
      printf '%s\n' "$0: ERROR: Package name is invalid, check for typos" >&2
      exit 1
   fi

   ## Not actually needed, mktemp can function perfectly well without TMPDIR
   # if [ -z "${TMPDIR:-}" ]; then
   #    printf '%s\n' "$0: ERROR: TMPDIR is unset." >&2
   #    exit 1
   # fi

   ## Ensure ${TMPDIR} is set
   if [ ! -v TMPDIR ]; then
      TMPDIR=''
   fi

   ## ${TMPDIR} is an already existing environment variable.
   TMPDIR_OLD="${TMPDIR}"

   TMPDIR_NEW="$(mktemp --directory)"

   ## equivs-build uses ${TMPDIR} for builds
   TMPDIR="${TMPDIR_NEW}"
   export TMPDIR

   equivs_file="${TMPDIR_NEW}/${package_to_replace}.equivs"
   ## equivs-build uses ${TMPDIR} for builds
   deb_file_original="${TMPDIR_NEW}/dummy-${package_to_replace}_99_all.deb"
   deb_file_copy="/var/lib/dummy-dependency/dummy-${package_to_replace}_99_all.deb"

   if [ "${cached_option}" = "true" ]; then
      printf '%s\n' "$0: INFO: '--cached' option detected: yes"
      if test -e "${deb_file_copy}" ; then
         printf '%s\n' "$0: INFO: Using already existing cached dummy replacement package for '${package_to_replace}'..."
      else
         printf '%s\n' "$0: INFO: Cached dummy replacement package for '${package_to_replace}' does not exist yet, creating..."
         create_dummy_dependency
      fi
   else
      printf '%s\n' "$0: INFO: Creating dummy replacement package for '${package_to_replace}'..."
      create_dummy_dependency
   fi

   ## Reset to previously set TMPDIR.
   TMPDIR="${TMPDIR_OLD}"

   ## Sanity test.
   test -r "${deb_file_copy}"

   #lintian --pedantic --info --display-info "${deb_file_copy}"

   if [ "${remove_option}" = '--purge' ]; then
      remove_action="purge"
   else
      remove_action="remove"
   fi

   printf '%s\n' "$0: INFO: '${remove_action}'ing package '${package_to_replace}' and installing 'dummy-${package_to_replace}'..."
   printf '%s\n' "$0: EXECUTING: apt-get-noninteractive ${yes_option} ${remove_action} -- ${package_to_replace} ${deb_file_copy}"
   if apt-get-noninteractive ${yes_option} "${remove_action}" -- "${package_to_replace}" "${deb_file_copy}" ; then
      printf '%s\n' "$0: INFO: Dummy package installed."
   else
      printf '%s\n' "$0: ERROR: 'apt-get-noninteractive' command failed!" >&2
      exit 1
   fi

   printf '%s\n' "$0: INFO: Done."
   exit 0
}

## Declare global variables
TMPDIR_OLD=''
TMPDIR_NEW=''
package_to_replace=""
yes_option=""
remove_option="--remove"
cached_option=""
cache_only_option=""

## Main execution
while [ "$#" -gt 0 ]; do
   case "$1" in
      -y|--yes)
         yes_option="--yes"
         shift
         ;;
      --remove|--purge)
         remove_option="$1"
         shift
         ;;
      --cached)
         cached_option="true"
         shift
         ;;
      --cache-only)
         cache_only_option="true"
         shift
         ;;
      *)
         package_to_replace="$1"
         shift
         ;;
   esac
done

if [ "$cached_option" = "true" ]; then
   if [ "$cache_only_option" = "true" ]; then
      printf '%s\n' "$0: ERROR: '--cached' option must not be combined with '--cache-only' option!" >&2
      exit 1
   fi
fi

[ -z "${package_to_replace}" ] && show_usage

dummy_dependency
