xref: /freebsd/usr.sbin/bsdconfig/usermgmt/share/user_input.subr (revision e7437ae907c89bf85a99c5cbb7ddd194a1ff1354)
1if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
2#
3# Copyright (c) 2012 Ron McDowell
4# Copyright (c) 2012-2014 Devin Teske
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28# $FreeBSD$
29#
30############################################################ INCLUDES
31
32BSDCFG_SHARE="/usr/share/bsdconfig"
33. $BSDCFG_SHARE/common.subr || exit 1
34f_dprintf "%s: loading includes..." usermgmt/user_input.subr
35f_include $BSDCFG_SHARE/dialog.subr
36f_include $BSDCFG_SHARE/strings.subr
37
38BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
39f_include_lang $BSDCFG_LIBE/include/messages.subr
40f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
41
42############################################################ CONFIGURATION
43
44#
45# Default location of shells(5)
46#
47: ${ETC_SHELLS:=/etc/shells}
48
49############################################################ FUNCTIONS
50
51# f_get_member_groups $var_to_set $user
52#
53# Get a list of additional groups $user is a member of in group(5).
54#
55f_get_member_groups()
56{
57	f_replaceall "$( pw groupshow -a | awk -F: -v user="$2" '{
58		if (!split($4, users, /,/)) next
59		for (u in users) if (users[u] == user) { print $1; next }
60	}' )" "[$NL]" "," "$1"
61}
62
63# f_input_user $user
64#
65# Given $user name or id, create the environment variables user_name, user_uid,
66# user_gid, user_class, user_password_expire, user_account_expire, user_gecos,
67# user_home_dir, user_shell, and user_member_groups (and user_password is reset
68# to NULL).
69#
70f_input_user()
71{
72	local funcname=f_input_user
73	local user="$1"
74
75	f_dprintf "$funcname: Getting info for user \`%s'" "$user"
76	eval "$( pw usershow "$user" 2> /dev/null | awk -F: '
77	function set_value(var, value) {
78		gsub(/'\''/, "'\''\\'\'\''", value)
79		printf "user_%s='\'%s\''\n", var, value
80	}
81	{
82		found = $1 != ""
83		set_value("name",            $1 )
84		set_value("password",        "" )
85		set_value("uid",             $3 )
86		set_value("gid",             $4 )
87		set_value("class",           $5 )
88		set_value("password_expire", $6 )
89		set_value("account_expire",  $7 )
90		set_value("gecos",           $8 )
91		set_value("home_dir",        $9 )
92		set_value("shell",           $10)
93		exit
94	}
95	END { if (!found) print "false" }' )"
96	local retval=$?
97
98	f_dprintf "$funcname: Getting group memberships for user \`%s'" "$user"
99	f_get_member_groups user_member_groups "$user"
100
101	return $retval
102}
103
104# f_dialog_menu_user_list [$default]
105#
106# Allows the user to select a login from a list. Optionally, if present and
107# non-NULL, initially highlight $default user.
108#
109f_dialog_menu_user_list()
110{
111	local prompt=
112	local menu_list="
113		'X $msg_exit' ''
114	" # END-QUOTE
115	local defaultitem="$1"
116	local hline="$hline_alnum_punc_tab_enter"
117
118	# Add users from passwd(5)
119	menu_list="$menu_list $( pw usershow -a | awk -F: '
120		function mprint(tag, item) {
121			gsub(/'\''/, "'\''\\'\'\''", tag)
122			gsub(/'\''/, "'\''\\'\'\''", item)
123			printf "'\'%s\'\ \'%s\''\n", tag, item
124		}
125		!/^[[:space:]]*(#|$)/ { mprint($1, $8) }
126	' )"
127
128	local height width rows
129	eval f_dialog_menu_size height width rows \
130	                        \"\$DIALOG_TITLE\"     \
131	                        \"\$DIALOG_BACKTITLE\" \
132	                        \"\$prompt\"           \
133	                        \"\$hline\"            \
134	                        $menu_list
135
136	local menu_choice
137	menu_choice=$( eval $DIALOG \
138		--title \"\$DIALOG_TITLE\"         \
139		--backtitle \"\$DIALOG_BACKTITLE\" \
140		--hline \"\$hline\"                \
141		--ok-label \"\$msg_ok\"            \
142		--cancel-label \"\$msg_cancel\"    \
143		--default-item \"\$defaultitem\"   \
144		--menu \"\$prompt\"                \
145		$height $width $rows               \
146		$menu_list                         \
147		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
148	)
149	local retval=$?
150	f_dialog_menutag_store -s "$menu_choice"
151	return $retval
152}
153
154# f_dialog_input_member_groups $var_to_set [$member_groups]
155#
156# Allows the user to edit group memberships for a given user. If the user does
157# not cancel or press ESC, the $var_to_set variable will hold the newly-
158# configured value upon return.
159#
160f_dialog_input_member_groups()
161{
162	local __var_to_set="$1" __input="$2"
163	local __prompt="$msg_member_of_groups"
164	local __menu_list="
165		'X' '$msg_continue'
166		'1' '$msg_select_groups_from_list'
167		'2' '$msg_enter_groups_manually'
168	" # END-QUOTE
169	local __defaultitem=
170	local __hline="$hline_alnum_space_tab_enter"
171
172	local __mheight __mwidth __mrows
173	eval f_dialog_menu_size __mheight __mwidth __mrows \
174	                        \"\$DIALOG_TITLE\"     \
175	                        \"\$DIALOG_BACKTITLE\" \
176	                        \"\$__prompt\"         \
177	                        \"\$__hline\"          \
178	                        $__menu_list
179
180	local __menu_choice __retval
181	while :; do
182		__menu_choice=$( eval $DIALOG \
183			--title \"\$DIALOG_TITLE\"         \
184			--backtitle \"\$DIALOG_BACKTITLE\" \
185			--hline \"\$__hline\"              \
186			--ok-label \"\$msg_ok\"            \
187			--cancel-label \"\$msg_cancel\"    \
188			--default-item \"\$__defaultitem\" \
189			--menu \"\$__prompt\"              \
190			$__mheight $__mwidth $__mrows      \
191			$__menu_list                       \
192			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
193		)
194		__retval=$?
195		f_dialog_data_sanitize __menu_choice
196		__defaultitem="$__menu_choice"
197		f_dprintf "retval=%u menu_choice=[%s]" \
198		          $__retval "$__menu_choice"
199
200		# Return if user has either pressed ESC or chosen Cancel/No
201		[ $__retval -eq $DIALOG_OK ] || return $__retval
202
203		local __member_groups
204		case "$__menu_choice" in
205		X) # Exit
206			break ;;
207		1) # Select Groups from a list
208			local __check_list= # Calculated below
209			local __group_list __g __grp __length=0
210			__group_list=$( pw groupshow -a |
211				awk -F: '!/^[[:space:]]*(#|$)/{print $1}' )
212			while [ $__length -ne ${#__group_list} ]; do
213				__g="${__group_list%%$NL*}" # First line
214				f_shell_escape "$__g" __grp
215
216				# Format of a checklist entry: tag item status
217				# NB: Setting both tag/item to group name below
218				__check_list="$__check_list '$__grp' '$__grp'"
219				case "$__input" in
220				"$__g"|"$__g",*|*,"$__g",*|*,"$__g")
221					__check_list="$__check_list on" ;;
222				*)
223					__check_list="$__check_list off"
224				esac
225
226				__length=${#__group_list}
227				__group_list="${__group_list#*$NL}" # Kill line
228			done
229
230			local __cheight __cwidth __crows
231
232			eval f_dialog_checklist_size \
233				__cheight __cwidth __crows \
234				\"\$DIALOG_TITLE\"     \
235				\"\$DIALOG_BACKTITLE\" \
236				\"\$__prompt\"         \
237				\"\$__hline\"          \
238				$__check_list
239			__member_groups=$( eval $DIALOG \
240				--title \"\$DIALOG_TITLE\"         \
241				--backtitle \"\$DIALOG_BACKTITLE\" \
242				--separate-output                  \
243				--hline \"\$__hline\"              \
244				--ok-label \"\$msg_ok\"            \
245				--cancel-label \"\$msg_cancel\"    \
246				--checklist \"\$__prompt\"         \
247				$__cheight $__cwidth $__crows      \
248				$__check_list                      \
249				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
250			) || continue
251				# Return to previous menu if user either
252				# pressed ESC or chose Cancel/No
253			f_dialog_data_sanitize __member_groups
254
255			#
256			# Convert the newline separated list into a comma-
257			# separated one so that if the user switches over to
258			# manual editing, list reflects checklist selections
259			#
260			f_replaceall "$__member_groups" "[$NL]" "," __input
261			;;
262		2) # Enter Groups manually
263			local __prompt2="$msg_groups"
264			__prompt2="$__prompt2 ($msg_separated_by_commas)"
265
266			f_dialog_input __member_groups \
267			               "$__prompt2" "$__input" \
268			               "$hline_num_tab_enter" || continue
269				# Return to previous menu if user either
270				# pressed ESC or chose Cancel/No
271
272			#
273			# Validate each of the groups the user has entered
274			#
275			local __all_groups_valid=1 __grp __grp_list
276			f_replaceall "$__member_groups" "," " " __grp_list
277			for __grp in $__grp_list; do
278				if ! f_quietly pw groupshow -n "$__grp"; then
279					f_show_msg "$msg_group_not_found" \
280					           "$__grp"
281					__all_groups_valid=
282					break
283				fi
284			done
285			[ "$__all_groups_valid" ] || continue
286
287			__input="$__member_groups"
288			;;
289		esac
290	done
291
292	setvar "$__var_to_set" "$__input"
293	return $DIALOG_OK
294}
295
296# f_dialog_input_name $var_to_set [$name]
297#
298# Allows the user to enter a new username for a given user. If the user does
299# not cancel or press ESC, the $var_to_set variable will hold the newly-
300# configured value upon return.
301#
302f_dialog_input_name()
303{
304	local __var_to_set="$1" __name="$2"
305
306	#
307	# Loop until the user provides taint-free/valid input
308	#
309	local __input="$__name"
310	while :; do
311		# Return if user has either pressed ESC or chosen Cancel/No
312		f_dialog_input __input "$msg_login" "$__input" \
313		               "$hline_alnum_tab_enter" || return $?
314
315		# Check for no-change
316		if [ "$__input" = "$__name" ]; then
317			setvar "$__var_to_set" "$__input"
318			return $DIALOG_OK
319		fi
320
321		# Check for NULL entry
322		if [ ! "$__input" ]; then
323			f_show_msg "$msg_login_is_empty"
324			continue
325		fi
326
327		# Check for invalid entry
328		case "$__input" in [!a-zA-Z]*)
329			f_show_msg "$msg_login_must_start_with_letter"
330			continue
331		esac
332
333		# Check for duplicate entry
334		if f_quietly pw usershow -n "$__input"; then
335			f_show_msg "$msg_login_already_used" "$__input"
336			continue
337		fi
338
339		setvar "$__var_to_set" "$__input"
340		break
341	done
342
343	return $DIALOG_OK
344}
345
346# f_dialog_input_password $var_to_set $dvar_to_set
347#
348# Prompt the user to enter a password (twice). If the user does not cancel or
349# press ESC, $var_to_set will hold the confirmed user entry. Otherwise, if the
350# user cancels or enters a NULL password (twice), they are given the choice to
351# disable password authentication for the given login, wherein $dvar_to_set has
352# a value of 1 to indicate password authentication should be disabled.
353#
354f_dialog_input_password()
355{
356	local __var_to_set="$1" __dvar_to_set="$2"
357	local __prompt1="$msg_password"
358	local __prompt2="$msg_reenter_password"
359	local __hline="$hline_alnum_punc_tab_enter"
360
361	local __height1 __width1
362	f_dialog_inputbox_size __height1 __width1 \
363	                       "$DIALOG_TITLE"     \
364	                       "$DIALOG_BACKTITLE" \
365	                       "$__prompt1"        \
366	                       ""                  \
367	                       "$__hline"
368	local __height2 __width2
369	f_dialog_inputbox_size __height2 __width2 \
370	                       "$DIALOG_TITLE"     \
371	                       "$DIALOG_BACKTITLE" \
372	                       "$__prompt2"        \
373	                       ""                  \
374	                       "$__hline"
375
376	#
377	# Loop until the user provides taint-free/valid input
378	#
379	local __retval __password1 __password2
380	while :; do
381		__password1=$( $DIALOG \
382			--title "$DIALOG_TITLE"         \
383			--backtitle "$DIALOG_BACKTITLE" \
384			--hline "$__hline"              \
385			--ok-label "$msg_ok"            \
386			--cancel-label "$msg_cancel"    \
387			--insecure                      \
388			--passwordbox "$__prompt1"      \
389			$__height1 $__width1            \
390			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
391		) || return $?
392			# Return if user either pressed ESC or chose Cancel/No
393		debug= f_dialog_line_sanitize __password1
394
395		__password2=$( $DIALOG \
396			--title "$DIALOG_TITLE"         \
397			--backtitle "$DIALOG_BACKTITLE" \
398			--hline "$__hline"              \
399			--ok-label "$msg_ok"            \
400			--cancel-label "$msg_cancel"    \
401			--insecure                      \
402			--passwordbox "$__prompt2"      \
403			$__height2 $__width2            \
404			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
405		) || return $?
406			# Return if user either pressed ESC or chose Cancel/No
407		debug= f_dialog_line_sanitize __password2
408
409		# Check for password mismatch
410		if [ "$__password1" != "$__password2" ]; then
411			f_show_msg "$msg_passwords_do_not_match"
412			continue
413		fi
414
415		# Check for NULL entry
416		if [ ! "$__password1" ]; then
417			f_dialog_yesno "$msg_disable_password_auth_for_account"
418			__retval=$?
419			if [ $__retval -eq $DIALOG_ESC ]; then
420				return $__retval
421			elif [ $__retval -eq $DIALOG_OK ]; then
422				setvar "$__dvar_to_set" 1
423			else
424				continue # back to password prompt
425			fi
426		else
427			setvar "$__dvar_to_set" ""
428		fi
429
430		setvar "$__var_to_set" "$__password1"
431		break
432	done
433
434	return $DIALOG_OK
435}
436
437# f_dialog_input_gecos $var_to_set [$gecos]
438#
439# Allow the user to enter new GECOS information for a given user. This
440# information is commonly used to store the ``Full Name'' of the user. If the
441# user does not cancel or press ESC, the $var_to_set variable will hold the
442# newly-configured value upon return.
443#
444f_dialog_input_gecos()
445{
446	local __var_to_set="$1" __input="$2"
447
448	# Return if user has either pressed ESC or chosen Cancel/No
449	f_dialog_input __input "$msg_full_name" "$__input" \
450	               "$hline_alnum_punc_tab_enter" || return $?
451
452	setvar "$__var_to_set" "$__input"
453	return $DIALOG_OK
454}
455
456# f_dialog_input_uid $var_to_set [$uid]
457#
458# Allow the user to enter a new UID for a given user. If the user does not
459# cancel or press ESC, the $var_to_set variable will hold the newly-configured
460# value upon return.
461#
462f_dialog_input_uid()
463{
464	local __var_to_set="$1" __input="$2"
465
466	# Return if user has either pressed ESC or chosen Cancel/No
467	f_dialog_input __input "$msg_user_id_leave_empty_for_default" \
468	               "$__input" "$hline_num_tab_enter" || return $?
469
470	setvar "$__var_to_set" "$__input"
471	return $DIALOG_OK
472}
473
474# f_dialog_input_gid $var_to_set [$gid]
475#
476# Allow the user to enter a new primary GID for a given user. If the user does
477# not cancel or press ESC, the $var_to_set variable will hold the newly-
478# configured value upon return.
479#
480f_dialog_input_gid()
481{
482	local __var_to_set="$1" __input="$2"
483
484	# Return if user has either pressed ESC or chosen Cancel/No
485	f_dialog_input __input "$msg_group_id_leave_empty_for_default" \
486	               "$__input" "$hline_num_tab_enter" || return $?
487
488	setvar "$__var_to_set" "$__input"
489	return $DIALOG_OK
490}
491
492# f_dialog_input_class $var_to_set [$class]
493#
494# Allow the user to enter a new login class for a given user. If the user does
495# not cancel or press ESC, the $var_to_set variable will hold the newly-
496# configured value upon return.
497#
498f_dialog_input_class()
499{
500	local __var_to_set="$1" __input="$2"
501
502	# Return if user has either pressed ESC or chosen Cancel/No
503	f_dialog_input __input "$msg_login_class" "$__input" \
504	               "$hline_alnum_tab_enter" || return $?
505
506	setvar "$__var_to_set" "$__input"
507	return $DIALOG_OK
508}
509
510# f_dialog_input_expire_password $var_to_set [$seconds]
511#
512# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
513# for when a given user's password must be changed. If the user does not cancel
514# or press ESC, the $var_to_set variable will hold the newly-configured value
515# upon return.
516#
517f_dialog_input_expire_password()
518{
519	local __var_to_set="$1" __input="$2"
520	local __prompt="$msg_password_expires_on"
521	local __menu_list="
522		'1' '$msg_password_does_not_expire'
523		'2' '$msg_edit_date_time_with_a_calendar'
524		'3' '$msg_enter_value_manually'
525	" # END-QUOTE
526	local __defaultitem= # Calculated below
527	local __hline="$hline_num_arrows_tab_enter"
528
529	local __mheight __mwidth __mrows
530	eval f_dialog_menu_size __mheight __mwidth __mrows \
531	                        \"\$DIALOG_TITLE\"     \
532	                        \"\$DIALOG_BACKTITLE\" \
533	                        \"\$__prompt\"         \
534	                        \"\$__hline\"          \
535	                        $__menu_list
536	local __cheight __cwidth
537	f_dialog_calendar_size __cheight __cwidth \
538	                       "$DIALOG_TITLE"     \
539	                       "$DIALOG_BACKTITLE" \
540	                       "$__prompt"         \
541	                       "$__hline"
542	local __theight __twidth
543	f_dialog_timebox_size __theight __twidth \
544	                      "$DIALOG_TITLE"     \
545	                      "$DIALOG_BACKTITLE" \
546	                      "$__prompt"         \
547	                      "$__hline"
548
549	#
550	# Loop until the user provides taint-free/cancellation-free input
551	#
552	local __retval __date_type
553	while :; do
554		__date_type=$( eval $DIALOG \
555			--title \"\$DIALOG_TITLE\"         \
556			--backtitle \"\$DIALOG_BACKTITLE\" \
557			--hline \"\$__hline\"              \
558			--default-item \"\$__defaultitem\" \
559			--ok-label \"\$msg_ok\"            \
560			--cancel-label \"\$msg_cancel\"    \
561			--menu \"\$__prompt\"              \
562			$__mheight $__mwidth $__mrows      \
563			$__menu_list                       \
564			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
565		)
566		__retval=$?
567		f_dialog_data_sanitize __date_type
568		__defaultitem="$__date_type"
569		f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"
570
571		# Return if user has either pressed ESC or chosen Cancel/No
572		[ $__retval -eq $DIALOG_OK ] || return $__retval
573
574		case "$__date_type" in
575		1) # Password does not expire
576			__input= break ;;
577
578		2) # Edit date/time with a calendar
579			local __input_date __input_time __ret_date __ret_time
580
581			local __seconds="$__input"
582			{ f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
583				__seconds=
584			__input_date=$( date -j -f "%s" -- "$__seconds" \
585			               		"+%d %m %Y" 2> /dev/null )
586			__ret_date=$( eval $DIALOG \
587				--title \"\$DIALOG_TITLE\"          \
588				--backtitle \"\$DIALOG_BACKTITLE\"  \
589				--hline \"\$__hline\"               \
590				--ok-label \"\$msg_ok\"             \
591				--cancel-label \"\$msg_cancel\"     \
592				--calendar \"\$__prompt\"           \
593				$__cheight $__cwidth                \
594				$__input_date                       \
595				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
596			)
597			__retval=$?
598			f_dialog_data_sanitize __ret_date
599			f_dprintf "retval=%u ret_date=[%s]" \
600			          $__retval "$__ret_date"
601
602			# Return to menu if either ESC or Cancel/No
603			[ $__retval -eq $DIALOG_OK ] || continue
604
605			__input_time=
606			[ "$__seconds" ] && __input_time=$( date -j \
607				-f %s -- "$__input" "+%H %M %S" 2> /dev/null )
608			__ret_time=$( eval $DIALOG \
609				--title \"\$DIALOG_TITLE\"         \
610				--backtitle \"\$DIALOG_BACKTITLE\" \
611				--hline \"\$__hline\"              \
612				--ok-label \"\$msg_ok\"            \
613				--cancel-label \"\$msg_cancel\"    \
614				--timebox \"\$__prompt\"           \
615				$__theight $__twidth               \
616				$__input_time                      \
617				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
618			)
619			__retval=$?
620			f_dialog_data_sanitize __ret_time
621			f_dprintf "retval=%u ret_time=[%s]" \
622			          $__retval "$__ret_time"
623
624			# Return to menu if either ESC or Cancel/No
625			[ $__retval -eq $DIALOG_OK ] || continue
626
627			__input=$( date -j -f "%d/%m/%Y %T" -- \
628				"$__ret_date $__ret_time" +%s 2> /dev/null )
629			f_dprintf "input=[%s]" "$__input"
630			break ;;
631
632		3) # Enter value manually
633			local __msg __new_input
634			f_sprintf __msg "$msg_password_expire_manual_edit" \
635			                "$( date -r 0 "+%c %Z" )"
636
637			# Return to menu if either ESC or Cancel/No
638			f_dialog_input __new_input \
639				"$__msg" "$__input" "$__hline" || continue
640
641			__input="$__new_input"
642			f_dprintf "input=[%s]" "$__input"
643			break ;;
644
645		esac
646
647	done # Loop forever
648
649	setvar "$__var_to_set" "$__input"
650	return $DIALOG_OK
651}
652
653# f_dialog_input_expire_account $var_to_set [$seconds]
654#
655# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
656# for when a given user's account should become expired. If the user does not
657# cancel or press ESC, the $var_to_set variable will hold the newly-configured
658# value upon return.
659#
660f_dialog_input_expire_account()
661{
662	local __var_to_set="$1" __input="$2"
663	local __prompt="$msg_account_expires_on"
664	local __menu_list="
665		'1' '$msg_account_does_not_expire'
666		'2' '$msg_edit_date_time_with_a_calendar'
667		'3' '$msg_enter_value_manually'
668	" # END-QUOTE
669	local __defaultitem= # Calculated below
670	local __hline="$hline_num_arrows_tab_enter"
671
672	local __mheight __mwidth __mrows
673	eval f_dialog_menu_size __mheight __mwidth __mrows \
674	                        \"\$DIALOG_TITLE\"     \
675	                        \"\$DIALOG_BACKTITLE\" \
676	                        \"\$__prompt\"         \
677	                        \"\$__hline\"          \
678	                        $__menu_list
679	local __cheight __cwidth
680	f_dialog_calendar_size __cheight __cwidth \
681	                       "$DIALOG_TITLE"     \
682	                       "$DIALOG_BACKTITLE" \
683	                       "$__prompt"         \
684	                       "$__hline"
685	local __theight __twidth
686	f_dialog_timebox_size __theight __twidth \
687	                      "$DIALOG_TITLE"     \
688	                      "$DIALOG_BACKTITLE" \
689	                      "$__prompt"         \
690	                      "$__hline"
691
692	#
693	# Loop until the user provides taint-free/cancellation-free input
694	#
695	local __retval __date_type
696	while :; do
697		__date_type=$( eval $DIALOG \
698			--title \"\$DIALOG_TITLE\"         \
699			--backtitle \"\$DIALOG_BACKTITLE\" \
700			--hline \"\$__hline\"              \
701			--default-item \"\$__defaultitem\" \
702			--ok-label \"\$msg_ok\"            \
703			--cancel-label \"\$msg_cancel\"    \
704			--menu \"\$__prompt\"              \
705			$__mheight $__mwidth $__mrows      \
706			$__menu_list                       \
707			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
708		)
709		__retval=$?
710		f_dialog_data_sanitize __date_type
711		__defaultitem="$__date_type"
712		f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"
713
714		# Return if user has either pressed ESC or chosen Cancel/No
715		[ $__retval -eq $DIALOG_OK ] || return $__retval
716
717		case "$__date_type" in
718		1) # Account does not expire
719			__input= break ;;
720
721		2) # Edit date/time with a calendar
722			local __input_date __input_time __ret_date __ret_time
723
724			local __seconds="$__input"
725			{ f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
726				__seconds=
727			__input_date=$( date -j -f "%s" -- "$__seconds" \
728			               		"+%d %m %Y" 2> /dev/null )
729			__ret_date=$( eval $DIALOG \
730				--title \"\$DIALOG_TITLE\"          \
731				--backtitle \"\$DIALOG_BACKTITLE\"  \
732				--hline \"\$__hline\"               \
733				--ok-label \"\$msg_ok\"             \
734				--cancel-label \"\$msg_cancel\"     \
735				--calendar \"\$__prompt\"           \
736				$__cheight $__cwidth                \
737				$__input_date                       \
738				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
739			)
740			__retval=$?
741			f_dialog_data_sanitize __ret_date
742			f_dprintf "retval=%u ret_date=[%s]" \
743			          $__retval "$__ret_date"
744
745			# Return to menu if either ESC or Cancel/No
746			[ $__retval -eq $DIALOG_OK ] || continue
747
748			__input_time=
749			[ "$__seconds" ] && __input_time=$( date -j \
750				-f %s -- "$__input" "+%H %M %S" 2> /dev/null )
751			__ret_time=$( eval $DIALOG \
752				--title \"\$DIALOG_TITLE\"         \
753				--backtitle \"\$DIALOG_BACKTITLE\" \
754				--hline \"\$__hline\"              \
755				--ok-label \"\$msg_ok\"            \
756				--cancel-label \"\$msg_cancel\"    \
757				--timebox \"\$__prompt\"           \
758				$__theight $__twidth               \
759				$__input_time                      \
760				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
761			)
762			__retval=$?
763			f_dialog_data_sanitize __ret_time
764			f_dprintf "retval=%u ret_time=[%s]" \
765			          $__retval "$__ret_time"
766
767			# Return to menu if either ESC or Cancel/No
768			[ $__retval -eq $DIALOG_OK ] || continue
769
770			__input=$( date -j -f "%d/%m/%Y %T" -- \
771				"$ret_date $ret_time" +%s 2> /dev/null )
772			f_dprintf "input=[%s]" "$__input"
773			break ;;
774
775		3) # Enter value manually
776			local __msg __new_input
777			f_sprintf __msg "$msg_account_expire_manual_edit" \
778			                "$( date -r 0 "+%c %Z" )"
779
780			# Return to menu if either ESC or Cancel/No
781			f_dialog_input __new_input \
782				"$__msg" "$__input" "$__hline" || continue
783
784			__input="$__new_input"
785			f_dprintf "input=[%s]" "$__input"
786			break ;;
787
788		esac
789
790	done # Loop forever
791
792	setvar "$__var_to_set" "$__input"
793	return $DIALOG_OK
794}
795
796# f_dialog_input_home_dir $var_to_set [$home_dir]
797#
798# Allow the user to enter a new home directory for a given login. If the user
799# does not cancel or press ESC, the $var_to_set variable will hold the newly-
800# configured value upon return.
801#
802f_dialog_input_home_dir()
803{
804	local __var_to_set="$1" __input="$2"
805
806	# Return if user has either pressed ESC or chosen Cancel/No
807	f_dialog_input __input "$msg_home_directory" "$__input" \
808	               "$hline_alnum_punc_tab_enter" || return $?
809
810	setvar "$__var_to_set" "$__input"
811	return $DIALOG_OK
812}
813
814# f_dialog_input_home_create $var_to_set
815#
816# Prompt the user to confirm creation of a given login's home directory. If the
817# user does not cancel (by choosing "No") or press ESC, the $var_to_set
818# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
819# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
820#
821f_dialog_input_home_create()
822{
823	local __var_to_set="$1"
824
825	f_dialog_yesno "$msg_create_home_directory"
826	local __retval=$?
827
828	if [ $__retval -eq $DIALOG_OK ]; then
829		setvar "$__var_to_set" "$msg_yes"
830	else
831		setvar "$__var_to_set" "$msg_no"
832	fi
833
834	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
835}
836
837# f_dialog_input_group_delete $var_to_set [$group]
838#
839# Prompt the user to confirm deletion of a given login's primary group. If the
840# user does not cancel (by choosing "No") or press ESC, the $var_to_set
841# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
842# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
843#
844f_dialog_input_group_delete()
845{
846	local __var_to_set="$1" __group="$2"
847
848	if f_isinteger "$__group"; then
849		if [ $__group -lt 1000 ]; then
850			f_dialog_noyes "$msg_delete_primary_group"
851		else
852			f_dialog_yesno "$msg_delete_primary_group"
853		fi
854	elif [ "$__group" ]; then
855		local __gid=0
856		__gid=$( pw groupshow "$__group" | awk -F: '{print $3}' )
857		if f_isinteger "$__gid" && [ $__gid -lt 1000 ]; then
858			f_dialog_noyes "$msg_delete_primary_group"
859		else
860			f_dialog_yesno "$msg_delete_primary_group"
861		fi
862	else
863		f_dialog_yesno "$msg_delete_primary_group"
864	fi
865	local __retval=$?
866
867	if [ $__retval -eq $DIALOG_OK ]; then
868		setvar "$__var_to_set" "$msg_yes"
869	else
870		setvar "$__var_to_set" "$msg_no"
871	fi
872
873	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
874}
875
876# f_dialog_input_home_delete $var_to_set
877#
878# Prompt the user to confirm deletion of a given login's home directory. If the
879# user does not cancel (by choosing "No") or press ESC, the $var_to_set
880# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
881# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
882#
883f_dialog_input_home_delete()
884{
885	local __var_to_set="$1"
886
887	f_dialog_yesno "$msg_delete_home_directory"
888	local __retval=$?
889
890	if [ $__retval -eq $DIALOG_OK ]; then
891		setvar "$__var_to_set" "$msg_yes"
892	else
893		setvar "$__var_to_set" "$msg_no"
894	fi
895
896	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
897}
898
899# f_dialog_input_dotfiles_create $var_to_set
900#
901# Prompt the user to confirm population of a given login's home directory with
902# sample dotfiles. If the user does not cancel (by choosing "No") or press ESC,
903# the $var_to_set variable will hold $msg_yes upon return, otherwise $msg_no.
904# Use these return variables ($msg_yes and $msg_no) for comparison to be i18n-
905# compatible.
906#
907f_dialog_input_dotfiles_create()
908{
909	local __var_to_set="$1"
910
911	f_dialog_yesno "$msg_create_dotfiles"
912	local __retval=$?
913
914	if [ $__retval -eq $DIALOG_OK ]; then
915		setvar "$__var_to_set" "$msg_yes"
916	else
917		setvar "$__var_to_set" "$msg_no"
918	fi
919
920	[ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
921}
922
923# f_dialog_input_shell $var_to_set [$shell]
924#
925# Allow the user to select a new shell for a given login. If the user does not
926# cancel or press ESC, the $var_to_set variable will hold the newly-configured
927# value upon return.
928#
929f_dialog_input_shell()
930{
931	local __funcname=f_dialog_input_shell
932	local __var_to_set="$1" __input="$2"
933	local __prompt="$msg_select_login_shell"
934	local __radio_list= # Calculated below
935	local __defaultitem="$2"
936	local __hline="$hline_arrows_space_tab_enter"
937
938	#
939	# Generate the radiolist of shells
940	#
941	local __shell_list __s __shell __length=0
942	f_eval_catch -k __shell_list $__funcname awk "awk '%s' \"%s\"" \
943		'!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" || return $FAILURE
944	while [ $__length -ne ${#__shell_list} ]; do
945		__s="${__shell_list%%$NL*}" # First line
946		f_shell_escape "$__s" __shell
947
948		# Format of a radiolist entry: tag item status
949		if [ "$__s" = "$__input" ]; then
950			__radio_list="$__radio_list '$__shell' '' 'on'"
951		else
952			__radio_list="$__radio_list '$__shell' '' 'off'"
953		fi
954
955		__length=${#__shell_list}
956		__shell_list="${__shell_list#*$NL}" # Kill line
957	done
958
959	local __height __width __rows
960	eval f_dialog_radiolist_size __height __width __rows \
961	                             \"\$DIALOG_TITLE\"     \
962	                             \"\$DIALOG_BACKTITLE\" \
963	                             \"\$__prompt\"         \
964	                             \"\$__hline\"          \
965	                             $__radio_list
966
967	__input=$( eval $DIALOG \
968		--title \"\$DIALOG_TITLE\"         \
969		--backtitle \"\$DIALOG_BACKTITLE\" \
970		--hline \"\$__hline\"              \
971		--ok-label \"\$msg_ok\"            \
972		--cancel-label \"\$msg_cancel\"    \
973		--default-item \"\$__defaultitem\" \
974		--radiolist \"\$__prompt\"         \
975		$__height $__width $__rows         \
976		$__radio_list                      \
977		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
978	) || return $?
979		# Return if user either pressed ESC or chose Cancel/No
980	f_dialog_data_sanitize __input
981
982	setvar "$__var_to_set" "$__input"
983	return $DIALOG_OK
984}
985
986# f_dialog_menu_user_add [$defaultitem]
987#
988# Present a menu detailing the properties of a login that is about to be added.
989# The user's menu choice is available using f_dialog_menutag_fetch(). Returns
990# success unless the user chose Cancel or pressed ESC. Data to display is taken
991# from environment variables user_account_expire, user_class,
992# user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
993# user_member_groups, user_name, user_password_expire, user_shell, and
994# user_uid. If $defaultitem is present and non-NULL, initially highlight the
995# item in the menu.
996#
997f_dialog_menu_user_add()
998{
999	local funcname=f_dialog_menu_user_add
1000	local prompt="$msg_save_exit_or_cancel"
1001	local menu_list # Calculated below
1002	local defaultitem="$1"
1003	local hline="$hline_arrows_tab_enter"
1004
1005	# Attempt to convert numeric UNIX time to calendar date/time
1006	local user_account_expires_on=
1007	if f_isinteger "$user_account_expire"; then
1008		[ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
1009			date -r "$user_account_expire" "+%F %T %Z"
1010		)
1011	else
1012		user_account_expires_on="$user_account_expire"
1013	fi
1014	local user_password_expires_on=
1015	if f_isinteger "$user_password_expire"; then
1016		[ $user_password_expire -ne 0 ] && user_password_expires_on=$(
1017			date -r "$user_password_expire" "+%F %T %Z"
1018		)
1019	else
1020		user_password_expires_on="$user_password_expire"
1021	fi
1022
1023	# Localize potentially hostile variables and escape their values
1024	# to the local variable (see f_shell_escape() of `strings.subr')
1025	local var
1026	for var in account_expires_on class dotfiles_create gecos gid \
1027		home_create home_dir member_groups name password_expires_on \
1028		shell uid \
1029	; do
1030		local _user_$var
1031		eval f_shell_escape \"\$user_$var\" _user_$var
1032	done
1033
1034	# Attempt to translate a numeric GID into `number (name)'
1035	if f_isinteger "$_user_gid"; then
1036		local _user_group
1037		_user_group=$( pw groupshow -g "$_user_gid" 2> /dev/null ) &&
1038			_user_group="${_user_group%%:*}" &&
1039			f_shell_escape "$_user_gid ($_user_group)" _user_gid
1040	fi
1041
1042	menu_list="
1043		'X' '$msg_add/$msg_exit'
1044		'1' '$msg_login: $_user_name'
1045		'2' '$msg_full_name: $_user_gecos'
1046		'3' '$msg_password: -----'
1047		'4' '$msg_user_id: $_user_uid'
1048		'5' '$msg_group_id: $_user_gid'
1049		'6' '$msg_member_of_groups: $_user_member_groups'
1050		'7' '$msg_login_class: $_user_class'
1051		'8' '$msg_password_expires_on: $_user_password_expires_on'
1052		'9' '$msg_account_expires_on: $_user_account_expires_on'
1053		'A' '$msg_home_directory: $_user_home_dir'
1054		'B' '$msg_shell: $_user_shell'
1055	" # END-QUOTE
1056	case "$user_home_dir" in
1057	/|/nonexistent|/var/empty) menu_list="$menu_list
1058		'-' '$msg_create_home_directory: $msg_n_a'
1059		'-' '$msg_create_dotfiles: $msg_n_a'
1060	   " # END-QUOTE
1061	   ;;
1062	*) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
1063		'-' '$msg_create_home_directory: $msg_n_a'
1064		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1065	   " # END-QUOTE
1066	   else menu_list="$menu_list
1067		'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
1068		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1069	   " # END-QUOTE
1070	   fi
1071	esac
1072
1073	local height width rows
1074	eval f_dialog_menu_size height width rows \
1075	                        \"\$DIALOG_TITLE\"     \
1076	                        \"\$DIALOG_BACKTITLE\" \
1077	                        \"\$prompt\"           \
1078	                        \"\$hline\"            \
1079	                        $menu_list
1080
1081	local menu_choice
1082	menu_choice=$( eval $DIALOG \
1083		--title \"\$DIALOG_TITLE\"         \
1084		--backtitle \"\$DIALOG_BACKTITLE\" \
1085		--hline \"\$hline\"                \
1086		--ok-label \"\$msg_ok\"            \
1087		--cancel-label \"\$msg_cancel\"    \
1088		--default-item \"\$defaultitem\"   \
1089		--keep-tite                        \
1090		--menu \"\$prompt\"                \
1091		$height $width $rows               \
1092		$menu_list                         \
1093		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1094	)
1095	local retval=$?
1096	f_dialog_data_sanitize menu_choice
1097	f_dialog_menutag_store "$menu_choice"
1098	return $retval
1099}
1100
1101# f_dialog_menu_user_delete $user [$defaultitem]
1102#
1103# Present a menu detailing the properties of a login that is about to be
1104# deleted. The user's menu choice is available using f_dialog_menutag_fetch().
1105# Returns success unless the user chose Cancel or pressed ESC. Data to display
1106# is populated automatically from the system accounting database for the given
1107# $user argument with the exception of two environment variables:
1108# user_group_delete and user_home_delete. If $defaultitem is present and non-
1109# NULL, initially highlight the item in the menu.
1110#
1111f_dialog_menu_user_delete()
1112{
1113	local prompt="$msg_delete_exit_or_cancel"
1114	local menu_list # Calculated below
1115	local defaultitem="$2"
1116	local hline="$hline_arrows_tab_enter"
1117
1118	local user_name user_password user_uid user_gid user_class
1119	local user_password_expire user_account_expire user_gecos
1120	local user_home_dir user_shell user_member_groups
1121	f_input_user "$1"
1122
1123	# Attempt to convert numeric UNIX time to calendar date/time
1124	local user_account_expires_on=
1125	if f_isinteger "$user_account_expire"; then
1126		[ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
1127			date -r "$user_account_expire" "+%F %T %Z"
1128		)
1129	else
1130		user_account_expires_on="$user_account_expire"
1131	fi
1132	local user_password_expires_on=
1133	if f_isinteger "$user_password_expire"; then
1134		[ $user_password_expire -ne 0 ] && user_password_expires_on=$(
1135			date -r "$user_password_expire" "+%F %T %Z"
1136		)
1137	else
1138		user_password_expires_on="$user_password_expire"
1139	fi
1140
1141	# Localize potentially hostile variables and escape their values
1142	# to the local variable (see f_shell_escape() of `strings.subr')
1143	local var
1144	for var in account_expires_on class gecos gid group_delete \
1145		home_delete home_dir member_groups name password_expires_on \
1146		shell uid \
1147	; do
1148		local _user_$var
1149		eval f_shell_escape \"\$user_$var\" _user_$var
1150	done
1151
1152	# Attempt to translate a numeric GID into `number (name)'
1153	if f_isinteger "$_user_gid"; then
1154		local _user_group
1155		_user_group=$( pw groupshow -g "$_user_gid" 2> /dev/null ) &&
1156			_user_group="${_user_group%%:*}" &&
1157			f_shell_escape "$_user_gid ($_user_group)" _user_gid
1158	fi
1159
1160	menu_list="
1161		'X' '$msg_delete/$msg_exit'
1162		'1' '$msg_login: $_user_name'
1163		'-' '$msg_full_name: $_user_gecos'
1164		'-' '$msg_password: -----'
1165		'-' '$msg_user_id: $_user_uid'
1166		'-' '$msg_group_id: $_user_gid'
1167		'-' '$msg_group_members: $_user_member_groups'
1168		'-' '$msg_login_class: $_user_class'
1169		'-' '$msg_password_expires_on: $_user_password_expires_on'
1170		'-' '$msg_account_expires_on: $_user_account_expires_on'
1171		'-' '$msg_home_directory: $_user_home_dir'
1172		'-' '$msg_shell: $_user_shell'
1173	" # END-QUOTE
1174	if f_quietly pw groupshow -g "$user_gid"; then menu_list="$menu_list
1175		'C' '$msg_delete_primary_group: ${_user_group_delete:-$msg_no}'
1176	" # END-QUOTE
1177	else menu_list="$menu_list
1178		'-' '$msg_delete_primary_group: $msg_n_a'
1179	" # END-QUOTE
1180	fi
1181	case "$user_home_dir" in
1182	/|/nonexistent|/var/empty) menu_list="$menu_list
1183		'-' '$msg_delete_home_directory: $msg_n_a'
1184	   " # END-QUOTE
1185	   ;;
1186	*) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
1187		'D' '$msg_delete_home_directory: ${_user_home_delete:-$msg_no}'
1188	   " # END-QUOTE
1189	   else menu_list="$menu_list
1190		'-' '$msg_delete_home_directory: $msg_n_a'
1191	   " # END-QUOTE
1192	   fi
1193	esac
1194
1195	local height width rows
1196	eval f_dialog_menu_size height width rows \
1197	                        \"\$DIALOG_TITLE\"     \
1198	                        \"\$DIALOG_BACKTITLE\" \
1199	                        \"\$prompt\"           \
1200	                        \"\$hline\"            \
1201	                        $menu_list
1202
1203	local menu_choice
1204	menu_choice=$( eval $DIALOG \
1205		--title \"\$DIALOG_TITLE\"         \
1206		--backtitle \"\$DIALOG_BACKTITLE\" \
1207		--hline \"\$hline\"                \
1208		--ok-label \"\$msg_ok\"            \
1209		--cancel-label \"\$msg_cancel\"    \
1210		--default-item \"\$defaultitem\"   \
1211		--keep-tite                        \
1212		--menu \"\$prompt\"                \
1213		$height $width $rows               \
1214		$menu_list                         \
1215		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1216	)
1217	local retval=$?
1218	f_dialog_data_sanitize menu_choice
1219	f_dialog_menutag_store "$menu_choice"
1220	return $retval
1221}
1222
1223# f_dialog_menu_user_edit [$defaultitem]
1224#
1225# Present a menu detailing the properties of a login that is about to be
1226# modified. The user's menu choice is available using f_dialog_menutag_fetch().
1227# Returns success unless the user chose Cancel or pressed ESC. Data to display
1228# is taken from environment variables user_account_expire, user_class,
1229# user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
1230# user_member_groups, user_name, user_password_expire, user_shell, and
1231# user_uid. If $defaultitem is present and non-NULL, initially highlight the
1232# item in the menu.
1233#
1234f_dialog_menu_user_edit()
1235{
1236	local prompt="$msg_save_exit_or_cancel"
1237	local menu_list # Calculated below
1238	local defaultitem="$1"
1239	local hline="$hline_arrows_tab_enter"
1240
1241	# Attempt to convert numeric UNIX time to calendar date/time
1242	local user_account_expires_on=
1243	if f_isinteger "$user_account_expire"; then
1244		[ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
1245			date -r "$user_account_expire" "+%F %T %Z"
1246		)
1247	else
1248		user_account_expires_on="$user_account_expire"
1249	fi
1250	local user_password_expires_on=
1251	if f_isinteger "$user_password_expire"; then
1252		[ $user_password_expire -ne 0 ] && user_password_expires_on=$(
1253			date -r "$user_password_expire" "+%F %T %Z"
1254		)
1255	else
1256		user_password_expires_on="$user_password_expire"
1257	fi
1258
1259	# Localize potentially hostile variables and escape their values
1260	# to the local variable (see f_shell_escape() of `strings.subr')
1261	local var
1262	for var in account_expires_on class dotfiles_create gecos gid \
1263		home_create home_dir member_groups name password_expires_on \
1264		shell uid \
1265	; do
1266		local _user_$var
1267		eval f_shell_escape \"\$user_$var\" _user_$var
1268	done
1269
1270	# Attempt to translate a numeric GID into `number (name)'
1271	if f_isinteger "$_user_gid"; then
1272		local _user_group
1273		_user_group=$( pw groupshow -g "$_user_gid" 2> /dev/null ) &&
1274			_user_group="${_user_group%%:*}" &&
1275			f_shell_escape "$_user_gid ($_user_group)" _user_gid
1276	fi
1277
1278	menu_list="
1279		'X' '$msg_save/$msg_exit'
1280		'1' '$msg_login: $_user_name'
1281		'2' '$msg_full_name: $_user_gecos'
1282		'3' '$msg_password: -----'
1283		'4' '$msg_user_id: $_user_uid'
1284		'5' '$msg_group_id: $_user_gid'
1285		'6' '$msg_member_of_groups: $_user_member_groups'
1286		'7' '$msg_login_class: $_user_class'
1287		'8' '$msg_password_expires_on: $_user_password_expires_on'
1288		'9' '$msg_account_expires_on: $_user_account_expires_on'
1289		'A' '$msg_home_directory: $_user_home_dir'
1290		'B' '$msg_shell: $_user_shell'
1291	" # END-QUOTE
1292	case "$user_home_dir" in
1293	/|/nonexistent|/var/empty) menu_list="$menu_list
1294		'-' '$msg_create_home_directory: $msg_n_a'
1295		'-' '$msg_create_dotfiles: $msg_n_a'
1296	   " # END-QUOTE
1297	   ;;
1298	*) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
1299		'-' '$msg_create_home_directory: $msg_n_a'
1300		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1301	   " # END-QUOTE
1302	   else menu_list="$menu_list
1303		'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
1304		'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1305	   " # END-QUOTE
1306	   fi
1307	esac
1308
1309	local height width rows
1310	eval f_dialog_menu_size height width rows \
1311	                        \"\$DIALOG_TITLE\"     \
1312	                        \"\$DIALOG_BACKTITLE\" \
1313	                        \"\$prompt\"           \
1314	                        \"\$hline\"            \
1315	                        $menu_list
1316
1317	local menu_choice
1318	menu_choice=$( eval $DIALOG \
1319		--title \"\$DIALOG_TITLE\"         \
1320		--backtitle \"\$DIALOG_BACKTITLE\" \
1321		--hline \"\$hline\"                \
1322		--ok-label \"\$msg_ok\"            \
1323		--cancel-label \"\$msg_cancel\"    \
1324		--default-item \"\$defaultitem\"   \
1325		--keep-tite                        \
1326		--menu \"\$prompt\"                \
1327		$height $width $rows               \
1328		$menu_list                         \
1329		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1330	)
1331	local retval=$?
1332	f_dialog_data_sanitize menu_choice
1333	f_dialog_menutag_store "$menu_choice"
1334	return $retval
1335}
1336
1337############################################################ MAIN
1338
1339f_dprintf "%s: Successfully loaded." usermgmt/user_input.subr
1340
1341fi # ! $_USERMGMT_USER_INPUT_SUBR
1342