1238438Sdteske#!/bin/sh
2238438Sdteske#-
3249746Sdteske# Copyright (c) 2012-2013 Devin Teske
4252980Sdteske# All rights reserved.
5238438Sdteske#
6238438Sdteske# Redistribution and use in source and binary forms, with or without
7238438Sdteske# modification, are permitted provided that the following conditions
8238438Sdteske# are met:
9238438Sdteske# 1. Redistributions of source code must retain the above copyright
10238438Sdteske#    notice, this list of conditions and the following disclaimer.
11238438Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12238438Sdteske#    notice, this list of conditions and the following disclaimer in the
13238438Sdteske#    documentation and/or other materials provided with the distribution.
14238438Sdteske#
15238438Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16252987Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17238438Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18238438Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19238438Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20252987Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21238438Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22238438Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23238438Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24238438Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25238438Sdteske# SUCH DAMAGE.
26238438Sdteske#
27238438Sdteske# $FreeBSD$
28238438Sdteske#
29238438Sdteske############################################################ INCLUDES
30238438Sdteske
31240684SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
32240684Sdteske. $BSDCFG_SHARE/common.subr || exit 1
33244675Sdteskef_dprintf "%s: loading includes..." "$0"
34240684Sdteskef_include $BSDCFG_SHARE/dialog.subr
35240684Sdteskef_include $BSDCFG_SHARE/mustberoot.subr
36240684Sdteskef_include $BSDCFG_SHARE/sysrc.subr
37240684Sdteskef_include $BSDCFG_SHARE/startup/rcconf.subr
38238438Sdteske
39240684SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="140.startup"
40238438Sdteskef_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
41238438Sdteske
42260678Sdteskef_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
43260678Sdteske	pgm="${ipgm:-$pgm}"
44238438Sdteske
45238438Sdteske############################################################ GLOBALS
46238438Sdteske
47238438Sdteske#
48238438Sdteske# Global map/menu-list for the main menu
49238438Sdteske#
50238438SdteskeRCCONF_MAP=
51238438SdteskeRCCONF_MENU_LIST=
52238438Sdteske
53238438Sdteske#
54238438Sdteske# Options
55238438Sdteske#
56238438Sdteske# Inherit SHOW_DESC value if set, otherwise default to 1
57240798Sdteske[ "${SHOW_DESC+set}" ] || SHOW_DESC=1
58238438Sdteske# Selectively inherit SHOW_* value (in order of preference)
59238438Sdteskeif [ "$SHOW_DEFAULT_VALUE" ]; then
60238438Sdteske	SHOW_DEFAULT_VALUE=1
61238438Sdteske	SHOW_CONFIGURED=
62238438Sdteske	SHOW_VALUE=
63238438Sdteskeelif [ "$SHOW_CONFIGURED" ]; then
64238438Sdteske	SHOW_DEFAULT_VALUE=
65238438Sdteske	SHOW_CONFIGURED=1
66238438Sdteske	SHOW_VALUE=
67238438Sdteskeelse
68238438Sdteske	SHOW_DEFAULT_VALUE=
69238438Sdteske	SHOW_CONFIGURED=
70238438Sdteske	SHOW_VALUE=1
71238438Sdteskefi
72238438Sdteske
73238438Sdteske############################################################ FUNCTIONS
74238438Sdteske
75249751Sdteske# dialog_create_main
76238438Sdteske#
77249751Sdteske# Create the dialog(1) main menu. Separated from dialog_menu_main (used to
78249751Sdteske# display the menu) to speed up execution (we only call this function when
79249751Sdteske# initializing or changing the view details).
80238438Sdteske#
81249751Sdteskedialog_create_main()
82238438Sdteske{
83238438Sdteske	# Show infobox for modes that take a while to calculate/display
84238438Sdteske	[ "$SHOW_DEFAULT_VALUE" -o "$SHOW_CONFIGURED" ] &&
85238438Sdteske		f_dialog_info "$msg_creating_menu_list"
86238438Sdteske
87249751Sdteske	RCCONF_MENU_LIST=$(
88240783Sdteske		. "$RC_DEFAULTS" > /dev/null
89240783Sdteske		source_rc_confs > /dev/null
90238438Sdteske		var_list=$( f_startup_rcconf_list )
91238438Sdteske		for var in $var_list; do
92238438Sdteske			eval export $var
93238438Sdteske			[ "$SHOW_DEFAULT_VALUE" ] && export \
94238438Sdteske				_${var}_default="$( f_sysrc_get_default $var )"
95238438Sdteske			[ "$SHOW_CONFIGURED" ] && export \
96238438Sdteske				_${var}_file="$( f_sysrc_find $var )"
97238438Sdteske		done
98238438Sdteske		export SHOW_VALUE SHOW_DESC SHOW_DEFAULT_VALUE SHOW_CONFIGURED
99238438Sdteske		export msg_default_value
100238438Sdteske		echo "$var_list" | awk '
101238438Sdteske		BEGIN {
102238438Sdteske			prefix = ""
103238438Sdteske		}
104238438Sdteske		{
105238438Sdteske			cur_prefix = tolower(substr($1, 1, 1))
106238438Sdteske			printf "'\''"
107238438Sdteske			if ( prefix != cur_prefix )
108238438Sdteske				prefix = cur_prefix
109238438Sdteske			else
110238438Sdteske				printf " "
111238438Sdteske			var = $1
112238438Sdteske			printf "%s'\'' '\''[", var
113238438Sdteske			if ( ENVIRON["_" var "_delete"] )
114238438Sdteske				printf "X"
115238438Sdteske			else
116238438Sdteske				printf " "
117238438Sdteske			printf "] "
118238438Sdteske			if ( ENVIRON["SHOW_DEFAULT_VALUE"] ) {
119238438Sdteske				default = ENVIRON["_" var "_default"]
120238438Sdteske				gsub(/'\''/, "'\''\\'\'\''", default)
121238438Sdteske				value = ENVIRON[var]
122238438Sdteske				gsub(/'\''/, "'\''\\'\'\''", value)
123238438Sdteske				printf ENVIRON["msg_default_value"] "; %s",
124238438Sdteske				       default, value
125238438Sdteske			} else if ( ENVIRON["SHOW_CONFIGURED"] ) {
126238438Sdteske				printf "%s", ENVIRON["_" var "_file"]
127238438Sdteske			} else { # SHOW_VALUE (default behavior)
128238438Sdteske				value = ENVIRON[var]
129238438Sdteske				gsub(/'\''/, "'\''\\'\'\''", value)
130238438Sdteske				printf "%s", value
131238438Sdteske			}
132238438Sdteske			printf "'\''"
133238438Sdteske			if ( ENVIRON["SHOW_DESC"] ) {
134238438Sdteske				desc = ENVIRON["_" var "_desc"]
135238438Sdteske				gsub(/'\''/, "'\''\\'\'\''", desc)
136238438Sdteske				printf " '\''%s'\''", desc
137238438Sdteske			}
138238438Sdteske			printf "\n"
139238438Sdteske		}'
140249751Sdteske	)
141249751Sdteske}
142238438Sdteske
143249751Sdteske# dialog_menu_main
144249751Sdteske#
145249751Sdteske# Display the dialog(1)-based application main menu.
146249751Sdteske#
147249751Sdteskedialog_menu_main()
148249751Sdteske{
149251264Sdteske	local prompt=
150251264Sdteske	local menu_list="
151251264Sdteske		'X $msg_exit_cancel'     '$msg_exit_cancel_desc'
152251264Sdteske		            ${SHOW_DESC:+'$msg_exit_cancel_help'}
153251264Sdteske		'> $msg_delete_selected' '$msg_delete_selected_desc'
154251264Sdteske		            ${SHOW_DESC:+'$msg_delete_selected_help'}
155251264Sdteske		'> $msg_all'             '$msg_all_desc'
156251264Sdteske		            ${SHOW_DESC:+'$msg_all_help'}
157251264Sdteske		'> $msg_none'            '$msg_none_desc'
158251264Sdteske		            ${SHOW_DESC:+'$msg_none_help'}
159251264Sdteske	${USE_XDIALOG:+
160251264Sdteske		'> $msg_view_details'    '$msg_view_details_desc'
161251264Sdteske		            ${SHOW_DESC:+'$msg_view_details_help'}
162251264Sdteske	}
163251264Sdteske	" # END-QUOTE
164251264Sdteske	local defaultitem= # Calculated below
165249751Sdteske	local hline="$hline_arrows_tab_enter"
166238438Sdteske
167249751Sdteske	#
168249751Sdteske	# [Re-]Accent the menu list before incorporating it
169249751Sdteske	#
170249751Sdteske	local rcconf_var details help menu_buf delete
171249751Sdteske	eval set -- $RCCONF_MENU_LIST
172249751Sdteske	while [ $# -gt 0 ]; do
173249751Sdteske		rcconf_var="$1" details="$2" delete=
174249751Sdteske		f_shell_escape "$details" details
175249751Sdteske		if [ "$SHOW_DESC" ]; then
176249751Sdteske			help="$3"
177249751Sdteske			f_shell_escape "$help" help
178249751Sdteske			shift 3 # rcconf_var/details/help
179249751Sdteske		else
180249751Sdteske			shift 2 # rcconf_var/details
181249751Sdteske		fi
182249751Sdteske
183249751Sdteske		# Update mark
184249751Sdteske		f_getvar _${rcconf_var# }_delete delete
185249751Sdteske		if [ "$delete" ]; then
186249751Sdteske			details="[X]${details#???}"
187249751Sdteske		else
188249751Sdteske			details="[ ]${details#???}"
189249751Sdteske		fi
190249751Sdteske
191249751Sdteske		# Update buffer with modified elements
192249751Sdteske		menu_buf="$menu_buf
193249751Sdteske		'$rcconf_var' '$details' ${SHOW_DESC:+'$help'}" # End-Quote
194249751Sdteske	done
195251264Sdteske	menu_list="$menu_list $menu_buf"
196249751Sdteske
197251266Sdteske	set -f # set noglob because descriptions in the $menu_list may contain
198251266Sdteske	       # `*' and get expanded by dialog(1) (doesn't affect Xdialog(1)).
199251266Sdteske	       # This prevents dialog(1) from expanding wildcards in help line.
200249751Sdteske
201251190Sdteske	local height width rows
202251190Sdteske	eval f_dialog_menu${SHOW_DESC:+_with_help}_size \
203251190Sdteske		height width rows      \
204251190Sdteske		\"\$DIALOG_TITLE\"     \
205251190Sdteske		\"\$DIALOG_BACKTITLE\" \
206251190Sdteske		\"\$prompt\"           \
207251190Sdteske		\"\$hline\"            \
208251190Sdteske		$menu_list
209238438Sdteske
210251244Sdteske	# Obtain default-item from previously stored selection
211251244Sdteske	f_dialog_default_fetch defaultitem
212251244Sdteske
213251236Sdteske	local menu_choice
214251236Sdteske	menu_choice=$( eval $DIALOG \
215251244Sdteske		--title \"\$DIALOG_TITLE\"         \
216251244Sdteske		--backtitle \"\$DIALOG_BACKTITLE\" \
217251244Sdteske		--hline \"\$hline\"                \
218251244Sdteske		--keep-tite                        \
219251244Sdteske		--ok-label \"\$msg_ok\"            \
220251244Sdteske		--cancel-label \"\$msg_cancel\"    \
221251244Sdteske		--help-button                      \
222251244Sdteske		--help-label \"\$msg_details\"     \
223251244Sdteske		${SHOW_DESC:+--item-help}          \
224251244Sdteske		--default-item \"\$defaultitem\"   \
225251244Sdteske		--menu \"\$prompt\"                \
226251244Sdteske		$height $width $rows               \
227251244Sdteske		$menu_list                         \
228240768Sdteske		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
229240768Sdteske	)
230240768Sdteske	local retval=$?
231251236Sdteske	f_dialog_data_sanitize menu_choice
232251236Sdteske	f_dialog_menutag_store "$menu_choice"
233249751Sdteske
234249751Sdteske	# Only update default-item on success
235256181Sdteske	[ $retval -eq $DIALOG_OK ] && f_dialog_default_store "$menu_choice"
236249751Sdteske
237240768Sdteske	return $retval
238238438Sdteske}
239238438Sdteske
240249751Sdteske# dialog_menu_confirm_delete $var1 [$var2 ...]
241238438Sdteske#
242249751Sdteske# Get the user's blessing to delete one or more variables. Returns success if
243249751Sdteske# (and only-if) the user confirms (does not press ESC or Cancel/NO). Does NOT
244249751Sdteske# return the user's menu-choice.
245238438Sdteske#
246249751Sdteskedialog_menu_confirm_delete()
247238438Sdteske{
248251264Sdteske	local prompt="$msg_are_you_sure_you_want_delete_the_following"
249251264Sdteske	local menu_list # Calculated below
250238438Sdteske	local hline="$hline_arrows_tab_enter"
251238438Sdteske
252256181Sdteske	[ $# -ge 1 ] || return $DIALOG_CANCEL
253238438Sdteske
254251266Sdteske	# If asked to delete only one variable, simply ask and return
255238438Sdteske	if [ $# -eq 1 ]; then
256251277Sdteske		f_noyes "$msg_are_you_sure_you_want_to_delete" "$1"
257238438Sdteske		return $?
258238438Sdteske	fi
259251266Sdteske	# Not reached unless requested to delete multiple variables
260238438Sdteske
261251266Sdteske	# Generate a menu to cleanly display the variables to be deleted
262251264Sdteske	local var_list
263238438Sdteske	var_list=$( for var in $*; do echo "$var"; done | sort -u )
264238438Sdteske	menu_list=$(
265238438Sdteske		. "$RC_DEFAULTS"
266238438Sdteske		source_rc_confs
267238438Sdteske		echo "$var_list" | awk '
268238438Sdteske		BEGIN {
269238438Sdteske			prefix = ""
270238438Sdteske		}
271238438Sdteske		{
272238438Sdteske			cur_prefix = tolower(substr($1, 1, 1))
273238438Sdteske			printf "'\''"
274238438Sdteske			if ( prefix != cur_prefix )
275238438Sdteske				prefix = cur_prefix
276238438Sdteske			else
277238438Sdteske				printf " "
278238438Sdteske			var = $1
279238438Sdteske			printf "%s'\'' '\'\''\n", var
280238438Sdteske		}'
281238438Sdteske	)
282238438Sdteske
283251190Sdteske	local height width rows
284251190Sdteske	eval f_dialog_menu_size height width rows \
285251190Sdteske	                        \"\$DIALOG_TITLE\"     \
286251190Sdteske	                        \"\$DIALOG_BACKTITLE\" \
287251190Sdteske	                        \"\$prompt\"           \
288251190Sdteske	                        \"\$hline\"            \
289251190Sdteske	                        $menu_list
290238438Sdteske
291238438Sdteske	local defaultno="defaultno"
292238438Sdteske	[ "$USE_XDIALOG" ] && defaultno="default-no"
293238438Sdteske
294249751Sdteske	eval $DIALOG \
295249751Sdteske		--title \"\$DIALOG_TITLE\"         \
296238438Sdteske		--backtitle \"\$DIALOG_BACKTITLE\" \
297238438Sdteske		--hline \"\$hline\"                \
298238438Sdteske		--$defaultno                       \
299238438Sdteske		--ok-label \"\$msg_ok\"            \
300238438Sdteske		--cancel-label \"\$msg_cancel\"    \
301251190Sdteske		--menu \"\$prompt\"                \
302251190Sdteske		$height $width $rows               \
303238438Sdteske		$menu_list                         \
304249751Sdteske		2> /dev/null
305249954Sdteske
306249954Sdteske	# Menu choice ignored; status of above command returned
307238438Sdteske}
308238438Sdteske
309238438Sdteske############################################################ MAIN
310238438Sdteske
311238438Sdteske# Incorporate rc-file if it exists
312238438Sdteske[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
313238438Sdteske
314238438Sdteske#
315238438Sdteske# Process command-line arguments
316238438Sdteske#
317250633Sdteskewhile getopts h$GETOPTS_STDARGS flag; do
318238438Sdteske	case "$flag" in
319252178Sdteske	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm" ;;
320238438Sdteske	esac
321238438Sdteskedone
322238438Sdteskeshift $(( $OPTIND - 1 ))
323238438Sdteske
324238438Sdteske#
325238438Sdteske# Initialize
326238438Sdteske#
327238438Sdteskef_dialog_title "$msg_delete_startup_directives"
328238438Sdteskef_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
329238438Sdteskef_mustberoot_init
330238438Sdteske
331249751Sdteske# Genreate $RCCONF_MAP of `var desc ...' per-line (see share/rcconf.subr)
332249751Sdteskef_dialog_info "$msg_creating_rcconf_map"
333249751Sdteskef_startup_rcconf_map RCCONF_MAP
334249751Sdteske
335249751Sdteske# Generate _${var}_desc variables from $RCCONF_MAP
336249751Sdteskef_startup_rcconf_map_expand RCCONF_MAP
337249751Sdteske
338249751Sdteske# Generate RCCONF_MENU_LIST from $RCCONF_MAP
339249751Sdteskedialog_create_main
340249751Sdteske
341251965Sdteske#
342251965Sdteske# Launch application main menu
343251965Sdteske#
344238438Sdteskewhile :; do
345238438Sdteske	dialog_menu_main
346238438Sdteske	retval=$?
347251236Sdteske	f_dialog_menutag_fetch mtag
348238438Sdteske
349238438Sdteske	if [ "$USE_XDIALOG" ]; then
350249751Sdteske		case "$mtag" in "> $msg_view_details")
351249751Sdteske			f_dialog_input_view_details && dialog_create_main
352238438Sdteske			continue
353238438Sdteske		esac
354256181Sdteske	elif [ $retval -eq $DIALOG_HELP ]; then
355238438Sdteske		# The ``Help'' button (labeled "Details") was pressed
356249751Sdteske		f_dialog_input_view_details && dialog_create_main
357238438Sdteske		continue
358238438Sdteske	fi
359238438Sdteske
360256181Sdteske	[ $retval -eq $DIALOG_OK ] || f_die
361238438Sdteske
362238438Sdteske	case "$mtag" in
363238438Sdteske	"X $msg_exit_cancel") break ;;
364238438Sdteske	"> $msg_delete_selected")
365238438Sdteske		delete_vars=
366238438Sdteske		for var in $( f_startup_rcconf_list ); do
367260678Sdteske			f_getvar _${var}_delete _delete
368260678Sdteske			[ "$_delete" ] || continue
369260678Sdteske			delete_vars="$delete_vars $var"
370238438Sdteske		done
371249751Sdteske		if dialog_menu_confirm_delete $delete_vars; then
372238438Sdteske			f_dialog_title "$msg_info"
373238438Sdteske			f_dialog_info "$msg_deleting_selected_directives"
374238438Sdteske			f_dialog_title_restore
375238438Sdteske			for var in $delete_vars; do
376260678Sdteske				f_eval_catch "$0" f_sysrc_delete \
377260678Sdteske					'f_sysrc_delete "%s"' "$var" || break
378238438Sdteske			done
379249751Sdteske			dialog_create_main
380238438Sdteske		fi
381238438Sdteske		;;
382238438Sdteske	"> $msg_all")
383238438Sdteske		for var in $( f_startup_rcconf_list ); do
384238438Sdteske			setvar _${var}_delete 1
385238438Sdteske			export _${var}_delete
386238438Sdteske		done
387238438Sdteske		;;
388238438Sdteske	"> $msg_none")
389238438Sdteske		var_list=$( set | awk -F= "
390238438Sdteske			/$STARTUP_RCCONF_REGEX/ {
391238438Sdteske				if (\$1 ~ /^_[[:alpha:]_][[:alnum:]_]*_delete/)
392238438Sdteske					print \$1
393238438Sdteske			}"
394238438Sdteske		)
395238438Sdteske		[ "$var_list" ] && unset $var_list
396238438Sdteske		;;
397238438Sdteske	*) # Anything else is a variable to edit
398238438Sdteske		var="${mtag# }"
399238438Sdteske
400238438Sdteske		# Toggle the state-variable and loop back to menu
401250317Sdteske		if f_isset _${var}_delete; then
402238438Sdteske			unset _${var}_delete
403238438Sdteske		else
404238438Sdteske			setvar _${var}_delete 1
405238438Sdteske			export _${var}_delete
406238438Sdteske		fi
407238438Sdteske	esac
408238438Sdteskedone
409238438Sdteske
410238438Sdteskeexit $SUCCESS
411238438Sdteske
412238438Sdteske################################################################################
413238438Sdteske# END
414238438Sdteske################################################################################
415