#!/bin/bash
#
# Copyright (c) Authors: https://www.armbian.com/authors
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.

# read distribution status
# shellcheck source=/dev/null
[[ -f /etc/lsb-release ]] && . /etc/lsb-release
[[ -f /etc/os-release ]] && . /etc/os-release
[[ -z "$DISTRIB_CODENAME" ]] && DISTRIB_CODENAME="${VERSION_CODENAME}"
[[ -n "$DISTRIB_CODENAME" && -f /etc/armbian-distribution-status ]] && DISTRIBUTION_STATUS=$(grep "^$DISTRIB_CODENAME" /etc/armbian-distribution-status | cut -d"=" -f2 | cut -d";" -f1)

. /etc/armbian-release

check_abort() {

	echo -e "\nDisabling user account creation procedure\n"
	rm -f /root/.not_logged_in_yet
	if [[ ${USER_SHELL} == zsh ]]; then
		printf "\nYou selected \e[0;91mZSH\x1B[0m as your default shell. If you want to use it right away, please logout and login! \n\n"
	fi
	trap - INT
	exit 0

}

mask2cidr() {
	nbits=0
	IFS=.
	for dec in $1 ; do
		case $dec in
			255) let nbits+=8;;
			254) let nbits+=7;;
			252) let nbits+=6;;
			248) let nbits+=5;;
			240) let nbits+=4;;
			224) let nbits+=3;;
			192) let nbits+=2;;
			128) let nbits+=1;;
			0);;
			*) echo "Error: $dec is not recognised"; exit 1
		esac
	done
	echo "$nbits"
}

createYAML() {
   local YAML="network:\n"
    YAML+="  $DEVTYPE:\n"
    YAML+="    $DEVICE_NAME:\n"
	if [[ "${PRESET_NET_USE_STATIC}" == 1 ]]; then
		YAML+="      addresses:\n"
		YAML+="        - $PRESET_NET_STATIC_IP/$PRESET_NET_STATIC_MASK\n"
		if [[ -n "${PRESET_NET_STATIC_GATEWAY}" ]]; then   YAML+="      routes:\n";fi
		if [[ -n "${PRESET_NET_STATIC_GATEWAY}" ]]; then   YAML+="        - to: default\n";fi
		if [[ -n "${PRESET_NET_STATIC_GATEWAY}" ]]; then   YAML+="          via: ${PRESET_NET_STATIC_GATEWAY}\n";fi
		if [[ -n "${PRESET_NET_STATIC_DNS}" ]]; then       YAML+="      nameservers:\n"; fi
		if [[ -n "${PRESET_NET_STATIC_DNS}" ]]; then       YAML+="        addresses: [$PRESET_NET_STATIC_DNS]\n"; fi
	else
		YAML+="      dhcp4: yes\n"
		YAML+="      dhcp6: yes\n"
	fi
	if [[ "${PRESET_NET_WIFI_ENABLED}" == 1 ]]; then
		if [[ -n "${PRESET_NET_WIFI_COUNTRYCODE}" ]]; then YAML+="      regulatory-domain: $PRESET_NET_WIFI_COUNTRYCODE\n"; fi
		if [[ -n "${PRESET_NET_WIFI_SSID}" ]]; then        YAML+="      access-points:\n"; fi
		if [[ -n "${PRESET_NET_WIFI_SSID}" ]]; then        YAML+="        \"$PRESET_NET_WIFI_SSID\":\n"; fi
		if [[ -n "${PRESET_NET_WIFI_KEY}" ]]; then         YAML+="          password: \"$PRESET_NET_WIFI_KEY\"\n" ; fi
	fi
	printf "%s" "$YAML"
}

do_firstrun_automated_network_configuration()
{
	#-----------------------------------------------------------------------------
	#Config FP
	local fp_config='/root/.not_logged_in_yet'

	#-----------------------------------------------------------------------------
	#Grab user requested settings
	if [[ -f $fp_config ]]; then

		# Convert line endings to Unix from Dos
		sed -i $'s/\r$//' "$fp_config"

		# check syntax
		bash -n "$fp_config" || return

		# Load vars directly from file
		source "$fp_config"

		# Obtain backward configuration compatibility
		PRESET_NET_STATIC_DNS=${PRESET_NET_STATIC_DNS// /,}
		PRESET_NET_STATIC_MASK=$(mask2cidr $PRESET_NET_STATIC_MASK)

		#-----------------------------------------------------------------------------
		# Set Network
		if [[ $PRESET_NET_CHANGE_DEFAULTS == 1 ]]; then

			# - Get name of 1st available ethernet and wifi adapter
			eth_index="$(ip link | awk -F: '$0 !~ "lo|vir|wl|^[^0-9]"{print $2;getline}' | sed 's/^[ \t]*//' | grep "^e" | head -1)"
			wlan_index="$(iw dev | awk '$1=="Interface"{print $2}' | head -n 1)"

			local CONFIG_NAME="-dhcp"
			# for static IP we only append settings
			if [[ $PRESET_NET_USE_STATIC == 1 ]]; then
				local CONFIG_NAME="-static"
			fi

			# at least one device has to exits
			if [[ -n $eth_index || -n $wlan_index ]]; then

				# - Wifi enable
				if [[ $PRESET_NET_WIFI_ENABLED == 1 ]]; then

						DEVICE_NAME=${wlan_index}
						DEVTYPE=wifis
						echo -e "$(createYAML)" > /etc/netplan/30-${DEVTYPE}${CONFIG_NAME}.yaml
						chmod 600 /etc/netplan/30-${DEVTYPE}${CONFIG_NAME}.yaml
						#Enable Wlan, disable Eth
						PRESET_NET_ETHERNET_ENABLED=0
						netplan apply > /dev/null 2>&1

				# - Ethernet enable
				elif [[ $PRESET_NET_ETHERNET_ENABLED == 1 ]]; then

						# remove dhcp config
						rm -f /etc/netplan/10-dhcp-all-interfaces.yaml

						DEVICE_NAME=${eth_index}
						DEVTYPE=ethernets
						echo -e "$(createYAML)" > /etc/netplan/30-${DEVTYPE}${CONFIG_NAME}.yaml
						chmod 600 /etc/netplan/30-${DEVTYPE}${CONFIG_NAME}.yaml
						# Enable Eth, disable Wlan
						PRESET_NET_WIFI_ENABLED=0
						netplan apply > /dev/null 2>&1
				fi

			fi
		fi
	fi
} #do_firstrun_automated_network_configuration

# Try to retrieve the local IP address to display
get_local_ip_addr() {
	# How many seconds to wait at maximum to find out the local IP address
	local ip_wait_seconds_counter=6
	local local_device_ip=""
	local retry_message=""

	while [[ -z "$local_device_ip" ]] && [ ${ip_wait_seconds_counter} -ge 0 ]; do
		local_device_ip=$(ip -4 addr show scope global | grep inet | awk '{print $2}' | cut -d/ -f1 | awk '{$1=$1}1' FS='\n' OFS=',' RS=)

		# Set retry message if some retries are left, but no IP address has been found yet
		if [[ -z "$local_device_ip" ]] && [[ $ip_wait_seconds_counter -gt 0 ]]; then
			retry_message="\e[1m\e[97mWaiting for local connection!\x1B[0m Retrying... (${ip_wait_seconds_counter})"
		# Empty retry message if IP address has been found
		elif [[ -n "$local_device_ip" ]]; then
			retry_message=""
		# Set timeout message if no retries are left and no IP address has been found
		else
			retry_message="\e[1m\e[31mNetwork connection timeout!\x1B[0m"
		fi

		# Display the message
		echo -e "\e[1A\e[KIP address: \x1B[92m${local_device_ip}\x1B[0m ${retry_message}"

		# Wait for 1 second if the IP has not yet been found
		if [[ -z "$local_device_ip" ]]; then
			sleep 1
		fi

		ip_wait_seconds_counter=$((ip_wait_seconds_counter - 1))
	done
}

read_password() {

	unset password
	unset charcount
	prompt="$1 password: "

	stty -echo

	charcount=0
	while IFS= read -p "$prompt" -r -s -n 1 char; do
		if [[ $char == $'\0' ]]; then
			break
		fi

		# Handle backspace
		if [[ $char == $'\177' ]]; then
			if [ $charcount -gt 0 ]; then
				charcount=$((charcount - 1))
				prompt=$'\b \b'
				password="${password%?}"
			else
				prompt=''
			fi
		else
			charcount=$((charcount + 1))
			prompt='*'
			password+="$char"
		fi
	done

	stty echo

}

set_shell() {

	readarray -t optionsAudits <<< "$(grep "zsh\|/bash" /etc/shells | sed 's/\/bin\///g' | sed 's/\/usr//g' | uniq)"
	USER_SHELL="bash"

	if [[ "${#optionsAudits[@]}" -gt 1 ]]; then
		while :; do
			while [[ ! "${reply}" =~ ^(1|2)$ ]]; do
				i=1
				echo -e "\nChoose default system command shell:\n"
				for o in "${optionsAudits[@]}"; do
					echo "$i) $o"
					((i++)) || true
				done
				if [ -z $PRESET_USER_SHELL ];then
					read -r reply
				else
					reply=1
					for index in "${!optionsAudits[@]}"; do
						if [[ "${optionsAudits[$index]}" == "$PRESET_USER_SHELL" ]]; then
							reply=$(($index + 1))
							break
						fi
					done
				fi
			done
			case $reply in
				"1" | "${optionsAudits[0]}")
					USER_SHELL="${optionsAudits[0]}"
					break
					;;
				"2" | "${optionsAudits[1]}")
					USER_SHELL="${optionsAudits[1]}"
					break
					;;
				*)
					USER_SHELL="${optionsAudits[0]}"
					break
					;;
			esac
		done
	# Display shell selection only if needs to be selected
	echo -e "\nShell: \x1B[92m${USER_SHELL^^}\x1B[0m"
	fi

	SHELL_PATH=$(grep "/$USER_SHELL$" /etc/shells | tail -1)
	chsh -s "$(grep -iF "/$USER_SHELL" /etc/shells | tail -1)"

	# change shell for future users
	sed -i "s|^SHELL=.*|SHELL=${SHELL_PATH}|" /etc/default/useradd
	sed -i "s|^DSHELL=.*|DSHELL=${SHELL_PATH}|" /etc/adduser.conf

}

set_timezone_and_locales() {

	# Grab this machine's public IP address
	PUBLIC_IP=$(curl --max-time 5 -s https://ipinfo.io/ip)

	# Check if we have wireless adaptor
	WIFI_DEVICE=$(LC_ALL=C iw dev | awk '$1=="Interface"{print $2}' 2> /dev/null)

	if [ -z "$PUBLIC_IP" ]; then

		# ask for connecting to wireless if wifi device is found
		if [[ -n "$WIFI_DEVICE" ]]; then
			echo -e "Internet connection was \x1B[91mnot detected\x1B[0m."
			echo ""
			unset response
			while [[ ! "${response}" =~ ^(Y|y|N|n)$ ]]; do
				if [ -z $PRESET_CONNECT_WIRELESS ];then
					read -r -p "Connect via wireless? [Y/n] " response
					response=${response:-Y}
				else
					response=n
				fi
			done
			if [[ "${response}" =~ ^(Y|y)$ ]]; then

				# We could have multiple devices
				if (( $(grep -c . <<<"$WIFI_DEVICE") > 1 )); then
					scanning=0
					while [[ ${scanning} -lt 3 ]]; do
						scanning=$(( scanning + 1 ))
						echo -e "\nMultiple wireless adaptors detected. Choose primary:\n"
						WIFI_DEVICES=($(printf '%s\n' "${WIFI_DEVICE[@]}" | sed 's/^[ \t]*//' | sed 's/"//g' | sed 's/ESSID://' | awk 'BEGIN{FS=OFS=","} {$NF=++count OFS $NF} 1'))
						for str in ${WIFI_DEVICES[@]}; do echo $str | sed "s/,/ \t /g"; done
						echo ""
						read -r -p "Enter a number of wireles adaptor: " input
						if [[ "$input" =~ ^[0-9]{,2}$ && -n "$input" ]] ; then break; fi
					done
					[[ -z $input ]] && input=1
					WIFI_DEVICE=$(echo ${WIFI_DEVICES[$input-1]} | cut -d"," -f2)
				fi

				# bring up wifi device (not done by networkd, only by NetworkManager)
				ip link set ${WIFI_DEVICE} up
				# get list of wireless networks
				scanning=0
				broken=1
				while [[ ${scanning} -lt 3 ]]; do
					sleep 0.5
					scanning=$(( scanning + 1 ))
					readarray -t ARRAY < <(iw dev ${WIFI_DEVICE} scan 2> /dev/null | egrep 'SSID' | sed 's/^[ \t]*//' | sed 's/"//g' | sed 's/SSID: //' | sed '/^$/d' | sort | uniq | awk 'BEGIN{FS=OFS=","} {$NF=++count OFS $NF} 1')
					if [[ ${#ARRAY[@]} -gt 0 ]]; then broken=0; break; fi
				done
				# wifi can also fail
				if [[ ${broken} == 1 ]]; then
					echo -e "\nWireless connection was \x1B[91mnot detected\x1B[0m.\n"
				else
					echo -e "\nDetected wireless networks:\n"
					scanning=0
					broken=1
					while [[ ${scanning} -lt 3 ]]; do
						scanning=$(( scanning + 1 ))
						while [[ 1 ]] ; do
							for str in "${ARRAY[@]}"; do echo $str | sed "s/,/ \t /"; done
							echo ""
							read -r -p "Enter a number of SSID: " input
							if [[ "$input" =~ ^[0-9]{,2}$ ]] ; then break; fi
						done
						# get password
						while [[ -n "${input}" ]] ; do
							SSID=$(echo ${ARRAY[$input-1]} | cut -d"," -f2-)
							echo ""
							read -r -p "Enter a password for ${SSID}: " password
							break
						done

						# generate config
						cat <<- EOF > /etc/netplan/30-wifis-dhcp.yaml
						# Created by Armbian firstlogin script
						network:
						  wifis:
						    ${WIFI_DEVICE}:
						      dhcp4: yes
						      dhcp6: yes
						      access-points:
						        "$SSID":
						         password: "${password}"
						EOF
						chmod 600 /etc/netplan/30-wifis-dhcp.yaml

						# apply to netplan
						systemctl daemon-reload
						netplan apply --timeout 0 2>/dev/null

						# wireless link probing
						pinging=10
						broken=1
						WIRELESSLINK=""
						echo ""
						while [[ ${pinging} -gt 1 && -n "${input}" && -n "${password}" ]]; do
							pinging=$(( pinging - 1 ))
							printf "\rProbing wireless link ($pinging)"
							WIRELESSLINK=$(iw "${WIFI_DEVICE}" link 2> /dev/null | grep "$SSID")
							sleep 2
							# exit if connection is suffesful
							if [[ "${WIRELESSLINK}" == *$SSID* ]]; then
								broken=0
								break
							fi
						done

						if [[ ${broken} == 1 ]]; then
							echo -e "\n\nWireless link was \x1B[91mnot detected\x1B[0m. Wrong password or weak signal."
						fi
						# get public IP probing
						broken=1
						pinging=10

						while [[ ${pinging} -gt 1 && -n "${input}" && -n "${password}" && "${WIRELESSLINK}" == *$SSID* ]]; do
							pinging=$(( pinging - 1 ))
							printf "\rProbing internet connection ($pinging)"
							PUBLIC_IP=$(curl --max-time 5 -s https://ipinfo.io/ip)
							if [[ -n "$PUBLIC_IP" ]]; then
								broken=0
								break
							else
								sleep 5
							fi
						done
						echo ""

						if [[ ${broken} == 0 ]]; then
							break
						fi
					done

						if [[ ${broken} == 1 ]]; then
							echo -e "\n\x1B[91mUnable to connect to Access Point\x1B[0m.\n"
							rm -f /etc/netplan/30-wifis-dhcp.yaml
							netplan apply --timeout 0 2>/dev/null
							systemctl daemon-reload
						fi

				fi # detected or not detected wireless network
			fi
			echo ""
		fi
	fi

	# Grab IP once again if not found
	sleep 3
	[[ -z "$PUBLIC_IP" && -n "$WIFI_DEVICE" ]] && PUBLIC_IP=$(curl --max-time 5 -s https://ipinfo.io/ip)

	# Call the geolocation API and capture the output
	RES=$(
		curl --max-time 5 -s "http://ipwhois.app/json/${PUBLIC_IP}" |
			jq '.timezone, .country, .country_code' |
			while read -r TIMEZONE; do
				read -r COUNTRY
				echo "${TIMEZONE},${COUNTRY},${COUNTRYCODE}" | tr --delete '"\n'
			done
	)

	TZDATA=$(echo "${RES}" | cut -d"," -f1)
	CCODE=$(echo "${RES}" | cut -d"," -f3 | xargs)

	unset response
	while [[ ! "${response}" =~ ^(Y|y|N|n)$ ]]; do
		if [ -z "${SET_LANG_BASED_ON_LOCATION}" ] && [ -n "${TZDATA}" ];then
			echo -e "Detected timezone: \x1B[92m$TZDATA\x1B[0m"
			echo ""
			read -r -p "Set user language based on your location? [Y/n] " response
			response=${response:-Y}
		else
			response=$SET_LANG_BASED_ON_LOCATION
			break
		fi
	done
	# change it only if we have a match and if we agree
	if [[ "${response}" =~ ^(N|n)$ ]]; then
		unset CCODE TZDATA
	fi

	LOCALES=$(grep territory /usr/share/i18n/locales/* | grep _"$CCODE" | cut -d ":" -f 1 | cut -d "/" -f 6 |
		xargs -I{} grep {} /usr/share/i18n/SUPPORTED | grep "UTF-8$" | cut -d " " -f 1)
	# UTF8 is not present everywhere so check again in case it returns empty value
	[[ -z "$LOCALES" ]] && LOCALES=$(grep territory /usr/share/i18n/locales/* | grep _"$CCODE" | cut -d ":" -f 1 | cut -d "/" -f 6 |
		xargs -I{} grep {} /usr/share/i18n/SUPPORTED | cut -d " " -f 1)
	readarray -t options <<< "${LOCALES}"

	if [ -z $PRESET_LOCALE ];then
		# when having more locales, prompt for choosing one
		if [[ "${#options[@]}" -gt 1 ]]; then
			options+=("Skip generating locales")
			echo -e "\nAt your location, more locales are possible:\n"
			PS3='Please enter your choice:'
			select opt in "${options[@]}"; do
				if [[ " ${options[*]} " == *" ${opt} "* ]]; then
					LOCALES=${opt}
					break
				fi
			done
		fi
	else
		LOCALES=$PRESET_LOCALE
	fi

	if [[ "${LOCALES}" != *Skip* ]]; then

		if [ -z $PRESET_TIMEZONE ];then
			# if TZDATA was not detected, we need to select one
			if [[ -z ${TZDATA} ]]; then
				TZDATA=$(tzselect | tail -1)
			fi
			echo ""
		else
			TZDATA=$PRESET_TIMEZONE
		fi

		timedatectl set-timezone "${TZDATA}"
		dpkg-reconfigure --frontend=noninteractive tzdata > /dev/null 2>&1

		# change default locales
		sed -i "s/=.*/=$(echo ${LOCALES} | cut -d" " -f1)/g" /etc/default/locale

		# generate locales
		sed -i 's/# '"${LOCALES}"'/'"${LOCALES}"'/' /etc/locale.gen
		echo -e "Generating locales: \x1B[92m${LOCALES}\x1B[0m"
		locale-gen "${LOCALES}" > /dev/null 2>&1

		# setting detected locales only for user
		{
			echo "export LC_ALL=$LOCALES"
			echo "export LANG=$LOCALES"
			echo "export LANGUAGE=$LOCALES"
		} >> /home/"$RealUserName"/.bashrc
		{
			echo "export LC_ALL=$LOCALES"
			echo "export LANG=$LOCALES"
			echo "export LANGUAGE=$LOCALES"
		} >> /home/"$RealUserName"/.xsessionrc

	fi
}

add_profile_sync_settings() {
	if [[ ! -f /usr/bin/psd ]]; then
		return 0
	fi

	/usr/bin/psd > /dev/null 2>&1
	config_file="${HOME}/.config/psd/psd.conf"
	if [ -f "${config_file}" ]; then
		# test for overlayfs
		sed -i 's/#USE_OVERLAYFS=.*/USE_OVERLAYFS="yes"/' "${config_file}"
		case $(/usr/bin/psd p 2> /dev/null | grep Overlayfs) in
			*active*)
				echo -e "\nConfigured profile sync daemon with overlayfs."
				;;
			*)
				echo -e "\nConfigured profile sync daemon."
				sed -i 's/USE_OVERLAYFS="yes"/#USE_OVERLAYFS="no"/' "${config_file}"
				;;
		esac
	fi
	systemctl --user enable psd.service > /dev/null 2>&1
	systemctl --user start psd.service > /dev/null 2>&1
}

add_user() {
	read -r -t 0 _
	REPEATS=3
	while [ -f "/root/.not_logged_in_yet" ]; do
		[[ -z "${PRESET_USER_NAME}" ]] && echo -e "\nPlease provide a username (eg. your first name): \c"
		if [ -z "$PRESET_USER_NAME" ];then
			read -r -e username
		else
			username="$PRESET_USER_NAME"
		fi
		if ! grep '^[a-zA-Z][a-zA-Z0-9]*$' <<< "$username" > /dev/null; then
			echo -e "\n\x1B[91mError\x1B[0m: illegal characters in username"
			return
		fi

		RealUserName="$(echo "$username" | tr '[:upper:]' '[:lower:]' | tr -d -c '[:alnum:]')"
		[ -z "$RealUserName" ] && return
		if ! id "$RealUserName" > /dev/null 2>&1; then break; else echo -e "Username \e[0;31m$RealUserName\x1B[0m already exists on the system."; fi
	done

	while [ -f "/root/.not_logged_in_yet" ]; do
		if [ -z "$PRESET_USER_PASSWORD" ];then
			read_password "Create user ($username)"
			echo ""
		else
			password="$PRESET_USER_PASSWORD"
		fi
		first_input="$password"
		if [ -z "$PRESET_USER_PASSWORD" ];then
			read_password "Repeat user ($username)"
			echo ""
		else
			password="$PRESET_USER_PASSWORD"
		fi
		second_input="$password"
		if [[ "$first_input" == "$second_input" ]]; then
			# minimal images might not have this
			if command -v cracklib-check > /dev/null 2>&1; then
				result="$(cracklib-check <<< "$password")"
				okay="$(awk -F': ' '{ print $2}' <<< "$result")"
				if [[ "$okay" != "OK" ]]; then
					echo -e "\n\e[0;31mWarning:\x1B[0m Weak password, $okay \b!"
				fi
			fi
			if [ -z "$PRESET_DEFAULT_REALNAME" ];then
				echo -e ""
				read -r -e -p "Please provide your real name: " -i "${RealUserName^}" RealName
			else
				RealName="$PRESET_DEFAULT_REALNAME"
			fi

			adduser --quiet --disabled-password --home /home/"$RealUserName" --gecos "$RealName" "$RealUserName"

			# download and add SSH key if defined
			if [[ -n "${PRESET_USER_KEY}" ]]; then
				mkdir -p /home/"$RealUserName"/.ssh/
				curl --retry 5 --connect-timeout 3 "${PRESET_USER_KEY}" > /home/"$RealUserName"/.ssh/authorized_keys 2> /dev/null
				chown -R "$RealUserName":"$RealUserName" /home/"$RealUserName"/.ssh/
			fi

			if [[ -n "$first_input" ]]; then
				(
					echo "$first_input"
					echo "$second_input"
				) | passwd "$RealUserName" > /dev/null 2>&1
			else
				passwd -d "$RealUserName" > /dev/null 2>&1
			fi
			for additionalgroup in sudo netdev audio video disk tty users games dialout plugdev input bluetooth systemd-journal ssh render; do
				usermod -aG "${additionalgroup}" "${RealUserName}" 2> /dev/null
			done

			# fix for gksu in Xenial
			touch /home/"$RealUserName"/.Xauthority
			chown "$RealUserName":"$RealUserName" /home/"$RealUserName"/.Xauthority
			RealName="$(awk -F":" "/^${RealUserName}:/ {print \$5}" < /etc/passwd | cut -d',' -f1)"
			[ -z "$RealName" ] && RealName="$RealUserName"
			echo -e "\nDear \e[0;92m${RealName}\x1B[0m, your account \e[0;92m${RealUserName}\x1B[0m has been created and is sudo enabled."
			echo -e "Please use this account for your daily work from now on.\n"
			rm -f /root/.not_logged_in_yet
			# set up profile sync daemon on desktop systems
			if command -v psd > /dev/null 2>&1; then
				echo -e "${RealUserName} ALL=(ALL) NOPASSWD: /usr/bin/psd-overlay-helper" >> /etc/sudoers
				touch /home/"${RealUserName}"/.activate_psd
				chown "$RealUserName":"$RealUserName" /home/"${RealUserName}"/.activate_psd
			fi
			break
		elif [[ -n $password ]]; then
			echo -e "Rejected - \e[0;31mpasswords do not match.\x1B[0m Try again [${REPEATS}]."
			REPEATS=$((REPEATS - 1))
		fi
		[[ "$REPEATS" -eq 0 ]] && logout
	done

}

if [[ -f /root/.not_logged_in_yet && -n $(tty) ]]; then

	. /root/.not_logged_in_yet

	# override configuration from URL
	if [[ -n "${PRESET_CONFIGURATION}" ]]; then
		curl --retry 5 --connect-timeout 3 "${PRESET_CONFIGURATION}" > /root/.not_logged_in_yet 2> /dev/null
	fi

	do_firstrun_automated_network_configuration

	# disable autologin
	rm -f /etc/systemd/system/getty@.service.d/override.conf
	rm -f /etc/systemd/system/serial-getty@.service.d/override.conf
	systemctl daemon-reload

	declare desktop_dm="none"
	declare -i desktop_is_sddm=0 desktop_is_lightdm=0 desktop_is_gdm3=0
	if [[ -f /usr/bin/sddm ]]; then
		desktop_dm="sddm"
		desktop_is_sddm=1
	fi
	if [[ -f /usr/sbin/lightdm ]]; then
		desktop_dm="lightdm"
		desktop_is_lightdm=1
	fi
	if [[ -f /usr/sbin/gdm3 ]]; then
		desktop_dm="gdm3"
		desktop_is_gdm3=1
	fi

	echo -e "\nWaiting for system to finish booting ..."
	systemctl is-system-running --wait > /dev/null

	# enable networkManager-wait-online.service
	# When NM is used the NetworkManager-wait-online.service must be enabled so that network-online.target is not reached until
	# NetworkManager has brought up all the interfaces. Service units that require the network to be up before starting rely
	# on network-online.target working correctly otherwise they will likely fail on boot
	# Same goes for systemd-networkd stack
	# https://github.com/armbian/build/issues/7896
	if
		systemctl is-enabled --quiet NetworkManager &&
		! systemctl is-enabled --quiet NetworkManager-wait-online
	then
		systemctl enable NetworkManager-wait-online
		# @TODO: determine if there is any value in starting it now
		echo "Waiting for network startup to complete..."
		systemctl start NetworkManager-wait-online
	fi

	if
		systemctl is-enabled --quiet systemd-networkd &&
		! systemctl is-enabled --quiet systemd-networkd-wait-online
	then
		systemctl enable systemd-networkd-wait-online
		# @TODO: determine if there is any value in starting it now
		echo "Waiting for network startup to complete..."
		systemctl start systemd-networkd-wait-online
	fi

	# Enable HiDPI support only if the framebuffer size is detectable
	FB_VIRTUAL_SIZE="/sys/class/graphics/fb0/virtual_size"
	HIDPI_THRESHOLD="1920"
	if [[ -r "$FB_VIRTUAL_SIZE" ]]; then
		fb_virtual_width=$(cut -d, -f1 < "$FB_VIRTUAL_SIZE" 2>/dev/null)
		if [[ "$fb_virtual_width" =~ ^[0-9]+$ && "$fb_virtual_width" -gt "${HIDPI_THRESHOLD}" ]]; then
			# Enable HiDPI in LightDM slick-greeter
			if [[ -f /etc/lightdm/slick-greeter.conf ]]; then
				if ! grep -q "^enable-hidpi *= *on" /etc/lightdm/slick-greeter.conf; then
					echo "enable-hidpi = on" >> /etc/lightdm/slick-greeter.conf
				fi
			fi

			# Set XFCE scaling factor in skeleton config
			XFCE_XSETTINGS="/etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml"
			if [[ -f "$XFCE_XSETTINGS" ]]; then
				sed -i 's|\(<property name="WindowScalingFactor" type="int" value="\)[^"]*\(">\)|\12\2|' "$XFCE_XSETTINGS"
			fi

			# Set a larger console font for framebuffer
			if [[ -f /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz ]]; then
				setfont /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz
			fi
		fi
	fi

	clear

	# In case VENDORPRETTYNAME is defined, display that
	[[ -n "${VENDORPRETTYNAME}" ]] && VENDOR="$VENDORPRETTYNAME"
	echo -e "Welcome to \e[1m\e[97m${VENDOR}\x1B[0m! \n"
	echo -e "Documentation: \e[1m\e[92m${VENDORDOCS}\x1B[0m | Community support: \e[1m\e[92m${VENDORSUPPORT}\x1B[0m\n"

	echo "" # empty line

	# Try to get the local IP address (script halts until IP was found or x retries were done)
	get_local_ip_addr

	[[ -z "$PRESET_ROOT_PASSWORD" ]] && echo "" # empty line

	trap '' 2
	REPEATS=3
	while [ -f "/root/.not_logged_in_yet" ]; do
		. /root/.not_logged_in_yet
		if [ -z "$PRESET_ROOT_PASSWORD" ];then
			read_password "Create root"
		else
			# allow automated install also in interactive session
			#if [ "$(who am i | awk '{print $2}')" != "tty1" ];then
			#	exit
			#fi
			password="$PRESET_ROOT_PASSWORD"
			# download SSH key if defined
			if [[ -n "${PRESET_ROOT_KEY}" ]]; then
				mkdir -p /root/.ssh/
				curl --retry 5 --connect-timeout 3 "${PRESET_ROOT_KEY}" > /root/.ssh/authorized_keys 2> /dev/null
			fi
		fi

		# Get current session identifiers
		current_tty=$(tty | sed 's:/dev/::')  # e.g., "tty1"
		current_pid=$$

		# Kill ONLY other active root SHELL sessions (not login processes)
		ps -u root -o pid,tty,comm |
		  awk -v me="$current_tty" -v mypid="$current_pid" '
		    NR>1 && $2 != "?" && $2 != me && $1 != mypid && $3 ~ /sh$/ {
		      print $1
		    }' |
		  xargs --no-run-if-empty kill -9

		# enable motd
		chmod +x /etc/update-motd.d/*

		first_input="$password"
		if [ -z "$PRESET_ROOT_PASSWORD" ];then
			echo ""
			read_password "Repeat root"
			echo ""
		else
			password="$PRESET_ROOT_PASSWORD"
		fi
		second_input="$password"
		if [[ "$first_input" == "$second_input" ]]; then
			# minimal might not have this
			if command -v cracklib-check > /dev/null 2>&1; then
				result="$(cracklib-check <<< "$password")"
				okay="$(awk -F': ' '{ print $2}' <<< "$result")"
				if [[ "$okay" != "OK" ]]; then
					echo -e "\n\e[0;31mWarning:\x1B[0m Weak password, $okay \b!"
				fi
			fi
			(
				echo "$first_input"
				echo "$second_input"
			) | passwd root > /dev/null 2>&1
			break
		elif [[ -n $password ]]; then
			echo -e "Rejected - \e[0;31mpasswords do not match.\x1B[0m Try again [${REPEATS}]."
			REPEATS=$((REPEATS - 1))
		fi
		[[ "$REPEATS" -eq 0 ]] && exit
	done
	trap - INT TERM EXIT

	# display support status
	if [ "$IMAGE_TYPE" != "nightly" ]; then
		if [[ "$BRANCH" == "edge" ]]; then
			echo -e "\nSupport status: \e[0;31mcommunity support\x1B[0m (edge kernel branch)"
		elif [[ "$DISTRIBUTION_STATUS" != "supported" ]]; then
			echo -e "\nSupport status: \e[0;31mcommunity support\x1B[0m (unsupported userspace)"
		elif [[ "$BOARD_TYPE" != "conf" ]]; then
			echo -e "\nSupport status: \e[0;31mcommunity support\x1B[0m (looking for a dedicated maintainer)"
		fi
	else

		echo -e "\e[0;31m\nWARNING!\x1B[0m\n\nYou are using an \e[0;31mautomated build\x1B[0m meant only for developers to provide"
		echo -e "constructive feedback to improve build system, OS settings or UX.\n"

		echo -e "If this does not apply to you, \e[0;31mSTOP NOW!\x1B[0m  Especially don't use this "
		echo -e "image for production since things might not work as expected or at "
		echo -e "all. They may  break anytime with next update."

	fi

	# ask user to select shell
	trap '' 2
	set_shell
	trap - INT TERM EXIT

	trap check_abort INT

	while [ -f "/root/.not_logged_in_yet" ]; do
		[[ -z "${PRESET_USER_NAME}" ]] && echo -e "\nCreating a new user account. Press <Ctrl-C> to abort"
		[[ "${desktop_dm}" != "none" ]] && echo -e "\n\e[0;31mDesktop environment will not be enabled if you abort the new user creation\x1B[0m"
		add_user
	done
	trap - INT TERM EXIT

	# ask user to select automated locales or not
	trap '' 2
	set_timezone_and_locales
	trap - INT TERM EXIT

	if [[ ${USER_SHELL} == zsh ]]; then
		printf "\nYou selected \e[0;91mZSH\x1B[0m as your default shell. If you want to use it right away, please logout and login! \n\n"
	fi

	# re-enable passing locale environment via ssh
	sed -e '/^#AcceptEnv LANG/ s/^#//' -i /etc/ssh/sshd_config
	# restart sshd daemon
	systemctl restart ssh.service

	# rpardini: hacks per-dm, very much legacy stuff that works by a miracle
	if [[ "${desktop_dm}" == "lightdm" ]] && [ -n "$RealName" ]; then

		mkdir -p /etc/lightdm/lightdm.conf.d
		cat <<- EOF > /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf
			[Seat:*]
			autologin-user=$RealUserName
			autologin-user-timeout=0
			user-session=xfce
		EOF

		# select gnome session (has to be first or it breaks budgie/cinnamon desktop autologin and user-session)
		# @TODO: remove this, gnome should use gdm3, not lightdm
		[[ -x $(command -v gnome-session) ]] && sed -i "s/user-session.*/user-session=ubuntu/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v gnome-session) ]] && sed -i "s/user-session.*/user-session=ubuntu/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select awesome session
		[[ -x $(command -v awesome) ]] && sed -i "s/user-session.*/user-session=awesome/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v awesome) ]] && sed -i "s/user-session.*/user-session=awesome/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select budgie session
		[[ -x $(command -v budgie-desktop) ]] && sed -i "s/user-session.*/user-session=budgie-desktop/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v budgie-desktop) ]] && sed -i "s/user-session.*/user-session=budgie-desktop/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select cinnamon session
		[[ -x $(command -v cinnamon) ]] && sed -i "s/user-session.*/user-session=cinnamon/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v cinnamon) ]] && sed -i "s/user-session.*/user-session=cinnamon/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select deepin session
		[[ -x $(command -v deepin-wm) ]] && sed -i "s/user-session.*/user-session=deepin/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v deepin-wm) ]] && sed -i "s/user-session.*/user-session=deepin/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select ice-wm session
		[[ -x $(command -v icewm-session) ]] && sed -i "s/user-session.*/user-session=icewm-session/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v icewm-session) ]] && sed -i "s/user-session.*/user-session=icewm-session/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select i3 session
		[[ -x $(command -v i3) ]] && sed -i "s/user-session.*/user-session=i3/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v i3) ]] && sed -i "s/user-session.*/user-session=i3/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select lxde session
		[[ -x $(command -v startlxde) ]] && sed -i "s/user-session.*/user-session=LXDE/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v startlxde) ]] && sed -i "s/user-session.*/user-session=LXDE/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select lxqt session
		[[ -x $(command -v startlxqt) ]] && sed -i "s/user-session.*/user-session=lxqt/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v startlxqt) ]] && sed -i "s/user-session.*/user-session=lxqt/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select mate session
		[[ -x $(command -v mate-wm) ]] && sed -i "s/user-session.*/user-session=mate/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v mate-wm) ]] && sed -i "s/user-session.*/user-session=mate/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select sway wayland session
		[[ -x $(command -v sway) ]] && sed -i "s/user-session.*/user-session=sway/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v sway) ]] && sed -i "s/user-session.*/user-session=sway/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		# select xmonad session
		[[ -x $(command -v xmonad) ]] && sed -i "s/user-session.*/user-session=xmonad/" /etc/lightdm/lightdm.conf.d/11-armbian.conf
		[[ -x $(command -v xmonad) ]] && sed -i "s/user-session.*/user-session=xmonad/" /etc/lightdm/lightdm.conf.d/22-armbian-autologin.conf

		ln -sf /lib/systemd/system/lightdm.service /etc/systemd/system/display-manager.service

		if [[ -f /var/run/resize2fs-reboot ]]; then
			# Let the user reboot now otherwise start desktop environment
			printf "\n\n\e[0;91mWarning: a reboot is needed to finish resizing the filesystem \x1B[0m \n"
			printf "\e[0;91mPlease reboot the system now \x1B[0m \n\n"
		else
			echo -e "\n\e[1m\e[39mNow starting desktop environment...\x1B[0m\n"
			sleep 1
			service lightdm start 2> /dev/null
			if [ -f /root/.desktop_autologin ]; then
				rm /root/.desktop_autologin
			else
				systemctl -q enable armbian-disable-autologin.timer
				systemctl start armbian-disable-autologin.timer
			fi
			# logout if logged at console
			who -la | grep root | grep -q tty1 && exit 1
		fi

	elif [[ "${desktop_dm}" == "gdm3" ]] && [ -n "$RealName" ]; then
		# 1st run goes without login
		mkdir -p /etc/gdm3
		cat <<- EOF > /etc/gdm3/custom.conf
			[daemon]
			AutomaticLoginEnable = true
			AutomaticLogin = $RealUserName
		EOF

		ln -sf /lib/systemd/system/gdm3.service /etc/systemd/system/display-manager.service

		if [[ -f /var/run/resize2fs-reboot ]]; then
			# Let the user reboot now otherwise start desktop environment
			printf "\n\n\e[0;91mWarning: a reboot is needed to finish resizing the filesystem \x1B[0m \n"
			printf "\e[0;91mPlease reboot the system now \x1B[0m \n\n"
		else
			echo -e "\n\e[1m\e[39mNow starting desktop environment...\x1B[0m\n"
			sleep 1
			service gdm3 start 2> /dev/null
			if [ -f /root/.desktop_autologin ]; then
				rm /root/.desktop_autologin
			else
				(
					sleep 20
					sed -i "s/AutomaticLoginEnable.*/AutomaticLoginEnable = false/" /etc/gdm3/custom.conf
				) &
			fi
			# logout if logged at console
			who -la | grep root | grep -q tty1 && exit 1
		fi
	elif [[ "${desktop_dm}" == "sddm" ]] && [ -n "$RealName" ]; then

		# create default sddm config
		mkdir -p /etc/sddm.conf.d

		if [ ! -e "/etc/sddm.conf.d/armbian.conf" ]; then
			cat <<- EOF > /etc/sddm.conf.d/armbian.conf
				[Theme]
				Current=breeze
				[General]
				InputMethod=none
			EOF
		fi

		# 1st run goes without login
		cat <<- EOF > /etc/sddm.conf.d/autologin.conf
			[Autologin]
			User=$RealUserName
		EOF
		echo -e "\n\e[1m\e[39mNow starting desktop environment via ${desktop_dm}...\x1B[0m\n"
		systemctl enable --now sddm 2> /dev/null

		if [ -f /root/.desktop_autologin ]; then
				rm /root/.desktop_autologin
		else
			systemctl -q enable armbian-disable-autologin.timer
		fi
		# logout if logged at console
		who -la | grep root | grep -q tty1 && exit 1

	else
		# no display manager detected -> clear screen and show motd
		clear
		run-parts --lsbsysinit /etc/update-motd.d

		# Display reboot recommendation if necessary
		if [[ -f /var/run/resize2fs-reboot ]]; then
			printf "\n\n\e[0;91mWarning: a reboot is needed to finish resizing the filesystem \x1B[0m \n"
			printf "\e[0;91mPlease reboot the system now \x1B[0m \n\n"
		fi

	fi
fi

# Run provisioning script if exists
if [[ -f /root/provisioning.sh ]]; then
	. /root/provisioning.sh
fi
