ACC SHELL

Path : /usr/share/YaST2/include/network/services/
File Upload :
Current File : //usr/share/YaST2/include/network/services/dns.ycp

/**
 * 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