ACC SHELL

Path : /usr/share/YaST2/include/nis/
File Upload :
Current File : //usr/share/YaST2/include/nis/ui.ycp

/**
 * File:
 *   include/nis/ui.ycp
 *
 * Package:
 *   Configuration of NIS
 *
 * Summary:
 *   User interface functions.
 *
 * Authors:
 *   Martin Vidner <mvidner@suse.cz>
 *
 * $Id: ui.ycp 54607 2009-01-14 10:59:22Z jsuchome $
 *
 * All user interface functions.
 *
 */

{
    textdomain "nis";

    import "Autologin";
    import "Confirm";
    import "CWMFirewallInterfaces";
    import "Label";
    import "Message";
    import "Mode";
    import "NetworkService";
    import "Nis";
    import "Package";
    import "Popup";
    import "Report";
    import "Sequencer";
    import "Stage";
    import "Wizard";

    /**
     * A Wizard Sequencer helper
     * @return	`next
     */
    define symbol JustNext () ``{
	return `next;
    }

    /*const*/ string broadcast_help =
	// Translators: network broadcast address
	_("<p>The <b>Broadcast</b> option enables searching
in the local network to find a server after the specified servers
fail to respond. It is a security risk.</p>
");

    /*const*/ string expert_help =
	// Translators: short for Expert settings
	_("<p><b>Expert</b> gives access to some
less frequently used settings.</p>
");

    /**
     * The dialog that appears when the [Abort] button is pressed.
     * @param touched data modified?
     * @return `abort if user really wants to abort, `back otherwise
     */
    define boolean ReallyAbort (boolean touched) ``{

	if (Stage::cont () && !contains (WFM::Args (), "from_users"))
	    return Popup::ConfirmAbort (`incomplete);
	return touched ? Popup::ReallyAbort (true) : true;
    }

    /**
     * Let the user choose some of a list of items
     * @param title	selectionbox title
     * @param items	a list of items
     * @return		items or nil on cancel
     */
    define list<string> ChooseItems (string title, list<string> items) ``{
	list<term> msb_items = maplist (string entry, items,
					 ``( `item (`id (entry), entry)));
	UI::OpenDialog (
	    `VBox (
		`HSpacing (40),
		`HBox (
		    `MultiSelectionBox (`id (`items), title, msb_items),
		    `VSpacing(10)
		    ),
		`HBox (
		    // pushbutton label
		    // Select all items (in this case NIS servers) of a list
		    `PushButton (`id (`all), _("Select &All")),
		    // pushbutton label
		    // Deselect all items (in this case NIS servers) of a list
		    `PushButton (`id (`none), _("Select &None"))
		    ),
		`HBox (
		    `PushButton (`id (`ok), `opt (`default, `key_F10),
				 Label::OKButton ()),
		    `PushButton (`id (`cancel), `opt (`key_F9),
				 Label::CancelButton())
		    )
		));
	UI::SetFocus (`id (`items));
	any ret = nil;
	do
	{
	    ret = UI::UserInput();
	    if (ret == `all)
	    {
		UI::ChangeWidget (`id (`items), `SelectedItems, items);
	    }
	    else if (ret == `none)
	    {
		UI::ChangeWidget (`id (`items), `SelectedItems, []);
	    }
	}
	while (ret != `cancel && ret != `ok);

	if (ret == `ok)
	{
	    items = (list<string>) UI::QueryWidget (`id (`items), `SelectedItems);
	}
	else
	{
	    items = nil;
	}
	UI::CloseDialog();

	return items;
    }

    /**
     * A cache of NIS servers found on the LAN for each domain.
     * @see SelectNisServers
     */
    map found_servers = $[]; // map <string, list <string> >

    /**
     * Scan the network for NIS servers and let the user select among them.
     * @param domain which domain
     * @return space separated list of servers or ""
     */
    define string SelectNisServers (string domain) ``{
	Wizard::SetScreenShotName ("nis-client-2a1-servers");
	if (Mode::screen_shot())
	{
	    found_servers[domain] = ["nis.example.com", "10.42.1.1", "10.42.1.2"];
	}

	if (!haskey (found_servers, domain))
	{
	    // popup window
	    // LAN: local area network
	    UI::OpenDialog (`Label (sformat (_("Scanning for NIS servers in domain %1 on this LAN..."), domain)));
	    found_servers[domain] = SCR::Read (add (.net.ypserv.find, domain));
	    UI::CloseDialog ();
	    if (found_servers[domain]:nil == nil)
	    {
		found_servers[domain] = ["internal-error"];
	    }
	}

	list <string> selected_servers =
	    // selection box label
	    ChooseItems (sformat (_("&NIS Servers in Domain %1"), domain),
			 found_servers[domain]:[]);
	y2milestone ("selected_servers: %1", selected_servers);
	if (selected_servers == nil)
	{
	    selected_servers = [];
	}
	Wizard::RestoreScreenShotName ();
	return mergestring (selected_servers, " ");
    }

    /**
     * The simple dialog
     * @return	`back, `abort, `next, `multiple or `expert
     */
    define symbol MainDialog () ``{

	Wizard::SetScreenShotName ("nis-client-2a-single");

	map<string,any> firewall_widget =
	    CWMFirewallInterfaces::CreateOpenFirewallWidget ($[
	    "services"	: [ "service:ypbind" ],
	    "display_details" : true,
	    // firewall openning help
	    "help" : _("<p><b>Firewall Settings</b><br>
To open the firewall to allow accessing the 'ypbind' service
from remote computers, set <b>Open Port in Firewall</b>.
To select interfaces on which to open the port, click <b>Firewall Details</b>.
This option is only available if the firewall is enabled.</p>
"),
	]);
	term firewall_layout = firewall_widget["custom_widget"]:`VBox ();

	// help text
	string help_text = _("<p>Enter your NIS domain, such as example.com,
 and the NIS server's address, such as nis.example.com or 10.20.1.1.</p>
") +

	// help text for netconfig part
	_("<p>Select the way how NIS configuration  will be modified. Normally, it is handled by netconfig script which merges the data statically defined here with those obtained dynamically (e.g. from DHCP client, NetworkManager etc.). This is the default, Default Policy option and it is sufficient for most of the configurations.
By choosing Only Manual Changes option, netconfig will no longer be allowed to modify configuration. You can however edit the file manually. By choosing Custom Policy option, you may specify a custom policy string, which consists of space-separated list of interface names, including wildcards, with STATIC/STATIC_FALLBACK as predefined special values. For more information, see netconfig manual page.</p>");

	// help text
	help_text = help_text + _("<p>Specify multiple servers
by separating their addresses with spaces.</p>
");

	help_text = help_text + broadcast_help;

	// help text
	help_text = help_text + _("<p>Automounter is a daemon that mounts directories automatically,
such as users' home directories.
It is assumed that its configuration files (auto.*) already exist,
either locally or over NIS.</p>");


	help_text = help_text + firewall_widget["help"]:"";


	string domain  = Nis::GetDomain ();
	string servers = Nis::GetServers ();

	// In this simple case, let's discard the distinction.
	boolean default_broadcast =
	    Nis::default_broadcast || Nis::global_broadcast;

	// the default is the current status
	// or true in case we were called during the installation
	boolean yp_client = Nis::start;
	if (Stage::cont () && !contains (WFM::Args (), "from_users"))
	    yp_client	= true;
	boolean autofs = Nis::_start_autofs;
	map<string,list> all_servers =
	    mapmap (string d, list s, Nis::multidomain_servers, ``(
		$[
		    d: [
			s,
			Nis::multidomain_broadcast[d]:false,
			Nis::slp_domain[d]:false
		    ]
		]
	));

	all_servers = add (all_servers, "",
	    [Nis::servers, Nis::default_broadcast]);

	list<string> additional_domains = [];

	foreach (string d, list s, all_servers, {
	    if (d != nil && d != "")
		additional_domains = add (additional_domains, d);
	});

	y2debug("all_servers: %1", all_servers);
	y2debug("additional_domains: %1", additional_domains);

	string automatic_label	= NetworkService::IsManaged () ?
	    // radio button label
	    _("Au&tomatic Setup (Via NetworkManager and DHCP)") :
	    // radio button label
	    _("Au&tomatic Setup (via DHCP)");

	boolean text_mode	= UI::GetDisplayInfo ()["TextMode"]:false;

	term con = nil;
	// frame label
	term nis_frame = `Frame (_("NIS client"), `HBox (`HSpacing (0.4),
	    `VBox (
		`VSpacing (0.2),
		`HBox (
		    `ComboBox(`id(`policy), `opt (`notify),
			// combo box label
			_("Netconfig NIS &Policy"), [
			// combo box item
			`item (`id (`nomodify), _("Only Manual Changes")),
			// combo box item
			`item (`id (`auto), _("Default Policy")),
			// combo box item
			`item (`id (`custom), _("Custom Policy"))
		    ]),
		    `HSpacing (),
		    `InputField (`id(`custompolicy), `opt (`hstretch),
			// text entry label
			_("C&ustom Policy"), "")
		),
		`VSpacing (0.2),
		text_mode ? `HBox (
		    `InputField (`id (`domain), `opt (`hstretch), _("N&IS Domain"), domain),
		    `HSpacing (),
		    `InputField (`id (`servers), `opt (`hstretch),
			_("&Addresses of NIS servers"), servers)
		) :
		`VBox (
		    // text entry label
		    `InputField (`id (`domain), `opt (`hstretch), _("N&IS Domain"), domain),
		    `VSpacing (0.2),
		    `InputField (`id (`servers), `opt (`hstretch),
			// text entry label
			_("&Addresses of NIS servers"), servers)
		),
		`HBox (
		    // check box label
		    `Left (`CheckBox (`id (`broadcast), `opt (`notify), _("Br&oadcast"), default_broadcast)),
		    // pushbutton label, find nis servers
		    // Shortcut must not conflict with Finish and Next (#29960)
		    `Right (`PushButton (`id (`find), _("Fin&d")))
		),
		`HBox(
		    `VBox(
			`Left(`Label(_("Additional NIS Domains"))),
			`HBox(
			    `HSpacing(1),
			    `Label(`id (`adddomains), `opt(`outputField, `hstretch), mergestring(additional_domains, ", "))
			)
		    ),
		    `HSpacing(1.2),
		    `VBox(
			`Label(""),
			// button label
			`PushButton (`id (`edit), _("&Edit"))
		    )
		),
		`VSpacing (0.3)
	    ), `HSpacing (0.4))
	);

	con = `HBox (`HSpacing (0.5), `VCenter (
	    `VBox (
		`VSpacing (0.4),
		`RadioButtonGroup (`id (`rd), `Left ( `HVSquash (`VBox (
		    `Left (`RadioButton (`id (`nisno), `opt (`notify),
			// radio button label
			_("Do &not use NIS"), !yp_client)
		    ),
		    `Left (`RadioButton (`id (`nisyes), `opt (`notify),
			// radio button label
			_("&Use NIS"), yp_client)
		    )
		)))),
		`VSpacing (0.4),
		nis_frame,
		`VSpacing (0.4),
		`Frame ("", `HBox (`HSpacing (0.4), firewall_layout)),
		`VSpacing (0.4),
		// checkbox label
		`CheckBox (`id(`autofs), _("Start Auto&mounter"), autofs),
		`VSpacing (0.4),
		`PushButton (`id (`expert), `opt (`key_F7),
		    // button label
		    // (short for Expert settings)
		    _("E&xpert...")
		),
		`VSpacing (0.4)
	)), `HSpacing (0.5));

	Wizard::SetContentsButtons (
	    // dialog title
	    _("Configuration of NIS client"), con, help_text,
	    Label::BackButton (), Stage::cont ()? Label::NextButton():Label::FinishButton ());
	Wizard::RestoreAbortButton ();

	CWMFirewallInterfaces::OpenFirewallInit (firewall_widget, "");

	UI::ChangeWidget (`id (`autofs), `Enabled, Nis::_autofs_allowed);

	if (Nis::policy == "")
	{
	    UI::ChangeWidget (`id (`policy), `Value, `id(`nomodify));
	    UI::ChangeWidget (`id (`custompolicy), `Enabled, false);
	}
	else if(Nis::policy == "auto" || Nis::policy == "STATIC *")
	{
	    UI::ChangeWidget (`id (`policy), `Value, `id(`auto));
	    UI::ChangeWidget (`id (`custompolicy), `Enabled, false);
	}
	else
	{
	    UI::ChangeWidget (`id (`policy), `Value, `id(`custom));
	    UI::ChangeWidget (`id (`custompolicy), `Enabled, true);
	    UI::ChangeWidget (`id (`custompolicy), `Value, Nis::policy);
	}
	map event	= $[];
	symbol result = nil;
	repeat
	{
	    y2milestone("LOOP: %1", result);
	    yp_client = (UI::QueryWidget (`id (`rd), `CurrentButton) != `nisno);
	    UI::ChangeWidget (`id (`expert), `Enabled, yp_client);
	    UI::ChangeWidget (`id (`policy), `Enabled, yp_client);
	    //UI::ChangeWidget (`id (`custompolicy), `Enabled, yp_client);
	    UI::ChangeWidget (`id (`autofs), `Enabled, yp_client);

	    boolean manual = (UI::QueryWidget(`id(`policy),`Value)== `nomodify);
	    UI::ChangeWidget (`id (`domain), `Enabled, !manual && yp_client);
	    UI::ChangeWidget (`id (`servers), `Enabled, !manual && yp_client);
	    UI::ChangeWidget (`id (`broadcast), `Enabled, !manual && yp_client);
	    UI::ChangeWidget (`id (`find), `Enabled, !manual && yp_client);
	    UI::ChangeWidget (`id (`edit), `Enabled, !manual && yp_client);
	    UI::ChangeWidget (`id (`adddomains), `Enabled,!manual && yp_client);

	    if (result == `policy)
	    {
		symbol mode = (symbol)UI::QueryWidget(`id(`policy), `Value);
		y2milestone("mode: %1", mode);
		if(mode == `nomodify || mode == `auto)
		{
		    y2milestone("Disable custompolicy");
		    UI::ChangeWidget (`id (`custompolicy), `Value, "");
		    UI::ChangeWidget (`id (`custompolicy), `Enabled, false);
		}
		else
		{
		    y2milestone("Enable custompolicy");
		    UI::ChangeWidget (`id (`custompolicy), `Value, Nis::policy);
		    UI::ChangeWidget (`id (`custompolicy), `Enabled, (true && yp_client));
		}
	    }
	    event	= UI::WaitForEvent ();
	    result	= (symbol) event["ID"]:nil;
	    CWMFirewallInterfaces::OpenFirewallHandle(firewall_widget,"",event);

	    if (result == `cancel)
	    {
		result = `abort;
	    }

	    if (result == `find)
	    {
		domain =  (string) UI::QueryWidget (`id (`domain), `Value);
		if (domain == "")
		{
		    // Message popup. The user wants to Find servers
		    // but the domain is unknown.
		    Popup::Message (_("Finding servers works only when the domain is known."));
		    UI::SetFocus (`id (`domain));
		}
		else
		{
		    string servers = SelectNisServers (domain);
		    if (servers != "")
		    {
			UI::ChangeWidget (`id (`servers), `Value, servers);
		    }
		}
	    }
	    else if (contains ([`next, `edit, `expert], result))
	    {
		yp_client = ((symbol) UI::QueryWidget (`id (`rd), `CurrentButton) != `nisno);

		// Using NIS and LDAP simultaneously is not supported (#36981).
		if (result == `next &&
		    yp_client && !Nis::start && Nis::UsersByLdap ())
		{
		    // yes-no popup
		    if (!Popup::YesNo (_("When you configure your machine as a NIS client,
you cannot retrieve the user data from LDAP.
Are you sure?")))
		    {
			result = nil;
			continue;
		    }
		}

		if (UI::QueryWidget (`id (`policy), `Value) == `custom)
		{
		    Nis::policy = (string)
			UI::QueryWidget (`id (`custompolicy), `Value);
		}
		else if (UI::QueryWidget (`id (`policy), `Value) == `auto)
		{
		    Nis::policy = "auto";
		}
		else
		{
		    Nis::policy = "";
		}
		domain = (string) UI::QueryWidget (`id (`domain), `Value);
		servers = (string) UI::QueryWidget (`id (`servers), `Value);
		default_broadcast = (boolean) UI::QueryWidget (`id (`broadcast), `Value);

		if (yp_client && !manual &&
		    domain != "" &&
		    !Nis::check_nisdomainname (domain))
		{
		    UI::SetFocus (`id (`domain));
		    Popup::Error (Nis::valid_nisdomainname ());
		    result = nil;
		    continue;
		}

		list<string> temp_ad = filter (
		    string a, splitstring (servers, " "), ``(a != ""));

		if (yp_client && !manual && !default_broadcast &&
		    servers != "" &&
		    (size (temp_ad) == 0 || find (string a, temp_ad,
		     ``(!Nis::check_address_nis (a))) != nil
		    )
		)
		{
		    UI::SetFocus (`id (`servers));
		    Popup::Message (Nis::valid_address_nis ());
		    result = nil;
		    continue;
		}
		if (result == `next)
		    CWMFirewallInterfaces::OpenFirewallStore (
			firewall_widget,"",event);
	    }
	}
	until (result == `edit || result == `next || result == `expert ||
	       (result == `abort && ReallyAbort (Nis::touched)) ||
	       (result == `back && (Stage::cont () || ReallyAbort (Nis::touched))));

	if (contains ([`next, `expert, `edit], result))
	{
	    Nis::Touch (Nis::start != yp_client);
	    Nis::start = yp_client;
	    Nis::dhcp_restart = false;
	    Nis::SetDomain (domain);
	    Nis::SetServers (servers);
	    Nis::Touch (Nis::default_broadcast != default_broadcast);
	    Nis::default_broadcast = default_broadcast;
	    Nis::Touch (Nis::global_broadcast != false);
	    Nis::global_broadcast = false;

	    boolean newautofs = Nis::_autofs_allowed && (boolean) UI::QueryWidget (`id (`autofs), `Value);
	    Nis::Touch (Nis::_start_autofs != newautofs);
	    Nis::_start_autofs = newautofs;
	}

	Wizard::RestoreScreenShotName ();
	return (symbol) result;
    }


    /**
     * The expert dialog
     * @return	`back, `abort or `next
     */
    define symbol ExpertDialog () {
	Wizard::SetScreenShotName ("nis-client-2c-expert");

	// help text 1/4
	string help_text = _("<p>Normally, it is possible for any host to query which server a client is using. Disabling <b>Answer Remote Hosts</b> restricts this only to the local host.</p>");

	// help text 2/4
	// Check, ie. turn on a check box
	help_text = help_text + _("<p>Check <b>Broken server</b> if answers from servers running on an unprivileged port should be accepted. It is a security risk and it is better to replace such a server.</p>");

	// help text 3/4
	help_text = help_text + _("<p>See <b>man ypbind</b> for details on other options.</p>");

	boolean local_only = Nis::local_only;
	boolean broken_server = Nis::broken_server;
	string options = Nis::options;

	term contents =
	    `HSquash (`VBox (
		`Frame (
		    // frame label
		    _("Expert settings"),
		    `VBox (
			`VSpacing (0.2),
			// check box label
			`Left (`CheckBox (`id (`remote), _("Ans&wer Remote Hosts"), !local_only)),
			// check box label
			`Left (`CheckBox (`id (`broken_server), _("Br&oken server"), broken_server)),
			`VSpacing (0.2),
			`InputField (`id (`options), `opt (`hstretch),
			    // text entry label (do not translate 'ypbind')
			    _("Other &ypbind options"), options),
			`VSpacing (0.2)
			)
		    ),
		`VSpacing ()
		));

	Wizard::SetContentsButtons (
	    // dialog title
	    _("Expert settings"), contents, help_text,
	    Label::CancelButton (), Label::OKButton ());
	Wizard::HideAbortButton ();

	map event	= $[];
	any result = nil;
	repeat
	{
	    event	= UI::WaitForEvent ();
	    result	= event["ID"]:nil;

	    if (result == `cancel)
	    {
		result = `abort;
	    }

	    if (result == `next)
	    {
		local_only = !(boolean) UI::QueryWidget (`id (`remote), `Value);
		broken_server = (boolean) UI::QueryWidget (`id (`broken_server), `Value);
		// TODO: disallow " in options
		options = (string) UI::QueryWidget (`id (`options), `Value);
	    }
	}
	until (result == `back || result == `next ||
	       (result == `abort && ReallyAbort (Nis::touched)));

	if (result == `next)
	{
	    Nis::Touch (Nis::local_only != local_only);
	    Nis::local_only = local_only;
	    Nis::Touch (Nis::broken_server != broken_server);
	    Nis::broken_server = broken_server;
	    Nis::Touch (Nis::options != options);
	    Nis::options = options;
	}

	Wizard::RestoreScreenShotName ();
	return (symbol) result;
    }

    string check_g = nil;
    /**
     * Constructs items for the domain table
     * @param	default_d	the default domain
     * @param	all_servers	map of @ref server_sp
     * @return a list of items
     * @see Nis#multidomain_servers TODO
     */
    define list DomainTableItems (string default_d, map<string,list> all_servers) ``{
	if (check_g == nil)
	{
	    check_g = UI::Glyph (`CheckMark);
	}

	y2debug("all_servers: %1", all_servers);
	// maps are sorted, so the default domain, "", comes first
	return maplist (string d, list server_sp, all_servers, ``(
			    `item (
				`id (d),
				d,
				// this would be a priority example x ]:
				(server_sp[1]:false)? check_g: "",
				(server_sp[2]:false)? check_g: "",
				mergestring (server_sp[0]:[], ", ")
				)
			    ));
    }

    /**
     * @param	default_d	the default domain
     * @param	all_servers show these items
     * @param	d	the selected item
     */
    define void UpdateDomainTable (string default_d, map<string,list> all_servers,
					  string d) ``{
	UI::ChangeWidget (`id (`domains), `Items,
			  DomainTableItems (default_d, all_servers));
	UI::ChangeWidget (`id (`domains), `CurrentItem, d);
    }

    /**
     * @param	m	a map
     * @return		keys of the map
     */
    define list mapkeys (map m) ``{
	return maplist (any k, any v, m, ``( k ));
    }

    /**
     * @tuple server_sp
     * 0 list(string)	server list
     * 1 boolean	broadcast
     */

    /**
     * Add/Edit a domain, including its name and servers
     * @param	init		currently selected domain: nil=add, ""=default
     * @param	default_d	the default domain
     * @param	server_sp	@ref server_sp
     * @param	existing	existing domains
     * @return [name, [ [server1, server2], broadcast? ]]
     */
    define list DomainPopup (string init, string default_d,
				    list server_sp, list<string> existing) ``{
	Wizard::SetScreenShotName ("nis-client-2b1-domain");

	string domain = (init == nil)? "": ((init == "") ? default_d: init);
	list<string> servers = server_sp[0]:[];
	string servers_s = mergestring (servers, "\n");
	boolean broadcast = server_sp[1]:false;
	boolean slp = server_sp[2]:false;

	term t_servers =
	    `VBox (
		`MultiLineEdit(`id (`servers),
			       // Translators: multilineedit label
			       // comma: ","
			       _("&Servers (separated by spaces or commas)"),
			       servers_s),
		`HBox (
		    `CheckBox (`id (`local_broadcast),
			       // checkbox label
			       _("&Broadcast"), broadcast),
		    `CheckBox (`id (`slp),
			       // checkbox label
			       _("&SLP"), slp),
		    // pushbutton label, find nis servers
		    // Shortcut must not conflict with Finish and Next (#29960)
		    `PushButton (`id (`find), _("Fin&d"))
		    ),
		`Empty ()
		);

	term contents =
	    `HBox(
		`HSpacing(1),
		`VBox(
		    `VSpacing(0.2),
		    // Translators: popup dialog heading
		    `Heading (_("Domain Settings")),
		    // Add a domain, Adding a domain? Edit...
		    // Translators: text entry label
		    `Left (`InputField (`id (`domain), _("&Domain name"), domain)),
		    `VSpacing(0.5),
		    t_servers,
		    `VSpacing(0.2), `ButtonBox (
			`PushButton (`id (`ok), `opt (`default, `key_F10),
			    Label::OKButton ()),
			`PushButton (`id (`cancel), `opt (`key_F9),
			    Label::CancelButton ())
		    ),
		    `VSpacing(0.2)
		    ),
		`HSpacing(1)
		);

	UI::OpenDialog (`opt(`decorated), contents);
	UI::SetFocus (`id (`domain));

	any ui = nil;
	while (true)
	{
	    ui = UI::UserInput ();
	    if (ui == `cancel)
	    {
		break;
	    }
	    else if (ui == `find)
	    {
		domain = (string) UI::QueryWidget (`id (`domain), `Value);
		if (domain == "")
		{
		    // Message popup. The user wants to Find servers
		    // but the domain is unknown.
		    Popup::Message (_("Finding servers works only when the domain is known."));
		    UI::SetFocus (`id (`domain));
		}
		else
		{
		    string servers = SelectNisServers (domain);
		    if (servers != "")
		    {
			UI::ChangeWidget (`id (`servers), `Value, servers);
		    }
		}
	    }
	    else if (ui == `ok)
	    {
		// Input validation
		// all querywidgets done now for consistency
		domain = (string) UI::QueryWidget (`id (`domain), `Value);
		servers_s = (string) UI::QueryWidget (`id (`servers), `Value);
		broadcast = (boolean) UI::QueryWidget (`id (`local_broadcast), `Value);
		slp = (boolean) UI::QueryWidget (`id (`slp), `Value);

		servers = splitstring (servers_s, ", \n");
		servers = filter (string s, servers, ``( s != "" ));
		string bad_server = (string) find (string s, servers, ``(
					      !Nis::check_address_nis (s)
					      ));

		if (!Nis::check_nisdomainname (domain)) //also disallows ""
		{
		    UI::SetFocus (`id (`domain));
		    Popup::Error (Nis::valid_nisdomainname ());
		}
		else if (init != "" && domain != init &&
			 contains (existing, domain))
		{
		    UI::SetFocus (`id (`domain));
		    // Translators: error message
		    Popup::Error (_("This domain is already defined."));
		}
		else if (bad_server != nil)
		{
		    UI::SetFocus (`id (`servers));
		    string msg = sformat (
			// Translators: error message
			_("The format of server address '%1' is not correct."), bad_server);
		    Popup::Error (msg + "\n\n" + Nis::valid_address_nis ());
		}
		// check options (local broadcast and slp)
		else if (broadcast && slp)
		{
		    UI::SetFocus (`id (`local_broadcast));
		    // error message, 'Broadcast' and 'SLP' are checkboxes
		    Popup::Error(_("Enabling both Broadcast and SLP options\ndoes not make any sense. Select just one option."));
		}
		else
		{
		    // all checks OK, break the input loop
		    break;
		}
	    }
	}

	UI::CloseDialog ();
	Wizard::RestoreScreenShotName ();
	return (ui == `ok)? [domain, [servers, broadcast, slp]] : nil;
    }

    /**
     * The servers dialog
     * @return	`back, `abort or `next
     */
    define symbol AdditionalDialog () {
	Wizard::SetScreenShotName ("nis-client-2b-multiple");

	// variable naming: _d means _domain, _s means _server
	map<string,list> all_servers = mapmap (string d, list s, Nis::multidomain_servers,
				  ``( $[d: [s, Nis::multidomain_broadcast[d]:false, Nis::slp_domain[d]:false]] ));

	// help text
	string help_text = _("<p>Specify the servers for additional domains.</p>");

	// help text
	help_text = help_text + broadcast_help;

	// help text
	help_text = help_text + _("<p>The Service Location Protocol (<b>SLP</b>) can be used to find NIS server.</p>");

	// "" means the default domain
	string current_d = "";

	// build the dialog contents
	term multiple = `VBox (
	    `VSpacing (0.8),
	    // dialog label
	    `Left (`Label(_("Additional Domains"))),
	    `Table (
		`id (`domains),
		`opt (`notify, `immediate),
		`header (
		    // table header
		    _("Domain"),
		    // table header
		    `Center (_("Broadcast")),
		    // table header - Service Location Protocol
		    `Center (_("SLP")),
		    // table header
		    _("Servers")),
		    DomainTableItems (nil, all_servers)
	    ),
	    `HBox (
		// button label
		`PushButton (`id (`add_d), `opt (`key_F3), _("A&dd")),
		`PushButton (`id (`edit_d),`opt(`key_F4), Label::EditButton ()),
		`PushButton (`id (`del_d), `opt(`key_F5), Label::DeleteButton())
	    ),
	    `VSpacing (1)
	);

	term nis_vbox =
	    `VBox (`VSpacing (0.2),
		   multiple,
		   `VSpacing (0.2)
		);

	term nis_frame =
	    // frame label
	    `Frame (_("NIS client"), nis_vbox);

	term contents = nis_vbox;

	Wizard::SetContentsButtons (
	    sformat ("%1 - %2",
		     // dialog title
		     _("Configuration of NIS client"),
		     // dialog subtitle
		     _("Additional Domains")), contents, help_text,
	    Label::CancelButton (), Label::OKButton ());
	Wizard::HideAbortButton ();

	any result = nil;

	while (true)
	{
	    current_d = (string) UI::QueryWidget (`id (`domains), `CurrentItem);
	    boolean any_d = current_d != nil;

	    UI::ChangeWidget (`id (`edit_d), `Enabled, any_d);
	    // deleting the defalut domain
	    // actually deletes only the server list
	    UI::ChangeWidget (`id (`del_d), `Enabled, any_d
			      /*&& current_d !=""*/);

	    // Kludge, because a `Table still does not have a shortcut.
	    // exclude textentry-notify
	    if (result != `domain)
	    {
		UI::SetFocus (`id (`domains));
	    }

	    result = UI::UserInput ();
	    if (result == `cancel)
	    {
		result = `abort;
	    }

	    // switch
	    if (result == `add_d)
	    {
		list name_servers = DomainPopup (nil, nil, [[], false], (list<string>)mapkeys (all_servers));
		if (name_servers != nil)
		{
		    string d = (string) name_servers[0]:nil;
		    list s_sp = name_servers[1]:[];
		    all_servers = add (all_servers, d, s_sp);
		    // show these items, d selected
		    UpdateDomainTable (nil, all_servers, d);
		}
	    }
	    else if (result == `edit_d)
	    {
		string d0 = (string) UI::QueryWidget (`id (`domains), `CurrentItem);

		if (d0 != nil)
		{
		    // editing the default domain is a special case
		    list name_servers = DomainPopup (d0, nil,
						     all_servers[d0]:[],
						     (list<string>) mapkeys (all_servers));
		    if (name_servers != nil)
		    {
			string d = (string) name_servers[0]:nil;
			list s_sp = name_servers[1]:[];
			string newkey = (d0=="")? "": d;
			all_servers = mapmap (string k, list v, all_servers,``(
						  (k == d0) ?
						  $[ newkey: s_sp ] :
						  $[ k: v]
						  ));
			// show these items, d selected
			// TODO: if it flickers,
			//  only replace the old line by a new one
			UpdateDomainTable (nil, all_servers, newkey);
		    }
		}
	    }
	    else if (result == `del_d)
	    {
		string d0 = (string) UI::QueryWidget (`id (`domains), `CurrentItem);
		if (d0 != nil)
		{
		    Wizard::SetScreenShotName ("nis-client-2b-del-dom");
		    // Translators: a yes-no popup
		    if (Popup::YesNo (_("Really delete this domain?")))
		    {
			all_servers = filter (string k, list v,
					      all_servers, ``(k != d0));
		    }
		    Wizard::RestoreScreenShotName ();
		    // show these items, the default domain selected
		    UpdateDomainTable (nil, all_servers, "");
		}
	    }
	    else if (result == `back || result == `next || (result == `abort &&
					 ReallyAbort (Nis::touched)))
	    {
		break;
	    }
	}

	if (result == `next)
	{
	    // add default server - it isn't displayed in the table
	    all_servers = add (all_servers, "",
			   [Nis::servers, Nis::default_broadcast]);

	    map<string,list<string> > only_servers = mapmap (string d, list v, all_servers, ``(
					   $[d: v[0]:[]]
					   ));
	    list<string> servers = only_servers[""]:[];
	    boolean default_broadcast = nil;
	    map<string,list<string> > multidomain_servers = nil;
	    map<string,boolean> multidomain_broadcast = nil;

	    map<string,boolean> only_broadcast = mapmap (string d, list v, all_servers, ``(
					     $[d: v[1]:false]
					     ));
	    default_broadcast = only_broadcast[""]:false;
	    multidomain_servers = filter (string d, list<string> v,
					  only_servers, ``( d != "") );
	    multidomain_broadcast = filter (string d, boolean v,
					    only_broadcast, ``( d != "") );

	    map slpdomain = mapmap (string d, list v, all_servers, ``(
					     $[d: v[2]:false]
					     ));

	    Nis::Touch (Nis::servers != servers);
	    Nis::servers = servers;
	    Nis::Touch (Nis::default_broadcast != default_broadcast);
	    Nis::default_broadcast = default_broadcast;
	    Nis::Touch (Nis::slp_domain != slpdomain);
	    Nis::slp_domain = slpdomain;
	    Nis::Touch (false); //TODO need to know earlier for abort?
	    Nis::multidomain_servers = multidomain_servers;
	    Nis::Touch (false); //TODO need to know earlier for abort?
	    Nis::multidomain_broadcast = multidomain_broadcast;
	}

	Wizard::RestoreScreenShotName ();
	return (symbol) result;
    }

    /**
     * Confirmation dialog
     * Also probes for packages that need to be installed (autofs)
     * #23050 don't display the dialog
     * @return `back or `next
     */
    define symbol SaveDialog () ``{
	Wizard::SetScreenShotName ("nis-client-3-save");

	string message = Nis::ProbePackages ();

	if (message != "")
	{
	    Popup::Message (message);
	}

	Wizard::RestoreScreenShotName ();
	return `next;
    }

    map Dialogs = $[
	"main"		: ``(MainDialog ()),
	"additional"	: ``(AdditionalDialog ()),
	"expert"	: ``(ExpertDialog ()),
	"common-next"	: [ ``( JustNext () ), true ],
	"end"		: ``(SaveDialog ()),
	];

    map Sequence = $[
	"ws_start"  : "main",
	"main"	       : $[
	    `next   : "common-next",
	    `expert : "expert",
	    `edit   : "additional",
	    `abort  : `abort
	    ],
	"additional"   : $[
	    `next   : "main",
	    `abort  : `abort
	    ],
	"expert"       : $[
	    `next   : "main",
	    `abort  : `abort
	    ],
	// This is will make AutoSequence finish without
	// confirmation. NormalSequence overrides it.
	"common-next"  : $[
	    `next   : `next,
	    ],
	"end"          : $[
	    `next   : `next
	    ]
	];

    /**
     * Dhcpcd writes yp.conf in the multidomain form.
     * Let's try rewriting it so that it fits into the simple dialog.
     * It is done only after read.
     */
    define void FitIntoSingle () ``{
	if (Nis::policy != "" && Nis::dhcpcd_running)
	{
	    string d = Nis::GetDomain ();
	    if (size (Nis::multidomain_servers) == 1)
	    {
		list<string> s = (list<string>) Nis::multidomain_servers[d]:[];
		// if there's only one entry, for the correct domain
		if (size (s) > 0)
		{
		    y2milestone ("Fitting into the simple dialog");
		    Nis::servers = s;
		    Nis::multidomain_servers = $[];
		    Nis::default_broadcast = Nis::multidomain_broadcast[d]:false;
		    Nis::multidomain_broadcast = $[];
		}
	    }
	}
    }

    /**
     * The normal workflow
     * @return `back, `abort or `next
     */
    define symbol NormalSequence() ``{
	map normal_override = $[
	    "common-next": $[
		`next: "end",
		],
	    ];

	Wizard::CreateDialog ();
	Wizard::SetDesktopIcon("nis");

	// checking for root permissions (#158483)
	if (!Confirm::MustBeRoot())
	{
	    UI::CloseDialog();
	    return `abort;
	}

	if (Mode::screen_shot())
	{
	    Nis::Fake ();
	}
	else
	{
	    Nis::Read ();
	}

	FitIntoSingle ();

	// the second map must override the first!
	symbol result = Sequencer::Run(Dialogs,
					 union (Sequence, normal_override));

	if (result == `next)
	{
	    if (Nis::start)
		// popup text FIXME better...
		Autologin::AskForDisabling(_("NIS is now enabled."));

	    // Install packages if needed.
	    // Cannot do it in Write, autoinstall does it differently.
	    if (size (Nis::install_packages) > 0)
	    {
		if (!Package::DoInstallAndRemove (Nis::install_packages, []))
		{
		    Popup::Error (Message::FailedToInstallPackages ());
		}
	    }

	    if (Nis::Write ())
	    {
		if (Nis::start && Nis::DomainChanged ())
		{
		    Popup::Warning (Message::DomainHasChangedMustReboot());
		}
	    }
	}
	UI::CloseDialog();
	return result;
    }

    /**
     * The autoinstallation workflow
     * @return `back, `abort or `next
     */
    define symbol AutoSequence() ``{
	Wizard::CreateDialog ();
	Wizard::SetDesktopIcon("nis");
	symbol ret = Sequencer::Run(Dialogs, Sequence);
	UI::CloseDialog ();
	return ret;
    }

}

ACC SHELL 2018