/**
 * File:	include/network/services/dns.ycp
 * Package:	Network configuration
 * Summary:	Hostname and DNS setup dialog
 * Authors:	Michal Svec <msvec@suse.cz>
 *
 * $Id: dns.ycp 22129 2005-03-02 10:04:23Z locilka $
 */

{

textdomain "network";

import "Arch";
import "DNS";
import "Hostname";
import "IP";
import "Label";
import "Lan";
import "NetworkConfig";
import "Popup";
import "Wizard";

include "network/routines.ycp";

/**
 * If there's running a process modifying resolv.conf,
 * present a wanrning popup and return the result.
 * @return true if resolv.conf should be modified
 * (ie. no process running, or user decided to do so)
 */
define boolean ModifyResolvConfPopup() {

    string process = DNS::resolv_conf_process;
    if(process == nil || process == "") return true;

    /* Warning popup text 1/2 */
    string text = _("<p>The resolver configuration file (/etc/resolv.conf)
has been temporarily modified by %1. You have two options:</p>") +

    /* Warning popup text 2/2 */
    _("<ol>
<li>Modify the current (changed) version of the file.</li>
<li>Press 'Accept' now and continue editing other (nonresolver) data. You
could return to this dialog later when the above service has terminated.</li>
</ol>
");

    /* has been modified by "unknown process" */
    text = sformat(text, size(process) > 1 ? process : _("unknown process"));

    UI::OpenDialog(`opt(`decorated), `VBox(
	`HSpacing(60),
	`HBox(
	    `VSpacing(8),
	    `RichText(text)
	),
	`HBox(
	    /* PushButton label */
	    `PushButton(`id(`accept), `opt(`default), _("&Accept")),
	    `HSpacing(2),
	    /* PushButton label */
	    `PushButton(`id(`modify), _("&Modify"))
	)
    ));

    any ret = UI::UserInput();
    UI::CloseDialog();

    DNS::resolv_conf_force = (ret == `modify);
    y2milestone ("resolv.conf modified by: %1, force: %2",
		 process, DNS::resolv_conf_force);
    return DNS::resolv_conf_force;
}

/**
 * Dialog for querying DNS & hostname info
 * @param standalone true if not run from another ycp client
 * @return user input
 */
define any DNSMainDialog(boolean standalone) {

    ScreenName("dns");

    string hostname = DNS::hostname;
    string domain = DNS::domain;
    list<string> nameservers = DNS::nameservers;
    list<string> searchlist = DNS::searchlist;
    boolean dhcp_hostname = NetworkConfig::DHCP["DHCLIENT_SET_HOSTNAME"]:false;
    boolean dhcp_resolv = NetworkConfig::DHCP["DHCLIENT_MODIFY_RESOLV_CONF"]:false;

    boolean has_dhcp = (Lan::bootproto == "dhcp") || Lan::AnyDHCPDevice();
    if(Arch::s390 ()) has_dhcp = false;

    /* DNS dialog caption */
    string caption = _("Host Name and Name Server Configuration");

    /* DNS dialog help 1/5 */
    string help = _("<p>Insert the host name and domain name for your
computer. Name server list and domain search list are optional.</p>") +

    /* DNS dialog help 2/5 */
    _("<p>A name server is a computer that translates host names into
IP addresses. This value must be entered as an <b>IP address</b>
(e.g., 10.10.0.1), not as a host name.</p>") +

    /* DNS dialog help 3/5 */
    _("<p>Search domain is the domain name where host name searching starts.
The primary search domain is usually the same as the <b>domain name</b> of
your computer (e.g., suse.de). There may be additional search domains
(e.g., suse.com).</p>") +

    /* DNS dialog help 4/5 */
    _("<p>If you are using DHCP to get an IP address, check whether to get
a host name via DHCP or to set name servers and searched domains via DHCP.</p>") +

    /* DNS dialog help 5/5 */
    _("<p>If you plan to use a dial-up Internet connection and have set up your
connection to use dynamic DNS assignment, these values will be temporarily
disabled during the connection.</p>");

    /* domain search */
    string s1 = "";
    string s2 = "";
    string s3 = "";

    /* name servers */
    string ns1 = "";
    string ns2 = "";
    string ns3 = "";

    /**
     * Check if internal data differ from the dialog values
     * @return true if differ
     */
    define boolean DNSModified() {

	/* FIXME:
	 * - the result is ignored ATM (ReallAbort is always true)
	 * - n* and s* changes seem to be ignored
	 */
	string hostname = (string) UI::QueryWidget(`id(`host), `Value);
	string domain = (string) UI::QueryWidget(`id(`domain), `Value);

	list nameservers = filter(string n, [ ns1, ns2, ns3 ], ``(n != ""));
	list searchlist = filter(string s, [ s1, s2, s3 ], ``(s != ""));

	boolean dhcp_hostname = (boolean) UI::QueryWidget(`id(`dn), `Value);
	boolean dhcp_resolv = (boolean) UI::QueryWidget(`id(`dr), `Value);

	return hostname != DNS::hostname || domain != DNS::domain ||
	    nameservers != DNS::nameservers || searchlist != DNS::searchlist ||
	    dhcp_resolv != NetworkConfig::DHCP["DHCLIENT_MODIFY_RESOLV_CONF"]:false ||
	    dhcp_hostname != NetworkConfig::DHCP["DHCLIENT_SET_HOSTNAME"]:false;
    }

    ns1 = nameservers[0]:"";
    ns2 = nameservers[1]:"";
    ns3 = nameservers[2]:"";

    s1 = searchlist[0]:"";
    s2 = searchlist[1]:"";
    s3 = searchlist[2]:"";
    // #49094: populate the search list
    if (s1 == "" && s2 == "" && s3 == "" && !dhcp_resolv)
    {
	s1 = domain;
    }

    /* DNS dialog contents */
    term contents = `HSquash(`VBox(
	/* Frame label */
	`Frame(_("Host Name and Domain Name"), `VBox(
	    `HBox(
		`TextEntry(`id(`host), Label::HostName (), hostname),
		`HSpacing (1),
		/* TextEntry label */
		`TextEntry(`id(`domain), _("&Domain Name"), domain)
	    ),
	    /* CheckBox label */
	    `Left(`CheckBox(`id(`dn), _("&Change Host Name via DHCP")))
	)),
	`VSpacing(1),
	/* Frame label */
	`Frame(_("Name Servers and Domain Search List"), `VBox(
	`HBox(
	    `VBox(
		/* TextEntry label */
		`TextEntry(`id(`ns1), _("Name Server &1"), ns1),
		/* TextEntry label */
		`TextEntry(`id(`ns2), _("Name Server &2"), ns2),
		/* TextEntry label */
		`TextEntry(`id(`ns3), _("Name Server &3"), ns3)
	    ),
	    `HSpacing (1),
	    `VBox(
		/* TextEntry label */
		`TextEntry(`id(`s1), _("Doma&in Search 1"), s1),
		/* TextEntry label */
		`TextEntry(`id(`s2), _("Do&main Search 2"), s2),
		/* TextEntry label */
		`TextEntry(`id(`s3), _("Dom&ain Search 3"), s3)
	    )
	),
	/* CheckBox label */
	`Left(`CheckBox(`id(`dr), `opt(`notify), _("&Update Name Servers and Search List via DHCP")))
	))
    ));

    if(standalone == true)
	Wizard::SetContentsButtons(caption, contents, help,
		Label::BackButton(), Label::FinishButton());
    else
	Wizard::SetContentsButtons(caption, contents, help,
		Label::BackButton(), Label::OKButton());

    UI::ChangeWidget(`id(`dn), `Enabled, has_dhcp);
    UI::ChangeWidget(`id(`dr), `Enabled, has_dhcp);
    if(has_dhcp) UI::ChangeWidget(`id(`dn), `Value, dhcp_hostname);
    if(has_dhcp) UI::ChangeWidget(`id(`dr), `Value, dhcp_resolv);

    UI::ChangeWidget(`id(`host), `ValidChars, Hostname::ValidChars);
    UI::ChangeWidget(`id(`domain), `ValidChars, Hostname::ValidCharsDomain);
    UI::ChangeWidget(`id(`s1), `ValidChars, Hostname::ValidCharsFQ);
    UI::ChangeWidget(`id(`s2), `ValidChars, Hostname::ValidCharsFQ);
    UI::ChangeWidget(`id(`s3), `ValidChars, Hostname::ValidCharsFQ);
    UI::ChangeWidget(`id(`ns1), `ValidChars, IP::ValidChars);
    UI::ChangeWidget(`id(`ns2), `ValidChars, IP::ValidChars);
    UI::ChangeWidget(`id(`ns3), `ValidChars, IP::ValidChars);

    if(ModifyResolvConfPopup() != true) {
	UI::ChangeWidget(`id(`dr), `Enabled, false);
	UI::ChangeWidget(`id(`s1), `Enabled, false);
	UI::ChangeWidget(`id(`s2), `Enabled, false);
	UI::ChangeWidget(`id(`s3), `Enabled, false);
	UI::ChangeWidget(`id(`ns1), `Enabled, false);
	UI::ChangeWidget(`id(`ns2), `Enabled, false);
	UI::ChangeWidget(`id(`ns3), `Enabled, false);
    }

    UI::SetFocus (`id (`host));

    any ret = nil;
    while(true) {

	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(DNSModified()) {
		DNS::modified = true;
		if(ReallyAbort()) break;
		DNS::modified = false;
		continue;
	    }
	    if(ReallyAbort()) break;
	    else continue;
	}
	/* hostname via dhcp */
	else if(ret == `dn) {
	    dhcp_hostname = (boolean) UI::QueryWidget(`id(`dn), `Value);
	    UI::ChangeWidget(`id(`host), `Enabled, !dhcp_hostname);
	    UI::ChangeWidget(`id(`domain), `Enabled, !dhcp_hostname);
	    continue;
	}
	/* resolv.conf via dhcp */
	else if(ret == `dr) {
	    dhcp_resolv = (boolean) UI::QueryWidget(`id(`dr), `Value);
	    UI::ChangeWidget(`id(`ns1), `Enabled, !dhcp_resolv);
	    UI::ChangeWidget(`id(`ns2), `Enabled, !dhcp_resolv);
	    UI::ChangeWidget(`id(`ns3), `Enabled, !dhcp_resolv);
	    UI::ChangeWidget(`id(`s1), `Enabled, !dhcp_resolv);
	    UI::ChangeWidget(`id(`s2), `Enabled, !dhcp_resolv);
	    UI::ChangeWidget(`id(`s3), `Enabled, !dhcp_resolv);
	    continue;
	}
	else if(ret == `back) {
	    break;
	}
	else if(ret == `next) {

	    if(!has_dhcp || !dhcp_hostname) {
		/* check host name and domain */
		if(!Hostname::Check((string) UI::QueryWidget(`id(`host), `Value))) {
		    UI::SetFocus(`id(`host));
		    /* Popup::Error text */
		    Popup::Error (_("The host name is invalid.") +
			"\n" + Hostname::ValidHost ());
		    continue;
		}
		if(!Hostname::CheckDomain((string) UI::QueryWidget(`id(`domain), `Value))) {
		    UI::SetFocus(`id(`domain));
		    /* Popup::Error text */
		    Popup::Error (_("The domain name is invalid.") +
			"\n" + Hostname::ValidDomain ());
		    continue;
		}
	    }

	    /* check nameservers */
	    ns1 = tolower((string) UI::QueryWidget(`id(`ns1), `Value));
	    ns2 = tolower((string) UI::QueryWidget(`id(`ns2), `Value));
	    ns3 = tolower((string) UI::QueryWidget(`id(`ns3), `Value));

	    if(ns1 != "" && !IP::Check(ns1)) {
		UI::SetFocus(`id(`ns1));
		/* Popup::Error text */
		Popup::Error(_("The primary name server is invalid."));
		continue;
	    }
	    if(ns2 != "" && !IP::Check(ns2)) {
		UI::SetFocus(`id(`ns2));
		/* Popup::Error text */
		Popup::Error(_("The secondary name server is invalid."));
		continue;
	    }
	    if(ns3 != "" && !IP::Check(ns3)) {
		UI::SetFocus(`id(`ns3));
		/* Popup::Error text */
		Popup::Error(_("The tertiary name server is invalid."));
		continue;
	    }

	    /* check search domains */
	    s1 = tolower((string) UI::QueryWidget(`id(`s1), `Value));
	    s2 = tolower((string) UI::QueryWidget(`id(`s2), `Value));
	    s3 = tolower((string) UI::QueryWidget(`id(`s3), `Value));

	    if(s1 != "" && !Hostname::CheckDomain(s1)) {
		UI::SetFocus(`id(`s1));
		/* Popup::Error text */
		Popup::Error(_("The primary search domain is invalid.") +
			     "\n" + Hostname::ValidDomain ());
		continue;
	    }
	    if(s2 != "" && !Hostname::CheckDomain(s2)) {
		UI::SetFocus(`id(`s2));
		/* Popup::Error text */
		Popup::Error(_("The secondary search domain is invalid.") +
			     "\n" + Hostname::ValidDomain ());
		continue;
	    }
	    if(s3 != "" && !Hostname::CheckDomain(s3)) {
		UI::SetFocus(`id(`s3));
		/* Popup::Error text */
		Popup::Error(_("The tertiary search domain is invalid.") +
			     "\n" + Hostname::ValidDomain ());
		continue;
	    }

	    break;
	}
	else {
	    y2error("unexpected retcode: %1", ret);
	    continue;
	}

    }

    if(ret == `next) {

	if(DNSModified()) {

	    DNS::hostname = (string) UI::QueryWidget(`id(`host), `Value);
	    DNS::domain = (string) UI::QueryWidget(`id(`domain), `Value);

	    /* resolv.conf(5): 3 nameservers are the limit */
	    DNS::nameservers = filter(string n, [ ns1, ns2, ns3 ], ``(n != ""));

	    /* resolv.conf(5): 256 search characters at max */
	    /* FIXME: we have screen space for only 3 (#40012) */
	    DNS::searchlist[0] = s1;
	    DNS::searchlist[1] = s2;
	    DNS::searchlist[2] = s3;
	    DNS::searchlist = filter(string s, DNS::searchlist, ``(s != ""));

	    NetworkConfig::DHCP["DHCLIENT_SET_HOSTNAME"] = (boolean) UI::QueryWidget(`id(`dn), `Value);
	    NetworkConfig::DHCP["DHCLIENT_MODIFY_RESOLV_CONF"] = (boolean) UI::QueryWidget(`id(`dr), `Value);

	    /* update modified flag */
	    DNS::modified = true;
	}
	else
	    y2debug("not modified");
    }

    return ret;
}

/* EOF */
}
