ACC SHELL
/**
* File: include/network/services/dns.ycp
* Package: Network configuration
* Summary: Hostname and DNS setup dialog
* Authors: Michal Svec <msvec@suse.cz>
* Martin Vidner <mvidner@suse.cz>
*
* $Id: dns.ycp 60556 2010-01-27 14:21:30Z kmachalkova $
*/
{
textdomain "network";
import "CWM";
import "DNS";
import "GetInstArgs";
import "Host";
import "Hostname";
import "IP";
import "Label";
import "Lan";
import "NetworkConfig";
import "Popup";
import "Map";
import "CWMTab";
include "network/routines.ycp";
include "network/widgets.ycp";
include "network/lan/help.ycp";
/**
* If we know that there are no interfaces with DHCP, we can disable
* the check boxes.
* Each dialog must set this variable.
* HostnameDialog does not know yet whether we will have DHCP so it
* assumes yes.
* DNSMainDialog can query Lan::.
*/
boolean has_dhcp = true;
/**
* If there's a process modifying resolv.conf, we warn the user before
* letting him change things that will be overwritten anyway.
* See also #61000.
*/
boolean resolver_modifiable = false;
/**
* original setup, used to determine whether data have been modified
*/
map settings_orig = $[];
/**
* CWM buffer for both dialogs. Note that NAMESERVERS and SEARCHLIST
* are lists and their widgets are suffixed.
*/
map hn_settings = $[];
/**
* @param l list of strings
* @return only non-empty items
*/
define list<string> NonEmpty (list<string> l) {
return filter (string s, l, ``(s != ""));
}
/**
* @return initial settings for this dialog in one map, from DNS::
*/
define map InitSettings () {
map settings = $[
"HOSTNAME": DNS::hostname,
"DOMAIN": DNS::domain,
"DHCP_HOSTNAME": DNS::dhcp_hostname,
"WRITE_HOSTNAME": DNS::write_hostname
];
// the rest is not so straightforward,
// because we have list variables but non-list widgets
/* domain search */
string searchstring = mergestring (DNS::searchlist, "\n");
// #49094: populate the search list
// #437759: discard 'site', nobody really wants that pre-set
if (searchstring == "" && settings["DOMAIN"]:"" != "site" )
{
searchstring = settings["DOMAIN"]:"";
}
settings["SEARCHLIST_S"] = searchstring;
settings["NAMESERVER_1"] = DNS::nameservers[0]:"";
settings["NAMESERVER_2"] = DNS::nameservers[1]:"";
settings["NAMESERVER_3"] = DNS::nameservers[2]:"";
settings_orig = settings;
return settings;
}
/**
* @param settings map of settings to be stored to DNS::
*/
define void StoreSettings (map settings) {
list<string> nameservers = [
settings["NAMESERVER_1"]:"",
settings["NAMESERVER_2"]:"",
settings["NAMESERVER_3"]:"",
];
list<string> searchlist = splitstring (settings["SEARCHLIST_S"]:"",
" ,\n\t");
DNS::hostname = settings["HOSTNAME"]:"";
DNS::domain = settings["DOMAIN"]:"";
DNS::nameservers = NonEmpty (nameservers);
DNS::searchlist = NonEmpty (searchlist);
DNS::dhcp_hostname = settings["DHCP_HOSTNAME"]:false;
DNS::write_hostname = settings["WRITE_HOSTNAME"]:true;
/* update modified flag */
DNS::modified = DNS::modified || (settings != settings_orig);
y2milestone("Modified DNS: %1", DNS::modified );
}
/**
* Default function to init the value of a widget.
* Used for push buttons.
* @param key id of the widget
*/
define void InitHnWidget (string key) {
any value = hn_settings[key]:nil;
UI::ChangeWidget (`id (key), `Value, value);
}
/**
* Default function to store the value of a widget.
* @param key id of the widget
* @param event the event being handled
*/
define void StoreHnWidget (string key, map event) {
any value = UI::QueryWidget (`id (key), `Value);
y2milestone("%1/%2", key, value);
hn_settings[key] = value;
}
/**
* Init handler for DHCP_HOSTNAME.
* enable or disable: is DHCP available?
* @param key the widget receiving the event
* @param event the event being handled
* @return nil so that the dialog loops on
*/
define void InitDhcpHostname (string key) {
UI::ChangeWidget (`id("DHCP_HOSTNAME"), `Enabled, has_dhcp);
if (!has_dhcp)
UI::ReplaceWidget(`id ("dh_host_text"),`Label(_("No interface with dhcp")));
// the hostname dialog proposes to update it by DHCP on a laptop (#326102)
else
UI::ChangeWidget(`id("DHCP_HOSTNAME"), `Value, hn_settings["DHCP_HOSTNAME"]:true);
return nil;
}
/**
* Event handler for resolver data (nameservers, searchlist)
* enable or disable: is DHCP available?
* @param key the widget receiving the event
* @param event the event being handled
* @return nil so that the dialog loops on
*/
define symbol HandleResolverData (string key, map event) {
//if this one is disabled, it means NM is in charge (see also initModifyResolvPolicy())
if ( (boolean) UI::QueryWidget(`id("MODIFY_RESOLV"),`Enabled ))
//thus, we should not re-enable already disabled widgets
UI::ChangeWidget (`id (key), `Enabled, resolver_modifiable);
return nil;
}
/**
* Validator for hostname, no_popup
* @param key the widget being validated
* @param event the event being handled
* @return whether valid
*/
define boolean ValidateHostname (string key, map event) {
boolean dhn = has_dhcp && (boolean) UI::QueryWidget (`id ("DHCP_HOSTNAME"), `Value);
// If the names are set by dhcp, the user may enter backup values
// here - N#28427. That is, host and domain name are optional then.
// For static config, they are mandatory.
string value = (string) UI::QueryWidget (`id (key), `Value);
if (!dhn || value != "")
{
return Hostname::Check (value);
}
return true;
}
/**
* Validator for domain name, no_popup
* @param key the widget being validated
* @param event the event being handled
* @return whether valid
*/
define boolean ValidateDomain (string key, map event) {
boolean dhn = has_dhcp && (boolean) UI::QueryWidget (`id ("DHCP_HOSTNAME"), `Value);
string value = (string) UI::QueryWidget (`id (key), `Value);
if (!dhn || value != "")
{
if (value=="local"){
if (!Popup::YesNo(_("It's not recomended to use .local as domainname due to Multicast DNS. Use it on your own risk?"))) return false;
}
return Hostname::CheckDomain (value);
}
return true;
}
/**
* Validator for the search list
* @param key the widget being validated
* @param event the event being handled
* @return whether valid
*/
define boolean ValidateSearchList (string key, map event) {
string value = (string) UI::QueryWidget (`id (key), `Value);
list<string> sl = NonEmpty (splitstring (value, " ,\n\t"));
string error = "";
if (size (sl) > 6)
{
/* Popup::Error text */
error = sformat (_("The search list can have at most %1 domains."), 6);
}
else if (size (mergestring (sl, " ")) > 256)
{
/* Popup::Error text */
error = sformat (_("The search list can have at most %1 characters."), 256);
}
string bad = find (string s, sl, {
if (! Hostname::CheckDomain (s)) {
/* Popup::Error text */
error = sformat (_("The search domain '%1' is invalid."), s) +
"\n" + Hostname::ValidDomain ();
return true;
}
return false;
});
if (error != "")
{
UI::SetFocus (`id (key));
Popup::Error (error);
return false;
}
return true;
}
void initPolicy(string key) {
//first initialize correctly
y2milestone("initPolicy: %1", UI::QueryWidget(`id("MODIFY_RESOLV"), `Value));
if(UI::QueryWidget(`id("MODIFY_RESOLV"), `Value) == `custom)
{
UI::ChangeWidget(`id("PLAIN_POLICY"), `Enabled, true);
if (UI::QueryWidget(`id("PLAIN_POLICY"), `Value) == "")
{
UI::ChangeWidget(`id("PLAIN_POLICY"), `Value, DNS::resolv_conf_policy);
}
}
else
{
UI::ChangeWidget(`id("PLAIN_POLICY"), `Value, "");
UI::ChangeWidget(`id("PLAIN_POLICY"), `Enabled, false);
}
//then disable if needed
disableItemsIfNM([ "PLAIN_POLICY" ], false);
}
symbol handlePolicy(string key, map event) {
y2milestone("handlePolicy");
if(UI::QueryWidget(`id("MODIFY_RESOLV"), `Value) == `custom)
{
DNS::resolv_conf_policy = (string)UI::QueryWidget(`id("PLAIN_POLICY"), `Value);
}
else if(UI::QueryWidget(`id("MODIFY_RESOLV"), `Value) == `auto)
{
DNS::resolv_conf_policy = "auto";
}
else
{
DNS::resolv_conf_policy = "";
}
}
void initModifyResolvPolicy (string key){
y2milestone("initModifyResolvPolicy");
//first initialize correctly
if(DNS::resolv_conf_policy == nil || DNS::resolv_conf_policy == "")
{
UI::ChangeWidget(`id("MODIFY_RESOLV"), `Value, `id(`nomodify) );
}
else if(DNS::resolv_conf_policy == "auto" || DNS::resolv_conf_policy == "STATIC *")
{
UI::ChangeWidget(`id("MODIFY_RESOLV"), `Value, `id(`auto) );
}
else
{
UI::ChangeWidget(`id("MODIFY_RESOLV"), `Value, `id(`custom) );
}
//then disable if needed
disableItemsIfNM(["MODIFY_RESOLV"], false);
}
symbol handleModifyResolvPolicy (string key, map event){
y2milestone("handleModifyResolvPolicy called: %1", UI::QueryWidget(`id("MODIFY_RESOLV"), `Value));
if (UI::QueryWidget(`id("MODIFY_RESOLV"), `Value) == `nomodify)
{
resolver_modifiable = false;
}
else
{
resolver_modifiable = true;
}
initPolicy(key);
y2milestone("Exit: resolver_modifiable = %1", resolver_modifiable);
return nil;
}
void initHostnameGlobal(string key){
// NetworkService::IsManaged () not: #169858, #156830
has_dhcp = Lan::AnyDHCPDevice ();
hn_settings = InitSettings ();
foreach(string key, (list<string>)Map::Keys(hn_settings),{
InitHnWidget(key);
});
//disable those if NM is in charge
disableItemsIfNM(
[ "NAMESERVER_1", "NAMESERVER_2", "NAMESERVER_3", "SEARCHLIST_S"],
false
);
}
void storeHostnameGlobal(string key, map event){
foreach(string key, (list<string>)Map::Keys(hn_settings),{
StoreHnWidget(key, event);
});
StoreSettings( hn_settings );
}
map<string, map<string,any> > widget_descr_dns = $[
"HOSTNAME": $[
"widget": `textentry,
/* textentry label */
"label": Label::HostName (),
"opt": [],
"help": help["hostname_global"]:"",
"valid_chars": Hostname::ValidChars,
"validate_type": `function_no_popup,
"validate_function": ValidateHostname,
// validation error popup
"validate_help": _("The hostname is invalid.") + "\n" + Hostname::ValidHost (),
],
"HOSTNAME_GLOBAL": $[
"widget": `empty,
// #91202
"init": initHostnameGlobal,
"store": storeHostnameGlobal
],
"DOMAIN": $[
"widget": `textentry,
/* textentry label */
"label": _("&Domain Name"),
"opt": [],
// Do nothing (the widget doesnt have notify anyway)
// In particular do not disable the host and domain name widgets,
// setting of FQDN should be possible even if DHCP overrides it.
// N#28427, N#63423.
// "handle": nil,
"valid_chars": Hostname::ValidCharsDomain,
"validate_type": `function_no_popup,
"validate_function": ValidateDomain,
// validation error popup
"validate_help": _("The domain name is invalid.") + "\n" + Hostname::ValidDomain (),
],
"DHCP_HOSTNAME": $[
"widget": `custom,
"custom_widget" : `HBox(
`CheckBox(`id("DHCP_HOSTNAME"), _("&Change Hostname via DHCP"), true),
`ReplacePoint( `id("dh_host_text"), `Empty() )
),
// help
"help": help["dhcp_hostname"]:"",
"init": InitDhcpHostname,
],
"WRITE_HOSTNAME": $[
"widget": `checkbox,
/* checkbox label */
"label": _("&Assign Hostname to Loopback IP"),
"opt": [],
// help
"help": help["write_hostname"]:"",
],
"MODIFY_RESOLV" : $[
"widget": `combobox,
"label": _("&Modify DNS configuration"),
"opt" : [`notify],
"items": [ [`nomodify, _("Only Manually")],
[`auto, _("Use Default Policy")],
[`custom, _("Use Custom Policy")] ],
"init" : initModifyResolvPolicy,
"handle": handleModifyResolvPolicy,
"help" : help["dns_config_policy"]:"",
],
"PLAIN_POLICY" : $[
"widget": `combobox,
"label": _("&Custom Policy Rule"),
"opt" : [`editable],
"items" : [ [`static, "STATIC"],
[`static_fallback, "STATIC_FALLBACK" ]
],
"init": initPolicy,
"handle": handlePolicy,
"help" : ""
],
"NAMESERVER_1": $[
"widget": `textentry,
/* textentry label */
"label": _("Name Server &1"),
"opt": [],
"help": "", // at "SEARCHLIST_S"
"handle": HandleResolverData,
"valid_chars": IP::ValidChars,
"validate_type": `function_no_popup,
"validate_function": ValidateIP,
// validation error popup
"validate_help": _("The IP address of the name server is invalid.")+ "\n" + IP::Valid4 (),
],
// NAMESERVER_2 and NAMESERVER_3 are cloned in the dialog function
"SEARCHLIST_S": $[
"widget": `multi_line_edit,
/* textentry label */
"label": _("Do&main Search"),
"opt": [],
"help": help["searchlist_s"]:"",
"handle": HandleResolverData,
// "valid_chars": Hostname::ValidCharsFQ, // TODO: whitespace. unused anyway?
"validate_type": `function,
"validate_function": ValidateSearchList,
],
];
widget_descr_dns["NAMESERVER_2"] = widget_descr_dns["NAMESERVER_1"]:$[];
widget_descr_dns["NAMESERVER_3"] = widget_descr_dns["NAMESERVER_1"]:$[];
// text entry label
widget_descr_dns["NAMESERVER_2", "label"] = _("Name Server &2");
// text entry label
widget_descr_dns["NAMESERVER_3", "label"] = _("Name Server &3");
term dns_contents =
`VBox(
`Frame( _("Hostname and Domain Name"),
`VBox(
`HBox(
"HOSTNAME",
"HOSTNAME_GLOBAL", // global help, init, store for all dialog
`HSpacing (1),
"DOMAIN"
),
/* CheckBox label */
`Left("DHCP_HOSTNAME"),
`Left("WRITE_HOSTNAME")
)),
`VSpacing(0.49),
`Left( `HBox(
"MODIFY_RESOLV",
`HSpacing (1),
"PLAIN_POLICY"
) ),
/* Frame label */
`Frame(_("Name Servers and Domain Search List"), `VBox(
`VSquash ( `HBox(
`HWeight (1, `VBox(
"NAMESERVER_1",
"NAMESERVER_2",
"NAMESERVER_3"
)),
`HSpacing (1),
`HWeight (1, "SEARCHLIST_S")
)),
`VSpacing(0.49)
)
),
`VStretch()
);
map dns_td = $[
"resolv" : $[
"header" : _("Hostname/DNS"),
"contents" : dns_contents,
"widget_names" : ["HOSTNAME", "HOSTNAME_GLOBAL", "DOMAIN", "DHCP_HOSTNAME", "WRITE_HOSTNAME", "MODIFY_RESOLV", "PLAIN_POLICY",
"NAMESERVER_1", "NAMESERVER_2", "NAMESERVER_3", "SEARCHLIST_S"]
]
];
define boolean ReallyAbortInst () {
return Popup::ConfirmAbort (`incomplete);
}
define symbol HostnameDialog () {
has_dhcp = true;
hn_settings = InitSettings ();
map functions = $[
"init" : InitHnWidget,
"store" : StoreHnWidget,
`abort : ReallyAbortInst,
];
term contents = `HSquash (
/* Frame label */
`Frame(_("Hostname and Domain Name"), `VBox(
`HBox(
"HOSTNAME",
`HSpacing (1),
"DOMAIN"
),
`Left ("DHCP_HOSTNAME"),
`Left ("WRITE_HOSTNAME")
))
);
symbol ret = CWM::ShowAndRun (
$[
"widget_descr": widget_descr_dns,
"contents": contents,
// dialog caption
"caption": _("Hostname and Domain Name"),
"back_button" : Label::BackButton (),
"next_button" : Label::NextButton (),
"fallback_functions" : functions,
"disable_buttons" : GetInstArgs::enable_back() ? [] : ["back_button"],
]);
if (ret == `next)
{
//Pre-populate resolv.conf search list with current domain name
//but only if none exists so far
string current_domain = hn_settings["DOMAIN"]:"";
//Need to modify hn_settings explicitly as SEARCHLIST_S widget
//does not exist in this dialog, thus StoreHnWidget won't do it
//#438167
if ( DNS::searchlist == [] && current_domain != "site")
hn_settings["SEARCHLIST_S"] = current_domain;
StoreSettings (hn_settings);
}
return ret;
}
/**
* Standalone dialog only - embedded one is handled separately
* via CWMTab
*/
define any DNSMainDialog(boolean standalone) {
string caption = _("Hostname and Name Server Configuration");
map functions = $[
"init" : InitHnWidget,
"store" : StoreHnWidget,
`abort : ReallyAbort,
];
Wizard::HideBackButton();
symbol ret = CWM::ShowAndRun (
$[
"widget_descr": widget_descr_dns,
"contents": dns_contents,
// dialog caption
"caption": caption,
"back_button" : Label::BackButton (),
"next_button" : Label::FinishButton (),
"fallback_functions" : functions,
]);
return ret;
}
/* EOF */
}
ACC SHELL 2018