#!/bin/sh
POSIXLY_CORRECT=1

# Stand-alone Mounter Icon AppRun for Fatdog64 sbm-browser.
# Copyright (C) 2025 The Fatdog64 Linux team.
# Licensed under the GNU General Public License Version 2

# Usage: AppRun [--help]

# Directory layout by lib_make_iconapp().

VERSION=@VERSION@

# Pre-installed dependencies (refer also to the main INSTALL.md file):
# busybox (id, su), cifs-utils, coreutils, defaulttexteditor, grep, gtksu,
# mpscan, samba4-cutdown, util-linux, yad.

i18n() {
	: @I18N@
}

usage() {
	printf "$i18n_X_M_usage_fmt\n" \
		"$0 [--edit-conf | --edit-passwd | --unmount ]"
}

set_trap () {
	unset STATUS
	export TMPD=$(mktemp -d -p "${TMPDIR:-/tmp}" "smbb_XXXXXX")
	chmod 700 "$TMPD" || exit 1
	export ERRDLG_IN="$TMPD/errdlg.in"
	trap "
	trap '' HUP INT TERM
	exec 2<&3
	error_handler
	clean_up
	" HUP INT TERM 0
}

clean_up() {
	rm -rf "${TMPD:?}"
	exit $STATUS
}

error_handler() {
	: "${MAIN_ERR:?}" "${ERRDLG_IN:?}"
	[ -s "$MAIN_ERR" ] || return 0
	cat "$MAIN_ERR" >&2
	if mkfifo "$ERRDLG_IN"; then
		error_dialog <> "$ERRDLG_IN" &
		sleep 0.5
		printf '\f\n' > "$ERRDLG_IN" &&
			cat "$MAIN_ERR" > "$ERRDLG_IN"
	fi
	wait $! 2> /dev/null
}

error_dialog() {
	local edit="${SMB_BROWSER_EDITOR:-defaulttexteditor}"
	local yad_options

	case $ACTION in
	(MOUNT) yad_options="
	--button=\"$i18n_X_M_passwd_prompt_btn_lbl:'$APPDIR/AppRun' --prompt\"
	--button=\"$i18n_X_M_change_passwd_btn_lbl:$edit secret\"
	--button=\"$i18n_X_M_change_host_btn_lbl:$edit .config.env\"
	"
	;;
	(UNMOUNT)
	;;
	esac

	env YAD_OPTIONS="
	--center --width=600 --height=300
	--on-top
	--window-icon=\".resources/iconapp.svg\"
	--title=\"$i18n_X_M_iconapp_wintitle\"
	--borders=10
	--text=\"$i18n_X_M_error_dialog_text\n\"
	$yad_options
	--button=\"$i18n_X_M_close_btn_lbl:0\" `# no icon for yadu portability`
	--buttons-layout=spread
	--tail
	" ${YAD_BIN:-yad} --text-info
}

main() { # fd 3
	cd "$(dirname "$0")"
	APPDIR="$(pwd -P)"
	i18n
	if [[ $1 == --help || $1 == -h ]]; then
			usage
			exit 0
	fi
	[ $(id -u) -eq 0 ] ||
		exec gtksu "$i18n_X_M_iconapp_wintitle" "$0" "$@"
	case $1 in
		(--edit-conf)
			exec ${SMB_BROWSER_EDITOR:-defaulttexteditor} .config.env
			;;
		(--edit-passwd)
			exec ${SMB_BROWSER_EDITOR:-defaulttexteditor} secret
			;;
		(--prompt)   # INTERNAL USAGE
			password_prompt M; exit $?
			;;
	esac

	set_trap && MAIN_ERR="$TMPD/main.err" &&
		exec 3>&2 2> "$MAIN_ERR" || exit 1

	case $1 in
		(--unmount)
			unmount_point M; STATUS=$?
			;;
		(*)
			ls "$APPDIR/.config.env" > /dev/null &&
				. ./.config.env &&
				mount_point M
				STATUS=$?
			;;
	esac
	exit ${STATUS:?}
}

mount_point() { # $1-mount_point
	local mp="${1:?}"
	local p ret errf envi

	ACTION=MOUNT

	if mountpoint -q M; then
		rox -d M
		return 0
	fi
	mkdir -p "$mp" || return $?

	if [ "${OPT#*guest}" = "$OPT" ]; then
		# Force mount.cifs into "permission denied" errno 13
		# since the credentials file path is unknown.
		[ -z "$CREDENTIALS" ] && envi='PASSWD=*'
	fi

	# Ensure credentials can only be set via the CREDENTIALS variable.
	OPT="$(echo "$OPT" | sed -e 's/\(credentials\|user\|pass\)=[^,]\+,\?//g')"
	OPT="${OPT:+$OPT,}${CREDENTIALS:+credentials=$CREDENTIALS}"
	OPT="${OPT%,}"

	# Try mounting by SITE then HOST then IP.
	#----------------------------------------

	errf="$TMPD/mount.err" ret=1
	: > "$errf"
	if [ -n "$SITE" ]; then
		env $envi mount.cifs "-o$OPT" "//$SITE/$SHARE" "$mp" 2>> "$errf"
		ret=$?
	fi
	if [ $ret != 0 ] && [ -n "$HOST" ] && ! is_ip "$HOST"; then
		p="$(nmblookup "$HOST")"
		p="${p%% *}"
		if is_ip "$p"; then
			env $envi mount.cifs "-o$OPT" "//$p/$SHARE" "$mp" 2>> "$errf"
			ret=$?
		fi
	fi
	if [ $ret != 0 ]; then
		env $envi mount.cifs "-o$OPT" "//$IP/$SHARE" "$mp" 2>> "$errf"
		ret=$?
	fi

	if [ $ret = 0 ]; then
		print_mounted_icon "$APPDIR/.resources" > .DirIcon
		rox -x "$APPDIR"
		rox -x "$mp"
		rox -d "$mp"
	else
		uniq "$errf" >&2
	fi
	return $ret
}

unmount_point() { # $1-mount_point
	local mp="${1:?}"

	ACTION=UNMOUNT

	[ -e "$mp" ] || return 0
	rox -D "$mp"
	sleep 0.1
	mountpoint -q "$mp" && umount "$mp"
	if mountpoint -q "$mp"; then
		echo "$i18n_X_M_cannot_unmount" >&2
		umount "$mp" # writes to stderr
	else
		print_unmounted_icon "$APPDIR/.resources" > .DirIcon
	fi
	rox -x "$APPDIR"
	rox -x "$mp"
}

password_dialog() {
	local top_lbl="$(printf "$i18n_X_M_password_dialog_text_fmt" \
		"${HOST:-${SITE:-$IP}}/$SHARE" "$IP")"

	env YAD_OPTIONS="
	--center --height=200
	--on-top
	--window-icon=\".resources/iconapp.svg\"
	--title=\"$i18n_X_M_iconapp_wintitle\"
	--borders=10
	--text=\"$top_lbl\"
	--button=\"$i18n_X_M_logon_btn_lbl:0\" `# no icon for yadu portability`
	--button=\"$i18n_X_M_cancel_btn_lbl:1\" `# no icon for yadu portability`
	--buttons-layout=spread
	--field=\"$i18n_X_M_form_username_lbl\"
	--field=\"$i18n_X_M_form_password_lbl\"
	" ${YAD_BIN:-yad} --form --separator='
'
}

password_prompt() { # $1-mount_point; fd 4
	if [ -z "$ERRDLG_IN" -o -z "$TMPD" ]; then
		echo "$i18n_X_M_error_invalid_context" >&2
		usage >&2
		exit 1
	fi
	local mp="${1:?}"
	local secf="$TMPD/prompt.sec"
	local band='____________________'

	exec 2> "$ERRDLG_IN" &&
		printf '\n%s %s %s\n' "$band" "$(date +%T)" "$band" >&2 &&
		: > "$secf" &&
		chmod 600 "$secf" &&
		ls "$APPDIR/.config.env" > /dev/null &&
		. ./.config.env ||
		return $?

	if password_dialog > "$secf"; then
		sed -i -e '
		1s/^/username=/
		2s/^/password=/
		3d
		' "$secf" &&
			CREDENTIALS="$secf" &&
			if mount_point "$mp"; then
				printf '%s\n' \
					"$i18n_X_M_remind_edit_passwd1" \
					"$i18n_X_M_remind_edit_passwd2" \
				>&2
				cat "$secf" >&2
				return 0
			fi
	fi
	return 1
}

print_mounted_icon() { # $1-base_url
	local base="$1"
	# https://gnome.pages.gitlab.gnome.org/librsvg/devel-docs/features.html
	# https://gnome.pages.gitlab.gnome.org/librsvg/rsvg-2.0/class.handle.html#security-and-locations-of-referenced-files
	echo "\
<svg width=\"48\" height=\"48\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">
<image xlink:href=\"$base/layer1\" width=\"48\" height=\"48\" />
<image xlink:href=\"$base/layer2\" width=\"48\" height=\"48\" />
<image xlink:href=\"$base/layer3\" width=\"48\" height=\"48\" />
</svg>"
}

print_unmounted_icon() { # $1-base_url
	local base="$1"
	echo "\
<svg width=\"48\" height=\"48\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">
<image xlink:href=\"$base/layer1\" width=\"48\" height=\"48\" />
</svg>"
}

is_ip() {
	echo "$1" | grep -Eq '^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$'
}

main "$@"

# vim:ft=sh:ts=8:noet:sw=0
