%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /usr/share/bsdconfig/usermgmt/
Upload File :
Create Path :
Current File : //usr/share/bsdconfig/usermgmt/user_input.subr

if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
############################################################ INCLUDES

BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_dprintf "%s: loading includes..." usermgmt/user_input.subr
f_include $BSDCFG_SHARE/dialog.subr
f_include $BSDCFG_SHARE/strings.subr

BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
f_include_lang $BSDCFG_LIBE/include/messages.subr
f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr

############################################################ CONFIGURATION

#
# Default location of shells(5)
#
: ${ETC_SHELLS:=/etc/shells}

############################################################ FUNCTIONS

# f_get_member_groups $var_to_set $user
#
# Get a list of additional groups $user is a member of in group(5).
#
f_get_member_groups()
{
	f_replaceall "$( pw groupshow -a | awk -F: -v user="$2" '{
		if (!split($4, users, /,/)) next
		for (u in users) if (users[u] == user) { print $1; next }
	}' )" "[$NL]" "," "$1"
}

# f_input_user $user
#
# Given $user name or id, create the environment variables user_name, user_uid,
# user_gid, user_class, user_password_expire, user_account_expire, user_gecos,
# user_home_dir, user_shell, and user_member_groups (and user_password is reset
# to NULL).
#
f_input_user()
{
	local funcname=f_input_user
	local user="$1"

	f_dprintf "$funcname: Getting info for user \`%s'" "$user"
	eval "$( pw usershow "$user" 2> /dev/null | awk -F: '
	function set_value(var, value) {
		gsub(/'\''/, "'\''\\'\'\''", value)
		printf "user_%s='\'%s\''\n", var, value
	}
	{
		found = $1 != ""
		set_value("name",            $1 )
		set_value("password",        "" )
		set_value("uid",             $3 )
		set_value("gid",             $4 )
		set_value("class",           $5 )
		set_value("password_expire", $6 )
		set_value("account_expire",  $7 )
		set_value("gecos",           $8 )
		set_value("home_dir",        $9 )
		set_value("shell",           $10)
		exit
	}
	END { if (!found) print "false" }' )"
	local retval=$?

	f_dprintf "$funcname: Getting group memberships for user \`%s'" "$user"
	f_get_member_groups user_member_groups "$user"

	return $retval
}

# f_dialog_menu_user_list [$default]
#
# Allows the user to select a login from a list. Optionally, if present and
# non-NULL, initially highlight $default user.
#
f_dialog_menu_user_list()
{
	local prompt=
	local menu_list="
		'X $msg_exit' ''
	" # END-QUOTE
	local defaultitem="$1"
	local hline="$hline_alnum_punc_tab_enter"

	# Add users from passwd(5)
	menu_list="$menu_list $( pw usershow -a | awk -F: '
		function mprint(tag, item) {
			gsub(/'\''/, "'\''\\'\'\''", tag)
			gsub(/'\''/, "'\''\\'\'\''", item)
			printf "'\'%s\'\ \'%s\''\n", tag, item
		}
		!/^[[:space:]]*(#|$)/ { mprint($1, $8) }
	' )"

	local height width rows
	eval f_dialog_menu_size height width rows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$prompt\"           \
	                        \"\$hline\"            \
	                        $menu_list

	local menu_choice
	menu_choice=$( eval $DIALOG \
		--title \"\$DIALOG_TITLE\"         \
		--backtitle \"\$DIALOG_BACKTITLE\" \
		--hline \"\$hline\"                \
		--ok-label \"\$msg_ok\"            \
		--cancel-label \"\$msg_cancel\"    \
		--default-item \"\$defaultitem\"   \
		--menu \"\$prompt\"                \
		$height $width $rows               \
		$menu_list                         \
		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
	)
	local retval=$?
	f_dialog_menutag_store -s "$menu_choice"
	return $retval
}

# f_dialog_input_member_groups $var_to_set [$member_groups]
#
# Allows the user to edit group memberships for a given user. If the user does
# not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_member_groups()
{
	local __var_to_set="$1" __input="$2"
	local __prompt="$msg_member_of_groups"
	local __menu_list="
		'X' '$msg_continue'
		'1' '$msg_select_groups_from_list'
		'2' '$msg_enter_groups_manually'
	" # END-QUOTE
	local __defaultitem=
	local __hline="$hline_alnum_space_tab_enter"

	local __mheight __mwidth __mrows
	eval f_dialog_menu_size __mheight __mwidth __mrows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$__prompt\"         \
	                        \"\$__hline\"          \
	                        $__menu_list

	local __menu_choice __retval
	while :; do
		__menu_choice=$( eval $DIALOG \
			--title \"\$DIALOG_TITLE\"         \
			--backtitle \"\$DIALOG_BACKTITLE\" \
			--hline \"\$__hline\"              \
			--ok-label \"\$msg_ok\"            \
			--cancel-label \"\$msg_cancel\"    \
			--default-item \"\$__defaultitem\" \
			--menu \"\$__prompt\"              \
			$__mheight $__mwidth $__mrows      \
			$__menu_list                       \
			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
		)
		__retval=$?
		f_dialog_data_sanitize __menu_choice
		__defaultitem="$__menu_choice"
		f_dprintf "retval=%u menu_choice=[%s]" \
		          $__retval "$__menu_choice"

		# Return if user has either pressed ESC or chosen Cancel/No
		[ $__retval -eq $DIALOG_OK ] || return $__retval

		local __member_groups
		case "$__menu_choice" in
		X) # Exit
			break ;;
		1) # Select Groups from a list
			local __check_list= # Calculated below
			local __group_list __g __grp __length=0
			__group_list=$( pw groupshow -a |
				awk -F: '!/^[[:space:]]*(#|$)/{print $1}' )
			while [ $__length -ne ${#__group_list} ]; do
				__g="${__group_list%%$NL*}" # First line
				f_shell_escape "$__g" __grp

				# Format of a checklist entry: tag item status
				# NB: Setting both tag/item to group name below
				__check_list="$__check_list '$__grp' '$__grp'"
				case "$__input" in
				"$__g"|"$__g",*|*,"$__g",*|*,"$__g")
					__check_list="$__check_list on" ;;
				*)
					__check_list="$__check_list off"
				esac

				__length=${#__group_list}
				__group_list="${__group_list#*$NL}" # Kill line
			done

			local __cheight __cwidth __crows

			eval f_dialog_checklist_size \
				__cheight __cwidth __crows \
				\"\$DIALOG_TITLE\"     \
				\"\$DIALOG_BACKTITLE\" \
				\"\$__prompt\"         \
				\"\$__hline\"          \
				$__check_list
			__member_groups=$( eval $DIALOG \
				--title \"\$DIALOG_TITLE\"         \
				--backtitle \"\$DIALOG_BACKTITLE\" \
				--separate-output                  \
				--hline \"\$__hline\"              \
				--ok-label \"\$msg_ok\"            \
				--cancel-label \"\$msg_cancel\"    \
				--checklist \"\$__prompt\"         \
				$__cheight $__cwidth $__crows      \
				$__check_list                      \
				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
			) || continue
				# Return to previous menu if user either
				# pressed ESC or chose Cancel/No
			f_dialog_data_sanitize __member_groups

			#
			# Convert the newline separated list into a comma-
			# separated one so that if the user switches over to
			# manual editing, list reflects checklist selections
			#
			f_replaceall "$__member_groups" "[$NL]" "," __input
			;;
		2) # Enter Groups manually
			local __prompt2="$msg_groups"
			__prompt2="$__prompt2 ($msg_separated_by_commas)"

			f_dialog_input __member_groups \
			               "$__prompt2" "$__input" \
			               "$hline_num_tab_enter" || continue
				# Return to previous menu if user either
				# pressed ESC or chose Cancel/No

			#
			# Validate each of the groups the user has entered
			#
			local __all_groups_valid=1 __grp __grp_list
			f_replaceall "$__member_groups" "," " " __grp_list
			for __grp in $__grp_list; do
				if ! f_quietly pw groupshow -n "$__grp"; then
					f_show_msg "$msg_group_not_found" \
					           "$__grp"
					__all_groups_valid=
					break
				fi
			done
			[ "$__all_groups_valid" ] || continue

			__input="$__member_groups" 
			;;
		esac
	done

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_name $var_to_set [$name]
#
# Allows the user to enter a new username for a given user. If the user does
# not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_name()
{
	local __var_to_set="$1" __name="$2"

	#
	# Loop until the user provides taint-free/valid input
	#
	local __input="$__name"
	while :; do
		# Return if user has either pressed ESC or chosen Cancel/No
		f_dialog_input __input "$msg_login" "$__input" \
		               "$hline_alnum_tab_enter" || return $?

		# Check for no-change
		if [ "$__input" = "$__name" ]; then
			setvar "$__var_to_set" "$__input"
			return $DIALOG_OK
		fi

		# Check for NULL entry
		if [ ! "$__input" ]; then
			f_show_msg "$msg_login_is_empty"
			continue
		fi

		# Check for invalid entry
		case "$__input" in [!a-zA-Z]*)
			f_show_msg "$msg_login_must_start_with_letter"
			continue
		esac

		# Check for duplicate entry
		if f_quietly pw usershow -n "$__input"; then
			f_show_msg "$msg_login_already_used" "$__input"
			continue
		fi

		setvar "$__var_to_set" "$__input"
		break
	done

	return $DIALOG_OK
}

# f_dialog_input_password $var_to_set $dvar_to_set
#
# Prompt the user to enter a password (twice). If the user does not cancel or
# press ESC, $var_to_set will hold the confirmed user entry. Otherwise, if the
# user cancels or enters a NULL password (twice), they are given the choice to
# disable password authentication for the given login, wherein $dvar_to_set has
# a value of 1 to indicate password authentication should be disabled.
#
f_dialog_input_password()
{
	local __var_to_set="$1" __dvar_to_set="$2"
	local __prompt1="$msg_password"
	local __prompt2="$msg_reenter_password"
	local __hline="$hline_alnum_punc_tab_enter"

	local __height1 __width1
	f_dialog_inputbox_size __height1 __width1 \
	                       "$DIALOG_TITLE"     \
	                       "$DIALOG_BACKTITLE" \
	                       "$__prompt1"        \
	                       ""                  \
	                       "$__hline"
	local __height2 __width2
	f_dialog_inputbox_size __height2 __width2 \
	                       "$DIALOG_TITLE"     \
	                       "$DIALOG_BACKTITLE" \
	                       "$__prompt2"        \
	                       ""                  \
	                       "$__hline"

	#
	# Loop until the user provides taint-free/valid input
	#
	local __retval __password1 __password2
	while :; do
		__password1=$( $DIALOG \
			--title "$DIALOG_TITLE"         \
			--backtitle "$DIALOG_BACKTITLE" \
			--hline "$__hline"              \
			--ok-label "$msg_ok"            \
			--cancel-label "$msg_cancel"    \
			--insecure                      \
			--passwordbox "$__prompt1"      \
			$__height1 $__width1            \
			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
		) || return $?
			# Return if user either pressed ESC or chose Cancel/No
		debug= f_dialog_line_sanitize __password1

		__password2=$( $DIALOG \
			--title "$DIALOG_TITLE"         \
			--backtitle "$DIALOG_BACKTITLE" \
			--hline "$__hline"              \
			--ok-label "$msg_ok"            \
			--cancel-label "$msg_cancel"    \
			--insecure                      \
			--passwordbox "$__prompt2"      \
			$__height2 $__width2            \
			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
		) || return $?
			# Return if user either pressed ESC or chose Cancel/No
		debug= f_dialog_line_sanitize __password2

		# Check for password mismatch
		if [ "$__password1" != "$__password2" ]; then
			f_show_msg "$msg_passwords_do_not_match"
			continue
		fi

		# Check for NULL entry
		if [ ! "$__password1" ]; then
			f_dialog_yesno "$msg_disable_password_auth_for_account"
			__retval=$?
			if [ $__retval -eq $DIALOG_ESC ]; then
				return $__retval
			elif [ $__retval -eq $DIALOG_OK ]; then
				setvar "$__dvar_to_set" 1
			else
				continue # back to password prompt
			fi
		else
			setvar "$__dvar_to_set" ""
		fi

		setvar "$__var_to_set" "$__password1"
		break
	done

	return $DIALOG_OK
}

# f_dialog_input_gecos $var_to_set [$gecos]
#
# Allow the user to enter new GECOS information for a given user. This
# information is commonly used to store the ``Full Name'' of the user. If the
# user does not cancel or press ESC, the $var_to_set variable will hold the
# newly-configured value upon return.
#
f_dialog_input_gecos()
{
	local __var_to_set="$1" __input="$2"

	# Return if user has either pressed ESC or chosen Cancel/No
	f_dialog_input __input "$msg_full_name" "$__input" \
	               "$hline_alnum_punc_tab_enter" || return $?

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_uid $var_to_set [$uid]
#
# Allow the user to enter a new UID for a given user. If the user does not
# cancel or press ESC, the $var_to_set variable will hold the newly-configured
# value upon return.
#
f_dialog_input_uid()
{
	local __var_to_set="$1" __input="$2"

	# Return if user has either pressed ESC or chosen Cancel/No
	f_dialog_input __input "$msg_user_id_leave_empty_for_default" \
	               "$__input" "$hline_num_tab_enter" || return $?

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_gid $var_to_set [$gid]
#
# Allow the user to enter a new primary GID for a given user. If the user does
# not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_gid()
{
	local __var_to_set="$1" __input="$2"

	# Return if user has either pressed ESC or chosen Cancel/No
	f_dialog_input __input "$msg_group_id_leave_empty_for_default" \
	               "$__input" "$hline_num_tab_enter" || return $?

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_class $var_to_set [$class]
#
# Allow the user to enter a new login class for a given user. If the user does
# not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_class()
{
	local __var_to_set="$1" __input="$2"

	# Return if user has either pressed ESC or chosen Cancel/No
	f_dialog_input __input "$msg_login_class" "$__input" \
	               "$hline_alnum_tab_enter" || return $?

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_expire_password $var_to_set [$seconds]
#
# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
# for when a given user's password must be changed. If the user does not cancel
# or press ESC, the $var_to_set variable will hold the newly-configured value
# upon return.
#
f_dialog_input_expire_password()
{
	local __var_to_set="$1" __input="$2"
	local __prompt="$msg_password_expires_on"
	local __menu_list="
		'1' '$msg_password_does_not_expire'
		'2' '$msg_edit_date_time_with_a_calendar'
		'3' '$msg_enter_value_manually'
	" # END-QUOTE
	local __defaultitem= # Calculated below
	local __hline="$hline_num_arrows_tab_enter"

	local __mheight __mwidth __mrows
	eval f_dialog_menu_size __mheight __mwidth __mrows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$__prompt\"         \
	                        \"\$__hline\"          \
	                        $__menu_list
	local __cheight __cwidth
	f_dialog_calendar_size __cheight __cwidth \
	                       "$DIALOG_TITLE"     \
	                       "$DIALOG_BACKTITLE" \
	                       "$__prompt"         \
	                       "$__hline"
	local __theight __twidth
	f_dialog_timebox_size __theight __twidth \
	                      "$DIALOG_TITLE"     \
	                      "$DIALOG_BACKTITLE" \
	                      "$__prompt"         \
	                      "$__hline"

	#
	# Loop until the user provides taint-free/cancellation-free input
	#
	local __retval __date_type
	while :; do
		__date_type=$( eval $DIALOG \
			--title \"\$DIALOG_TITLE\"         \
			--backtitle \"\$DIALOG_BACKTITLE\" \
			--hline \"\$__hline\"              \
			--default-item \"\$__defaultitem\" \
			--ok-label \"\$msg_ok\"            \
			--cancel-label \"\$msg_cancel\"    \
			--menu \"\$__prompt\"              \
			$__mheight $__mwidth $__mrows      \
			$__menu_list                       \
			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
		)
		__retval=$?
		f_dialog_data_sanitize __date_type
		__defaultitem="$__date_type"
		f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"

		# Return if user has either pressed ESC or chosen Cancel/No
		[ $__retval -eq $DIALOG_OK ] || return $__retval

		case "$__date_type" in
		1) # Password does not expire
			__input= break ;;

		2) # Edit date/time with a calendar
			local __input_date __input_time __ret_date __ret_time

			local __seconds="$__input"
			{ f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
				__seconds=
			__input_date=$( date -j -f "%s" -- "$__seconds" \
			               		"+%d %m %Y" 2> /dev/null )
			__ret_date=$( eval $DIALOG \
				--title \"\$DIALOG_TITLE\"          \
				--backtitle \"\$DIALOG_BACKTITLE\"  \
				--hline \"\$__hline\"               \
				--ok-label \"\$msg_ok\"             \
				--cancel-label \"\$msg_cancel\"     \
				--calendar \"\$__prompt\"           \
				$__cheight $__cwidth                \
				$__input_date                       \
				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
			)
			__retval=$?
			f_dialog_data_sanitize __ret_date
			f_dprintf "retval=%u ret_date=[%s]" \
			          $__retval "$__ret_date"

			# Return to menu if either ESC or Cancel/No
			[ $__retval -eq $DIALOG_OK ] || continue

			__input_time=
			[ "$__seconds" ] && __input_time=$( date -j \
				-f %s -- "$__input" "+%H %M %S" 2> /dev/null )
			__ret_time=$( eval $DIALOG \
				--title \"\$DIALOG_TITLE\"         \
				--backtitle \"\$DIALOG_BACKTITLE\" \
				--hline \"\$__hline\"              \
				--ok-label \"\$msg_ok\"            \
				--cancel-label \"\$msg_cancel\"    \
				--timebox \"\$__prompt\"           \
				$__theight $__twidth               \
				$__input_time                      \
				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
			)
			__retval=$?
			f_dialog_data_sanitize __ret_time
			f_dprintf "retval=%u ret_time=[%s]" \
			          $__retval "$__ret_time"

			# Return to menu if either ESC or Cancel/No
			[ $__retval -eq $DIALOG_OK ] || continue

			__input=$( date -j -f "%d/%m/%Y %T" -- \
				"$__ret_date $__ret_time" +%s 2> /dev/null )
			f_dprintf "input=[%s]" "$__input"
			break ;;

		3) # Enter value manually
			local __msg __new_input
			f_sprintf __msg "$msg_password_expire_manual_edit" \
			                "$( date -r 0 "+%c %Z" )"

			# Return to menu if either ESC or Cancel/No
			f_dialog_input __new_input \
				"$__msg" "$__input" "$__hline" || continue

			__input="$__new_input"
			f_dprintf "input=[%s]" "$__input"
			break ;;

		esac

	done # Loop forever

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_expire_account $var_to_set [$seconds]
#
# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
# for when a given user's account should become expired. If the user does not
# cancel or press ESC, the $var_to_set variable will hold the newly-configured
# value upon return.
#
f_dialog_input_expire_account()
{
	local __var_to_set="$1" __input="$2"
	local __prompt="$msg_account_expires_on"
	local __menu_list="
		'1' '$msg_account_does_not_expire'
		'2' '$msg_edit_date_time_with_a_calendar'
		'3' '$msg_enter_value_manually'
	" # END-QUOTE
	local __defaultitem= # Calculated below
	local __hline="$hline_num_arrows_tab_enter"

	local __mheight __mwidth __mrows 
	eval f_dialog_menu_size __mheight __mwidth __mrows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$__prompt\"         \
	                        \"\$__hline\"          \
	                        $__menu_list
	local __cheight __cwidth
	f_dialog_calendar_size __cheight __cwidth \
	                       "$DIALOG_TITLE"     \
	                       "$DIALOG_BACKTITLE" \
	                       "$__prompt"         \
	                       "$__hline"
	local __theight __twidth
	f_dialog_timebox_size __theight __twidth \
	                      "$DIALOG_TITLE"     \
	                      "$DIALOG_BACKTITLE" \
	                      "$__prompt"         \
	                      "$__hline"

	#
	# Loop until the user provides taint-free/cancellation-free input
	#
	local __retval __date_type
	while :; do
		__date_type=$( eval $DIALOG \
			--title \"\$DIALOG_TITLE\"         \
			--backtitle \"\$DIALOG_BACKTITLE\" \
			--hline \"\$__hline\"              \
			--default-item \"\$__defaultitem\" \
			--ok-label \"\$msg_ok\"            \
			--cancel-label \"\$msg_cancel\"    \
			--menu \"\$__prompt\"              \
			$__mheight $__mwidth $__mrows      \
			$__menu_list                       \
			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
		)
		__retval=$?
		f_dialog_data_sanitize __date_type
		__defaultitem="$__date_type"
		f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"

		# Return if user has either pressed ESC or chosen Cancel/No
		[ $__retval -eq $DIALOG_OK ] || return $__retval

		case "$__date_type" in
		1) # Account does not expire
			__input= break ;;

		2) # Edit date/time with a calendar
			local __input_date __input_time __ret_date __ret_time

			local __seconds="$__input"
			{ f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
				__seconds=
			__input_date=$( date -j -f "%s" -- "$__seconds" \
			               		"+%d %m %Y" 2> /dev/null )
			__ret_date=$( eval $DIALOG \
				--title \"\$DIALOG_TITLE\"          \
				--backtitle \"\$DIALOG_BACKTITLE\"  \
				--hline \"\$__hline\"               \
				--ok-label \"\$msg_ok\"             \
				--cancel-label \"\$msg_cancel\"     \
				--calendar \"\$__prompt\"           \
				$__cheight $__cwidth                \
				$__input_date                       \
				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
			)
			__retval=$?
			f_dialog_data_sanitize __ret_date
			f_dprintf "retval=%u ret_date=[%s]" \
			          $__retval "$__ret_date"

			# Return to menu if either ESC or Cancel/No
			[ $__retval -eq $DIALOG_OK ] || continue

			__input_time=
			[ "$__seconds" ] && __input_time=$( date -j \
				-f %s -- "$__input" "+%H %M %S" 2> /dev/null )
			__ret_time=$( eval $DIALOG \
				--title \"\$DIALOG_TITLE\"         \
				--backtitle \"\$DIALOG_BACKTITLE\" \
				--hline \"\$__hline\"              \
				--ok-label \"\$msg_ok\"            \
				--cancel-label \"\$msg_cancel\"    \
				--timebox \"\$__prompt\"           \
				$__theight $__twidth               \
				$__input_time                      \
				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
			)
			__retval=$?
			f_dialog_data_sanitize __ret_time
			f_dprintf "retval=%u ret_time=[%s]" \
			          $__retval "$__ret_time"

			# Return to menu if either ESC or Cancel/No
			[ $__retval -eq $DIALOG_OK ] || continue

			__input=$( date -j -f "%d/%m/%Y %T" -- \
				"$ret_date $ret_time" +%s 2> /dev/null )
			f_dprintf "input=[%s]" "$__input"
			break ;;

		3) # Enter value manually
			local __msg __new_input
			f_sprintf __msg "$msg_account_expire_manual_edit" \
			                "$( date -r 0 "+%c %Z" )"

			# Return to menu if either ESC or Cancel/No
			f_dialog_input __new_input \
				"$__msg" "$__input" "$__hline" || continue

			__input="$__new_input"
			f_dprintf "input=[%s]" "$__input"
			break ;;

		esac

	done # Loop forever

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_home_dir $var_to_set [$home_dir]
#
# Allow the user to enter a new home directory for a given login. If the user
# does not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_home_dir()
{
	local __var_to_set="$1" __input="$2"

	# Return if user has either pressed ESC or chosen Cancel/No
	f_dialog_input __input "$msg_home_directory" "$__input" \
	               "$hline_alnum_punc_tab_enter" || return $?

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_input_home_create $var_to_set
#
# Prompt the user to confirm creation of a given login's home directory. If the
# user does not cancel (by choosing "No") or press ESC, the $var_to_set
# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
#
f_dialog_input_home_create()
{
	local __var_to_set="$1"

	f_dialog_yesno "$msg_create_home_directory"
	local __retval=$?

	if [ $__retval -eq $DIALOG_OK ]; then
		setvar "$__var_to_set" "$msg_yes"
	else
		setvar "$__var_to_set" "$msg_no"
	fi

	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}

# f_dialog_input_group_delete $var_to_set [$group]
#
# Prompt the user to confirm deletion of a given login's primary group. If the
# user does not cancel (by choosing "No") or press ESC, the $var_to_set
# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
#
f_dialog_input_group_delete()
{
	local __var_to_set="$1" __group="$2"

	if f_isinteger "$__group"; then
		if [ $__group -lt 1000 ]; then
			f_dialog_noyes "$msg_delete_primary_group"
		else
			f_dialog_yesno "$msg_delete_primary_group"
		fi
	elif [ "$__group" ]; then
		local __gid=0
		__gid=$( pw groupshow "$__group" | awk -F: '{print $3}' )
		if f_isinteger "$__gid" && [ $__gid -lt 1000 ]; then
			f_dialog_noyes "$msg_delete_primary_group"
		else
			f_dialog_yesno "$msg_delete_primary_group"
		fi
	else
		f_dialog_yesno "$msg_delete_primary_group"
	fi
	local __retval=$?

	if [ $__retval -eq $DIALOG_OK ]; then
		setvar "$__var_to_set" "$msg_yes"
	else
		setvar "$__var_to_set" "$msg_no"
	fi

	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}

# f_dialog_input_home_delete $var_to_set
#
# Prompt the user to confirm deletion of a given login's home directory. If the
# user does not cancel (by choosing "No") or press ESC, the $var_to_set
# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
#
f_dialog_input_home_delete()
{
	local __var_to_set="$1"

	f_dialog_yesno "$msg_delete_home_directory"
	local __retval=$?

	if [ $__retval -eq $DIALOG_OK ]; then
		setvar "$__var_to_set" "$msg_yes"
	else
		setvar "$__var_to_set" "$msg_no"
	fi

	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}

# f_dialog_input_dotfiles_create $var_to_set
#
# Prompt the user to confirm population of a given login's home directory with
# sample dotfiles. If the user does not cancel (by choosing "No") or press ESC,
# the $var_to_set variable will hold $msg_yes upon return, otherwise $msg_no.
# Use these return variables ($msg_yes and $msg_no) for comparison to be i18n-
# compatible.
#
f_dialog_input_dotfiles_create()
{
	local __var_to_set="$1"

	f_dialog_yesno "$msg_create_dotfiles"
	local __retval=$?

	if [ $__retval -eq $DIALOG_OK ]; then
		setvar "$__var_to_set" "$msg_yes"
	else
		setvar "$__var_to_set" "$msg_no"
	fi

	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}

# f_dialog_input_shell $var_to_set [$shell]
#
# Allow the user to select a new shell for a given login. If the user does not
# cancel or press ESC, the $var_to_set variable will hold the newly-configured
# value upon return.
#
f_dialog_input_shell()
{
	local __funcname=f_dialog_input_shell
	local __var_to_set="$1" __input="$2"
	local __prompt="$msg_select_login_shell"
	local __radio_list= # Calculated below
	local __defaultitem="$2"
	local __hline="$hline_arrows_space_tab_enter"

	#
	# Generate the radiolist of shells
	#
	local __shell_list __s __shell __length=0
	f_eval_catch -k __shell_list $__funcname awk "awk '%s' \"%s\"" \
		'!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" || return $FAILURE
	while [ $__length -ne ${#__shell_list} ]; do
		__s="${__shell_list%%$NL*}" # First line
		f_shell_escape "$__s" __shell

		# Format of a radiolist entry: tag item status
		if [ "$__s" = "$__input" ]; then
			__radio_list="$__radio_list '$__shell' '' 'on'"
		else
			__radio_list="$__radio_list '$__shell' '' 'off'"
		fi

		__length=${#__shell_list}
		__shell_list="${__shell_list#*$NL}" # Kill line
	done

	local __height __width __rows
	eval f_dialog_radiolist_size __height __width __rows \
	                             \"\$DIALOG_TITLE\"     \
	                             \"\$DIALOG_BACKTITLE\" \
	                             \"\$__prompt\"         \
	                             \"\$__hline\"          \
	                             $__radio_list

	__input=$( eval $DIALOG \
		--title \"\$DIALOG_TITLE\"         \
		--backtitle \"\$DIALOG_BACKTITLE\" \
		--hline \"\$__hline\"              \
		--ok-label \"\$msg_ok\"            \
		--cancel-label \"\$msg_cancel\"    \
		--default-item \"\$__defaultitem\" \
		--radiolist \"\$__prompt\"         \
		$__height $__width $__rows         \
		$__radio_list                      \
		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
	) || return $?
		# Return if user either pressed ESC or chose Cancel/No
	f_dialog_data_sanitize __input

	setvar "$__var_to_set" "$__input"
	return $DIALOG_OK
}

# f_dialog_menu_user_add [$defaultitem]
#
# Present a menu detailing the properties of a login that is about to be added.
# The user's menu choice is available using f_dialog_menutag_fetch(). Returns
# success unless the user chose Cancel or pressed ESC. Data to display is taken
# from environment variables user_account_expire, user_class,
# user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
# user_member_groups, user_name, user_password_expire, user_shell, and
# user_uid. If $defaultitem is present and non-NULL, initially highlight the
# item in the menu.
#
f_dialog_menu_user_add()
{
	local funcname=f_dialog_menu_user_add
	local prompt="$msg_save_exit_or_cancel"
	local menu_list # Calculated below
	local defaultitem="$1"
	local hline="$hline_arrows_tab_enter"

	# Attempt to convert numeric UNIX time to calendar date/time
	local user_account_expires_on=
	if f_isinteger "$user_account_expire"; then
		[ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
			date -r "$user_account_expire" "+%F %T %Z"
		)
	else
		user_account_expires_on="$user_account_expire"
	fi
	local user_password_expires_on=
	if f_isinteger "$user_password_expire"; then
		[ $user_password_expire -ne 0 ] && user_password_expires_on=$(
			date -r "$user_password_expire" "+%F %T %Z"
		)
	else
		user_password_expires_on="$user_password_expire"
	fi

	# Localize potentially hostile variables and escape their values
	# to the local variable (see f_shell_escape() of `strings.subr')
	local var
	for var in account_expires_on class dotfiles_create gecos gid \
		home_create home_dir member_groups name password_expires_on \
		shell uid \
	; do
		local _user_$var
		eval f_shell_escape \"\$user_$var\" _user_$var
	done

	# Attempt to translate a numeric GID into `number (name)'
	if f_isinteger "$_user_gid"; then
		local _user_group
		_user_group=$( pw groupshow -g "$_user_gid" 2> /dev/null ) &&
			_user_group="${_user_group%%:*}" &&
			f_shell_escape "$_user_gid ($_user_group)" _user_gid
	fi

	menu_list="
		'X' '$msg_add/$msg_exit'
		'1' '$msg_login: $_user_name'
		'2' '$msg_full_name: $_user_gecos'
		'3' '$msg_password: -----'
		'4' '$msg_user_id: $_user_uid'
		'5' '$msg_group_id: $_user_gid'
		'6' '$msg_member_of_groups: $_user_member_groups'
		'7' '$msg_login_class: $_user_class'
		'8' '$msg_password_expires_on: $_user_password_expires_on'
		'9' '$msg_account_expires_on: $_user_account_expires_on'
		'A' '$msg_home_directory: $_user_home_dir'
		'B' '$msg_shell: $_user_shell'
	" # END-QUOTE
	case "$user_home_dir" in
	/|/nonexistent|/var/empty) menu_list="$menu_list
		'-' '$msg_create_home_directory: $msg_n_a'
		'-' '$msg_create_dotfiles: $msg_n_a'
	   " # END-QUOTE
	   ;;
	*) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
		'-' '$msg_create_home_directory: $msg_n_a'
		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
	   " # END-QUOTE
	   else menu_list="$menu_list
		'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
	   " # END-QUOTE
	   fi
	esac

	local height width rows
	eval f_dialog_menu_size height width rows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$prompt\"           \
	                        \"\$hline\"            \
	                        $menu_list

	local menu_choice
	menu_choice=$( eval $DIALOG \
		--title \"\$DIALOG_TITLE\"         \
		--backtitle \"\$DIALOG_BACKTITLE\" \
		--hline \"\$hline\"                \
		--ok-label \"\$msg_ok\"            \
		--cancel-label \"\$msg_cancel\"    \
		--default-item \"\$defaultitem\"   \
		--keep-tite                        \
		--menu \"\$prompt\"                \
		$height $width $rows               \
		$menu_list                         \
		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
	)
	local retval=$?
	f_dialog_data_sanitize menu_choice
	f_dialog_menutag_store "$menu_choice"
	return $retval
}

# f_dialog_menu_user_delete $user [$defaultitem]
#
# Present a menu detailing the properties of a login that is about to be
# deleted. The user's menu choice is available using f_dialog_menutag_fetch().
# Returns success unless the user chose Cancel or pressed ESC. Data to display
# is populated automatically from the system accounting database for the given
# $user argument with the exception of two environment variables:
# user_group_delete and user_home_delete. If $defaultitem is present and non-
# NULL, initially highlight the item in the menu.
#
f_dialog_menu_user_delete()
{
	local prompt="$msg_delete_exit_or_cancel"
	local menu_list # Calculated below
	local defaultitem="$2"
	local hline="$hline_arrows_tab_enter"

	local user_name user_password user_uid user_gid user_class
	local user_password_expire user_account_expire user_gecos
	local user_home_dir user_shell user_member_groups
	f_input_user "$1"

	# Attempt to convert numeric UNIX time to calendar date/time
	local user_account_expires_on=
	if f_isinteger "$user_account_expire"; then
		[ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
			date -r "$user_account_expire" "+%F %T %Z"
		)
	else
		user_account_expires_on="$user_account_expire"
	fi
	local user_password_expires_on=
	if f_isinteger "$user_password_expire"; then
		[ $user_password_expire -ne 0 ] && user_password_expires_on=$(
			date -r "$user_password_expire" "+%F %T %Z"
		)
	else
		user_password_expires_on="$user_password_expire"
	fi

	# Localize potentially hostile variables and escape their values
	# to the local variable (see f_shell_escape() of `strings.subr')
	local var
	for var in account_expires_on class gecos gid group_delete \
		home_delete home_dir member_groups name password_expires_on \
		shell uid \
	; do
		local _user_$var
		eval f_shell_escape \"\$user_$var\" _user_$var
	done

	# Attempt to translate a numeric GID into `number (name)'
	if f_isinteger "$_user_gid"; then
		local _user_group
		_user_group=$( pw groupshow -g "$_user_gid" 2> /dev/null ) &&
			_user_group="${_user_group%%:*}" &&
			f_shell_escape "$_user_gid ($_user_group)" _user_gid
	fi

	menu_list="
		'X' '$msg_delete/$msg_exit'
		'1' '$msg_login: $_user_name'
		'-' '$msg_full_name: $_user_gecos'
		'-' '$msg_password: -----'
		'-' '$msg_user_id: $_user_uid'
		'-' '$msg_group_id: $_user_gid'
		'-' '$msg_group_members: $_user_member_groups'
		'-' '$msg_login_class: $_user_class'
		'-' '$msg_password_expires_on: $_user_password_expires_on'
		'-' '$msg_account_expires_on: $_user_account_expires_on'
		'-' '$msg_home_directory: $_user_home_dir'
		'-' '$msg_shell: $_user_shell'
	" # END-QUOTE
	if f_quietly pw groupshow -g "$user_gid"; then menu_list="$menu_list
		'C' '$msg_delete_primary_group: ${_user_group_delete:-$msg_no}'
	" # END-QUOTE
	else menu_list="$menu_list
		'-' '$msg_delete_primary_group: $msg_n_a'
	" # END-QUOTE
	fi
	case "$user_home_dir" in
	/|/nonexistent|/var/empty) menu_list="$menu_list
		'-' '$msg_delete_home_directory: $msg_n_a'
	   " # END-QUOTE
	   ;;
	*) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
		'D' '$msg_delete_home_directory: ${_user_home_delete:-$msg_no}'
	   " # END-QUOTE
	   else menu_list="$menu_list
		'-' '$msg_delete_home_directory: $msg_n_a'
	   " # END-QUOTE
	   fi
	esac

	local height width rows
	eval f_dialog_menu_size height width rows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$prompt\"           \
	                        \"\$hline\"            \
	                        $menu_list

	local menu_choice
	menu_choice=$( eval $DIALOG \
		--title \"\$DIALOG_TITLE\"         \
		--backtitle \"\$DIALOG_BACKTITLE\" \
		--hline \"\$hline\"                \
		--ok-label \"\$msg_ok\"            \
		--cancel-label \"\$msg_cancel\"    \
		--default-item \"\$defaultitem\"   \
		--keep-tite                        \
		--menu \"\$prompt\"                \
		$height $width $rows               \
		$menu_list                         \
		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
	)
	local retval=$?
	f_dialog_data_sanitize menu_choice
	f_dialog_menutag_store "$menu_choice"
	return $retval
}

# f_dialog_menu_user_edit [$defaultitem]
#
# Present a menu detailing the properties of a login that is about to be
# modified. The user's menu choice is available using f_dialog_menutag_fetch().
# Returns success unless the user chose Cancel or pressed ESC. Data to display
# is taken from environment variables user_account_expire, user_class,
# user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
# user_member_groups, user_name, user_password_expire, user_shell, and
# user_uid. If $defaultitem is present and non-NULL, initially highlight the
# item in the menu.
#
f_dialog_menu_user_edit()
{
	local prompt="$msg_save_exit_or_cancel"
	local menu_list # Calculated below
	local defaultitem="$1"
	local hline="$hline_arrows_tab_enter"

	# Attempt to convert numeric UNIX time to calendar date/time
	local user_account_expires_on=
	if f_isinteger "$user_account_expire"; then
		[ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
			date -r "$user_account_expire" "+%F %T %Z"
		)
	else
		user_account_expires_on="$user_account_expire"
	fi
	local user_password_expires_on=
	if f_isinteger "$user_password_expire"; then
		[ $user_password_expire -ne 0 ] && user_password_expires_on=$(
			date -r "$user_password_expire" "+%F %T %Z"
		)
	else
		user_password_expires_on="$user_password_expire"
	fi

	# Localize potentially hostile variables and escape their values
	# to the local variable (see f_shell_escape() of `strings.subr')
	local var
	for var in account_expires_on class dotfiles_create gecos gid \
		home_create home_dir member_groups name password_expires_on \
		shell uid \
	; do
		local _user_$var
		eval f_shell_escape \"\$user_$var\" _user_$var
	done

	# Attempt to translate a numeric GID into `number (name)'
	if f_isinteger "$_user_gid"; then
		local _user_group
		_user_group=$( pw groupshow -g "$_user_gid" 2> /dev/null ) &&
			_user_group="${_user_group%%:*}" &&
			f_shell_escape "$_user_gid ($_user_group)" _user_gid
	fi

	menu_list="
		'X' '$msg_save/$msg_exit'
		'1' '$msg_login: $_user_name'
		'2' '$msg_full_name: $_user_gecos'
		'3' '$msg_password: -----'
		'4' '$msg_user_id: $_user_uid'
		'5' '$msg_group_id: $_user_gid'
		'6' '$msg_member_of_groups: $_user_member_groups'
		'7' '$msg_login_class: $_user_class'
		'8' '$msg_password_expires_on: $_user_password_expires_on'
		'9' '$msg_account_expires_on: $_user_account_expires_on'
		'A' '$msg_home_directory: $_user_home_dir'
		'B' '$msg_shell: $_user_shell'
	" # END-QUOTE
	case "$user_home_dir" in
	/|/nonexistent|/var/empty) menu_list="$menu_list
		'-' '$msg_create_home_directory: $msg_n_a'
		'-' '$msg_create_dotfiles: $msg_n_a'
	   " # END-QUOTE
	   ;;
	*) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
		'-' '$msg_create_home_directory: $msg_n_a'
		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
	   " # END-QUOTE
	   else menu_list="$menu_list
		'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
	   " # END-QUOTE
	   fi
	esac

	local height width rows
	eval f_dialog_menu_size height width rows \
	                        \"\$DIALOG_TITLE\"     \
	                        \"\$DIALOG_BACKTITLE\" \
	                        \"\$prompt\"           \
	                        \"\$hline\"            \
	                        $menu_list

	local menu_choice
	menu_choice=$( eval $DIALOG \
		--title \"\$DIALOG_TITLE\"         \
		--backtitle \"\$DIALOG_BACKTITLE\" \
		--hline \"\$hline\"                \
		--ok-label \"\$msg_ok\"            \
		--cancel-label \"\$msg_cancel\"    \
		--default-item \"\$defaultitem\"   \
		--keep-tite                        \
		--menu \"\$prompt\"                \
		$height $width $rows               \
		$menu_list                         \
		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
	)
	local retval=$?
	f_dialog_data_sanitize menu_choice
	f_dialog_menutag_store "$menu_choice"
	return $retval
}

############################################################ MAIN

f_dprintf "%s: Successfully loaded." usermgmt/user_input.subr

fi # ! $_USERMGMT_USER_INPUT_SUBR

Zerion Mini Shell 1.0