#!/bin/bash

## Copyright (C) 2012 - 2023 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -x
set -e

true "INFO: Currently running script: ${BASH_SOURCE} $@"

MYDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "${MYDIR}"

source ~/derivative-maker/help-steps/pre
source ~/derivative-maker/help-steps/colors
source ~/derivative-maker/help-steps/variables

cd "${dist_binary_build_folder}"

sanity_tests() {
   command -v mktorrent >/dev/null
   command -v transmission-show >/dev/null
   command -v signify-openbsd >/dev/null
   test -f "${signify_public_key}"
   test -f "${signify_private_key}"
   test -f "${binary_image_installer_dist_source}"

   "${dist_source_help_steps_folder}/signing-key-test" "$@"
}

installer_dist() {
   if [ ! "${dist_build_installer_dist}" = "true" ]; then
      return 0
   fi

   command -v git >/dev/null
   command -v str_replace >/dev/null

   cp "${binary_image_installer_dist_source}" "${binary_image_installer_dist_file}"

   installer_dist_source_folder="$(dirname "${binary_image_installer_dist_source}")"
   pushd "${installer_dist_source_folder}"
   git_tag_current="$(git describe --always --abbrev=1000000000)"
   ## example git_tag_current:
   ## 11.7-1
   ## example git_tag_current:
   ## 11.7-1-23-g5e70e4d81e494e66b296f89136b1ac332e8a738d
   popd

   search="commit-hash-replace-me"
   replace="${git_tag_current}"
   file_name="${binary_image_installer_dist_file}"
   str_replace "${search}" "${replace}" "${file_name}"
}

windows_installer() {
   if [ ! "${dist_build_windows_installer}" = "true" ]; then
      true "$0: INFO: Skip ${FUNCNAME}, because dist_build_windows_installer is not set to true."
      return 0
   fi

   if ! test -r "${binary_image_ova_file}" ; then
      error "$0: binary_image_ova_file ${binary_image_ova_file} does not exist!"
   fi

   test -d "$binary_build_folder_dist/virtualbox-windows-installer-binary"
   pushd "$binary_build_folder_dist/virtualbox-windows-installer-binary" >/dev/null

   local counter
   counter=0
   for file_name in ./VirtualBox-*.exe ; do
      counter=$((counter + 1))
   done

   if [ "${counter}" -gt "1" ]; then
      true "$0: ERROR: Multiple file matching VirtualBox-*.exe!"
      exit 1
   fi

   test -r "${file_name}"
   FILE_VBOX_INST_EXE=$(realpath "${file_name}")
   test -r "${FILE_VBOX_INST_EXE}"

   "${dist_developer_meta_files_folder}/usr/bin/dm-virtualbox-installer-exe-verify-windows"

   FILE_VCREDIST_INST_EXE=$(realpath "vc_redist.x64.exe")
   test -r "$FILE_VCREDIST_INST_EXE"

   "${dist_developer_meta_files_folder}/usr/bin/dm-virtualbox-installer-vc_redist-verify-windows"

   popd >/dev/null

   ## environment variables read by Whonix-Installer build.sh
   TARGET_SYSTEM="WINDOWS"
   FILE_LICENSE="${source_code_folder_dist}/packages/whonix/whonix-base-files/usr/share/whonix/WHONIX_BINARY_LICENSE_AGREEMENT"
   FILE_WHONIX_OVA="${binary_image_ova_file}"
   FILE_WHONIX_STARTER_MSI="${source_code_folder_dist}/windows/Whonix-Starter/WhonixStarterInstaller.msi"
   #FILE_VBOX_INST_EXE="${FILE_VBOX_INST_EXE}"
   FILE_INSTALLER_BINARY_FINAL="${binary_image_windows_installer_file}"
   export TARGET_SYSTEM FILE_LICENSE FILE_VCREDIST_INST_EXE FILE_WHONIX_OVA FILE_WHONIX_STARTER_MSI FILE_VBOX_INST_EXE FILE_INSTALLER_BINARY_FINAL

   VERSION="${dist_build_version}"
   VERSION_FULL=$(basename "${binary_image_ova_file}")
   MANUFACTURE="ENCRYPTED SUPPORT LP"
   DESCRIPTION="Whonix-Starter"
   export VERSION VERSION_FULL MANUFACTURE DESCRIPTION

   pushd "${source_code_folder_dist}/windows/Whonix-Starter" >/dev/null
   ## Make sure everything is rebuilt and no previously auto generated files are accidentally re-used.
   git clean --force -d -X
   ## Creates WhonixStarterInstaller.msi
   ./build_on_linux_for_win64
   ## Not possible at this time as this would delete WhonixStarterInstaller.msi
   #git clean --force -d -X
   popd >/dev/null

   rm --force "${binary_image_windows_installer_file}"

   pushd "${source_code_folder_dist}/windows/Whonix-Installer" >/dev/null
   git clean --force -d -X
   ## Requires already existing WhonixStarterInstaller.msi
   ## Creates ${binary_image_windows_installer_file}
   "${source_code_folder_dist}/windows/Whonix-Installer/build.sh"
   git clean --force -d -X
   popd >/dev/null

   pushd "${source_code_folder_dist}/windows/Whonix-Starter" >/dev/null
   ## Delete WhonixStarterInstaller.msi and other auto generated files.
   git clean --force -d -X
   popd >/dev/null

   test -r "${binary_image_windows_installer_file}"
}

libvirt_compress() {
   local continue_maybe
   continue_maybe=no
   if [ "${dist_build_raw}" = "true" ]; then
      continue_maybe=yes
   fi
   if [ "${dist_build_qcow2}" = "true" ]; then
      continue_maybe=yes
   fi
   if [ "${dist_build_source_archive}" = "true" ]; then
      continue_maybe=yes
   fi
   if [ "${continue_maybe}" = "no" ]; then
      return 0
   fi

   legal_files_copy

   if [ "${dist_build_qcow2}" = "true" ]; then
      rm --force "$(basename "${libvirt_target_qcow2_xz_archive_file}")"
      true "INFO: Checking if all files to be added to libvirt_target_qcow2_xz_archive_file ${libvirt_target_qcow2_xz_archive_file} exist..."
   fi
   if [ "${dist_build_raw}" = "true" ]; then
      rm --force "$(basename "${libvirt_target_raw_xz_archive_file}")"
      true "INFO: Checking if all files to be added to libvirt_target_raw_xz_archive_file ${libvirt_target_raw_xz_archive_file} exist..."
   fi
   if [ "${dist_build_source_archive}" = "true" ]; then
      rm --force "$(basename "${source_archive_xz_file}")"
      true "INFO: Checking if all files to be added to source_archive_xz_file ${source_archive_xz_file} exist..."
   fi

   true "dist_build_type_short: $dist_build_type_short"
   if [ "${dist_build_type_short}" = "kicksecure" ]; then
      test -f "${dist_binary_build_folder}/KICKSECURE_BINARY_LICENSE_AGREEMENT"
      test -f "${dist_binary_build_folder}/KICKSECURE_DISCLAIMER"
   elif [ "${dist_build_type_short}" = "whonix" ]; then
      test -f "${dist_binary_build_folder}/WHONIX_BINARY_LICENSE_AGREEMENT"
      test -f "${dist_binary_build_folder}/WHONIX_DISCLAIMER"
   fi
   if [ "${dist_build_source_archive}" = "true" ]; then
      true "dist_build_source_archive..."
   fi

   true "vm_multiple: $vm_multiple"
   if [ "${dist_build_source_archive}" = "true" ]; then
      true "dist_build_source_archive..."
   elif [ "${vm_multiple}" = "false" ]; then
      true "vm_multiple: no"
      true "SHORT_VMNAME: $SHORT_VMNAME"
      test -f "${dist_binary_build_folder}/${SHORT_VMNAME}.xml"
      if [ "${dist_build_raw}" = "true" ]; then
         test -f "${dist_binary_build_folder}/${VMNAME}-${dist_build_version}.${target_architecture_pretty_name}.raw"
      fi
      if [ "${dist_build_qcow2}" = "true" ]; then
         test -f "${dist_binary_build_folder}/${VMNAME}-${dist_build_version}.${target_architecture_pretty_name}.qcow2"
      fi
   else
      true "vm_multiple: yes"
      test -f "${dist_binary_build_folder}/Whonix-Gateway.xml"
      test -f "${dist_binary_build_folder}/Whonix-Workstation.xml"

      true "libvirt_target_network_file_external: $libvirt_target_network_file_external"
      test -f "${libvirt_target_network_file_external}"
      true "libvirt_target_network_file_internal: $libvirt_target_network_file_internal"
      test -f "${libvirt_target_network_file_internal}"

      if [ "${dist_build_raw}" = "true" ]; then
         test -f "${dist_binary_build_folder}/Whonix-Gateway-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.raw"
         test -f "${dist_binary_build_folder}/Whonix-Workstation-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.raw"
         true "INFO: Ok, all files to be added to ${libvirt_target_raw_xz_archive_file} exist."
      fi
      if [ "${dist_build_qcow2}" = "true" ]; then
         test -f "${dist_binary_build_folder}/Whonix-Gateway-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.qcow2"
         test -f "${dist_binary_build_folder}/Whonix-Workstation-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.qcow2"
         true "INFO: Ok, all files to be added to ${libvirt_target_qcow2_xz_archive_file} exist."
      fi
   fi

   ## Not using `gzip`, because it cannot handle sparse files:
   ## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=535987
   #pv "${dist_binary_build_folder}/Whonix-Gateway-${dist_build_version}.qcow2" | gzip -n - > "${dist_binary_build_folder}/Whonix-Gateway-${dist_build_version}.libvirt.tar.gz"
   #pv "${dist_binary_build_folder}/Whonix-Workstation-${dist_build_version}.qcow2" | gzip -n - > "${dist_binary_build_folder}/Whonix-Workstation-${dist_build_version}.libvirt.tar.gz"

   ## Using `tar` with `--xz` and `--mtime="2014-05-06 00:00:00"`:
   ## - will result in a deterministic archive. We do not have deterministic
   ##   images yet in the first place (but at least verifiable ones), but
   ##   hopefully some day. Does not hurt to already use tar options that do
   ##   not add unnecessary non-deterministic contents.
   ## Not using tar --verbose:
   ## - slows down tar too much.

   local file_list_compress_full_path

   if [ "${dist_build_source_archive}" = "true" ]; then
      file_list_compress_full_path+="${source_code_folder_dist} "
   elif [ "${dist_build_type_short}" = "kicksecure" ]; then
      file_list_compress_full_path+="${dist_binary_build_folder}/KICKSECURE_BINARY_LICENSE_AGREEMENT "
      file_list_compress_full_path+="${dist_binary_build_folder}/KICKSECURE_DISCLAIMER "
   elif [ "${dist_build_type_short}" = "whonix" ]; then
      file_list_compress_full_path+="${dist_binary_build_folder}/WHONIX_BINARY_LICENSE_AGREEMENT "
      file_list_compress_full_path+="${dist_binary_build_folder}/WHONIX_DISCLAIMER "
   fi

   true "vm_multiple: $vm_multiple"
   if [ "${dist_build_source_archive}" = "true" ]; then
      true "dist_build_source_archive..."
   elif [ "${vm_multiple}" = "false" ]; then
      true "vm_multiple: false"
      file_list_compress_full_path+="${dist_binary_build_folder}/${SHORT_VMNAME}.xml "

      if [ "${dist_build_raw}" = "true" ]; then
         file_list_compress_full_path+="${dist_binary_build_folder}/${VMNAME}-${dist_build_version}.${target_architecture_pretty_name}.raw "
      fi
      if [ "${dist_build_qcow2}" = "true" ]; then
         file_list_compress_full_path+="${dist_binary_build_folder}/${VMNAME}-${dist_build_version}.${target_architecture_pretty_name}.qcow2 "
      fi
   else
      true "vm_multiple: true"
      file_list_compress_full_path+="${dist_binary_build_folder}/Whonix-Gateway.xml "
      file_list_compress_full_path+="${dist_binary_build_folder}/Whonix-Workstation.xml "
      file_list_compress_full_path+="${libvirt_target_network_file_external} "
      file_list_compress_full_path+="${libvirt_target_network_file_internal} "

      true "dist_build_raw for raw image: $dist_build_raw"
      if [ "${dist_build_raw}" = "true" ]; then
         file_list_compress_full_path+="${dist_binary_build_folder}/Whonix-Gateway-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.raw "
         file_list_compress_full_path+="${dist_binary_build_folder}/Whonix-Workstation-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.raw "
      fi
      true "dist_build_qcow2 for qcow image: $dist_build_qcow2"
      if [ "${dist_build_qcow2}" = "true" ]; then
         file_list_compress_full_path+="${dist_binary_build_folder}/Whonix-Gateway-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.qcow2 "
         file_list_compress_full_path+="${dist_binary_build_folder}/Whonix-Workstation-${dist_build_desktop}-${dist_build_version}.${target_architecture_pretty_name}.qcow2 "
      fi
   fi

   ## XXX: --target raw and --target qcow2 can currently not be combined but that seems unlikely.
   ## XXX: --target source can currently not be combined.
   true "dist_build_source_archive: $dist_build_source_archive"
   if [ "${dist_build_source_archive}" = "true" ]; then
      xz_archive="${source_archive_xz_file}"
   fi
   true "dist_build_raw: $dist_build_raw"
   if [ "${dist_build_raw}" = "true" ]; then
      xz_archive="${libvirt_target_raw_xz_archive_file}"
   fi
   true "dist_build_qcow2: $dist_build_qcow2"
   if [ "${dist_build_qcow2}" = "true" ]; then
      xz_archive="${libvirt_target_qcow2_xz_archive_file}"
   fi

   true "file_list_compress_full_path: ${file_list_compress_full_path}"

   local test_operator
   if [ "${dist_build_source_archive}" = "true" ]; then
      test_operator="-d"
      $SUDO_TO_ROOT rm --force --recursive "${dist_binary_build_folder}/derivative-maker"
      cp --archive --no-dereference --preserve=all "${source_code_folder_dist}" "${dist_binary_build_folder}"
   else
      test_operator="-f"
   fi

   local file_name_item_full_path
   for file_name_item_full_path in ${file_list_compress_full_path} ; do
      test "${test_operator}" "${file_name_item_full_path}"
      filelist_base_name+=" $(basename "${file_name_item_full_path}")"
   done

   local file_name_item_base_name
   for file_name_item_base_name in ${filelist_base_name} ; do
      test "${test_operator}" "${file_name_item_base_name}"
   done

   ## TODO: add progress meter (using `pv`?)
   tar \
      --create \
      --owner=0 --group=0 --numeric-owner \
      --mode=go=rX,u+rw,a-s \
      --sort=name \
      --sparse \
      --mtime='2015-10-21 00:00Z' \
      --xz \
      --directory="${dist_binary_build_folder}" \
      --file "$(basename "${xz_archive}")" \
      ${filelist_base_name}

   strip-nondeterminism "${xz_archive}"

   sync

   ## sanity test
   if [ ! -r "${xz_archive}" ]; then
      error "xz_archive ${xz_archive} not readable!"
   fi

   if [ "${dist_build_source_archive}" = "true" ]; then
      ## Not deleting source code.
      return 0
   fi

   for file_name_item_full_path in ${file_list_compress_full_path} ; do
      ## Safe disk space.
      ## Delete raw and ova images in ${dist_binary_build_folder} after xz archive has been created.
      safe-rm -f "${file_name_item_full_path}"
   done
}

virtualbox_export() {
   if [ ! "${dist_build_virtualbox}" = "true" ]; then
      return 0
   fi

   if [ "$vm_names_to_be_exported" = "" ]; then
      error "vm_names_to_be_exported is unset!"
   fi

   legal_files_copy

   local producturl vendorurl vendor eulafile_user description
   if [ "${dist_build_type_short}" = "kicksecure" ]; then
      producturl="https://www.${project_clearnet}"
      vendor="Kicksecure"
      eulafile_user="${dist_binary_build_folder}/KICKSECURE_BINARY_LICENSE_AGREEMENT"
   else
      producturl="https://www.${project_clearnet}/wiki/Other_Operating_Systems"
      vendor="Whonix"
      eulafile_user="${dist_binary_build_folder}/WHONIX_BINARY_LICENSE_AGREEMENT"
   fi

   vendorurl="https://www.${project_clearnet}"
   description="\
Build Version [A]: ${dist_build_version}

Stay tuned! [B]

Please donate! [C]

[A] https://www.${project_clearnet}/wiki/Build_Version
[B] https://www.${project_clearnet}/wiki/Stay_Tuned
[C] https://www.${project_clearnet}/wiki/Donate"

   $SUDO_TO_ROOT rm --force "${binary_image_ova_file}"
   $SUDO_TO_ROOT rm --force "${HOMEVAR_VBOX_TEMP}/temp.ova"

   local eulafile_vbox_temp binary_image_text_vbox_temp
   eulafile_vbox_temp="${HOMEVAR_VBOX_TEMP}/temp-eulafile.txt"
   binary_image_text_vbox_temp="${HOMEVAR_VBOX_TEMP}/temp-binary-image-text.txt"

   $SUDO_TO_ROOT cp "${eulafile_user}" "${HOMEVAR_VBOX_TEMP}/temp-eulafile.txt"
   $SUDO_TO_ROOT chown "dm-vbox-temp:dm-vbox-temp" "${eulafile_vbox_temp}"

   $SUDO_TO_ROOT cp "${binary_image_text}" "${binary_image_text_vbox_temp}"
   $SUDO_TO_ROOT chown "dm-vbox-temp:dm-vbox-temp" "${binary_image_text_vbox_temp}"

   ## https://forums.whonix.org/t/allow-us-to-download-the-vm-files-in-a-compressed-format-like-zip-7z-gzip-etc/14210/6
   TAR_OPTIONS="\
      ${TAR_OPTIONS}
      --owner=0 --group=0 --numeric-owner \
      --mode=go=rX,u+rw,a-s \
      --sort=name \
      --sparse \
      --mtime='2015-10-21 00:00Z' \
      --xz \
      "
   export TAR_OPTIONS
   XZ_OPT="${XZ_OPT} -9"
   export XZ_OPT

   ## --vsys needs to precede --eulafile.
   if [ "${vm_multiple}" = "false" ]; then
      $SUDO_TO_VBOX_TEMP \
         VBoxManage \
            export "${VMNAME}" \
            --vsys "0" \
            --eulafile "${eulafile_vbox_temp}" \
            --description "${description}" \
            --manifest \
            --product "${VMNAME}" \
            --producturl "${producturl}" \
            --vendor "${vendor}" \
            --vendorurl "${vendorurl}" \
            --version "${dist_build_version}" \
            --output "${HOMEVAR_VBOX_TEMP}/temp.ova"
   else
      $SUDO_TO_VBOX_TEMP \
         VBoxManage \
            export ${vm_names_to_be_exported} \
            --output "${HOMEVAR_VBOX_TEMP}/temp.ova" \
            --vsys '0' \
               --eulafile "${eulafile_vbox_temp}" \
               --description "${description}" \
               --manifest \
               --product "Whonix-Gateway" \
               --producturl "https://www.${project_clearnet}/wiki/Whonix-Gateway" \
               --vendor "Whonix" \
               --vendorurl "https://www.${project_clearnet}" \
               --version "${dist_build_version}" \
            --vsys '1' \
               --eulafile "${binary_image_text_vbox_temp}" \
               --description "${description}" \
               --manifest \
               --product "Whonix-Workstation" \
               --producturl "https://www.${project_clearnet}/wiki/Whonix-Workstation" \
               --vendor "Whonix" \
               --vendorurl "https://www.${project_clearnet}" \
               --version "${dist_build_version}"
   fi

   ## Sanity test.
   $SUDO_TO_VBOX_TEMP test -r "${HOMEVAR_VBOX_TEMP}/temp.ova"
   ## Move from dm-vbox-temp user home folder to normal user home folder.
   $SUDO_TO_ROOT mv --verbose "${HOMEVAR_VBOX_TEMP}/temp.ova" "${binary_image_ova_file}"
   ## Fix permissions because file previously needed to be moved from one user to another using root rights.
   $SUDO_TO_ROOT chown "$user_name:$user_name" "${binary_image_ova_file}"

   ## Only important for redistribution.
   ## VirtualBox creates ${binary_image_ova_file} with u+r only, which is problematic
   ## with respect to rsync.
   chmod ugo+r "${binary_image_ova_file}"

   sync

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

   ## Sanity test.
   ##
   ## A different --vmname is required, because ${VMNAME} does already exist
   ## in the list of imported VirtualBox machines.
   ##
   ## Not using $SUDO_TO_VBOX_TEMP because binary_image_ova_file is stored in
   ## normal user home folder. Not in dm-vbox-temp user home folder.
   if [ "${vm_multiple}" = "false" ]; then
      VBoxManage \
         import "${binary_image_ova_file}" \
         --vsys "0" \
         --eula show \
         --vmname "${VMNAME}-${dist_build_version}"

      VBoxManage \
         import "${binary_image_ova_file}" \
         --vsys "0" \
         --eula accept \
         --vmname "${VMNAME}-${dist_build_version}" \
         --dry-run
   else
      VBoxManage \
         import "${binary_image_ova_file}" \
         --vsys "0" \
            --eula show \
            --vmname "Whonix-Gateway-${dist_build_version}" \
         --vsys "1" \
            --eula show \
            --vmname "Whonix-Workstation-${dist_build_version}" \

      VBoxManage \
         import "${binary_image_ova_file}" \
         --vsys "0" \
            --eula accept \
            --vmname "Whonix-Gateway-${dist_build_version}" \
            --dry-run \
         --vsys "1" \
            --eula accept \
            --vmname "Whonix-Workstation-${dist_build_version}" \
            --dry-run
   fi

   local vm_name_to_be_deleted
   for vm_name_to_be_deleted in ${vm_names_to_be_exported} ; do
      ## Safe disk space.
      ## Delete temporary VM in temporary VM user build folder to save disk space
      ## during the build process.
      $SUDO_TO_VBOX_TEMP VBoxManage unregistervm "$vm_name_to_be_deleted" --delete || true
      $SUDO_TO_ROOT safe-rm -r -f "$HOMEVAR_VBOX_TEMP/VirtualBox VMs/$vm_name_to_be_deleted"
   done
}

sign_cmd_gpg() {
   ## GPG signatures do not authenticate filenames by default, therefore add
   ## the name of the file as a OpenPGP notation so at least users that look
   ## at OpenPGP notations have a chance to detect if file names have been
   ## tampered with.
   ${gpg_bin} --detach-sign --armor --yes --set-notation "file@name"="$(basename "$1")" "$1"
}

sign_cmd_signify() {
   ## To create a key for signify-openbsd, see:
   ## derivative-maker help-steps/signing-key-create

   ## Big file are unfortunately unsupported by signify.
   if [ "$file_size_mb" -ge "1000" ]; then
      return 0
   fi
   ## https://forums.whonix.org/t/signify-openbsd/7842
   signify-openbsd -S -s "${signify_private_key}" -m "$1" -x "$2"
   ## Sanity test.
   test -f "$2"
}

verify_cmd_gpg() {
   ${gpg_bin} --verify-options show-notations --verify "$1"
}

verify_cmd_signinfy() {
   if [ "$file_size_mb" -ge "100" ]; then
      return 0
   fi
   signify-openbsd -V -p "${signify_public_key}" -m "$1" -x "$2"
}

sign_and_verify() {
   file_size_bytes=$(stat -c%s "$1")
   # Convert bytes to megabytes
   file_size_mb=$(echo "scale=0; $file_size_bytes / 1024 / 1024" | bc)

   sign_cmd_gpg "${1}"
   verify_cmd_gpg "${1}.asc"
   sign_cmd_signify "${1}" "${1}.sig"
   verify_cmd_signinfy "${1}" "${1}.sig"
}

signatures_create() {
   local var_names file_list upload_url_part
   var_names=()
   file_list=()
   upload_url_part=()

   if [ "${dist_build_virtualbox}" = "true" ]; then
      var_names+=("binary_image_ova_file")
      file_list+=("${binary_image_ova_file}")
      upload_url_part+=("ova")
   fi
   if [ "${dist_build_raw}" = "true" ]; then
      var_names+=("libvirt_target_raw_xz_archive_file")
      file_list+=("${libvirt_target_raw_xz_archive_file}")
      upload_url_part+=("raw")
   fi
   if [ "${dist_build_qcow2}" = "true" ]; then
      var_names+=("libvirt_target_qcow2_xz_archive_file")
      file_list+=("${libvirt_target_qcow2_xz_archive_file}")
      upload_url_part+=("libvirt")
   fi
   if [ "${dist_build_iso}" = "true" ]; then
      var_names+=("binary_image_iso_file")
      file_list+=("${binary_image_iso_file}")
      upload_url_part+=("iso")
   fi
   if [ "${dist_build_installer_dist}" = "true" ]; then
      var_names+=("binary_image_installer_dist_file")
      file_list+=("${binary_image_installer_dist_file}")
      upload_url_part+=("dist-installer-cli")
   fi
   if [ "${dist_build_windows_installer}" = "true" ]; then
      var_names+=("binary_image_windows_installer_file")
      file_list+=("${binary_image_windows_installer_file}")
      upload_url_part+=("windows")
   fi
   if [ "${dist_build_source_archive}" = "true" ]; then
      var_names+=("source_archive_xz_file")
      file_list+=("${source_archive_xz_file}")
      upload_url_part+=("source")
   fi

   ## Thanks to:
   ## https://github.com/moba/createtortorrents/blob/master/createtorrents.sh
   ##
   ## List of trackers (Use with care!):
   ## https://github.com/XIU2/TrackersListCollection
   TRACKERS=""
   ## https://fosstorrents.com/tracker/
   TRACKERS+="http://fosstorrents.com:6969/announce"
   TRACKERS+=","
   TRACKERS+="udp://fosstorrents.com:6969/announce"
   TRACKERS+=","
   ## https://opentrackr.org/
   TRACKERS+="udp://tracker.opentrackr.org:1337/announce"
   TRACKERS+=","
   ## https://torrent.eu.org/
   TRACKERS+="udp://tracker.torrent.eu.org:451"
   true "TRACKERS: ${TRACKERS}"

   ## Debugging.
   pwd

   set -o nounset

   local i
   for i in "${!file_list[@]}"; do
      true "Variable Name: ${var_names[i]}"
      true "Variable Content: ${file_list[i]}"
      true "upload_url_part: ${upload_url_part[i]}"

      local file_item url_part_item
      file_item="${file_list[i]}"
      url_part_item="${upload_url_part[i]}"

      local base_name
      base_name=$(basename "${file_item}")

      rm --force "${file_item}.torrent"
      mktorrent \
         --verbose \
         --announce="${TRACKERS}" \
         --web-seed "https://download.${project_clearnet}/${url_part_item}/${dist_build_version}/${base_name}" \
         -o "${file_item}.torrent" \
         "${file_item}"
      transmission-show "${file_item}.torrent"

      ## Using `basename` so we end up with relative paths in hash sums file.
      sha512sum "${base_name}" | tee "${file_item}.sha512sums" >/dev/null
      sha512sum --check "${file_item}.sha512sums"

      sign_and_verify "${file_item}"
      sign_and_verify "${file_item}.torrent"
      sign_and_verify "${file_item}.sha512sums"
   done

   ## TODO: Remove when whole script is ready for nounset.
   set +o nounset
}

legal_files_copy() {
   ## libvirt_compress uses --directory="${dist_binary_build_folder}"
   if [ "${dist_build_type_short}" = "kicksecure" ]; then
      cp "${source_code_folder_dist}/packages/kicksecure/kicksecure-base-files/usr/share/kicksecure/KICKSECURE_BINARY_LICENSE_AGREEMENT" "${dist_binary_build_folder}/KICKSECURE_BINARY_LICENSE_AGREEMENT"
      cp "${source_code_folder_dist}/packages/kicksecure/kicksecure-base-files/usr/share/kicksecure/KICKSECURE_DISCLAIMER" "${dist_binary_build_folder}/KICKSECURE_DISCLAIMER"
   else
      cp "${source_code_folder_dist}/packages/whonix/whonix-base-files/usr/share/whonix/WHONIX_BINARY_LICENSE_AGREEMENT" "${dist_binary_build_folder}/WHONIX_BINARY_LICENSE_AGREEMENT"
      cp "${source_code_folder_dist}/packages/whonix/whonix-base-files/usr/share/whonix/WHONIX_DISCLAIMER" "${dist_binary_build_folder}/WHONIX_DISCLAIMER"
   fi
}

main() {
   sanity_tests "$@"

   if [ "${dist_build_type_long}" = "gateway" ]; then
      true "$0: INFO: Skip, because dist_build_type_long is gateway. Not needed because of unified Whonix-Gateway and Whonix-Workstation images."
      return 0
   fi

   vm_multiple=false
   if [ "${dist_build_type_long}" = "workstation" ]; then
      vm_multiple=true
      ## dist_build_desktop could be KDE, CLI, Xfce, RPi or CUSTOM
      vm_names_to_be_exported="Whonix-Gateway-${dist_build_desktop} Whonix-Workstation-${dist_build_desktop}"
   fi
   if [ "${dist_build_type_long}" = "custom-workstation" ]; then
      vm_names_to_be_exported="${VMNAME}"
   fi
   if [ "${dist_build_type_short}" = "kicksecure" ]; then
      vm_names_to_be_exported="${VMNAME}"
   fi

   installer_dist
   libvirt_compress
   virtualbox_export
   windows_installer
   signatures_create
   sync
}

main "$@"
