if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1 # # Copyright (c) 2006-2012 Devin Teske # All Rights Reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # ############################################################ INCLUDES BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_include $BSDCFG_SHARE/strings.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" f_include_lang $BSDCFG_LIBE/include/messages.subr ############################################################ CONFIGURATION # # Default file descriptor to link to stdout for dialog(1) passthru allowing # execution of dialog from within a sub-shell (so-long as its standard output # is explicitly redirected to this file descriptor). # : ${DIALOG_TERMINAL_PASSTHRU_FD:=3} ############################################################ GLOBALS # # Default name of dialog(1) utility # NOTE: This is changed to "Xdialog" by the optional `-X' argument # DIALOG="dialog" # # Default dialog(1) title and backtitle text # DIALOG_TITLE="$pgm" DIALOG_BACKTITLE="bsdconfig" # # Settings used while interacting with dialog(1) # DIALOG_MENU_TAGS="123456789ABCDEFGHIJKLMNOPQRSTUVWYZabcdefghijklmnopqrstuvwxyz" # # Declare that we are fully-compliant with Xdialog(1) by unset'ing all # compatibility settings. # unset XDIALOG_HIGH_DIALOG_COMPAT unset XDIALOG_FORCE_AUTOSIZE unset XDIALOG_INFOBOX_TIMEOUT # # Default behavior is to call f_dialog_init() automatically if not already # called manually by the time the first f_dialog_*() function is used. # : ${DIALOG_SELF_INITIALIZE=1} ############################################################ GENERIC FUNCTIONS # f_dialog_title [$new_title] # # Set the title of future dialog(1) ($DIALOG_TITLE) or backtitle of Xdialog(1) # ($DIALOG_BACKTITLE) invocations. If no arguments are given or the first # argument is NULL, the current title is returned. # # Each time this function is called, a backup of the current values is made # allowing a one-time (single-level) restoration of the previous title using the # f_dialog_title_restore() function (below). # f_dialog_title() { local new_title="$1" if [ "$new_title" ]; then if [ "$USE_XDIALOG" ]; then _DIALOG_BACKTITLE="$DIALOG_BACKTITLE" DIALOG_BACKTITLE="$new_title" else _DIALOG_TITLE="$DIALOG_TITLE" DIALOG_TITLE="$new_title" fi else if [ "$USE_XDIALOG" ]; then echo "$DIALOG_BACKTITLE" else echo "$DIALOG_TITLE" fi fi } # f_dialog_title_restore # # Restore the previous title set by the last call to f_dialog_title(). # Restoration is non-recursive and only works to restore the most-recent title. # f_dialog_title_restore() { if [ "$USE_XDIALOG" ]; then DIALOG_BACKTITLE="$_DIALOG_BACKTITLE" else DIALOG_TITLE="$_DIALOG_TITLE" fi } # f_dialog_backtitle [$new_backtitle] # # Set the backtitle of future dialog(1) ($DIALOG_BACKTITLE) or title of # Xdialog(1) ($DIALOG_TITLE) invocations. If no arguments are given or the # first argument is NULL, the current backtitle is returned. # f_dialog_backtitle() { local new_backtitle="$1" if [ "$new_backtitle" ]; then if [ "$USE_XDIALOG" ]; then _DIALOG_TITLE="$DIALOG_TITLE" DIALOG_TITLE="$new_backtitle" else _DIALOG_BACKTITLE="$DIALOG_BACKTITLE" DIALOG_BACKTITLE="$new_backtitle" fi else if [ "$USE_XDIALOG" ]; then echo "$DIALOG_TITLE" else echo "$DIALOG_BACKTITLE" fi fi } # f_dialog_backtitle_restore # # Restore the previous backtitle set by the last call to f_dialog_backtitle(). # Restoration is non-recursive and only works to restore the most-recent # backtitle. # f_dialog_backtitle_restore() { if [ "$USE_XDIALOG" ]; then DIALOG_TITLE="$_DIALOG_TITLE" else DIALOG_BACKTITLE="$_DIALOG_BACKTITLE" fi } ############################################################ SIZE FUNCTIONS # f_dialog_infobox_size $title $backtitle $prompt [$hline] # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--infobox' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, and [optionally] hline returning # the optimal width and height for the box (not exceeding the actual terminal # width or height). # # Newline character sequences (``\n'') in $prompt are expanded as-is done by # dialog(1). # # Output is in the format of "height width". # f_dialog_infobox_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" n=0 local min_width max_size if [ "$USE_XDIALOG" ]; then min_width=35 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_width=24 max_size=$( stty size ) # usually "24 80" fi local max_height="${max_size%%[$IFS]*}" local max_width="${max_size##*[$IFS]}" local height width=$min_width # # Bump width for long titles (but don't exceed terminal width). # n=$(( ${#title} + 4 )) if [ $n -gt $width -a $n -gt $min_width ]; then # Add 16.6% width for Xdialog(1) [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi # # For Xdialog(1), bump width for long backtitles (which appear within # the window; don't exceed maximum width). # if [ "$USE_XDIALOG" ]; then n=$(( ${#btitle} + 4 )) n=$(( $n + $n / 6 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # # Bump width for long prompts (if not already at maximum width). # if [ $width -lt $max_width ]; then n=$( echo "$prompt" | f_longest_line_length ) n=$(( $n + 4 )) # Add 16.6% width for Xdialog(1) [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # # Bump width for long hlines (if not already at maximum width). # NOTE: Though Xdialog(1) supports `--hline', it's not currently used. # if [ ! "$USE_XDIALOG" ]; then if [ $width -lt $max_width ]; then n=$(( ${#hline} + 10 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi fi # # Set height based on number of rows in prompt # height=$( echo -n "$prompt" | f_number_of_lines ) height=$(( $height + 2 )) # # For Xdialog(1) bump height if backtitle is enabled (displayed in the # X11 window with a separator line between the backtitle and msg text) # if [ "$USE_XDIALOG" -a "$btitle" ]; then n=$( echo "$btitle" | f_number_of_lines ) height=$(( $height + $n + 2 )) fi # Make sure height is less than maximum screen size [ $height -le $max_height ] || height=$max_height # Return both echo "$height $width" } # f_dialog_buttonbox_size $title $backtitle $prompt [$hline] # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--msgbox' and `--yesno' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, and [optionally] hline returning # the optimal width and height for the box (not exceeding the actual terminal # width or height). # # Newline character sequences (``\n'') in $prompt are expanded as-is done by # dialog(1). # # Output is in the format of "height width". # f_dialog_buttonbox_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" local size="$( f_dialog_infobox_size \ "$title" "$btitle" "$prompt" "$hline" )" local height="${size%%[$IFS]*}" local width="${size##*[$IFS]}" # Add height to accomodate the buttons height=$(( $height + 2 )) # Adjust for clipping with Xdialog(1) on Linux/GTK2 [ "$USE_XDIALOG" ] && height=$(( $height + 3 )) # # Enforce maximum height regardless # local max_size if [ "$USE_XDIALOG" ]; then max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else max_size=$( stty size ) # usually "24 80" fi local max_height="${max_size%%[$IFS]*}" [ $height -le $max_height ] || height=$max_height # Return both echo "$height $width" } # f_dialog_inputbox_size $title $backtitle $prompt $init [$hline] # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--inputbox' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, initial text, and [optionally] # hline returning the optimal width and height for the box (not exceeding the # actual terminal width and height). # # Newline character sequences (``\n'') in $prompt are expanded as-is done by # dialog(1). # # Output is in the format of "height width". # f_dialog_inputbox_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" init="$4" hline="$5" n local size="$( f_dialog_buttonbox_size \ "$title" "$btitle" "$prompt" "$hline" )" local height="${size%%[$IFS]*}" local width="${size##*[$IFS]}" local min_width max_size if [ "$USE_XDIALOG" ]; then min_width=35 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_width=24 max_size=$( stty size ) # usually "24 80" fi local max_height="${max_size%%[$IFS]*}" local max_width="${max_size##*[$IFS]}" # # Add height to accomodate the input box # [ ! "$USE_XDIALOG" ] && height=$(( $height + 3 )) [ $height -le $max_height ] || height=$max_height # # Bump width for initial text (if not already at maximum width). # NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it! # if [ $width -lt $max_width ]; then n=$(( ${#init} + 7 )) # Add 16.6% width for Xdialog(1) [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # Return both echo "$height $width" } # f_xdialog_2inputsbox_size $title $backtitle $prompt \ # $label1 $init1 $label2 $init2 # # Xdialog(1) does not perform auto-sizing of the width and height of # `--2inputsbox' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, label for the first field, initial # text for said field, label for the second field, and initial text for said # field returning the optimal width and height for the box (not exceeding the # actual terminal width and height). # # Newline character sequences (``\n'') in $prompt are expanded as-is done by # Xdialog(1). # # Output is in the format of "height width". # f_xdialog_2inputsbox_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" local label1="$4" init1="$5" label2="$6" init2="$7" n local size="$( f_dialog_inputbox_size \ "$title" "$btitle" "$prompt" "$init1" )" local height="${size%%[$IFS]*}" local width="${size##*[$IFS]}" local min_width=35 local max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION local max_height="${max_size%%[$IFS]*}" local max_width="${max_size##*[$IFS]}" # Add height for first label height=$(( $height + 2 )) # # Bump width for first label text (if not already at maximum width). # if [ $width -lt $max_width ]; then n=$(( ${#label1} + 7 )) # Add 16.6% width for Xdialog(1) n=$(( $n + $n / 6 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # Add height for second label height=$(( $height + 2 )) # # Bump width for second label text (if not already at maximum width). # if [ $width -lt $max_width ]; then n=$(( ${#label2} + 7 )) # Add 16.6% width for Xdialog(1) n=$(( $n + $n / 6 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # Add height for a second inputbox height=$(( $height + 2 )) # # Bump width for second initial text (if not already at maximum width). # NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it! # if [ $width -lt $max_width ]; then n=$(( ${#init2} + 7 )) # Add 16.6% width for Xdialog(1) n=$(( $n + $n / 6 )) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # Return both echo "$height $width" } # f_dialog_menu_size $title $backtitle $prompt $hline \ # $tag1 $item1 $tag2 $item2 ... # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--menu' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, hline and list of tag/item pairs, # returning the optimal width and height for the menu (not exceeding the actual # terminal width or height). # # Output is in the format of "height width rows". # f_dialog_menu_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" n=0 local min_width min_rows max_size if [ "$USE_XDIALOG" ]; then min_width=35 min_rows=1 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_width=24 min_rows=0 max_size=$( stty size ) # usually "24 80" fi local max_width="${max_size##*[$IFS]}" local max_height="${max_size%%[$IFS]*}" local box_size="$( f_dialog_infobox_size \ "$title" "$btitle" "$prompt" "$hline" )" local box_height="${box_size%%[$IFS]*}" local box_width="${box_size##*[$IFS]}" local max_rows=$(( $max_height - 8 )) local height width=$box_width rows=$min_rows shift 4 # title/btitle/prompt/hline # If there's no prompt, bump the max-rows by 1 [ "$prompt" ] || max_rows=$(( $max_rows + 1 )) # # The sum total between the longest tag-length and longest item-length # should be used for the menu width (not to exceed terminal width). # # Also, calculate the number of rows (not to exceed terminal height). # local longest_tag=0 longest_item=0 while [ $# -ge 2 ]; do local tag="$1" item="$2" shift 2 # tag/item [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag} [ ${#item} -gt $longest_item ] && longest_item=${#item} [ $rows -lt $max_rows ] && rows=$(( $rows + 1 )) done # Update width n=$(( $longest_tag + $longest_item + 10 )) [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi # Fix rows and set height [ $rows -gt 0 ] || rows=1 if [ "$USE_XDIALOG" ]; then height=$(( $rows + $box_height + 7 )) else height=$(( $rows + $box_height + 4 )) fi [ $height -le $max_height ] || height=$max_height # Return all three echo "$height $width $rows" } # f_dialog_menu_with_help_size $title $backtitle $prompt $hline \ # $tag1 $item1 $help1 $tag2 $item2 $help2 ... # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--menu' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, hline and list of tag/item/help # triplets, returning the optimal width and height for the menu (not exceeding # the actual terminal width or height). # # Output is in the format of "height width rows". # f_dialog_menu_with_help_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" n=0 local min_width min_rows max_size if [ "$USE_XDIALOG" ]; then min_width=35 min_rows=1 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_width=24 min_rows=0 max_size=$( stty size ) # usually "24 80" fi local max_width="${max_size##*[$IFS]}" local max_height="${max_size%%[$IFS]*}" local box_size="$( f_dialog_infobox_size \ "$title" "$btitle" "$prompt" "$hline" )" local box_height="${box_size%%[$IFS]*}" local box_width="${box_size##*[$IFS]}" local max_rows=$(( $max_height - 8 )) local height width=$box_width rows=$min_rows shift 4 # title/btitle/prompt/hline # If there's no prompt, bump the max-rows by 1 [ "$prompt" ] || max_rows=$(( $max_rows + 1 )) # # The sum total between the longest tag-length and longest item-length # should be used for the menu width (not to exceed terminal width). # # Also, calculate the number of rows (not to exceed terminal height). # # Also, calculate the longest help while we're here. This will be used # to influence the width of the menu if (and only-if) using Xdialog(1). # local longest_tag=0 longest_item=0 longest_help=0 while [ $# -ge 3 ]; do local tag="$1" item="$2" help="$3" shift 3 # tag/item/help [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag} [ ${#item} -gt $longest_item ] && longest_item=${#item} [ ${#help} -gt $longest_help ] && longest_help=${#help} [ $rows -lt $max_rows ] && rows=$(( $rows + 1 )) done # Update width n=$(( $longest_tag + $longest_item + 10 )) [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi # Update width for help text if using Xdialog(1) if [ "$USE_XDIALOG" ]; then n=$(( $longest_help + 10 )) n=$(( $n + $n / 6 )) # +16.6% if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi fi # Fix rows and set height [ $rows -gt 0 ] || rows=1 if [ "$USE_XDIALOG" ]; then height=$(( $rows + $box_height + 8 )) else height=$(( $rows + $box_height + 4 )) fi [ $height -le $max_height ] || height=$max_height # Return all three echo "$height $width $rows" } # f_dialog_radiolist_size $title $backtitle $prompt $hline \ # $tag1 $item1 $status1 $tag2 $item2 $status2 ... # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--radiolist' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, hline and list of tag/item/status # triplets, returning the optimal width and height for the radiolist (not # exceeding the actual terminal width or height). # # Output is in the format of "height width rows". # f_dialog_radiolist_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" n=0 local min_width min_rows max_size if [ "$USE_XDIALOG" ]; then min_width=35 min_rows=1 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_width=24 min_rows=0 max_size=$( stty size ) # usually "24 80" fi local max_width="${max_size##*[$IFS]}" local max_height="${max_size%%[$IFS]*}" local box_size="$( f_dialog_infobox_size \ "$title" "$btitle" "$prompt" "$hline" )" local box_height="${box_size%%[$IFS]*}" local box_width="${box_size##*[$IFS]}" local max_rows=$(( $max_height - 8 )) local height width=$box_width rows=$min_rows shift 4 # title/btitle/prompt/hline # # The sum total between the longest tag-length, longest item-length, # and radio-button width should be used for the menu width (not to # exceed terminal width). # # Also, calculate the number of rows (not to exceed terminal height). # local longest_tag=0 longest_item=0 while [ $# -ge 2 ]; do local tag="$1" item="$2" help="$3" shift 3 # tag/item/status [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag} [ ${#item} -gt $longest_item ] && longest_item=${#item} [ $rows -lt $max_rows ] && rows=$(( $rows + 1 )) done # Update width n=$(( $longest_tag + $longest_item + 13 )) [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1) if [ $n -gt $width -a $n -gt $min_width ]; then if [ $n -lt $max_width ]; then width=$n else width=$max_width fi fi # Fix rows and set height [ $rows -gt 0 ] || rows=1 if [ "$USE_XDIALOG" ]; then height=$(( $rows + $box_height + 7 )) else height=$(( $rows + $box_height + 4 )) fi [ $height -le $max_height ] || height=$max_height # Return all three echo "$height $width $rows" } # f_dialog_calendar_size $title $backtitle $prompt [$hline] # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--calendar' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, and [optionally] hline returning # the optimal width and height for the box (not exceeding the actual terminal # width and height). # # Newline character sequences (``\n'') in $prompt are expanded as-is done by # dialog(1). # # Output is in the format of "height width". # f_dialog_calendar_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" n local size="$( f_dialog_infobox_size \ "$title" "$btitle" "$prompt" "$hline" )" local height="${size%%[$IFS]*}" local width="${size##*[$IFS]}" local min_width min_height max_size if [ "$USE_XDIALOG" ]; then min_height=15 min_width=55 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_height=0 min_width=40 max_size=$( stty size ) # usually "24 80" fi local max_height="${max_size%%[$IFS]*}" local max_width="${max_size##*[$IFS]}" # # Enforce the minimum width for displaying the calendar # [ $width -ge $min_width ] || width=$min_width # # When using dialog(1), the calendar box is unique from other dialog(1) # boxes in-that the height passed should not accomodate the 15-lines # required to display the calendar. This does not apply to Xdialog(1). # # When using Xdialog(1), the height must accomodate the 15-lines # required to display the calendar. # # NOTE: Also under dialog(1), because we can't predict whether the user # has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract # 16 rather than 15. This does not apply to Xdialog(1). # max_height=$(( $max_height - 16 )) height=$( echo "$prompt" | f_number_of_lines ) if [ "$USE_XDIALOG" ]; then # Add height to accomodate for the embedded calendar widget height=$(( $height + $min_height - 1 )) # Also, bump height if backtitle is enabled if [ "$btitle" ]; then local n="$( echo "$btitle" | f_number_of_lines )" height=$(( $height + $n + 2 )) fi else [ "$prompt" ] && height=$(( $height + 1 )) fi [ $height -le $max_height ] || height=$max_height # # The calendar box refuses to display if too large. # max_width=$(( $max_width - 2 )) [ $width -le $max_width ] || width=$max_width # Return both echo "$height $width" } # f_dialog_timebox_size $title $backtitle $prompt [$hline] # # Not all versions of dialog(1) perform auto-sizing of the width and height of # `--timebox' boxes sensibly. # # This function helps solve this issue by taking as arguments (in order of # appearance) the title, backtitle, prompt, and [optionally] hline returning # the optimal width and height for the box (not exceeding the actual terminal # width and height). # # Newline character sequences (``\n'') in $prompt are expanded as-is done by # dialog(1). # # Output is in the format of "height width". # f_dialog_timebox_size() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local title="$1" btitle="$2" prompt="$3" hline="$4" n local size="$( f_dialog_infobox_size \ "$title" "$btitle" "$prompt" "$hline" )" local height="${size%%[$IFS]*}" local width="${size##*[$IFS]}" local min_width min_height max_size if [ "$USE_XDIALOG" ]; then min_width=40 max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION else min_height=0 min_width=20 max_size=$( stty size ) # usually "24 80" fi local max_height="${max_size%%[$IFS]*}" local max_width="${max_size##*[$IFS]}" # # Enforce the minimum width for displaying the timebox # [ $width -ge $min_width ] || width=$min_width # # When using dialog(1), the timebox box is unique from other dialog(1) # boxes in-that the height passed should not accomodate the 6-lines # required to display the timebox. This does not apply to Xdialog(1). # # When using Xdialog(1), the height seems to have no effect. All values # provide the same results. # # NOTE: Also under dialog(1), because we can't predict whether the user # has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract # 7 rather than 6. This does not apply to Xdialog(1). # if [ "$USE_XDIALOG" ]; then height=0 # Autosize; all values produce same results else max_height=$(( $max_height - 7 )) height=$( echo "$prompt" | f_number_of_lines ) height=$(( $height + 1 )) [ $height -le $max_height ] || height=$max_height [ "$prompt" ] && height=$(( $height + 1 )) fi # # The timebox box refuses to display if too large. # max_width=$(( $max_width - 2 )) [ $width -le $max_width ] || width=$max_width # Return both echo "$height $width" } ############################################################ CLEAR FUNCTIONS # f_dialog_clear # # Clears any/all previous dialog(1) displays. # f_dialog_clear() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init $DIALOG --clear } ############################################################ INFO FUNCTIONS # f_dialog_info $info_text ... # # Throw up a dialog(1) infobox. The infobox remains until another dialog is # displayed or `dialog --clear' (or dialog_clear) is called. # f_dialog_info() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local info_text="$*" local size="$( f_dialog_infobox_size \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$info_text" )" eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ ${USE_XDIALOG:+--ignore-eof} \ ${USE_XDIALOG:+--no-buttons} \ --infobox \"\$info_text\" $size } # f_xdialog_info $info_text ... # # Throw up an Xdialog(1) infobox and do not dismiss it until stdin produces # EOF. This implies that you must execute this either as an rvalue to a pipe, # lvalue to indirection or in a sub-shell that provides data on stdin. # f_xdialog_info() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local info_text="$*" local size="$( f_dialog_infobox_size \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$info_text" )" eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --no-close --no-buttons \ --infobox \"\$info_text\" $size \ -1 # timeout of -1 means abort when EOF on stdin } ############################################################ MSGBOX FUNCTIONS # f_dialog_msgbox $msg_text ... # # Throw up a dialog(1) msgbox. The msgbox remains until the user presses ENTER # or ESC, acknowledging the modal dialog. # # If the user presses ENTER, the exit status is zero (success), otherwise if # the user presses ESC the exit status is 255. # f_dialog_msgbox() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local msg_text="$*" local size="$( f_dialog_buttonbox_size \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$msg_text" )" eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --ok-label \"\$msg_ok\" \ --msgbox \"\$msg_text\" $size } ############################################################ TEXTBOX FUNCTIONS # f_dialog_textbox $file # # Display the contents of $file (or an error if $file does not exist, etc.) in # a dialog(1) textbox (which has a scrollable region for the text). The textbox # remains until the user presses ENTER or ESC, acknowledging the modal dialog. # # If the user presses ENTER, the exit status is zero (success), otherwise if # the user presses ESC the exit status is 255. # f_dialog_textbox() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local file="$1" local contents retval size contents=$( cat "$file" 2>&1 ) retval=$? size=$( f_dialog_buttonbox_size \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$contents" ) if [ $retval -eq $SUCCESS ]; then eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --exit-label \"\$msg_ok\" \ --no-cancel \ --textbox \"\$file\" $size else eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --ok-label \"\$msg_ok\" \ --msgbox \"\$contents\" $size fi } ############################################################ YESNO FUNCTIONS # f_dialog_yesno $msg_text ... # # Display a dialog(1) Yes/No prompt to allow the user to make some decision. # The yesno prompt remains until the user presses ENTER or ESC, acknowledging # the modal dialog. # # If the user chooses YES the exit status is zero, or chooses NO the exit # status is one, or presses ESC the exit status is 255. # f_dialog_yesno() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local msg_text="$*" local hline="$hline_arrows_tab_enter" local size="$( f_dialog_buttonbox_size \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$msg_text" \ "$hline" )" if [ "$USE_XDIALOG" ]; then eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_yes\" \ --cancel-label \"\$msg_no\" \ --yesno \"\$msg_text\" $size else eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --yes-label \"\$msg_yes\" \ --no-label \"\$msg_no\" \ --yesno \"\$msg_text\" $size fi } # f_dialog_noyes $msg_text ... # # Display a dialog(1) No/Yes prompt to allow the user to make some decision. # The noyes prompt remains until the user presses ENTER or ESC, acknowledging # the modal dialog. # # If the user chooses YES the exit status is zero, or chooses NO the exit # status is one, or presses ESC the exit status is 255. # # NOTE: This is just like the f_dialog_yesno function except "No" is default. # f_dialog_noyes() { [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init local msg_text="$*" local hline="$hline_arrows_tab_enter" local size="$( f_dialog_buttonbox_size \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$msg_text" \ "$hline" )" if [ "$USE_XDIALOG" ]; then eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --default-no \ --ok-label \"\$msg_yes\" \ --cancel-label \"\$msg_no\" \ --yesno \"\$msg_text\" $size else eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --defaultno \ --yes-label \"\$msg_yes\" \ --no-label \"\$msg_no\" \ --yesno \"\$msg_text\" $size fi } ############################################################ INPUT FUNCTIONS # f_dialog_inputstr # # Obtain the inputstr entered by the user from the most recently displayed # dialog(1) inputbox and clean up any temporary files. # f_dialog_inputstr() { # Skip warnings and trim leading/trailing whitespace from user input eval echo \"\$DIALOG_INPUTBOX_$$\" | awk ' BEGIN { found = 0 } { if ( ! found ) { if ( $0 ~ /^$/ ) next if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next found = 1 } sub(/^[[:space:]]*/, "") sub(/[[:space:]]*$/, "") print } ' setvar DIALOG_INPUTBOX_$$ "" # scrub memory in case data was sensitive return $SUCCESS } ############################################################ MENU FUNCTIONS # f_dialog_menutag # # Obtain the menutag chosen by the user from the most recently displayed # dialog(1) menu and clean up any temporary files. # f_dialog_menutag() { # Skip warnings eval echo \"\$DIALOG_MENU_$$\" | awk ' BEGIN { found = 0 } { if ( found ) # ... just spew { print next } if ( $0 ~ /^$/ ) next if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next found = 1 print } ' setvar DIALOG_MENU_$$ "" # scrub memory in case data was sensitive return $SUCCESS } # f_dialog_menutag2item $tag_chosen $tag1 $item1 $tag2 $item2 ... # # To use the `--menu' option of dialog(1) you must pass an ordered list of # tag/item pairs on the command-line. When the user selects a menu option the # tag for that item is printed to stderr. # # This function allows you to dereference the tag chosen by the user back into # the item associated with said tag. # # Pass the tag chosen by the user as the first argument, followed by the # ordered list of tag/item pairs (HINT: use the same tag/item list as was # passed to dialog(1) for consistency). # # If the tag cannot be found, NULL is returned. # f_dialog_menutag2item() { local tag="$1" tagn item shift 1 # tag while [ $# -gt 0 ]; do tagn="$1" item="$2" shift 2 # tagn/item if [ "$tag" = "$tagn" ]; then echo "$item" return $SUCCESS fi done return $FAILURE } # f_dialog_menutag2item_with_help $tag_chosen $tag1 $item1 $help1 \ # $tag2 $item2 $help2 ... # # To use the `--menu' option of dialog(1) with the `--item-help' option, you # must pass an ordered list of tag/item/help triplets on the command-line. When # the user selects a menu option the tag for that item is printed to stderr. # # This function allows you to dereference the tag chosen by the user back into # the item associated with said tag (help is discarded/ignored). # # Pass the tag chosen by the user as the first argument, followed by the # ordered list of tag/item/help triplets (HINT: use the same tag/item/help list # as was passed to dialog(1) for consistency). # # If the tag cannot be found, NULL is returned. # f_dialog_menutag2item_with_help() { local tag="$1" tagn item shift 1 # tag while [ $# -gt 0 ]; do tagn="$1" item="$2" shift 3 # tagn/item/help if [ "$tag" = "$tagn" ]; then echo "$item" return $SUCCESS fi done return $FAILURE } # f_dialog_menutag2index $tag_chosen $tag1 $item1 $tag2 $item2 ... # # To use the `--menu' option of dialog(1) you must pass an ordered list of # tag/item pairs on the command-line. When the user selects a menu option the # tag for that item is printed to stderr. # # This function allows you to dereference the tag chosen by the user back into # the index associated with said tag. The index is the one-based tag/item pair # array position within the ordered list of tag/item pairs passed to dialog(1). # # Pass the tag chosen by the user as the first argument, followed by the # ordered list of tag/item pairs (HINT: use the same tag/item list as was # passed to dialog(1) for consistency). # # If the tag cannot be found, NULL is returned. # f_dialog_menutag2index() { local tag="$1" tagn n=1 shift 1 # tag while [ $# -gt 0 ]; do tagn="$1" shift 2 # tagn/item if [ "$tag" = "$tagn" ]; then echo $n return $SUCCESS fi n=$(( $n + 1 )) done return $FAILURE } # f_dialog_menutag2index_with_help $tag_chosen $tag1 $item1 $help1 \ # $tag2 $item2 $help2 ... # # To use the `--menu' option of dialog(1) with the `--item-help' option, you # must pass an ordered list of tag/item/help triplets on the command-line. When # the user selects a menu option the tag for that item is printed to stderr. # # This function allows you to dereference the tag chosen by the user back into # the index associated with said tag. The index is the one-based tag/item/help # triplet array position within the ordered list of tag/item/help triplets # passed to dialog(1). # # Pass the tag chosen by the user as the first argument, followed by the # ordered list of tag/item/help triplets (HINT: use the same tag/item/help list # as was passed to dialog(1) for consistency). # # If the tag cannot be found, NULL is returned. # f_dialog_menutag2index_with_help() { local tag="$1" tagn n=1 shift 1 # tag while [ $# -gt 0 ]; do tagn="$1" shift 3 # tagn/item/help if [ "$tag" = "$tagn" ]; then echo $n return $SUCCESS fi n=$(( $n + 1 )) done return $FAILURE } ############################################################ INIT FUNCTIONS # f_dialog_init # # Initialize (or re-initialize) the dialog module after setting/changing any # of the following environment variables: # # USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate # that Xdialog(1) should be used instead of dialog(1). # # SECURE Either NULL or Non-NULL. If given a value will indicate # that (while running as root) sudo(8) authentication is # required to proceed. # f_dialog_init() { DIALOG_SELF_INITIALIZE= # # Clone terminal stdout so we can redirect to it from within sub-shells # eval exec $DIALOG_TERMINAL_PASSTHRU_FD\>\&1 # # Process stored command-line arguments # SECURE=$( set -- "$ARGV" while getopts S flag > /dev/null; do case "$flag" in S) echo 1;; \?) continue;; esac done ) USE_XDIALOG=$( set -- "$ARGV" while getopts SX flag > /dev/null; do case "$flag" in S|X) echo 1;; \?) continue;; esac done ) # # Process `-X' command-line option # [ "$USE_XDIALOG" ] && DIALOG=Xdialog # # Sanity check, or die gracefully # if ! f_have $DIALOG; then unset USE_XDIALOG failed_dialog="$DIALOG" DIALOG=dialog f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$failed_dialog" fi # # If we're already running as root but we got there by way of sudo(8) # and we have X11, we should merge the xauth(1) credentials from our # original user. # if [ "$USE_XDIALOG" ] && [ "$( id -u )" = "0" ] && [ "$SUDO_USER" -a "$DISPLAY" ] then if ! f_have xauth; then # Die gracefully, as we [likely] can't use Xdialog(1) unset USE_XDIALOG DIALOG=dialog f_die 1 "$msg_no_such_file_or_directory" "$pgm" "xauth" fi HOSTNAME=$(hostname) displaynum="${DISPLAY#*:}" eval xauth -if \~$SUDO_USER/.Xauthority extract - \ \"\$HOSTNAME/unix:\$displaynum\" \ \"\$HOSTNAME:\$displaynum\" | sudo sh -c 'xauth -ivf \ ~root/.Xauthority merge - > /dev/null 2>&1' fi # # Probe Xdialog(1) for maximum height/width constraints, or die # gracefully # if [ "$USE_XDIALOG" ]; then if ! maxsize=$( LANG= LC_ALL= $DIALOG --print-maxsize 2>&1 ) then # Xdialog(1) failed, fall back to dialog(1) unset USE_XDIALOG size=$( f_dialog_buttonbox_size "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$maxsize" "" ) eval dialog \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --ok-label \"\$msg_ok\" \ --msgbox \"\$maxsize\" $size exit $FAILURE fi XDIALOG_MAXSIZE=$( set -- ${maxsize##*:} height=${1%,} width=$2 echo $height $width ) unset maxsize fi # # If using Xdialog(1), swap DIALOG_TITLE with DIALOG_BACKTITLE. # The reason for this is because many dialog(1) applications use # --backtitle for the program name (which is better suited as # --title with Xdialog(1)). # if [ "$USE_XDIALOG" ]; then _DIALOG_TITLE="$DIALOG_TITLE" DIALOG_TITLE="$DIALOG_BACKTITLE" DIALOG_BACKTITLE="$_DIALOG_TITLE" unset _DIALOG_TITLE fi } fi # ! $_DIALOG_SUBR