1if [ ! "$_MEDIA_WLAN_SUBR" ]; then _MEDIA_WLAN_SUBR=1
2#
3# Copyright (c) 2013-2016 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD$
28#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_dprintf "%s: loading includes..." media/wlan.subr
34f_include $BSDCFG_SHARE/device.subr
35f_include $BSDCFG_SHARE/dialog.subr
36f_include $BSDCFG_SHARE/strings.subr
37f_include $BSDCFG_SHARE/sysrc.subr
38
39BSDCFG_LIBE="/usr/libexec/bsdconfig"
40f_include_lang $BSDCFG_LIBE/include/messages.subr
41
42############################################################ GLOBALS
43
44NWIRELESS_CONFIGS=0
45NWSCAN_RESULTS=0
46
47#
48# Settings used while interacting with various dialog(1) menus
49#
50: ${DIALOG_MENU_WLAN_SCAN_DURATION:=5}
51: ${DIALOG_MENU_WLAN_SHOW_ALL=}
52: ${DIALOG_MENU_WLAN_SHOW_CONFIGURED=1}
53: ${DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS=1}
54
55#
56# Structure to contain the wpa_supplicant.conf(5) default overrides
57#
58f_struct_define WPA_DEFAULTS \
59	ap_scan			\
60	ctrl_interface		\
61	ctrl_interface_group	\
62	eapol_version		\
63	fast_reauth
64
65#
66# Structure of wpa_supplicant.conf(5) network={ ... } entry
67#
68f_struct_define WPA_NETWORK \
69	anonymous_identity	\
70	auth_alg		\
71	bssid			\
72	ca_cert			\
73	ca_cert2		\
74	client_cert		\
75	client_cert2		\
76	dh_file			\
77	dh_file2		\
78	eap			\
79	eap_workaround		\
80	eapol_flags		\
81	eappsk			\
82	engine			\
83	engine_id		\
84	frequency		\
85	group			\
86	identity		\
87	key_id			\
88	key_mgmt		\
89	mixed_cell		\
90	mode			\
91	nai			\
92	pac_file		\
93	pairwise		\
94	password		\
95	pcsc			\
96	phase1			\
97	phase2			\
98	pin			\
99	priority		\
100	private_key		\
101	private_key2		\
102	private_key2_passwd	\
103	private_key_passwd	\
104	proto			\
105	psk			\
106	scan_ssid		\
107	server_nai		\
108	ssid			\
109	subject_match		\
110	subject_match2		\
111	wep_key0		\
112	wep_key1		\
113	wep_key2		\
114	wep_key3		\
115	wpa_ptk_rekey		\
116	wep_tx_keyidx
117
118#
119# The following properties are ``Lists'' and as such should not be quoted.
120# Everything else should be quoted.
121#
122WPA_NETWORK_LIST_PROPERTIES="
123	auth_algo
124	eap
125	group
126	key_mgmt
127	pairwise
128	proto
129" # END-QUOTE
130
131#
132# Structure of wpa_cli(8) `scan_results' entry
133#
134f_struct_define WPA_SCAN_RESULT \
135	bssid	\
136	flags	\
137	freq	\
138	siglev	\
139	ssid
140
141#
142# Structure of a menu item in the wireless editor
143#
144f_struct_define WLAN_MENU_ITEM \
145	letter		\
146	ssid		\
147	nconfigs	\
148	nfound		\
149	help
150
151############################################################ FUNCTIONS
152
153# f_wpa_supplicant_init $file
154#
155# Initialize $file with basic contents of new wpa_supplicant.conf(5).
156#
157f_wpa_supplicant_init()
158{
159	local funcname=f_wpa_supplicant_init
160	local conf_file="$1" tmpfile
161
162	# Create a temporary file
163	f_eval_catch -k tmpfile $funcname mktemp 'mktemp -t "%s"' "$pgm" ||
164		return $FAILURE
165
166	# Make it unreadable by anyone but ourselves
167	f_eval_catch $funcname chmod \
168		'chmod 0600 "%s"' "$tmpfile" || return $FAILURE
169
170	# Make it owned by root/wheel
171	f_eval_catch $funcname chown \
172		'chown 0:0 "%s"' "$tmpfile" || return $FAILURE
173
174	# Populate it
175	cat <<-EOF >> "$tmpfile"
176	ctrl_interface=/var/run/wpa_supplicant
177	eapol_version=2
178	ap_scan=1
179	fast_reauth=1
180	EOF
181	echo >> "$tmpfile"
182
183	# Move it into place
184	f_eval_catch $funcname mv 'mv "%s" "%s"' "$tmpfile" "$conf_file"
185}
186
187# f_wpa_supplicant_parse $file [struct_prefix [count_var]]
188#
189# Parse wpa_supplicant.conf(5) $file. Default overrides are stored in a struct
190# (see struct.subr for additional details) named `{struct_prefix}defaults'. See
191# WPA_DEFAULTS struct definition in the GLOBALS section above.
192#
193# In addition, for each one of the wireless networks we parse from $file,
194# create a struct named `struct_prefixN' where `N' is a number starting from 1
195# and ending in $count_var (zero means no networks). See WPA_NETWORK struct
196# definition in the GLOBALS section above.
197#
198# If a `blob-base64-*={ ... }' entry appears, a struct named
199# `{struct_prefix}blob_base64_*' is created and the `data' property holds the
200# base64 encoded binary data without whitespace.
201#
202# Custom `*={ ... }' definitions are also supported, but should be unique
203# (unlike the `network' definition). A struct named `{struct_prefix}*' is
204# created if at least one property is defined in the block.
205#
206f_wpa_supplicant_parse()
207{
208	local file="$1" struct_prefix="$2" count_var="$3"
209
210	[ "$count_var" ] && setvar "$count_var" 0
211
212	[ "$file" ] || file=$( f_sysrc_get wpa_supplicant_conf_file )
213	if [ ! -e "$file" ]; then
214		f_dprintf "%s: No such file or directory" "$file"
215		return $FAILURE
216	fi
217
218	local list_properties
219	f_replaceall "$WPA_NETWORK_LIST_PROPERTIES" "$NL" "" list_properties
220	eval "$( awk \
221		-v count_var="$count_var"         \
222		-v struct_prefix="$struct_prefix" \
223		-v list_properties="$list_properties" '
224	BEGIN {
225		if (!count_var && !struct_prefix) exit
226		blob = count = custom_struct = network = 0
227		split(list_properties, lists, FS)
228	}
229	function set_value(struct, prop, value)
230	{
231		quoted = substr(value, 0, 1) == "\""
232		for (l in lists) if (list = prop == lists[l]) break
233		# Remove data after whitespace if unquoted and not a list
234		if (!quoted && !list) sub("[[:space:]].*", "", value)
235		# Otherwise if quoted and not a list, remove the quotes
236		# NB: wep_keyN needs to retain quoting if/when present
237		else if (quoted && !list && prop !~ /^wep_key[[:digit:]]+/) {
238			sub("^\"", "", value)
239			sub("\".*", "", value)
240		}
241		gsub(/'\''/, "'\''\\'\'\''", value) # Sanitize the value
242		if (!created[struct]) {
243			print "debug= f_struct_free", struct
244			print "debug= f_struct_new WPA_NETWORK", struct
245			created[struct] = 1
246		}
247		printf "debug= %s set %s '\'%s\''\n", struct, prop, value
248	}
249	{
250		if ($1 ~ /^network={/) {
251			empty = 1 # We do not increment count unless !empty
252			network = 1
253			next
254		} else if (match($1, "^blob-base64-[[:alnum:]_./-]+={")) {
255			blob = 1
256			blob_data = ""
257			struct = struct_prefix "blob_bas64_"
258			struct = struct substr($1, 13, RLENGTH - 14)
259			next
260		} else if (match($1, "^[[:alnum:]_./-]+={")) {
261			empty = 1
262			custom_struct = 1
263			struct = struct_prefix substr($1, 0, RLENGTH - 2)
264			gsub(/[^[:alnum:]_]/, "_", struct)
265			next
266		} else if ($1 ~ /^}/) {
267			if (blob) {
268				gsub("[[:space:]]", "", blob_data)
269				set_value(struct, "data", blob_data)
270			}
271			blob = custom_struct = network = 0
272			next
273		} else if (!match($0, /^[[:space:]]*[[:alnum:]_]+=/))
274			next
275
276		if (blob) {
277			blob_data = blob_data $0
278			next
279		} else if (network) {
280			if (empty) { count++; empty = 0 }
281			struct = struct_prefix count
282		} else if (!custom_struct)
283			struct = struct_prefix "defaults"
284
285		if (!struct_prefix) next
286
287		prop = substr($0, 0, RLENGTH - 1)
288		sub(/^[[:space:]]*/, "", prop)
289		value = substr($0, RSTART + RLENGTH)
290
291		set_value(struct, prop, value)
292	}
293	END { if (count_var) print count_var "=" count }' "$file" )"
294}
295
296# f_wpa_scan_results_parse [struct_prefix [count_var]]
297#
298# Parse the results of wpa_cli(8) `scan_results' into a series of structs (see
299# struct.subr for additional details) named `struct_prefixN' where `N' is a
300# number starting from 1 and ending in $count_var (zero means no results). See
301# WPA_SCAN_RESULT struct definition in the GLOBALS section above.
302#
303f_wpa_scan_results_parse()
304{
305	local struct_prefix="$1" count_var="$2"
306
307	[ "$count_var" ] && setvar "$count_var" 0
308
309	eval "$( wpa_cli scan_results 2> /dev/null | awk \
310		-v count_var="$count_var" \
311		-v struct_prefix="$struct_prefix" '
312	BEGIN {
313		if (!count_var && !struct_prefix) exit
314		count = 0
315		seg = "[[:xdigit:]][[:xdigit:]]"
316		bssid = seg":"seg":"seg":"seg":"seg":"seg
317		freq = siglev = flags = "[^[:space:]]+"
318		S = "[[:space:]]+"
319		line = bssid S freq S siglev S flags
320		line = "^[[:space:]]*" line "[[:space:]]*"
321	}
322	function set_value(struct, prop, value)
323	{
324		gsub(/'\''/, "'\''\\'\'\''", value) # Sanitize the value
325		if (!created[struct]) {
326			print "debug= f_struct_free", struct
327			print "debug= f_struct_new WPA_SCAN_RESULT", struct
328			created[struct] = 1
329		}
330		printf "debug= %s set %s '\'%s\''\n", struct, prop, value
331	}
332	{
333		if (!match($0, line)) next
334		ssid = substr($0, RLENGTH + 1)
335
336		count++
337		if (!struct_prefix) next
338
339		struct = struct_prefix count
340		set_value(struct, "ssid", ssid)
341		set_value(struct, "bssid",  $1)
342		set_value(struct, "freq",   $2)
343		set_value(struct, "siglev", $3)
344		set_value(struct, "flags",  $4)
345	}
346	END { if (count_var) print count_var "=" count }' )"
347}
348
349# f_wpa_scan_match_network WPA_SCAN_RESULT WPA_NETWORK
350#
351# Compares a WPA_SCAN_RESULT struct to a WPA_NETWORK struct. If they appear to
352# be a match returns success, otherwise failure.
353#
354f_wpa_scan_match_network()
355{
356	local scan_struct="$1" wireless_struct="$2"
357	local cp debug=
358
359	f_struct "$scan_struct" || return $FAILURE
360	f_struct "$wireless_struct" || return $FAILURE
361
362	local scan_ssid scan_bssid
363	$scan_struct get ssid scan_ssid
364	$scan_struct get bssid scan_bssid
365	local wireless_ssid wireless_bssid
366	$wireless_struct get ssid wireless_ssid
367	$wireless_struct get bssid wireless_bssid
368
369	local id_matched=
370	if [ "$wireless_ssid" -a "$wireless_bssid" ]; then
371		# Must match both SSID and BSSID
372		[ "$scan_ssid" = "$wireless_ssid" -a \
373		  "$scan_bssid" = "$wireless_bssid" ] && id_matched=1
374	elif [ "$wireless_ssid" ]; then
375		# Must match SSID only
376		[ "$scan_ssid" = "$wireless_ssid" ] && id_matched=1
377	elif [ "$wireless_bssid" ]; then
378		# Must match BSSID only
379		[ "$scan_bssid" = "$wireless_bssid" ] && id_matched=1
380	fi
381	[ "$id_matched" ] || return $FAILURE
382
383
384	#
385	# Get the scanned flags for the next few comparisons
386	#
387	local flags
388	$scan_struct get flags flags
389
390	#
391	# Compare configured key management against scanned network
392	#
393	if $wireless_struct get key_mgmt cp && [ "$cp" -a "$cp" != "NONE" ]
394	then
395		local mgmt mgmt_matched=
396		for mgmt in $cp; do
397			local mgmt2="$mgmt"
398			[ "$mgmt" != "${mgmt#WPA-}" ] &&
399				mgmt2="WPA2${mgmt#WPA}"
400			case "$flags" in
401			"$mgmt"|"$mgmt"-*|*-"$mgmt"|*-"$mgmt"-*)
402				mgmt_matched=1 break ;;
403			"$mgmt2"|"$mgmt2"-*|*-"$mgmt2"|*-"$mgmt2"-*)
404				mgmt_matched=1 break ;;
405			esac
406		done
407		[ "$mgmt_matched" ] || return $FAILURE
408	fi
409
410	local enc type flag
411
412	#
413	# Compare configured encryption against scanned network
414	#
415	for enc in psk:PSK eap:EAP \
416		wep_key0:WEP wep_key1:WEP wep_key2:WEP wep_key3:WEP
417	do
418		type=${enc%%:*}
419		flag=${enc#*:}
420		{ debug= $wireless_struct get $type cp && [ "$cp" ]; } ||
421			continue
422		# Configured network requires encryption
423		case "$flags" in "[$flag]"|*"-$flag-"*)
424			break # Success; stop after first match
425		esac
426		return $FAILURE
427	done
428	cp="" # sensitive info
429
430	#
431	# Compare scanned network encryption against configuration
432	# NB: Scanned network flags indicates _one_ of PSK EAP or WEP
433	# NB: Otherwise, no encryption (so encryption won't match)
434	#
435	local enc_wanted=
436	for enc in -PSK-:psk -EAP-:eap; do
437		flag=${enc%%:*}
438		type=${enc#*:}
439		case "$flags" in *"$flag"*)
440			enc_wanted=1
441			{ debug= $wireless_struct get $type cp &&
442				[ "$cp" ]; } || return $FAILURE
443			break # success
444		esac
445	done
446	case "$flags" in *"[WEP]"*)
447		enc_wanted=1
448		local wep_found=
449		for type in wep_key0 wep_key1 wep_key2 wep_key3; do
450			debug= $wireless_struct get $type cp && [ "$cp" ] &&
451				wep_found=1 break
452		done
453		[ "$wep_found" ] || return $FAILURE
454	esac
455	if [ ! "$enc_wanted" ]; then
456		# No match if the network specifies encryption
457		for type in psk eap wep_key0 wep_key1 wep_key2 wep_key3; do
458			debug= $wireless_struct get $type cp && [ "$cp" ] &&
459				return $FAILURE
460		done
461	fi
462	cp="" # sensitive info
463
464	return $SUCCESS
465}
466
467# f_wpa_scan_find_matches scans_prefix $scans_count \
468#                         wireless_prefix $wireless_count
469#
470# For each struct from `{scans_prefix}1' up to `{scans_prefix}$scans_count'
471# (see struct.subr for additional details) compare the wireless network info
472# (defined as struct WPA_SCAN_RESULT) to that of each configured wireless
473# stored in `{wireless_prefix}1' (defined as struct WPA_NETWORK) up to
474# `{wireless_prefix}$wireless_count'.
475#
476# If a scanned network is deemed to be a match to a configured wireless
477# network, a new `match' property is set on the WPA_NETWORK struct with a value
478# of `{scans_prefix}N' (where N represents the scanned network that matched).
479# At the same time, a new `matched' property is set on the WPA_SCAN_RESULT
480# struct with a value of 1, indicating that this network has been matched to a
481# stored [known] configuration and that it should not be displayed in menus.
482#
483# NB: If a matching entry is not correct, the user can optionally `Forget' the
484# network and that will cause the WPA_SCAN_RESULT to no longer match anything,
485# causing it to appear in the menus again.
486#
487# Return status should be ignored.
488#
489f_wpa_scan_find_matches()
490{
491	local scans_prefix="$1" scans_count="$2"
492	local wireless_prefix="$3" wireless_count="$4"
493	local matches
494
495	[ "$scans_count" -a "$wireless_count" ] || return $SUCCESS
496	f_isinteger "$scans_count" || return $FAILURE
497	f_isinteger "$wireless_count" || return $FAILURE
498
499	#
500	# Go through and eradicate any flags we set in a prior run, as things
501	# might have changed on us (either from the config side or scan side)
502	#
503	local w=1
504	while [ $w -le $wireless_count ]; do
505		f_struct "$wireless_prefix$w" set matches ""
506		w=$(( $w + 1 ))
507	done
508
509	#
510	# Find matches and set match data on structs
511	#
512	local s=1
513	while [ $s -le $scans_count ]; do
514		f_struct "$scans_prefix$s" set matched ""
515		w=1
516		while [ $w -le $wireless_count ]; do
517			if f_wpa_scan_match_network \
518				"$scans_prefix$s" "$wireless_prefix$w"
519			then
520				f_struct "$scans_prefix$s" set matched 1
521				debug= f_struct "$wireless_prefix$w" \
522				         get matches matches
523				matches="$matches${matches:+ }$scans_prefix$s"
524				f_struct "$wireless_prefix$w" \
525				         set matches "$matches"
526				break # to next scan result
527			fi
528			w=$(( $w + 1 ))
529		done
530		s=$(( $s + 1 ))
531	done
532}
533
534# f_dialog_menu_wlandev_edit $wlandev [$defaultitem]
535#
536# Display a list of wireless network devices (wlan*) associated with
537# $wlandev (e.g., `iwn0'). Allow the user to create and destroy wlan interfaces
538# while selecting ones to be cloned at startup (by setting `wlans_$wlandev').
539#
540f_dialog_menu_wlandev_edit()
541{
542	local funcname=f_dialog_menu_wlandev_edit
543	local wlandev="$1" defaultitem="$2"
544	local title="$DIALOG_TITLE"
545	local btitle="$DIALOG_BACKTITLE"
546	local prompt # Calculated below
547	local hline="$hline_arrows_tab_enter"
548
549	[ "$wlandev" ] || return $FAILURE
550
551	f_sprintf prompt "$msg_select_wlan_interfaces_for" "wlandev"
552
553	#
554	# Initially mark wlan devices with a %parent of $wlandev
555	#
556	local dev devs if list_to_save=
557	f_device_find "" $DEVICE_TYPE_NETWORK devs
558	for dev in $devs; do
559		f_struct "$dev" get name if || continue
560		case "$if" in wlan[0-9]*)
561			parent=$( sysctl -n net.wlan.${if#wlan}.%parent \
562				2> /dev/null )
563			if [ "$parent" = "$if" ]; then
564				local _wlanmark_$if="X"
565				list_to_save="$list_to_save $if"
566			fi
567		esac
568	done
569	list_to_save="${list_to_save# }"
570
571	#
572	# Operate in a loop so we can create/destroy interfaces from here
573	#
574	while :; do
575		#
576		# Refresh list of wlan interfaces
577		#
578		local wlanlist=
579		f_device_rescan_network
580		f_device_find "" $DEVICE_TYPE_NETWORK devs
581		for dev in $devs; do
582			f_struct "$dev" get name if || continue
583			case "$if" in wlan[0-9]*)
584				wlanlist="$wlanlist $if"
585			esac
586		done
587
588		#
589		# Build menu list of wlan devices
590		#
591		local menu_list="
592			'> $msg_save_exit'  '$msg_return_to_previous_menu'
593			'> $msg_create_new' 'wlan'
594			'> $msg_destroy'    '...'
595		" # END-QUOTE
596		local parent X
597		for if in $wlanlist; do
598			f_getvar _wlanmark_$if-" " X
599			menu_list="$menu_list '[$X] $if' '%parent: $parent'"
600			[ "$defaultitem" = "$if" ] && defaultitem="[$X] $if"
601		done
602
603		#
604		# Ask user to make a choice
605		#
606		local height width rows
607		eval f_dialog_menu_size height width rows \
608			\"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" \
609			$menu_list
610		local menu_choice
611		menu_choice=$( eval $DIALOG \
612			--title \"\$title\"              \
613			--backtitle \"\$btitle\"         \
614			--hline \"\$hline\"              \
615			--ok-label \"\$msg_select\"      \
616			--cancel-label \"\$msg_cancel\"  \
617			--default-item \"\$defaultitem\" \
618			--menu \"\$prompt\"              \
619			$height $width $rows             \
620			$menu_list                       \
621			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
622		) || return $FAILURE
623		f_dialog_data_sanitize menu_choice
624
625		case "$menu_choice" in
626		"> $msg_save_exit") # Save list to rc.conf(5) `wlans_$wlandev'
627			f_eval_catch $funcname f_sysrc_set \
628				'f_sysrc_set "wlans_%s" "%s"' \
629				"$wlandev" "$list_to_save" || continue
630			break # to success
631			;;
632		"> $msg_create_new") # Create new wlan interface for wlandev
633			local wlan
634			f_eval_catch -k wlan $funcname ifconfig \
635				'ifconfig wlan create wlandev "%s"' \
636				"$wlandev" || continue
637			local _wlanmark_$wlan="X"
638			list_to_save="$list_to_save${list_to_save:+ }$wlan"
639			;;
640		"> $msg_destroy") # Display a menu to pick one item to destroy
641			[ "$wlanlist" ] || continue # Nothing to destroy
642
643			menu_list=
644			for if in $wlanlist; do
645				menu_list="$menu_list '$if' ''"
646			done
647			local msg="$msg_pick_an_interface_to_destroy"
648			eval f_dialog_menu_size height width rows \
649			    \"\$title\" \"$btitle\" \"\$msg\" \"\" $menu_list
650			menu_choice=$( eval $DIALOG \
651				--title \"\$title\"             \
652				--backtitle \"\$btitle\"        \
653				--ok-label \"\$msg_destroy\"    \
654				--cancel-label \"\$msg_cancel\" \
655				--menu \"\$msg\"                \
656				$height $width $rows            \
657				$menu_list                      \
658				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
659			) || continue
660			f_dialog_data_sanitize menu_choice
661			f_eval_catch $funcname ifconfig \
662				'ifconfig "%s" destroy' "$menu_choice"
663			;;
664		"[ ] wlan"[0-9]*) # Unmarked; Mark
665			if="${menu_choice#??? }"
666			local _wlanmark_$if="X"
667			list_to_save="$list_to_save${list_to_save:+ }$if"
668			;;
669		"[X] wlan"[0-9]*) # Marked; Unmark
670			menu_choice="${menu_choice#??? }"
671			local _wlanmark_$menu_choice=" "
672			local new_list_to_save=
673			for if in $list_to_save; do
674				[ "$if" = "$menu_choice" ] && continue
675				new_list_to_save="$new_list_to_save $if"
676			done
677			list_to_save="${new_list_to_save# }"
678			;;
679		esac
680	done
681
682	return $SUCCESS
683}
684
685# f_dialog_scan_wireless
686#
687# Initiate a scan for wireless networks. If wpa_supplicant(8) is not running
688# but a wlan interface has been created, start an instance of wpa_supplicant(8)
689# with the first wlan(4) interface we find. After initiating the scan, displays
690# a message for 5 seconds (with option to dismiss). Returns failure if an error
691# occurs, otherwise success.
692#
693f_dialog_scan_wireless()
694{
695	local funcname=f_dialog_scan_wireless
696
697	#
698	# Try to communicate with a running wpa_supplicant(8)
699	#
700	if ! f_eval_catch -d $funcname wpa_cli 'wpa_cli ping'; then
701
702		# If there is indeed one running, bail!
703		if ps axo ucomm= | grep -qw wpa_supplicant; then
704			f_show_msg "$msg_failed_to_reach_wpa_supplicant" \
705			           "$msg_wpa_cli_ping_failed"
706			return $FAILURE
707		fi
708
709		# Try and find a wlan device so we can start wpa_supplicant
710		local dev devs if wlan=
711		f_device_rescan_network
712		f_device_find "" $DEVICE_TYPE_NETWORK devs
713		for dev in $devs; do
714			f_struct "$dev" get name if || continue
715			case "$if" in wlan[0-9]*)
716				wlan=$if
717				break
718			esac
719		done
720		if [ ! "$wlan" ]; then
721			# We can't start wpa_supplicant without wlan interface
722			# Tell the user they have to create one by navigating
723			# to a Wireless device to create a wlan interface. But
724			# let's go one step further and find an interface that
725			# we can provide in the prompt text.
726			local wlandev=
727			for if in $devs; do
728				case "$if" in wlan[0-9]*) next; esac
729				if f_device_is_wireless $if; then
730					wlandev=$if
731					break
732				fi
733			done
734			if [ "$wlandev" ]; then
735				f_show_msg "$msg_cant_start_wpa_supplicant" \
736				           "$wlandev"
737			else
738				# Warn user, appears no wireless available
739				f_show_msg "$msg_warning_no_wireless_devices"
740			fi
741			return $FAILURE
742		fi
743
744		# NB: Before we can proceed to fire up wpa_supplicant(8), let's
745		# make sure there is a bare-bones wpa_supplicant.conf(5) for it
746		local conf_file
747		conf_file=$( f_sysrc_get wpa_supplicant_conf_file )
748		if [ ! -e "$conf_file" ]; then
749			f_wpa_supplicant_init "$conf_file" || return $FAILURE
750			f_eval_catch -d $funcname wpa_cli 'wpa_cli reconfigure'
751		fi
752
753		# Try and start wpa_supplicant(8)
754		f_eval_catch $funcname wpa_supplicant \
755		        '/etc/rc.d/wpa_supplicant start "%s"' "$wlan" ||
756			return $FAILURE
757
758		# Try to reach this new wpa_supplicant(8)
759		if ! f_eval_catch -d $funcname wpa_cli 'wpa_cli ping'; then
760			f_show_msg "$msg_failed_to_reach_wpa_supplicant" \
761			           "$msg_wpa_cli_ping_failed"
762			return $FAILURE
763		fi
764
765	fi # ! f_quietly wpa_cli ping
766
767	# If we reach hear, then it should be OK to scan the airwaves
768	f_eval_catch -d $funcname wpa_cli 'wpa_cli scan' || return $FAILURE
769
770	# Return immediately if a duration is: null or not a number >= 1
771	local duration="$DIALOG_MENU_WLAN_SCAN_DURATION"
772	f_isinteger "$duration" || return $SUCCESS
773	[ $duration -gt 0 ] || return $SUCCESS
774
775	# Display a message that times-out if not dismissed manually
776	local prompt
777	f_sprintf prompt "$msg_scanning_wireless_pausing" "$duration"
778	f_dialog_pause "$prompt" "$duration"
779}
780
781# f_dialog_wireless_edit $ssid
782#
783# Display a menu to allow the user to either create a new entry for the
784# wpa_supplicants.conf(5) file, or to edit values for an existing entry.
785#
786# If more than one wireless network is found to match $ssid, a sub-menu is
787# presented, allowing the user to select the desired network.
788#
789f_dialog_wireless_edit()
790{
791	local title="$DIALOG_TITLE"
792	local btitle="$DIALOG_BACKTITLE"
793	local prompt1="$msg_select_the_configuration_you_would_like"
794	local prompt2 # Calculated below
795	local hline="$hline_alnum_arrows_punc_tab_enter"
796	local ssid="$1" bssid="$2"
797
798	f_sprintf prompt2 "$msg_wireless_network_configuration_for" "$ssid"
799
800	#
801	# Find one or more configurations that match the SSID selection
802	#
803	local height1 width1 rows1 menu_list1=
804	local n=0 nmatches=0 tag wssid wbssid help matches=
805	while [ $n -lt $NWIRELESS_CONFIGS ]; do
806		n=$(( $n + 1 ))
807
808		debug= f_struct WIRELESS_$n get ssid wssid
809		[ "$ssid" = "$wssid" ] || continue
810		debug= f_struct WIRELESS_$n get bssid wbssid
811		[ "${bssid:-$wbssid}" = "$wbssid" ] || continue
812
813		nmatches=$(( $nmatches + 1 ))
814		[ $nmatches -le ${#DIALOG_MENU_TAGS} ] || break
815		f_substr -v tag "$DIALOG_MENU_TAGS" $nmatches 1
816
817		f_wireless_describe WIRELESS_$n help
818		menu_list1="$menu_list1
819			'$tag $wssid' '$wbssid' '$help'
820		" # END-QUOTE
821
822		matches="$matches WIRELESS_$n"
823	done
824	if [ $nmatches -eq 0 ]; then
825		f_show_msg "$msg_cannot_edit_wireless_ssid" "$ssid"
826		return $FAILURE
827	elif [ $nmatches -eq 1 ]; then
828		struct=${matches# }
829	else
830		eval f_dialog_menu_with_help_size height1 width1 rows1 \
831			\"\$title\" \"\$btitle\" \"\$prompt1\" \"\$hline\" \
832			$menu_list1
833	fi
834
835	#
836	# Operate in a loop; for the case of $nmatches > 1, we can cycle back
837	# to allow the user to make another choice after inspecting each one.
838	#
839	local menu_choice index struct defaultitem1=
840	while :; do
841		if [ $nmatches -gt 1 ]; then
842			menu_choice=$( eval $DIALOG \
843				--title \"\$title\"               \
844				--backtitle \"\$btitle\"          \
845				--hline \"\$hline\"               \
846				--ok-label \"\$msg_select\"       \
847				--cancel-label \"\$msg_cancel\"   \
848				--item-help                       \
849				--default-item \"\$defaultitem1\" \
850				--menu \"\$prompt1\"              \
851				$height1 $width1 $rows1           \
852				$menu_list1                       \
853				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
854			) || return $FAILURE
855			f_dialog_data_sanitize menu_choice
856			defaultitem1="$menu_choice"
857			index=$( eval f_dialog_menutag2index_with_help \
858				\"\$menu_choice\" $menu_list1 )
859			struct=$( set -- $matches; eval echo \${$index} )
860		fi
861
862		#
863		# Operate within another loop to allow editing multiple values
864		#
865		local menu_list2 height2 width2 rows2 member
866		while :; do
867			menu_list2="
868				'> $msg_save_exit'
869					'$msg_return_to_previous_menu'
870			" # END-QUOTE
871			n=0
872			for member in $_struct_typedef_WPA_NETWORK; do
873				[ "$member" = "ssid" ] && continue
874				debug= $struct get $member value || continue
875				n=$(( $n + 1 ))
876				[ $n -le ${#DIALOG_MENU_TAGS} ] || break
877				f_substr -v tag "$DIALOG_MENU_TAGS" $n 1
878				if [ ${#value} -gt 32 ]; then
879					f_snprintf value 29 "%s" "$value"
880					value="$value..."
881				fi
882				case "$member" in
883				password|pin|private_key_passwd|psk|wep_key*)
884					f_replaceall "$value" "?" "*" value ;;
885				esac
886				f_shell_escape "$value" value
887				menu_list2="$menu_list2
888					'$tag $member' '$value'
889				" # END-QUOTE
890			done
891			eval f_dialog_menu_size height2 width2 rows2 \
892				\"\$title\" \"\$btitle\" \"\$prompt2\" \
893				\"\$hline\" $menu_list2
894			menu_choice=$( eval $DIALOG \
895				--title \"\$title\"               \
896				--backtitle \"\$btitle\"          \
897				--hline \"\$hline\"               \
898				--ok-label \"\$msg_select\"       \
899				--cancel-label \"\$msg_cancel\"   \
900				--default-item \"\$defaultitem2\" \
901				--menu \"\$prompt2\"              \
902				$height2 $width2 $rows2           \
903				$menu_list2                       \
904				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
905			) || break
906			f_dialog_data_sanitize menu_choice
907			defaultitem2="$menu_choice"
908
909			# XXXDT Unfinished
910		done
911		[ $nmatches -eq 1 ] && break
912	done
913
914	#
915	# XXXDT Unfinished
916	# This is where we display a menu that edits the entry
917	# And then we modify the wpa_supplicants.conf(5) config file
918	# XXXDT Unfinished
919	#
920
921	return $FAILURE # XXXDT Simulating DIALOG_CANCEL to mean ``no changes''
922}
923
924# f_wireless_describe WPA_NETWORK [$var_to_set]
925#
926# Provide a description of the WPA_NETWORK struct. If $var_to_set is missing or
927# NULL, the description is provided on standard output (which is less preferred
928# due to performance; e.g., if called in a loop).
929#
930f_wireless_describe()
931{
932	local __struct="$1" __var_to_set="$2" debug=
933
934	[ "$__var_to_set" ] && setvar "$__var_to_set" ""
935	f_struct "$__struct" || return $FAILURE
936
937	#
938	# Basic description is `proto key_mgmt group eap'
939	#
940	local __member __cp __desc=
941	for __member in proto key_mgmt group eap; do
942		$__struct get $__member __cp && [ "$__cp" ] &&
943			__desc="$__desc${__desc:+ }$__cp"
944	done
945
946	local __check __kk
947
948	#
949	# Make sure we add WEP40/WEP140 even if omitted from the key_mgmt
950	# section of entry
951	#
952	local __wep_keyN __f_wireless_describe_first_char __length
953	for __wep_keyN in wep_key0 wep_key1 wep_key2 wep_key3; do
954		$__struct get $__wep_keyN __kk
955		[ "$__kk" ] || continue
956
957		# What type is it? ASCII or HEX?
958		__check=WEP
959		f_substr -v __f_wireless_describe_first_char "$__kk" 1 1
960		case "$__f_wireless_describe_first_char" in
961		\") # ASCII
962			__length=$(( ${#__kk} - 2 ))
963			if [ $__length -le 5 ]; then
964				__check=WEP40
965			elif [ $__length -le 13 ]; then
966				__check=WEP104
967			fi ;;
968		*) # HEX
969			__length=${#__kk}
970			if [ $__length -eq 10 ]; then
971				__check=WEP40
972			elif [ $__length -le 26 ]; then
973				__check=WEP104
974			fi
975		esac
976		__kk="" # sensitive info
977
978		case "$__desc" in
979		*"$__check"*) : already there ;;
980		*) __desc="$__desc${__desc:+ }$__check"
981		esac
982	done
983
984	#
985	# Make sure we display PSK even if omitted
986	# from the key_mgmt section of the entry
987	#
988	$__struct get psk __kk
989	if [ "$__kk" ]; then
990		__kk="" # sensitive info
991		__check=PSK
992		case "$__desc" in
993		*"$__check"*) : already there ;;
994		*) __desc="$__desc${__desc:+ }$__check"
995		esac
996	fi
997
998	#
999	# Produce results
1000	#
1001	if [ "$__var_to_set" ]; then
1002		setvar "$__var_to_set" "${__desc:-NONE}"
1003	else
1004		echo "$__desc"
1005	fi
1006}
1007
1008# f_menu_wireless_configs
1009#
1010# Generates the tag/item/help triplets for wireless network menu (`--item-help'
1011# required) from wpa_supplicant.conf(5) [WPA_NETWORK] structs.
1012#
1013f_menu_wireless_configs()
1014{
1015	[ "$DIALOG_MENU_WLAN_SHOW_CONFIGURED" ] || return $SUCCESS
1016
1017	echo "' - $msg_configured_ssids -' ' - $msg_details -' ''"
1018
1019	local n=0 nunique=0 debug=
1020	local ssid ussid matches nmatches nconfigs nfound help desc w
1021	while [ $n -lt $NWIRELESS_CONFIGS ]; do
1022		n=$(( $n + 1 ))
1023
1024		f_struct WIRELESS_$n get ssid ssid
1025		[ ! "$DIALOG_MENU_WLAN_SHOW_ALL" -a ! "$ssid" ] && continue
1026
1027		local u=0 unique=1
1028		while [ $u -lt $nunique ]; do
1029			u=$(( $u + 1 ))
1030			menuitem_$u get ssid ussid
1031			[ "$ssid" != "$ussid" ] || unique= break
1032		done
1033		if [ "$unique" ]; then
1034			nunique=$(( $nunique + 1 ))
1035			u=$nunique
1036
1037			# Set SSID and initialize number of configs found (1)
1038			f_struct_new WLAN_MENU_ITEM menuitem_$u
1039			menuitem_$u set ssid "$ssid"
1040			menuitem_$u set nconfigs 1
1041
1042			# Set number of wireless networks that match config
1043			WIRELESS_$n get matches matches
1044			f_count nmatches $matches
1045			menuitem_$u set nfound $nmatches
1046
1047			# Set help to description of the wireless config
1048			f_wireless_describe WIRELESS_$n desc
1049			menuitem_$u set help "$desc"
1050		else
1051			# Increment number of configs found with this SSID
1052			menuitem_$u get nconfigs nconfigs
1053			nconfigs=$(( $nconfigs + 1 ))
1054			menuitem_$u set nconfigs $nconfigs
1055
1056			# Add number of matched networks to existing count
1057			WIRELESS_$n get matches matches
1058			f_count nmatches $matches
1059			menuitem_$u get nfound nfound
1060			nfound=$(( $nfound + $nmatches ))
1061			menuitem_$u set nfound $nfound
1062
1063			# Combine description with existing help
1064			menuitem_$u get help help
1065			f_wireless_describe WIRELESS_$n desc
1066			for w in $desc; do
1067				case "$help" in
1068				"$w"|"$w "*|*" $w"|*" $w "*) : already there ;;
1069				*) help="$help $w"
1070				esac
1071			done
1072			menuitem_$u set help "${help# }"
1073		fi
1074	done
1075
1076	n=0
1077	while [ $n -lt $nunique ]; do
1078		n=$(( $n + 1 ))
1079		menuitem_$n get ssid ssid
1080
1081		menuitem_$n get nconfigs nconfigs
1082		desc="$nconfigs $msg_configured_lc"
1083		[ $nconfigs -lt 10 ] && desc=" $desc"
1084		menuitem_$n get nfound nfound
1085		[ $nfound -gt 0 ] && desc="$desc $nfound $msg_found"
1086
1087		menuitem_$n get help help
1088		echo "'[X] $ssid' '$desc' '$help'"
1089	done | sort -bf | awk 'BEGIN { prefix = "" }
1090	{
1091		cur_prefix = toupper(substr($0, 6, 1))
1092		if (cur_prefix != "'\''" && prefix != cur_prefix ) {
1093			prefix = cur_prefix
1094			printf "'\''%c%s\n", prefix, substr($0, 2)
1095		} else
1096			printf "'\'' %s\n", substr($0, 2)
1097	}'
1098}
1099
1100# f_menu_wpa_scan_results
1101#
1102# Generates the tag/item/help triplets for wireless network menu (`--item-help'
1103# required) from wpa_cli(8) `scan_results' [WPA_SCAN_RESULT] structs.
1104#
1105f_menu_wpa_scan_results()
1106{
1107	[ "$DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS" ] || return $SUCCESS
1108
1109	if [ "$DIALOG_MENU_WLAN_SHOW_ALL" ]; then
1110		echo "' - $msg_discovered_ssids -' ' - $msg_details -' ''"
1111	else
1112		echo "' - $msg_discovered_ssids -' '' ''"
1113	fi
1114
1115	local n=0 nunique=0 debug=
1116	local ssid ussid matched nfound help flags f
1117	while [ $n -lt $NWSCAN_RESULTS ]; do
1118		n=$(( $n + 1 ))
1119
1120		WSCANS_$n get ssid ssid
1121		[ ! "$DIALOG_MENU_WLAN_SHOW_ALL" -a ! "$ssid" ] && continue
1122
1123		WSCANS_$n get matched matched
1124		[ "$DIALOG_MENU_WLAN_SHOW_CONFIGURED" -a "$matched" ] &&
1125			continue
1126
1127		local u=0 unique=1
1128		while [ $u -lt $nunique ]; do
1129			u=$(( $u + 1 ))
1130			menuitem_$u get ssid ussid
1131			[ "$ssid" != "$ussid" ] || unique= break
1132		done
1133		if [ "$unique" ]; then
1134			nunique=$(( $nunique + 1 ))
1135			u=$nunique
1136
1137			# Set SSID and initialize number of networks found (1)
1138			f_struct_new WLAN_MENU_ITEM menuitem_$u
1139			menuitem_$u set ssid "$ssid"
1140			menuitem_$u set nfound 1
1141
1142			# Set help to flags
1143			WSCANS_$n get flags flags
1144			f_replaceall "$flags" "[" " " flags
1145			f_replaceall "$flags" "]" "" flags
1146			flags="${flags# }"
1147			case "$flags" in
1148			"") flags="NONE" ;;
1149			ESS) flags="NONE ESS" ;;
1150			esac
1151			menuitem_$u set help "$flags"
1152		else
1153			# Increment number of networks found with this SSID
1154			menuitem_$u get nfound nfound
1155			nfound=$(( $nfound + 1 ))
1156			menuitem_$u set nfound $nfound
1157
1158			# Combine flags into existing help
1159			WSCANS_$n get flags flags
1160			f_replaceall "$flags" "[" " " flags
1161			f_replaceall "$flags" "]" "" flags
1162			local flags_ess=
1163			case "$flags" in *" ESS")
1164				flags_ess=1
1165				flags="${flags% ESS}"
1166			esac
1167			local help_ess=
1168			menuitem_$u get help help
1169			case "$help" in *" ESS")
1170				help_ess=1
1171				help="${help% ESS}"
1172			esac
1173			for f in ${flags:-NONE}; do
1174				case "$help" in
1175				"$f"|"$f "*|*" $f"|*" $f "*) : already there ;;
1176				*) help="$help $f"
1177				esac
1178			done
1179			[ "$flags_ess" -a ! "$help_ess" ] && help="$help ESS"
1180			menuitem_$u set help "${help# }"
1181		fi
1182	done
1183
1184	local desc n=0
1185	while [ $n -lt $nunique ]; do
1186		n=$(( $n + 1 ))
1187		menuitem_$n get ssid ssid
1188
1189		desc=
1190		if [ "$DIALOG_MENU_WLAN_SHOW_ALL" ]; then
1191			menuitem_$n get nfound nfound
1192			desc="$nfound $msg_found"
1193			[ $nfound -lt 10 ] && desc=" $desc"
1194		fi
1195
1196		menuitem_$n get help help
1197		echo "'[ ] $ssid' '$desc' '$help'"
1198	done | sort -bf | awk 'BEGIN { prefix = "" }
1199	{
1200		cur_prefix = toupper(substr($0, 6, 1))
1201		if (cur_prefix != "'\''" && prefix != cur_prefix ) {
1202			prefix = cur_prefix
1203			printf "'\''%c%s\n", prefix, substr($0, 2)
1204		} else
1205			printf "'\'' %s\n", substr($0, 2)
1206	}'
1207}
1208
1209# f_dialog_menu_wireless_edit
1210#
1211# Display a list of wireless networks configured in wpa_supplicants.conf(5) and
1212# (if wpa_supplicant(8) is running) also displays scan results for unconfigured
1213# wireless networks.
1214#
1215f_dialog_menu_wireless_edit()
1216{
1217	local funcname=f_dialog_menu_wireless_edit
1218	local title="$DIALOG_TITLE"
1219	local btitle="$DIALOG_BACKTITLE"
1220	local prompt="$msg_wireless_networks_text"
1221	local menu_list # Calculated below
1222	local defaultitem= # Calculated below
1223	local hline="$hline_alnum_arrows_punc_tab_enter"
1224
1225	f_show_info "$msg_loading_wireless_menu"
1226
1227	local conf_file
1228	conf_file=$( f_sysrc_get wpa_supplicant_conf_file )
1229
1230	#
1231	# Operate in a loop so we can edit wpa_supplicant.conf(5) and rescan
1232	# for new wireless networks from here.
1233	#
1234	local do_parse=1 remake_menu=1 item
1235	while :; do
1236		#
1237		# If this is the first time here, parse wpa_supplicant.conf(5),
1238		# scan the airwaves, and compare to find matches.
1239		#
1240		if [ "$do_parse" -a "$DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS" ]
1241		then
1242			f_dprintf "$funcname: Parsing wireless scan results"
1243			f_dialog_scan_wireless &&
1244				f_wpa_scan_results_parse WSCANS_ NWSCAN_RESULTS
1245			f_dprintf "$funcname: Parsed %i scanned networks" \
1246			          $NWSCAN_RESULTS
1247		fi
1248		if [ "$do_parse" -a "$DIALOG_MENU_WLAN_SHOW_CONFIGURED" ]
1249		then
1250			f_dprintf "$funcname: Parsing wpa_supplicants.conf(5)"
1251			f_wpa_supplicant_parse "$conf_file" \
1252			                       WIRELESS_ NWIRELESS_CONFIGS
1253			f_dprintf "%s: Parsed %i wireless configurations" \
1254				  $funcname $NWIRELESS_CONFIGS
1255			f_wpa_scan_find_matches WSCANS_ $NWSCAN_RESULTS \
1256			                        WIRELESS_ $NWIRELESS_CONFIGS
1257		fi
1258		do_parse=
1259
1260		if [ "$remake_menu" ]; then
1261			remake_menu=
1262
1263			#
1264			# Add both items scanned from the airwaves and networks
1265			# parsed from wpa_supplicants.conf(5). Latter items are
1266			# marked, sorted, and added to top of list above the
1267			# former (which are unmarked and sorted separately).
1268			#
1269			f_dprintf "$funcname: Building menu list..."
1270			menu_list=$(
1271				# Process wpa_supplicant.conf(5) structs
1272				f_menu_wireless_configs
1273				# Process wpa_cli(8) `scan_results' structs
1274				f_menu_wpa_scan_results
1275			)
1276			f_dprintf "$funcname: menu list built."
1277
1278			#
1279			# Add static top-level menu items
1280			#
1281			local XA=" " XC=" " XS=" "
1282			[ "$DIALOG_MENU_WLAN_SHOW_ALL"          ] && XA="X"
1283			[ "$DIALOG_MENU_WLAN_SHOW_CONFIGURED"   ] && XC="X"
1284			[ "$DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS" ] && XS="X"
1285			menu_list="
1286				'> $msg_exit' '$msg_return_to_previous_menu'
1287					''
1288				'> $msg_rescan_wireless'   '*'
1289					'$msg_rescan_wireless_help'
1290				'> $msg_forget_all'        '*'
1291					'$msg_forget_all_help'
1292				'> $msg_show_configured'   '[$XC]'
1293					'$msg_show_configured_help'
1294				'> $msg_show_scan_results' '[$XS]'
1295					'$msg_show_scan_results_help'
1296				'> $msg_show_all'          '[$XA]'
1297					'$msg_show_all_help'
1298				'> $msg_manually_connect'  '...'
1299					'$msg_manually_connect_help'
1300			$menu_list" # END-QUOTE
1301		fi
1302
1303		local height width rows
1304		eval f_dialog_menu_with_help_size height width rows \
1305			\"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" \
1306			$menu_list
1307
1308		local menu_choice
1309		menu_choice=$( eval $DIALOG \
1310			--title \"\$title\"              \
1311			--backtitle \"\$btitle\"         \
1312			--hline \"\$hline\"              \
1313			--ok-label \"\$msg_select\"      \
1314			--cancel-label \"\$msg_cancel\"  \
1315			--item-help                      \
1316			--default-item \"\$defaultitem\" \
1317			--menu \"\$prompt\"              \
1318			$height $width $rows             \
1319			$menu_list                       \
1320			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1321		) || break
1322		f_dialog_data_sanitize menu_choice
1323		defaultitem="$menu_choice"
1324
1325		case "$menu_choice" in
1326		"> $msg_exit") break ;;
1327		"> $msg_rescan_wireless") do_parse=1 remake_menu=1 ;;
1328		"> $msg_forget_all")
1329			if f_noyes "$msg_forget_all_confirm"; then
1330				f_eval_catch $funcname rm \
1331					'rm -f "%s"' "$conf_file" || continue
1332				f_wpa_supplicant_init "$conf_file" || continue
1333				f_eval_catch -d $funcname wpa_cli \
1334					'wpa_cli reconfigure'
1335				f_wpa_supplicant_parse "$conf_file" \
1336					WIRELESS_ NWIRELESS_CONFIGS
1337				f_wpa_scan_find_matches \
1338					WSCANS_ $NWSCAN_RESULTS \
1339					WIRELESS_ $NWIRELESS_CONFIGS
1340				do_parse=1 remake_menu=1
1341			fi ;;
1342		"> $msg_show_configured")
1343			item=$( eval f_dialog_menutag2item_with_help \
1344			        		\"\$menu_choice\" $menu_list )
1345			if [ "$item" = "[ ]" ]; then
1346				DIALOG_MENU_WLAN_SHOW_CONFIGURED=1
1347			else
1348				DIALOG_MENU_WLAN_SHOW_CONFIGURED=
1349			fi
1350			remake_menu=1 ;;
1351		"> $msg_show_scan_results")
1352			item=$( eval f_dialog_menutag2item_with_help \
1353			        		\"\$menu_choice\" $menu_list )
1354			if [ "$item" = "[ ]" ]; then
1355				DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS=1
1356			else
1357				DIALOG_MENU_WLAN_SHOW_SCAN_RESULTS=
1358			fi
1359			remake_menu=1 ;;
1360		"> $msg_show_all")
1361			item=$( eval f_dialog_menutag2item_with_help \
1362			        		\"\$menu_choice\" $menu_list )
1363			if [ "$item" = "[ ]" ]; then
1364				DIALOG_MENU_WLAN_SHOW_ALL=1
1365			else
1366				DIALOG_MENU_WLAN_SHOW_ALL=
1367			fi
1368			remake_menu=1 ;;
1369		"> $msg_manually_connect")
1370			f_dialog_wireless_edit && remake_menu=1 ;;
1371		?"[X] "*)
1372			ssid="${menu_choice#??X? }"
1373			f_dialog_wireless_edit "$ssid" || continue
1374			do_parse=1 remake_menu=1 ;;
1375		"[ ] "*)
1376			:
1377			: XXXDT Unfinished
1378			:
1379			;;
1380		esac
1381	done
1382
1383	#
1384	# XXXDT Unfinished
1385	#
1386}
1387
1388############################################################ MAIN
1389
1390f_dprintf "%s: Successfully loaded." media/wlan.subr
1391
1392fi # ! $_MEDIA_WLAN_SUBR
1393