#!/bin/bash
# Part of kalipi-config https://github.com/Re4son/RPi-Tweaks/tree/master/kalipi-config
# Based on raspi-config https://github.com/RPi-Distro/raspi-config
#
# re4son [at] re4son-kernel.com
#
# See LICENSE file for copyright and license details

INTERACTIVE=True
ASK_TO_REBOOT=0
BLACKLIST=/etc/modprobe.d/kalipi-blacklist.conf
CONFIG=/boot/config.txt
PROG_NAME="$0"
ARGS="$@"
VERSION="5.10-1.0.0"


if [[ ! "$LD_LIBRARY_PATH" =~ (^|:)"/opt/vc/lib"(|/)(:|$) ]]; then
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/vc/lib/;
fi


info() {
    system="$1"
    group="${system}"
    shift
    FG="1;32m"
    BG="40m"
    echo "[\033[${FG}\033[${BG}${system}\033[0m] $*"
}

is_pi () {
  ARCH=$(dpkg --print-architecture)
  if [ "$ARCH" = "armhf" ] || [ "$ARCH" = "armel" ]; then
    return 0
  else
    return 1
  fi
}


if is_pi ; then
  CMDLINE=/boot/cmdline.txt
else
  CMDLINE=/proc/cmdline
fi

is_pione() {
   if grep -q "^Revision\s*:\s*00[0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo; then
      return 0
   elif grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[0-36][0-9a-fA-F]$" /proc/cpuinfo ; then
      return 0
   else
      return 1
   fi
}

is_pitwo() {
   grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]04[0-9a-fA-F]$" /proc/cpuinfo
   return $?
}

is_pizero() {
   grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[9cC][0-9a-fA-F]$" /proc/cpuinfo
   return $?
}

set_sudo_user() {
  if [ -z "$SUDO_USER" ]; then
    SUDO_USER=root
  fi
  return 0
}

get_pi_type() {
   if is_pione; then
      echo 1
   elif is_pitwo; then
      echo 2
   else
      echo 0
   fi
}

is_live() {
    grep -q "boot=live" $CMDLINE
    return $?
}

is_ssh() {
  if pstree -p | egrep --quiet --extended-regexp ".*sshd.*\($$\)"; then
    return 0
  else
    return 1
  fi
}

print_version() {
    echo "kalipi-config $VERSION"
    exit 0
}

check_bin(){
  BIN_PATH=$(which $1)
  if [ "" = "$BIN_PATH" ]; then
    echo 0
  else
    echo 1
  fi
}

check_pkg(){
  PKG_STATUS=$(dpkg-query -W --showformat='${Status}\n' $1|grep "install ok installed")
  if [ "" = "$PKG_STATUS" ]; then
    echo 0
  else
    echo 1
  fi
}

calc_wt_size() {
  # NOTE: it's tempting to redirect stderr to /dev/null, so supress error 
  # output from tput. However in this case, tput detects neither stdout or 
  # stderr is a tty and so only gives default 80, 24 values
  WT_HEIGHT=17
  WT_WIDTH=$(tput cols)

  if [ -z "$WT_WIDTH" ] || [ "$WT_WIDTH" -lt 100 ]; then
    WT_WIDTH=90
  elif [ "$WT_WIDTH" -gt 178 ]; then
    WT_WIDTH=120
  else
    WT_WIDTH=$((WT_WIDTH-10))
  fi
  WT_MENU_HEIGHT=$(($WT_HEIGHT-7))
}

do_about() {
  whiptail --msgbox "\
kalipi-config version $VERSION

This tool provides a straight-forward way of doing initial
configuration of the Kali-Pi. Although it can be run
at any time, some of the options may have difficulties if
you have heavily customised your installation.\
" 20 70 1
}

function do_kalipi_tft_config() {
    BIN_PATH=$(which kalipi-tft-config)
    if [ "" = "$BIN_PATH" ]; then
    whiptail --msgbox "\
Error:
The tool "kalipi-tft-config" cannot be found on this system.
It can be installed from this site:
https://github.com/Re4son/RPi-Tweaks/tree/master/kalipi-tft-config
" 20 70 1
    else
        exec $BIN_PATH
    fi
}

get_partvars () {
    ROOT_PART_DEV=$(findmnt / -o source -n)
    ROOT_PART_NAME=$(echo "$ROOT_PART_DEV" | cut -d "/" -f 3)
    ROOT_DEV_NAME=$(echo /sys/block/*/"${ROOT_PART_NAME}" | cut -d "/" -f 4)
    ROOT_DEV="/dev/${ROOT_DEV_NAME}"
    ROOT_PART_NUM=$(cat "/sys/block/${ROOT_DEV_NAME}/${ROOT_PART_NAME}/partition")

    BOOT_PART_DEV=$(findmnt /boot -o source -n)
    BOOT_PART_NAME=$(echo "$BOOT_PART_DEV" | cut -d "/" -f 3)
    BOOT_DEV_NAME=$(echo /sys/block/*/"${BOOT_PART_NAME}" | cut -d "/" -f 4)
    BOOT_PART_NUM=$(cat "/sys/block/${BOOT_DEV_NAME}/${BOOT_PART_NAME}/partition")

    OLD_DISKID=$(fdisk -l "$ROOT_DEV" | sed -n 's/Disk identifier: 0x\([^ ]*\)/\1/p')
    ROOT_DEV_SIZE=$(cat "/sys/block/${ROOT_DEV_NAME}/size")

    TARGET_END=$((ROOT_DEV_SIZE - 1))
    PARTITION_TABLE=$(parted -m "$ROOT_DEV" unit s print | tr -d 's')

    LAST_PART_NUM=$(echo "$PARTITION_TABLE" | tail -n 1 | cut -d ":" -f 1)
    ROOT_PART_LINE=$(echo "$PARTITION_TABLE" | grep -e "^${ROOT_PART_NUM}:")
    ROOT_PART_START=$(echo "$ROOT_PART_LINE" | cut -d ":" -f 2)
    ROOT_PART_END=$(echo "$ROOT_PART_LINE" | cut -d ":" -f 3)
}

check_partvars () {
  if [ "$BOOT_DEV_NAME" != "$ROOT_DEV_NAME" ]; then
      FAIL_REASON="Boot and root partitions are on different devices"
      return 1
  fi

  if [ "$ROOT_PART_NUM" -ne "$LAST_PART_NUM" ]; then
    FAIL_REASON="Root partition should be last partition"
    return 1
  fi

  if [ "$ROOT_PART_END" -gt "$TARGET_END" ]; then
    FAIL_REASON="Root partition runs past the end of device"
    return 1
  fi

  if [ ! -b "$ROOT_DEV" ] || [ ! -b "$ROOT_PART_DEV" ] || [ ! -b "$BOOT_PART_DEV" ] ; then
    FAIL_REASON="Could not determine partitions"
    return 1
  fi
}

fix_partuuid() {
  DISKID="$(fdisk -l "$ROOT_DEV" | sed -n 's/Disk identifier: 0x\([^ ]*\)/\1/p')"

  sed -i "s/${OLD_DISKID}/${DISKID}/g" /etc/fstab
  sed -i "s/${OLD_DISKID}/${DISKID}/" /boot/cmdline.txt
}

do_expand_rootfs() {
  get_partvars
  if ! check_partvars; then
    whiptail --msgbox "Could not expand filesystem, please try manually.\n${FAIL_REASON}" 20 60
    return 1
  fi
  if ! parted -m "$ROOT_DEV" u s resizepart "$ROOT_PART_NUM" "$TARGET_END"; then
    whiptail --msgbox "Could not expand filesystem, please try manually.\nRoot partition resize failed" 20 60
    return 1
  fi
  partprobe "$ROOT_DEV"
  resize2fs $ROOT_PART_DEV
  fix_partuuid
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Root partition has been resized successfully." 20 60 2
  fi
}

set_config_var() {
  lua - "$1" "$2" "$3" <<EOF > "$3.bak"
local key=assert(arg[1])
local value=assert(arg[2])
local fn=assert(arg[3])
local file=assert(io.open(fn))
local made_change=false
for line in file:lines() do
  if line:match("^#?%s*"..key.."=.*$") then
    line=key.."="..value
    made_change=true
  end
  print(line)
end

if not made_change then
  print(key.."="..value)
end
EOF
mv "$3.bak" "$3"
}

clear_config_var() {
  lua - "$1" "$2" <<EOF > "$2.bak"
local key=assert(arg[1])
local fn=assert(arg[2])
local file=assert(io.open(fn))
for line in file:lines() do
  if line:match("^%s*"..key.."=.*$") then
    line="#"..line
  end
  print(line)
end
EOF
mv "$2.bak" "$2"
}

get_config_var() {
  lua - "$1" "$2" <<EOF
local key=assert(arg[1])
local fn=assert(arg[2])
local file=assert(io.open(fn))
local found=false
for line in file:lines() do
  local val = line:match("^%s*"..key.."=(.*)$")
  if (val ~= nil) then
    print(val)
    found=true
    break
  end
end
if not found then
   print(0)
end
EOF
}

get_overscan() {
  OVS=$(get_config_var disable_overscan $CONFIG)
  if [ $OVS -eq 1 ]; then
    echo 1
  else
    echo 0
  fi
}

do_overscan() {
  DEFAULT=--defaultno
  CURRENT=0
  if [ $(get_overscan) -eq 0 ]; then
      DEFAULT=
      CURRENT=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like to enable compensation for displays with overscan?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq $CURRENT ]; then
    ASK_TO_REBOOT=1
  fi
  if [ $RET -eq 0 ] ; then
    set_config_var disable_overscan 0 $CONFIG
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    sed $CONFIG -i -e "s/^overscan_/#overscan_/"
    set_config_var disable_overscan 1 $CONFIG
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Display overscan compensation is $STATUS" 20 60 1
  fi
}

get_pixdub() {
  if is_pi ; then
    FBW=$(get_config_var framebuffer_width $CONFIG)
    if [ $FBW -eq 0 ]; then
      echo 1
    else
      echo 0
    fi
  else
    if [ -e /etc/profile.d/pd.sh ] ; then
      echo 0
    else
      echo 1
    fi
  fi
}

is_number() {
  case $1 in
    ''|*[!0-9]*) return 0 ;;
    *) return 1 ;;
  esac
}

do_pixdub() {
  DEFAULT=--defaultno
  CURRENT=0
  if [ $(get_pixdub) -eq 0 ]; then
      DEFAULT=
      CURRENT=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like to enable pixel doubling?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if is_pi ; then
    if [ $RET -eq 0 ] ; then
	  XVAL=$(xrandr 2>&1 | grep current | cut -f2 -d, | cut -f3 -d' ')
	  YVAL=$(xrandr 2>&1 | grep current | cut -f2 -d, | cut -f5 -d' ')
	  if is_number $XVAL || is_number $YVAL ; then
        if [ "$INTERACTIVE" = True ]; then
          whiptail --msgbox "Could not read current screen dimensions - unable to enable pixel doubling" 20 60 1
        fi
	    return 1
	  fi
	  NEWX=`expr $XVAL / 2`
	  NEWY=`expr $YVAL / 2`
      set_config_var framebuffer_width $NEWX $CONFIG
      set_config_var framebuffer_height $NEWY $CONFIG
      set_config_var scaling_kernel 8 $CONFIG
      STATUS=enabled
    elif [ $RET -eq 1 ]; then
      clear_config_var framebuffer_width $CONFIG
      clear_config_var framebuffer_height $CONFIG
      clear_config_var scaling_kernel $CONFIG
      STATUS=disabled
    else
      return $RET
    fi
  else
    if [ -e /etc/profile.d/pd.sh ] ; then
      rm /etc/profile.d/pd.sh
    fi
    if [ $RET -eq 0 ] ; then
      DEV=$(xrandr | grep -w connected | cut -f1 -d' ')
      for item in $DEV
      do
        echo xrandr --output $item --scale 0.5x0.5 >> /etc/profile.d/pd.sh
      done
      STATUS=enabled
    elif [ $RET -eq 1 ]; then
      STATUS=disabled
    else
      return $RET
    fi
  fi
  if [ $RET -eq $CURRENT ]; then
    ASK_TO_REBOOT=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Pixel doubling is $STATUS" 20 60 1
  fi
}

do_change_pass() {
  AVAIL_USERS=$(awk -F'[/:]' '{if (($3 >= 1000 && $3 != 65534) || $3 == 0) print $1}' /etc/passwd)
  whiptail --msgbox "Users on this system (Tip: use copy and paste):\n\n$AVAIL_USERS" 20 90
  USER=$(whiptail --inputbox "Please enter the username to change the poassword of\n(leave empty for $SUDO_USER):" 20 60 3>&1 1>&2 2>&3)
  if [ $? -ne 0 ]; then
          return 0
  elif [ -z "$USER" ]; then
	  USER=$SUDO_USER
  fi
  whiptail --msgbox "You will now be asked to enter a new password for user \"$USER\"" 20 60 1
  passwd $USER &&
  whiptail --msgbox "Password changed successfully" 20 60 1
}

do_configure_keyboard() {
  printf "Reloading keymap. This may take a short while\n"
  if [ "$INTERACTIVE" = True ]; then
    dpkg-reconfigure keyboard-configuration
  else
    local KEYMAP="$1"
    sed -i /etc/default/keyboard -e "s/^XKBLAYOUT.*/XKBLAYOUT=\"$KEYMAP\"/"
    dpkg-reconfigure -f noninteractive keyboard-configuration
  fi
  invoke-rc.d keyboard-setup start
  setsid sh -c 'exec setupcon -k --force <> /dev/tty1 >&0 2>&1'
  udevadm trigger --subsystem-match=input --action=change
  return 0
}

do_change_locale() {
  if [ "$INTERACTIVE" = True ]; then
    dpkg-reconfigure locales
  else
    local LOCALE="$1"
    if ! LOCALE_LINE="$(grep "^$LOCALE " /usr/share/i18n/SUPPORTED)"; then
      return 1
    fi
    local ENCODING="$(echo $LOCALE_LINE | cut -f2 -d " ")"
    echo "$LOCALE $ENCODING" > /etc/locale.gen
    sed -i "s/^\s*LANG=\S*/LANG=$LOCALE/" /etc/default/locale
    dpkg-reconfigure -f noninteractive locales
  fi
}

do_change_timezone() {
  if [ "$INTERACTIVE" = True ]; then
    dpkg-reconfigure tzdata
  else
    local TIMEZONE="$1"
    if [ ! -f "/usr/share/zoneinfo/$TIMEZONE" ]; then
      return 1;
    fi
    rm /etc/localtime
    echo "$TIMEZONE" > /etc/timezone
    dpkg-reconfigure -f noninteractive tzdata
  fi
}

get_wifi_country() {
   grep country= /etc/wpa_supplicant/wpa_supplicant.conf | cut -d "=" -f 2
}

do_wifi_country() {
  oIFS="$IFS"
  if [ "$INTERACTIVE" = True ]; then
    IFS="/"
    value=$(cat /usr/share/zoneinfo/iso3166.tab | tail -n +26 | tr '\t' '/' | tr '\n' '/')
    COUNTRY=$(whiptail --menu "Select the country in which the Pi is to be used" 20 60 10 ${value} 3>&1 1>&2 2>&3)
  else
    COUNTRY=$1
    true
  fi
  if [ $? -eq 0 ];then
    if [ -e /etc/wpa_supplicant/wpa_supplicant.conf ]; then
        if grep -q "^country=" /etc/wpa_supplicant/wpa_supplicant.conf ; then
            sed -i --follow-symlinks "s/^country=.*/country=$COUNTRY/g" /etc/wpa_supplicant/wpa_supplicant.conf
        else
            sed -i --follow-symlinks "1i country=$COUNTRY" /etc/wpa_supplicant/wpa_supplicant.conf
        fi
    else
        echo "country=$COUNTRY" > /etc/wpa_supplicant/wpa_supplicant.conf
    fi
    if [ "$INTERACTIVE" = True ]; then
        whiptail --msgbox "Wi-fi country set to $COUNTRY" 20 60 1
    fi
    ASK_TO_REBOOT=1
  fi
  IFS=$oIFS
}

get_hostname() {
    cat /etc/hostname | tr -d " \t\n\r"
}

do_hostname() {
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "\
Please note: RFCs mandate that a hostname's labels \
may contain only the ASCII letters 'a' through 'z' (case-insensitive), 
the digits '0' through '9', and the hyphen.
Hostname labels cannot begin or end with a hyphen. 
No other symbols, punctuation characters, or blank spaces are permitted.\
" 20 70 1
  fi
  CURRENT_HOSTNAME=`cat /etc/hostname | tr -d " \t\n\r"`
  if [ "$INTERACTIVE" = True ]; then
    NEW_HOSTNAME=$(whiptail --inputbox "Please enter a hostname" 20 60 "$CURRENT_HOSTNAME" 3>&1 1>&2 2>&3)
  else
    NEW_HOSTNAME=$1
    true
  fi
  if [ $? -eq 0 ]; then
    echo $NEW_HOSTNAME > /etc/hostname
    sed -i "s/127.0.1.1.*$CURRENT_HOSTNAME/127.0.1.1\t$NEW_HOSTNAME/g" /etc/hosts
    ASK_TO_REBOOT=1
  fi
}

do_memory_split() { # Memory Split
  if [ -e /boot/start_cd.elf ]; then
    # New-style memory split setting
    ## get current memory split from /boot/config.txt
    arm=$(vcgencmd get_mem arm | cut -d '=' -f 2 | cut -d 'M' -f 1)
    gpu=$(vcgencmd get_mem gpu | cut -d '=' -f 2 | cut -d 'M' -f 1)
    tot=$(($arm+$gpu))
    if [ $tot -gt 512 ]; then
      CUR_GPU_MEM=$(get_config_var gpu_mem_1024 $CONFIG)
    elif [ $tot -gt 256 ]; then
      CUR_GPU_MEM=$(get_config_var gpu_mem_512 $CONFIG)
    else
      CUR_GPU_MEM=$(get_config_var gpu_mem_256 $CONFIG)
    fi
    if [ -z "$CUR_GPU_MEM" ] || [ $CUR_GPU_MEM = "0" ]; then
      CUR_GPU_MEM=$(get_config_var gpu_mem $CONFIG)
    fi
    [ -z "$CUR_GPU_MEM" ] || [ $CUR_GPU_MEM = "0" ] && CUR_GPU_MEM=64
    ## ask users what gpu_mem they want
    if [ "$INTERACTIVE" = True ]; then
      NEW_GPU_MEM=$(whiptail --inputbox "How much memory (MB) should the GPU have?  e.g. 16/32/64/128/256" \
        20 70 -- "$CUR_GPU_MEM" 3>&1 1>&2 2>&3)
    else
      NEW_GPU_MEM=$1
      true
    fi
    if [ $? -eq 0 ]; then
      if [ $(get_config_var gpu_mem_1024 $CONFIG) != "0" ] || [ $(get_config_var gpu_mem_512 $CONFIG) != "0" ] || [ $(get_config_var gpu_mem_256 $CONFIG) != "0" ]; then
        if [ "$INTERACTIVE" = True ]; then
          whiptail --msgbox "Device-specific memory settings were found. These have been cleared." 20 60 2
        fi
        clear_config_var gpu_mem_1024 $CONFIG
        clear_config_var gpu_mem_512 $CONFIG
        clear_config_var gpu_mem_256 $CONFIG
      fi
      set_config_var gpu_mem "$NEW_GPU_MEM" $CONFIG
      ASK_TO_REBOOT=1
    fi
  else # Old firmware so do start.elf renaming
    get_current_memory_split
    MEMSPLIT=$(whiptail --menu "Set memory split.\n$MEMSPLIT_DESCRIPTION" 20 60 10 \
      "240" "240MiB for ARM, 16MiB for VideoCore" \
      "224" "224MiB for ARM, 32MiB for VideoCore" \
      "192" "192MiB for ARM, 64MiB for VideoCore" \
      "128" "128MiB for ARM, 128MiB for VideoCore" \
      3>&1 1>&2 2>&3)
    if [ $? -eq 0 ]; then
      set_memory_split ${MEMSPLIT}
      ASK_TO_REBOOT=1
    fi
  fi
}

get_current_memory_split() {
  AVAILABLE_SPLITS="128 192 224 240"
  MEMSPLIT_DESCRIPTION=""
  for SPLIT in $AVAILABLE_SPLITS;do
    if [ -e /boot/arm${SPLIT}_start.elf ] && cmp /boot/arm${SPLIT}_start.elf /boot/start.elf >/dev/null 2>&1;then
      CURRENT_MEMSPLIT=$SPLIT
      MEMSPLIT_DESCRIPTION="Current: ${CURRENT_MEMSPLIT}MiB for ARM, $((256 - $CURRENT_MEMSPLIT))MiB for VideoCore"
      break
    fi
  done
}

set_memory_split() {
  cp -a /boot/arm${1}_start.elf /boot/start.elf
  sync
}

do_overclock() {
  if ! is_pione && ! is_pitwo; then
    whiptail --msgbox "This Pi cannot be overclocked." 20 60 2
    return 1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "\
Be aware that overclocking may reduce the lifetime of your
Raspberry Pi. If overclocking at a certain level causes
system instability, try a more modest overclock. Hold down
shift during boot to temporarily disable overclock.
See http://elinux.org/RPi_Overclocking for more information.\
" 20 70 1
   if is_pione; then
    OVERCLOCK=$(whiptail --menu "Choose overclock preset" 20 60 10 \
      "None" "700MHz ARM, 250MHz core, 400MHz SDRAM, 0 overvolt" \
      "Modest" "800MHz ARM, 250MHz core, 400MHz SDRAM, 0 overvolt" \
      "Medium" "900MHz ARM, 250MHz core, 450MHz SDRAM, 2 overvolt" \
      "High" "950MHz ARM, 250MHz core, 450MHz SDRAM, 6 overvolt" \
      "Turbo" "1000MHz ARM, 500MHz core, 600MHz SDRAM, 6 overvolt" \
      3>&1 1>&2 2>&3)
   elif is_pitwo; then
    OVERCLOCK=$(whiptail --menu "Choose overclock preset" 20 60 10 \
      "None" "900MHz ARM, 250MHz core, 450MHz SDRAM, 0 overvolt" \
      "High" "1000MHz ARM, 500MHz core, 500MHz SDRAM, 2 overvolt" \
      3>&1 1>&2 2>&3)
   fi
  else
    OVERCLOCK=$1
    true
  fi
  if [ $? -eq 0 ]; then
    case "$OVERCLOCK" in
      None)
        clear_overclock
        ;;
      Modest)
        set_overclock Modest 800 250 400 0
        ;;
      Medium)
        set_overclock Medium 900 250 450 2
        ;;
      High)
        if is_pione; then
          set_overclock High 950 250 450 6
        else
          set_overclock High 1000 500 500 2
        fi
        ;;
      Turbo)
        set_overclock Turbo 1000 500 600 6
        ;;
      *)
        whiptail --msgbox "Program error, unrecognised overclock preset" 20 60 2
        return 1
        ;;
    esac
    ASK_TO_REBOOT=1
  fi
}

set_overclock() {
  set_config_var arm_freq $2 $CONFIG &&
  set_config_var core_freq $3 $CONFIG &&
  set_config_var sdram_freq $4 $CONFIG &&
  set_config_var over_voltage $5 $CONFIG &&
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Set overclock to preset '$1'" 20 60 2
  fi
}

clear_overclock () {
  clear_config_var arm_freq $CONFIG &&
  clear_config_var core_freq $CONFIG &&
  clear_config_var sdram_freq $CONFIG &&
  clear_config_var over_voltage $CONFIG &&
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Set overclock to preset 'None'" 20 60 2
  fi
}

get_ssh() {
  if service ssh status | grep -q inactive; then
    echo 1
  else
    echo 0
  fi
}

do_ssh() {
  if [ -e /var/log/regen_ssh_keys.log ] && ! grep -q "^finished" /var/log/regen_ssh_keys.log; then
    whiptail --msgbox "Initial ssh key generation still running. Please wait and try again." 20 60 2
    return 1
  fi
  DEFAULT=--defaultno
  if [ $(get_ssh) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the SSH server to be enabled?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    systemctl enable ssh &&
    systemctl start ssh &&
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    systemctl disable ssh &&
    systemctl stop ssh &&
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "The SSH server is $STATUS" 20 60 1
  fi
}

get_vnc() {
  if systemctl status vncserver-x11-serviced.service  | grep -q inactive; then
    echo 1
  else
    echo 0
  fi
}

do_vnc() {
  DEFAULT=--defaultno
  if [ $(get_vnc) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the VNC Server to be enabled?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    if [ ! -d /usr/share/doc/realvnc-vnc-server ] ; then
        apt-get install realvnc-vnc-server
    fi
    systemctl enable vncserver-x11-serviced.service &&
    systemctl start vncserver-x11-serviced.service &&
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    systemctl disable vncserver-x11-serviced.service &&
    systemctl stop vncserver-x11-serviced.service &&
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "The VNC Server is $STATUS" 20 60 1
  fi
}

get_spi() {
  if grep -q -E "^(device_tree_param|dtparam)=([^,]*,)*spi(=(on|true|yes|1))?(,.*)?$" $CONFIG; then
    echo 0
  else
    echo 1
  fi
}

do_spi() {
  DEFAULT=--defaultno
  if [ $(get_spi) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the SPI interface to be enabled?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    SETTING=on
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    SETTING=off
    STATUS=disabled
  else
    return $RET
  fi

  set_config_var dtparam=spi $SETTING $CONFIG &&
  if ! [ -e $BLACKLIST ]; then
    touch $BLACKLIST
  fi
  sed $BLACKLIST -i -e "s/^\(blacklist[[:space:]]*spi[-_]bcm2708\)/#\1/"
  dtparam spi=$SETTING

  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "The SPI interface is $STATUS" 20 60 1
  fi
}

get_i2c() {
  if grep -q -E "^(device_tree_param|dtparam)=([^,]*,)*i2c(_arm)?(=(on|true|yes|1))?(,.*)?$" $CONFIG; then
    echo 0
  else
    echo 1
  fi
}

do_i2c() {
  DEFAULT=--defaultno
  if [ $(get_i2c) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the ARM I2C interface to be enabled?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    SETTING=on
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    SETTING=off
    STATUS=disabled
  else
    return $RET
  fi

  set_config_var dtparam=i2c_arm $SETTING $CONFIG &&
  if ! [ -e $BLACKLIST ]; then
    touch $BLACKLIST
  fi
  sed $BLACKLIST -i -e "s/^\(blacklist[[:space:]]*i2c[-_]bcm2708\)/#\1/"
  sed /etc/modules -i -e "s/^#[[:space:]]*\(i2c[-_]dev\)/\1/"
  if ! grep -q "^i2c[-_]dev" /etc/modules; then
    printf "i2c-dev\n" >> /etc/modules
  fi
  dtparam i2c_arm=$SETTING
  modprobe i2c-dev

  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "The ARM I2C interface is $STATUS" 20 60 1
  fi
}

get_serial() {
  if grep -q -E "console=(serial0|ttyAMA0|ttyS0)" $CMDLINE ; then
    echo 0
  else
    echo 1
  fi
}

get_serial_hw() {
  if grep -q -E "^enable_uart=1" $CONFIG ; then
    echo 0
  elif grep -q -E "^enable_uart=0" $CONFIG ; then
    echo 1
  elif [ -e /dev/serial0 ] ; then
    echo 0
  else
    echo 1
  fi
}

do_serial() {
  DEFAULTS=--defaultno
  DEFAULTH=--defaultno
  CURRENTS=0
  CURRENTH=0
  if [ $(get_serial) -eq 0 ]; then
      DEFAULTS=
      CURRENTS=1
  fi
  if [ $(get_serial_hw) -eq 0 ]; then
      DEFAULTH=
      CURRENTH=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like a login shell to be accessible over serial?" $DEFAULTS 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq $CURRENTS ]; then
    ASK_TO_REBOOT=1
  fi
  if [ $RET -eq 0 ]; then
    if grep -q "console=ttyAMA0" $CMDLINE ; then
      if [ -e /proc/device-tree/aliases/serial0 ]; then
        sed -i $CMDLINE -e "s/console=ttyAMA0/console=serial0/"
      fi
    elif ! grep -q "console=ttyAMA0" $CMDLINE && ! grep -q "console=serial0" $CMDLINE ; then
      if [ -e /proc/device-tree/aliases/serial0 ]; then
        sed -i $CMDLINE -e "s/root=/console=serial0,115200 root=/"
      else
        sed -i $CMDLINE -e "s/root=/console=ttyAMA0,115200 root=/"
      fi
    fi
    set_config_var enable_uart 1 $CONFIG
    SSTATUS=enabled
    HSTATUS=enabled
  elif [ $RET -eq 1 ]; then
    sed -i $CMDLINE -e "s/console=ttyAMA0,[0-9]\+ //"
    sed -i $CMDLINE -e "s/console=serial0,[0-9]\+ //"
    SSTATUS=disabled
    if [ "$INTERACTIVE" = True ]; then
      whiptail --yesno "Would you like the serial port hardware to be enabled?" $DEFAULTH 20 60 2
      RET=$?
    else
      RET=1
    fi
    if [ $RET -eq $CURRENTH ]; then
     ASK_TO_REBOOT=1
    fi
    if [ $RET -eq 0 ]; then
      set_config_var enable_uart 1 $CONFIG
      HSTATUS=enabled
    elif [ $RET -eq 1 ]; then
      set_config_var enable_uart 0 $CONFIG
      HSTATUS=disabled
    else
      return $RET
    fi
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
      whiptail --msgbox "The serial login shell is $SSTATUS\nThe serial interface is $HSTATUS" 20 60 1
  fi
}

disable_kalipi_config_at_boot() {
  if [ -e /etc/profile.d/kalipi-config.sh ]; then
    rm -f /etc/profile.d/kalipi-config.sh
    if [ -e /etc/systemd/system/getty@tty1.service.d/kalipi-config-override.conf ]; then
      rm /etc/systemd/system/getty@tty1.service.d/kalipi-config-override.conf
    fi
    telinit q
  fi
}

get_boot_cli() {
  if systemctl get-default | grep -q multi-user ; then
    echo 0
  else
    echo 1
  fi
}

get_autologin() {
  if [ $(get_boot_cli) -eq 0 ]; then
    # booting to CLI - check the autologin in getty or initd */
    if grep -q autologin /etc/systemd/system/getty.target.wants/getty@tty1.service ; then
      echo 0
    else
      echo 1
    fi
  else
    # booting to desktop - check the autologin for lightdm */
    if grep -q "^autologin-user=" /etc/lightdm/lightdm.conf ; then
      echo 0
    else
      echo 1
    fi
  fi
}

do_boot_behaviour() {
  OVERWRITE="/etc/systemd/system/getty@tty1.service.d/override.conf"
  P=$(dirname "${OVERWRITE}")
  ## Remove autologin if previously set
  if [ -f ${OVERWRITE} ]; then
        rm -f ${OVERWRITE}
  fi
  if [ "$INTERACTIVE" = True ]; then
    BOOTOPT=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Boot Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT \
      "B1 Console" "Text console, requiring user to login" \
      "B2 Console Autologin" "Text console, automatically logged in as user of your choice" \
      "B3 Desktop" "Desktop GUI, requiring user to login" \
      "B4 Desktop Autologin" "Desktop GUI, automatically logged in as user of your choice" \
      3>&1 1>&2 2>&3)
  else
    BOOTOPT=$1
    true
  fi
  if [ $? -eq 0 ]; then
    case "$BOOTOPT" in
      B1*)
        systemctl set-default multi-user.target
        ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
	if [ -f ${OVERWRITE} ]; then
            rm -f ${OVERWRITE}
        fi
        ;;
      B2*)
        USER=$(whiptail --inputbox "Please enter the username for autologon\n(leave empty for $SUDO_USER):" 20 60 3>&1 1>&2 2>&3)
        if [ $? -ne 0 ]; then
          return 0
        elif [ -z "$USER" ]; then
	  USER=$SUDO_USER
	fi
        systemctl set-default multi-user.target
        ln -fs /etc/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
	if [ ! -d ${P} ]; then
            mkdir -p ${P}
        fi
        cat >> ${OVERWRITE} <<EOF
# --- added by kalipi-config ---
# enable autologin
[Service]
ExecStart=
ExecStart=-/sbin/agetty -a $USER --noclear %I $TERM
Type=idle
# --- end kalipi-config ---
EOF
        ;;
      B3*)
        if [ -e /etc/init.d/lightdm ]; then
          systemctl set-default graphical.target
          ln -fs /lib/systemd/system/getty@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
          sed /etc/lightdm/lightdm.conf -i -e "s/^autologin-user=.*/#autologin-user=/"
          ## disable_kalipi_config_at_boot
        else
          whiptail --msgbox "Do 'sudo apt-get install lightdm' to allow configuration of boot to desktop" 20 60 2
          return 1
        fi
        ;;
      B4*)
        if [ -e /etc/init.d/lightdm ]; then
          USER=$(whiptail --inputbox "Please enter the username for autologon\n(leave empty for $SUDO_USER):" 20 60 3>&1 1>&2 2>&3)
          if [ $? -ne 0 ]; then
            return 0
          elif [ -z "$USER" ]; then
            USER=$SUDO_USER
          fi
          systemctl set-default graphical.target
          ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
          sed /etc/lightdm/lightdm.conf -i -e "s/^\(#\|\)autologin-user=.*/autologin-user=$USER/"
	  if [ "$USER" == "root" ]; then # Allow root login
	    sed /etc/pam.d/lightdm-autologin -i -e "s/required pam_succeed_if.so user != root quiet_success/required pam_succeed_if.so user != anything quiet_success/"
	  fi 
          ## disable_kalipi_config_at_boot
        else
          whiptail --msgbox "Do 'sudo apt-get install lightdm' to allow configuration of boot to desktop" 20 60 2
          return 1
        fi
        ;;
      *)
        whiptail --msgbox "Program error, unrecognised boot option" 20 60 2
        return 1
        ;;
    esac
    ASK_TO_REBOOT=1
  fi
}

get_boot_wait() {
  if test -e /etc/systemd/system/dhcpcd.service.d/wait.conf; then
    echo 0
  else
    echo 1
  fi
}

do_boot_wait() {
  DEFAULT=--defaultno
  if [ $(get_boot_wait) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like boot to wait until a network connection is established?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    mkdir -p /etc/systemd/system/dhcpcd.service.d/
    cat > /etc/systemd/system/dhcpcd.service.d/wait.conf << EOF
[Service]
ExecStart=
ExecStart=/usr/lib/dhcpcd5/dhcpcd -q -w
EOF
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    rm -f /etc/systemd/system/dhcpcd.service.d/wait.conf
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Waiting for network on boot is $STATUS" 20 60 1
  fi
}

get_boot_splash() {
  if is_pi ; then
    if grep -q "splash" $CMDLINE ; then
      echo 0
    else
      echo 1
    fi
  else
    if grep -q "GRUB_CMDLINE_LINUX_DEFAULT.*splash" /etc/default/grub ; then
      echo 0
    else
      echo 1
    fi
  fi
}

do_boot_splash() {
  if [ ! -e /usr/share/plymouth/themes/pix/pix.script ]; then
    if [ "$INTERACTIVE" = True ]; then
      whiptail --msgbox "The splash screen is not installed so cannot be activated" 20 60 2
    fi
    return 1
  fi
  DEFAULT=--defaultno
  if [ $(get_boot_splash) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like to show the splash screen at boot?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    if is_pi ; then
      if ! grep -q "splash" $CMDLINE ; then
        sed -i $CMDLINE -e "s/$/ quiet splash plymouth.ignore-serial-consoles/"
      fi
    else
      sed -i /etc/default/grub -e "s/GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"/GRUB_CMDLINE_LINUX_DEFAULT=\"\1 quiet splash plymouth.ignore-serial-consoles\"/"
      sed -i /etc/default/grub -e "s/  \+/ /g"
      sed -i /etc/default/grub -e "s/GRUB_CMDLINE_LINUX_DEFAULT=\" /GRUB_CMDLINE_LINUX_DEFAULT=\"/"
      update-grub
    fi
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    if is_pi ; then
      if grep -q "splash" $CMDLINE ; then
        sed -i $CMDLINE -e "s/ quiet//"
        sed -i $CMDLINE -e "s/ splash//"
        sed -i $CMDLINE -e "s/ plymouth.ignore-serial-consoles//"
      fi
    else
      sed -i /etc/default/grub -e "s/GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)quiet\(.*\)\"/GRUB_CMDLINE_LINUX_DEFAULT=\"\1\2\"/"
      sed -i /etc/default/grub -e "s/GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)splash\(.*\)\"/GRUB_CMDLINE_LINUX_DEFAULT=\"\1\2\"/"
      sed -i /etc/default/grub -e "s/GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)plymouth.ignore-serial-consoles\(.*\)\"/GRUB_CMDLINE_LINUX_DEFAULT=\"\1\2\"/"
      sed -i /etc/default/grub -e "s/  \+/ /g"
      sed -i /etc/default/grub -e "s/GRUB_CMDLINE_LINUX_DEFAULT=\" /GRUB_CMDLINE_LINUX_DEFAULT=\"/"
      update-grub
    fi
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Splash screen at boot is $STATUS" 20 60 1
  fi
}

get_rgpio() {
  if test -e /etc/systemd/system/pigpiod.service.d/public.conf; then
    echo 0
  else
    echo 1
  fi
}

do_rgpio() {
  DEFAULT=--defaultno
  if [ $(get_rgpio) -eq 0 ]; then
    DEFAULT=
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the GPIO server to be accessible over the network?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq 0 ]; then
    mkdir -p /etc/systemd/system/pigpiod.service.d/
    cat > /etc/systemd/system/pigpiod.service.d/public.conf << EOF
[Service]
ExecStart=
ExecStart=/usr/bin/pigpiod
EOF
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    rm -f /etc/systemd/system/pigpiod.service.d/public.conf
    STATUS=disabled
  else
    return $RET
  fi
  systemctl daemon-reload
  if systemctl -q is-enabled pigpiod ; then
    systemctl restart pigpiod
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Remote access to the GPIO server is $STATUS" 20 60 1
  fi
}

get_camera() {
  CAM=$(get_config_var start_x $CONFIG)
  if [ $CAM -eq 1 ]; then
    echo 0
  else
    echo 1
  fi
}

do_camera() {
  if [ ! -e /boot/start_x.elf ]; then
    whiptail --msgbox "Your firmware appears to be out of date (no start_x.elf). Please update" 20 60 2
    return 1
  fi
  sed $CONFIG -i -e "s/^startx/#startx/"
  sed $CONFIG -i -e "s/^fixup_file/#fixup_file/"

  DEFAULT=--defaultno
  CURRENT=0
  if [ $(get_camera) -eq 0 ]; then
      DEFAULT=
      CURRENT=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the camera interface to be enabled?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq $CURRENT ]; then
    ASK_TO_REBOOT=1
  fi
  if [ $RET -eq 0 ]; then
    set_config_var start_x 1 $CONFIG
    CUR_GPU_MEM=$(get_config_var gpu_mem $CONFIG)
    if [ -z "$CUR_GPU_MEM" ] || [ "$CUR_GPU_MEM" -lt 128 ]; then
      set_config_var gpu_mem 128 $CONFIG
    fi
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    set_config_var start_x 0 $CONFIG
    sed $CONFIG -i -e "s/^start_file/#start_file/"
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "The camera interface is $STATUS" 20 60 1
  fi
}

get_onewire() {
  if grep -q -E "^dtoverlay=w1-gpio" $CONFIG; then
    echo 0
  else
    echo 1
  fi
}

do_onewire() {
  DEFAULT=--defaultno
  CURRENT=0
  if [ $(get_onewire) -eq 0 ]; then
    DEFAULT=
    CURRENT=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like the one-wire interface to be enabled?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq $CURRENT ]; then
    ASK_TO_REBOOT=1
  fi
  if [ $RET -eq 0 ]; then
    sed $CONFIG -i -e "s/^#dtoverlay=w1-gpio/dtoverlay=w1-gpio/"
    if ! grep -q -E "^dtoverlay=w1-gpio" $CONFIG; then
      printf "dtoverlay=w1-gpio\n" >> $CONFIG
    fi
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    sed $CONFIG -i -e "s/^dtoverlay=w1-gpio/#dtoverlay=w1-gpio/"
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "The one-wire interface is $STATUS" 20 60 1
  fi
}

do_gldriver() {
  if [ ! -e /boot/overlays/vc4-kms-v3d.dtbo ]; then
    whiptail --msgbox "Driver and kernel not present on your system. Please update" 20 60 2
    return 1
  fi
  if [ $(dpkg -l libgl1-mesa-dri | tail -n 1 | cut -d ' ' -f 1) != "ii" ]; then
    whiptail --msgbox "libgl1-mesa-dri not found - please install" 20 60 2
    return 1
  fi
  GLOPT=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "GL Driver" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT \
    "G1 GL (Full KMS)" "OpenGL desktop driver with full KMS" \
    "G2 GL (Fake KMS)" "OpenGL desktop driver with fake KMS" \
    "G3 Legacy" "Original non-GL desktop driver" \
    3>&1 1>&2 2>&3)
  if [ $? -eq 0 ]; then
    case "$GLOPT" in
      G1*)
        if ! grep -q -E "^dtoverlay=vc4-kms-v3d" $CONFIG; then
          ASK_TO_REBOOT=1
        fi
        sed $CONFIG -i -e "s/^dtoverlay=vc4-fkms-v3d/#dtoverlay=vc4-fkms-v3d/"
        sed $CONFIG -i -e "s/^#dtoverlay=vc4-kms-v3d/dtoverlay=vc4-kms-v3d/"
        if ! grep -q -E "^dtoverlay=vc4-kms-v3d" $CONFIG; then
          printf "dtoverlay=vc4-kms-v3d\n" >> $CONFIG
        fi
        STATUS="The full KMS GL driver is enabled."
        ;;
      G2*)
        if ! grep -q -E "^dtoverlay=vc4-fkms-v3d" $CONFIG; then
          ASK_TO_REBOOT=1
        fi
        sed $CONFIG -i -e "s/^dtoverlay=vc4-kms-v3d/#dtoverlay=vc4-kms-v3d/"
        sed $CONFIG -i -e "s/^#dtoverlay=vc4-fkms-v3d/dtoverlay=vc4-fkms-v3d/"
        if ! grep -q -E "^dtoverlay=vc4-fkms-v3d" $CONFIG; then
          printf "dtoverlay=vc4-fkms-v3d\n" >> $CONFIG
        fi
        STATUS="The fake KMS GL driver is enabled."
        ;;
      G3*)
        if grep -q -E "^dtoverlay=vc4-f?kms-v3d" $CONFIG; then
          ASK_TO_REBOOT=1
        fi
        sed $CONFIG -i -e "s/^dtoverlay=vc4-kms-v3d/#dtoverlay=vc4-kms-v3d/"
        sed $CONFIG -i -e "s/^dtoverlay=vc4-fkms-v3d/#dtoverlay=vc4-fkms-v3d/"
        STATUS="The GL driver is disabled."
        ;;
      *)
        whiptail --msgbox "Program error, unrecognised boot option" 20 60 2
        return 1
        ;;
    esac
  else
    return 0
  fi
  if echo "$GLOPT" | grep -q -E "1" ; then
    if grep -q "splash" $CMDLINE ; then
      sed -i $CMDLINE -e "s/ quiet//"
      sed -i $CMDLINE -e "s/ splash//"
      sed -i $CMDLINE -e "s/ plymouth.ignore-serial-consoles//"
    fi
    sed $CONFIG -i -e "s/^gpu_mem/#gpu_mem/"
  fi
  whiptail --msgbox "$STATUS" 20 60 1
 }

get_net_names() {
##  if grep -q "net.ifnames=0" $CMDLINE || [ "$(readlink -f /etc/systemd/network/99-default.link)" = "/dev/null" ] ; then
  if grep -q "net.ifnames=0" $CMDLINE || [ "$(readlink -f /etc/udev/rules.d/73-usb-net-by-mac.rules)" = "/dev/null" ] ; then
    echo 1
  else
    echo 0
  fi
}

do_net_names () {
  DEFAULT=--defaultno
  CURRENT=0
  if [ $(get_net_names) -eq 0 ]; then
    DEFAULT=
    CURRENT=1
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --yesno "Would you like to enable predictable network interface names?" $DEFAULT 20 60 2
    RET=$?
  else
    RET=$1
  fi
  if [ $RET -eq $CURRENT ]; then
    ASK_TO_REBOOT=1
  fi
  if [ $RET -eq 0 ]; then
    sed -i $CMDLINE -e "s/net.ifnames=0 *//"
    rm -f /etc/udev/rules.d/73-usb-net-by-mac.rules
    STATUS=enabled
  elif [ $RET -eq 1 ]; then
    ln -sf /dev/null /etc/udev/rules.d/73-usb-net-by-mac.rules
    STATUS=disabled
  else
    return $RET
  fi
  if [ "$INTERACTIVE" = True ]; then
    whiptail --msgbox "Predictable network interface names are $STATUS" 20 60 1
  fi
 }

do_update() {
    TEMP_FILE="/tmp/kalipi-config"
    info UPDATE "Downloading update"
    wget -O ${TEMP_FILE} https://raw.githubusercontent.com/Re4son/RPi-Tweaks/master/kalipi-config/kalipi-config
    if [ "$(grep Re4son ${TEMP_FILE})" ]; then
        cp $TEMP_FILE $PROG_NAME
        chmod +x $PROG_NAME
        rm -f $TEMP_FILE
        info UPDATE "Replaced old version:"
        echo "kalipi-config Setup $VERSION"
        echo
        info UPDATE "With new version:"
        "$PROG_NAME" --version
        sleep 2 &&
        exec "$PROG_NAME"
    fi
}

do_audio() {
  if [ "$INTERACTIVE" = True ]; then
    AUDIO_OUT=$(whiptail --menu "Choose the audio output" 20 60 10 \
      "0" "Auto" \
      "1" "Force 3.5mm ('headphone') jack" \
      "2" "Force HDMI" \
      3>&1 1>&2 2>&3)
  else
    AUDIO_OUT=$1
  fi
  if [ $? -eq 0 ]; then
    amixer cset numid=3 "$AUDIO_OUT"
  fi
}

do_resolution() {
  if [ "$INTERACTIVE" = True ]; then
    CMODE=$(get_config_var hdmi_mode $CONFIG)
    CGROUP=$(get_config_var hdmi_group $CONFIG)
    if [ $CMODE -eq 0 ] ; then
      CSET="Default"
    elif [ $CGROUP -eq 2 ] ; then
      CSET="DMT Mode "$CMODE
    else
      CSET="CEA Mode "$CMODE
    fi
    oIFS="$IFS"
    IFS="/"
    if tvservice -d /dev/null | grep -q Nothing ; then
      value="Default/720x480/DMT Mode 4/640x480 60Hz 4:3/DMT Mode 9/800x600 60Hz 4:3/DMT Mode 16/1024x768 60Hz 4:3/DMT Mode 85/1280x720 60Hz 16:9/DMT Mode 35/1280x1024 60Hz 5:4/DMT Mode 51/1600x1200 60Hz 4:3/DMT Mode 82/1920x1080 60Hz 16:9/"
    else
      value="Default/Monitor preferred resolution/"
      value=$value$(tvservice -m CEA | grep progressive | cut -b 12- | sed 's/mode \([0-9]\+\): \([0-9]\+\)x\([0-9]\+\) @ \([0-9]\+\)Hz \([0-9]\+\):\([0-9]\+\), clock:[0-9]\+MHz progressive/CEA Mode \1\/\2x\3 \4Hz \5:\6/' | tr '\n' '/')
      value=$value$(tvservice -m DMT | grep progressive | cut -b 12- | sed 's/mode \([0-9]\+\): \([0-9]\+\)x\([0-9]\+\) @ \([0-9]\+\)Hz \([0-9]\+\):\([0-9]\+\), clock:[0-9]\+MHz progressive/DMT Mode \1\/\2x\3 \4Hz \5:\6/' | tr '\n' '/')
    fi
    RES=$(whiptail --default-item $CSET --menu "Choose screen resolution" 20 60 10 ${value} 3>&1 1>&2 2>&3)
    STATUS=$?
    IFS=$oIFS
    if [ $STATUS -eq 0 ] ; then
      GRS=$(echo "$RES" | cut -d ' ' -f 1)
      MODE=$(echo "$RES" | cut -d ' ' -f 3)
      if [ $GRS = "Default" ] ; then
        MODE=0
      elif [ $GRS = "DMT" ] ; then
        GROUP=2
      else
        GROUP=1
      fi
    fi
  else
    GROUP=$1
    MODE=$2
    STATUS=0
  fi
  if [ $STATUS -eq 0 ]; then
    if [ $MODE -eq 0 ]; then
      clear_config_var hdmi_force_hotplug $CONFIG
      clear_config_var hdmi_group $CONFIG
      clear_config_var hdmi_mode $CONFIG
    else
      set_config_var hdmi_force_hotplug 1 $CONFIG
      set_config_var hdmi_group $GROUP $CONFIG
      set_config_var hdmi_mode $MODE $CONFIG
    fi
    if [ "$INTERACTIVE" = True ]; then
      if [ $MODE -eq 0 ] ; then
        whiptail --msgbox "The resolution is set to default" 20 60 1
      else
        whiptail --msgbox "The resolution is set to $GRS mode $MODE" 20 60 1
      fi
    fi
    if [ $MODE -eq 0 ] ; then
      TSET="Default"
    elif [ $GROUP -eq 2 ] ; then
      TSET="DMT Mode "$MODE
    else
      TSET="CEA Mode "$MODE
    fi
    if [ "$TSET" != "$CSET" ] ; then
      ASK_TO_REBOOT=1
    fi
  fi
}

list_wlan_interfaces() {
  for dir in /sys/class/net/*/wireless; do
    if [ -d "$dir" ]; then
      basename "$(dirname "$dir")"
    fi
  done
}

do_wifi_ssid_passphrase() {
  WPASUPPCONF="/etc/wpa_supplicant/wpa_supplicant.conf"
  INTERFACES="/etc/network/interfaces"
  RESTART_IF=0
  RET=0
  IFACE_LIST="$(list_wlan_interfaces)"
  IFACE="$(echo "$IFACE_LIST" | head -n 1)"

  if [ -z "$IFACE" ]; then
    if [ "$INTERACTIVE" = True ]; then
      whiptail --msgbox "No wireless interface found" 20 60
    fi
    return 1
  fi
  
  sed /etc/dhcp/dhclient.conf -i -e "s/^\(#\|\)timeout .*;/timeout 10;/"
  
  nm_status=$(/bin/systemctl status network-manager)
  if [[ $nm_status = *"is running"* ]] || [[ $nm_status = *"active (running)"* ]]; then
    systemctl stop network-manager && systemctl disable network-manager
    echo "is running"
  fi
 
  IS_IF_DEFINED=$(grep "${IFACE}" $INTERFACES) 
  if [ -z "$IS_IF_DEFINED" ]; then

    cat >> $INTERFACES <<EOF

auto wlan0
iface wlan0 inet dhcp
wpa-conf $WPASUPPCONF
EOF

  fi

  if [ ! -f "$WPASUPPCONF" ]; then
    echo "country=AU" > "$WPASUPPCONF"
    RESTART_IF=1
  fi

  IS_UPDATE_CONFIG_DEFINED=$(grep "update_config" $WPASUPPCONF) 
  IS_UPDATE_CONFIG_ZERO=$(grep "update_config=0" $WPASUPPCONF) 
  if [ -z "$IS_UPDATE_CONFIG_DEFINED" ]; then
    sed -i '1s/^/update_config=1\n/' $WPASUPPCONF
    RESTART_IF=1
  elif [ ! -z "$IS_UPDATE_CONFIG_ZERO" ]; then
    sed -i 's/update_config=0/update_config=1/' $WPASUPPCONF
    echo "UPDATE_CONFIG_IS_ZERO"
    RESTART_IF=1
  fi
  IS_CTRL_DEFINED=$(grep "ctrl_interface" $WPASUPPCONF)
  if [ -z "$IS_CTRL_DEFINED" ] ; then
    sed -i '1s/^/ctrl_interface=DIR=\/var\/run\/wpa_supplicant GROUP=netdev\n/' $WPASUPPCONF
    RESTART_IF=1
  fi

  if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then
    RESTART_IF=1
  fi

  if [ "$RESTART_IF" -eq 1 ]; then
    ifdown $IFACE
    sleep 2
    ifup $IFACE
  fi

  if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then
    if [ "$INTERACTIVE" = True ]; then
      whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60
    fi
    return 1
  fi

  AVAIL_SSID=$(/sbin/iw wlan0 scan|grep SSID)
  whiptail --msgbox "Available WiFi Networks (Tip: use copy and paste):\n\n$AVAIL_SSID" 20 90

  SSID="$1"
  while [ -z "$SSID" ] && [ "$INTERACTIVE" = True ]; do
    SSID=$(whiptail --inputbox "Please enter SSID" 20 60 3>&1 1>&2 2>&3)
    if [ $? -ne 0 ]; then
      return 0
    elif [ -z "$SSID" ]; then
      whiptail --msgbox "SSID cannot be empty. Please try again." 20 60
    fi
  done

  PASSPHRASE="$2"
  while [ "$INTERACTIVE" = True ]; do
    PASSPHRASE=$(whiptail --passwordbox "Please enter passphrase. Leave it empty if none." 20 60 3>&1 1>&2 2>&3)
    if [ $? -ne 0 ]; then
      return 0
    else
      break
    fi
  done

  # Escape special characters for embedding in regex below
  local ssid="$(echo "$SSID" \
   | sed 's;\\;\\\\;g' \
   | sed -e 's;\.;\\\.;g' \
         -e 's;\*;\\\*;g' \
         -e 's;\+;\\\+;g' \
         -e 's;\?;\\\?;g' \
         -e 's;\^;\\\^;g' \
         -e 's;\$;\\\$;g' \
         -e 's;\/;\\\/;g' \
         -e 's;\[;\\\[;g' \
         -e 's;\];\\\];g' \
         -e 's;{;\\{;g'   \
         -e 's;};\\};g'   \
         -e 's;(;\\(;g'   \
         -e 's;);\\);g'   \
         -e 's;";\\\\\";g')"

  wpa_cli -i "$IFACE" list_networks \
   | tail -n +2 | cut -f -2 | grep -P "\t$ssid$" | cut -f1 \
   | while read ID; do
    wpa_cli -i "$IFACE" remove_network "$ID" > /dev/null 2>&1
  done

  ID="$(wpa_cli -i "$IFACE" add_network)"
  wpa_cli -i "$IFACE" set_network "$ID" ssid "\"$SSID\"" 2>&1 | grep -q "OK"
  RET=$((RET + $?))

  if [ -z "$PASSPHRASE" ]; then
    wpa_cli -i "$IFACE" set_network "$ID" key_mgmt NONE 2>&1 | grep -q "OK"
    RET=$((RET + $?))
  else
    wpa_cli -i "$IFACE" set_network "$ID" psk "\"$PASSPHRASE\"" 2>&1 | grep -q "OK"
    RET=$((RET + $?))
  fi

  if [ $RET -eq 0 ]; then
    wpa_cli -i "$IFACE" enable_network "$ID" > /dev/null 2>&1
  else
    wpa_cli -i "$IFACE" remove_network "$ID" > /dev/null 2>&1
    if [ "$INTERACTIVE" = True ]; then
      whiptail --msgbox "Failed to set SSID or passphrase" 20 60
    fi
  fi
  wpa_cli -i "$IFACE" save_config > /dev/null 2>&1

  ## Replace the passphrase with a hash in wpa_supplicant.conf
  PASSHASH="$(wpa_passphrase "$SSID" "$PASSPHRASE"|grep -e "^\spsk"| sed -e 's/^\s*//')"

  sed /etc/wpa_supplicant/wpa_supplicant.conf -i -e "s/psk=\"$PASSPHRASE\"/$PASSHASH/"
  echo "$IFACE_LIST" | while read IFACE; do
    wpa_cli -i "$IFACE" reconfigure > /dev/null 2>&1
  done
  
  ifdown $IFACE
  sleep 2
  ifup $IFACE

  return $RET
}

do_swap_nexmon_firmware() {
  local is_43430_nexmon="$(strings "/lib/firmware/brcm/brcmfmac43430-sdio.bin"|grep nexmon)"
  if [ ! -f /lib/firmware/brcm/brcmfmac43430-sdio.nexmon.bin ]; then
    if [ ! "" == "$is_43430_nexmon" ]; then
      cp -f /lib/firmware/brcm/brcmfmac43430-sdio.bin /lib/firmware/brcm/brcmfmac43430-sdio.nexmon.bin 
    else
      whiptail --msgbox "No nexmon firmware found.\nInstall the Re4son-Kernel and try again." 20 60
      return
    fi 
  fi
  if [ ! -f /lib/firmware/brcm/brcmfmac43430-sdio.rpi.bin ]; then
    wget https://raw.githubusercontent.com/RPi-Distro/firmware-nonfree/master/brcm/brcmfmac43430-sdio.bin -O /lib/firmware/brcm/brcmfmac43430-sdio.rpi.bin
      if [ ! -f /lib/firmware/brcm/brcmfmac43430-sdio.rpi.bin ]; then
         whiptail --msgbox "No OEM firmware found.\n Download OEM firmware to /lib/firmware/brcm/brcmfmac43430-sdio.rpi.bin and try again." 20 60
         return
      fi
  fi
  if [ ! "" == "$is_43430_nexmon" ]; then
    whiptail --yesno "Nexmon firmware is currently installed. Would you like to replace it with OEM firmware?" $DEFAULT 20 60 2
    RET=$?
    if [ $RET -eq 0 ]; then
      cp -f /lib/firmware/brcm/brcmfmac43430-sdio.rpi.bin /lib/firmware/brcm/brcmfmac43430-sdio.bin
      whiptail --msgbox "OEM firmware successfully installed." 20 60
    fi
  else
    whiptail --yesno "OEM firmware is currently installed. Would you like to replace it with nexmon firmware?" $DEFAULT 20 60 2
    RET=$?
    if [ $RET -eq 0 ]; then
      cp -f /lib/firmware/brcm/brcmfmac43430-sdio.nexmon.bin /lib/firmware/brcm/brcmfmac43430-sdio.bin
      whiptail --msgbox "Nexmon firmware successfully installed." 20 60
    fi
  fi
  rmmod brcmfmac
  modprobe brcmfmac
  return 
}

do_swap_nexmon_firmware_plus() {
  local is_43455_nexmon="$(strings "/lib/firmware/brcm/brcmfmac43455-sdio.bin"|grep nexmon)"
  if [ ! -f /lib/firmware/brcm/brcmfmac43455-sdio.nexmon.bin ]; then
    if [ ! "" == "$is_43455_nexmon" ]; then
      cp -f /lib/firmware/brcm/brcmfmac43455-sdio.bin /lib/firmware/brcm/brcmfmac43455-sdio.nexmon.bin 
    else
      whiptail --msgbox "No nexmon firmware found.\nInstall the Re4son-Kernel and try again." 20 60
      return
    fi 
  fi
  if [ ! -f /lib/firmware/brcm/brcmfmac43455-sdio.rpi.bin ]; then
    wget https://raw.githubusercontent.com/RPi-Distro/firmware-nonfree/master/brcm/brcmfmac43455-sdio.bin -O /lib/firmware/brcm/brcmfmac43455-sdio.rpi.bin
      if [ ! -f /lib/firmware/brcm/brcmfmac43455-sdio.rpi.bin ]; then
         whiptail --msgbox "No OEM firmware found.\n Download OEM firmware to /lib/firmware/brcm/brcmfmac43455-sdio.rpi.bin and try again." 20 60
         return
      fi
  fi
  if [ ! "" == "$is_43455_nexmon" ]; then
    whiptail --yesno "Nexmon firmware is currently installed. Would you like to replace it with OEM firmware?" $DEFAULT 20 60 2
    RET=$?
    if [ $RET -eq 0 ]; then
      cp -f /lib/firmware/brcm/brcmfmac43455-sdio.rpi.bin /lib/firmware/brcm/brcmfmac43455-sdio.bin
      whiptail --msgbox "OEM firmware successfully installed." 20 60
    fi
  else
    whiptail --yesno "OEM firmware is currently installed. Would you like to replace it with nexmon firmware?" $DEFAULT 20 60 2
    RET=$?
    if [ $RET -eq 0 ]; then
      cp -f /lib/firmware/brcm/brcmfmac43455-sdio.nexmon.bin /lib/firmware/brcm/brcmfmac43455-sdio.bin
      whiptail --msgbox "Nexmon firmware successfully installed." 20 60
    fi
  fi
  rmmod brcmfmac
  modprobe brcmfmac
  return 
}

do_finish() {
##  disable_kalipi_config_at_boot
  if [ $ASK_TO_REBOOT -eq 1 ]; then
    whiptail --yesno "Would you like to reboot now?" 20 60 2
    if [ $? -eq 0 ]; then # yes
      sync
      reboot
    fi
  fi
  exit 0
}

# $1 = filename, $2 = key name
get_json_string_val() {
  sed -n -e "s/^[[:space:]]*\"$2\"[[:space:]]*:[[:space:]]*\"\(.*\)\"[[:space:]]*,$/\1/p" $1
}

# TODO: This is probably broken
do_apply_os_config() {
  [ -e /boot/os_config.json ] || return 0
  NOOBSFLAVOUR=$(get_json_string_val /boot/os_config.json flavour)
  NOOBSLANGUAGE=$(get_json_string_val /boot/os_config.json language)
  NOOBSKEYBOARD=$(get_json_string_val /boot/os_config.json keyboard)

  if [ -n "$NOOBSFLAVOUR" ]; then
    printf "Setting flavour to %s based on os_config.json from NOOBS. May take a while\n" "$NOOBSFLAVOUR"

    printf "Unrecognised flavour. Ignoring\n"
  fi

  # TODO: currently ignores en_gb settings as we assume we are running in a 
  # first boot context, where UK English settings are default
  case "$NOOBSLANGUAGE" in
    "en")
      if [ "$NOOBSKEYBOARD" = "gb" ]; then
        DEBLANGUAGE="" # UK english is the default, so ignore
      else
        DEBLANGUAGE="en_US.UTF-8"
      fi
      ;;
    "de")
      DEBLANGUAGE="de_DE.UTF-8"
      ;;
    "fi")
      DEBLANGUAGE="fi_FI.UTF-8"
      ;;
    "fr")
      DEBLANGUAGE="fr_FR.UTF-8"
      ;;
    "hu")
      DEBLANGUAGE="hu_HU.UTF-8"
      ;;
    "ja")
      DEBLANGUAGE="ja_JP.UTF-8"
      ;;
    "nl")
      DEBLANGUAGE="nl_NL.UTF-8"
      ;;
    "pt")
      DEBLANGUAGE="pt_PT.UTF-8"
      ;;
    "ru")
      DEBLANGUAGE="ru_RU.UTF-8"
      ;;
    "zh_CN")
      DEBLANGUAGE="zh_CN.UTF-8"
      ;;
    *)
      printf "Language '%s' not handled currently. Run sudo kalipi-config to set up" "$NOOBSLANGUAGE"
      ;;
  esac

  if [ -n "$DEBLANGUAGE" ]; then
    printf "Setting language to %s based on os_config.json from NOOBS. May take a while\n" "$DEBLANGUAGE"
    do_change_locale "$DEBLANGUAGE"
  fi

  if [ -n "$NOOBSKEYBOARD" -a "$NOOBSKEYBOARD" != "gb" ]; then
    printf "Setting keyboard layout to %s based on os_config.json from NOOBS. May take a while\n" "$NOOBSKEYBOARD"
    do_configure_keyboard "$NOOBSKEYBOARD"
  fi
  return 0
}

nonint() {
  "$@"
}

#
# Command line options for non-interactive use
#
for i in $*
do
  case $i in
  --version)
    INTERACTIVE=False
    print_version
    exit 1
    ;;
  --memory-split)
    OPT_MEMORY_SPLIT=GET
    printf "Not currently supported\n"
    exit 1
    ;;
  --memory-split=*)
    OPT_MEMORY_SPLIT=`echo $i | sed 's/[-a-zA-Z0-9]*=//'`
    printf "Not currently supported\n"
    exit 1
    ;;
  --expand-rootfs)
    INTERACTIVE=False
    do_expand_rootfs
    printf "Please reboot\n"
    exit 0
    ;;
  --apply-os-config)
    INTERACTIVE=False
    do_apply_os_config
    exit $?
    ;;
  nonint)
    INTERACTIVE=False
    "$@"
    exit $?
    ;;
  *)
    # unknown option
    ;;
  esac
done

if [ "GET" = "${OPT_MEMORY_SPLIT:-}" ]; then
  set -u # Fail on unset variables
  get_current_memory_split
  echo $CURRENT_MEMSPLIT
  exit 0
fi

# Everything else needs to be run as root
if [ $(id -u) -ne 0 ]; then
  printf "\nProgram must be run as root. Try 'sudo kalipi-config'\n\n"
  exit 1
fi

if [ -n "${OPT_MEMORY_SPLIT:-}" ]; then
  set -e # Fail when a command errors
  set_memory_split "${OPT_MEMORY_SPLIT}"
  exit 0
fi
# Check dependencies
PROGRAMS=("whiptail" "parted" "lua" "pstree" "amixer")
PACKAGES=("whiptail" "parted" "lua5.1" "psmisc" "alsa-utils")
missingprogs=""
missingpkgs=""
for i in "${!PROGRAMS[@]}"; do
  if [ $(check_bin ${PROGRAMS[$i]}) -eq 0 ]; then
    missingpkgs="${missingpkgs}${PACKAGES[$i]} "
  fi
done
if [ "" != "$missingpkgs" ]; then
  printf "\nThe following packages are missing:         $missingpkgs\n"
  printf "Please install them before continuing, i.e.:\n"
  printf "\nsudo apt install $missingpkgs\n\n"
  exit 1
fi
# And we want /boot to be mounted
if ! grep -q boot /proc/mounts; then
    mount /boot
fi
if ! grep -q boot /proc/mounts; then
    printf "\n/boot must be mounted. Try 'mount /boot'\n\n"
    exit 1 
fi

set_sudo_user

do_internationalisation_menu() {
  calc_wt_size
  FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Localisation Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \
    "I1 Change Locale" "Set up language and regional settings to match your location" \
    "I2 Change Timezone" "Set up timezone to match your location" \
    "I3 Change Keyboard Layout" "Set the keyboard layout to match your keyboard" \
    "I4 Change Wi-fi Country" "Set the legal channels used in your country" \
    3>&1 1>&2 2>&3)
  RET=$?
  if [ $RET -eq 1 ]; then
    return 0
  elif [ $RET -eq 0 ]; then
    case "$FUN" in
      I1\ *) do_change_locale ;;
      I2\ *) do_change_timezone ;;
      I3\ *) do_configure_keyboard ;;
      I4\ *) do_wifi_country ;;
      *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
    esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
  fi
}

do_interface_menu() {
  calc_wt_size
  FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Interfacing Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \
    "P1 Camera" "Enable/Disable connection to the Raspberry Pi Camera" \
    "P2 SSH" "Enable/Disable remote command line access to your Pi using SSH" \
    "P3 SPI" "Enable/Disable automatic loading of SPI kernel module" \
    "P4 I2C" "Enable/Disable automatic loading of I2C kernel module" \
    "P5 Serial" "Enable/Disable shell and kernel messages on the serial connection" \
    "P6 1-Wire" "Enable/Disable one-wire interface" \
    "P7 Remote GPIO" "Enable/Disable remote access to GPIO pins" \
    3>&1 1>&2 2>&3)
  RET=$?
  if [ $RET -eq 1 ]; then
    return 0
  elif [ $RET -eq 0 ]; then
    case "$FUN" in
      P1\ *) do_camera ;;
      P2\ *) do_ssh ;;
      P3\ *) do_spi ;;
      P4\ *) do_i2c ;;
      P5\ *) do_serial ;;
      P6\ *) do_onewire ;;
      P7\ *) do_rgpio ;;
      *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
    esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
  fi
}

do_advanced_menu() {
  calc_wt_size
  FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Advanced Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \
    "A1 Expand Filesystem" "Ensures that all of the SD card storage is available to the OS" \
    "A2 Overscan" "You may need to configure overscan if black bars are present on display" \
    "A3 Memory Split" "Change the amount of memory made available to the GPU" \
    "A4 Audio" "Force audio out through HDMI or 3.5mm jack" \
    "A5 Resolution" "Set a specific screen resolution" \
    "A6 Pixel Doubling" "Enable/Disable 2x2 pixel mapping" \
    "A7 GL Driver" "Enable/Disable experimental desktop GL driver" \
    3>&1 1>&2 2>&3)
  RET=$?
  if [ $RET -eq 1 ]; then
    return 0
  elif [ $RET -eq 0 ]; then
    case "$FUN" in
      A1\ *) do_expand_rootfs ;;
      A2\ *) do_overscan ;;
      A3\ *) do_memory_split ;;
      A4\ *) do_audio ;;
      A5\ *) do_resolution ;;
      A6\ *) do_pixdub ;;
      A7\ *) do_gldriver ;;
      *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
    esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
  fi
}

do_boot_menu() {
  calc_wt_size
  if is_live ; then
    FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Boot Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \
      "B1 Desktop / CLI" "Choose whether to boot into a desktop environment or the command line" \
      "B2 Wait for Network at Boot" "Choose whether to wait for network connection during boot" \
      3>&1 1>&2 2>&3)
  else
    FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Boot Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \
      "B1 Desktop / CLI" "Choose whether to boot into a desktop environment or the command line" \
      "B2 Wait for Network at Boot" "Choose whether to wait for network connection during boot" \
      3>&1 1>&2 2>&3)
  fi
  RET=$?
  if [ $RET -eq 1 ]; then
    return 0
  elif [ $RET -eq 0 ]; then
    case "$FUN" in
      B1\ *) do_boot_behaviour ;;
      B2\ *) do_boot_wait ;;
      *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
    esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
  fi
}

do_network_menu() {
  calc_wt_size
  FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Network Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \
    "N1 Hostname" "Set the visible name for this Pi on a network" \
    "N2 Wi-fi" "Enter SSID and passphrase" \
    "N3 Network interface names" "Enable/Disable predictable network interface names" \
    "N4 Swap 43430 firmware" "Swap nexmon firmware and OEM firmware for Raspberry Pi 0W/3" \
    "N5 Swap 43455 firmware" "Swap nexmon firmware and OEM firmware for Raspberry Pi 3+" \
    3>&1 1>&2 2>&3)
  RET=$?
  if [ $RET -eq 1 ]; then
    return 0
  elif [ $RET -eq 0 ]; then
    case "$FUN" in
      N1\ *) do_hostname ;;
      N2\ *) do_wifi_ssid_passphrase ;;
      N3\ *) do_net_names ;;
      N4\ *) do_swap_nexmon_firmware ;;
      N5\ *) do_swap_nexmon_firmware_plus ;;
      *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
    esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
  fi
}

#
# Interactive use loop
#
if [ "$INTERACTIVE" = True ]; then
  [ -e $CONFIG ] || touch $CONFIG
  calc_wt_size
  while true; do
    if is_pi ; then
      FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --backtitle "$(cat /proc/device-tree/model| tr -d '\0')" --menu "Setup Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Finish --ok-button Select \
        "01 Change User Password" "Change password for any user" \
        "02 Network Options" "Configure network settings" \
        "03 Boot Options" "Configure options for start-up" \
        "04 Localisation Options" "Set up language and regional settings to match your location" \
        "05 Interfacing Options" "Configure connections to peripherals" \
        "06 Overclock" "Configure overclocking for your Pi" \
        "07 Advanced Options" "Configure advanced settings" \
        "08 Kali-Pi TFT Config" "Run the kalipi-tft-config tool to set up a tft screen" \
        "09 About kalipi-config" "Information about this configuration tool" \
        3>&1 1>&2 2>&3)
    else
      FUN=$(whiptail --title "Kali-Pi Software Configuration Tool (kalipi-config)" --menu "Setup Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Finish --ok-button Select \
        "01 Change User Password" "Change password for the current user" \
        "02 Network Options" "Configure network settings" \
        "03 Boot Options" "Configure options for start-up" \
        "04 Localisation Options" "Set up language and regional settings to match your location" \
        "05 SSH" "Enable/Disable remote command line access to your PC using SSH" \
        "06 Pixel Doubling" "Enable/Disable 2x2 pixel mapping" \
        "08 Kali-Pi TFT Config" "Run the kalipi-tft-config tool to set up a tft screen" \
        "09 About kalipi-config" "Information about this configuration tool" \
        3>&1 1>&2 2>&3)
    fi
    RET=$?
    if [ $RET -eq 1 ]; then
      do_finish
    elif [ $RET -eq 0 ]; then
      if is_pi ; then
        case "$FUN" in
          01\ *) do_change_pass ;;
          02\ *) do_network_menu ;;
          03\ *) do_boot_menu ;;
          04\ *) do_internationalisation_menu ;;
          05\ *) do_interface_menu ;;
          06\ *) do_overclock ;;
          07\ *) do_advanced_menu ;;
          08\ *) do_kalipi_tft_config;;
          09\ *) do_about ;;
          *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
        esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
      else
        case "$FUN" in
          01\ *) do_change_pass ;;
          02\ *) do_network_menu ;;
          03\ *) do_boot_menu ;;
          04\ *) do_internationalisation_menu ;;
          05\ *) do_ssh ;;
          06\ *) do_pixdub ;;
          08\ *) do_kalipi_tft_config;;
          09\ *) do_about ;;
          *) whiptail --msgbox "Program error: unrecognized option" 20 60 1 ;;
        esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1
      fi
    else
      exit 1
    fi
  done
fi
