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