/**
 * File:	include/ntp-client/misc.ycp
 * Package:	Configuration of ntp-client
 * Summary:	Miscelanous functions for configuration of ntp-client.
 * Authors:	Jiri Srain <jsrain@suse.cz>
 *
 * $Id: misc.ycp 21565 2005-02-14 11:29:56Z jsrain $
 */

{

textdomain "ntp-client";

import "CWMFirewallInterfaces";
import "IP";
import "Popup";
import "Progress";
import "Service";

include "ntp-client/clocktypes.ycp";

/**
 * Ask user if exit without saving
 * @return boolean true if exit
 */
define boolean reallyExit () ``{
    // yes-no popup
    return Popup::YesNo (_("Really exit?
All changes will be lost."));
}

boolean reallyExitSimple () {
    if (NtpClient::run_service
	    == (UI::QueryWidget (`id ("start"), `CurrentButton) == "boot")
	&& NtpClient::selected_record["address"]:""
	    == UI::QueryWidget (`id ("server_address"), `Value)
    )
    {
	return true;
    }
    return reallyExit ();
}

// FIXME this is quite ugly ... the whole checkinf if something was changed
// ... but it works :-)
boolean sync_record_modified = false;

boolean reallyExitComplex () {
    if (NtpClient::run_service
	    == (UI::QueryWidget (`id ("start"), `CurrentButton) == "boot")
        && NtpClient::run_chroot
	    == UI::QueryWidget (`id ("run_chroot"), `Value)
	&& NtpClient::config_dhcp
	    == UI::QueryWidget (`id ("config_dhcp"), `Value)
	&& (! CWMFirewallInterfaces::OpenFirewallModified ("firewall"))
	&& (! sync_record_modified)
    )
    {
	return true;
    }
    sync_record_modified = true;
    return reallyExit ();
}

/**
 * Restart the NTP daemon service
 */
define void restartNtpDaemon () ``{
    Service::RunInitScript("xntpd", "restart");
}

/**
 * Write the NTP settings without displaying progress
 */
define void silentWrite () ``{
    boolean progress_orig = Progress::set (false);
    NtpClient::Write ();
    Progress::set (progress_orig);
}

/**
 * Parse string to map of options
 * @param options_string string of options
 * @param with_param a list of options that must have a parameter
 * @param without_param a list of options that don't have any parameter
 * @return map options as a map
 */
define map string2opts (string options_string, list<string> with_param,
        list<string> without_param)
    ``{
    list<string> l = splitstring (options_string, " ");
    l = filter (string e, l, ``(e != ""));
    boolean ignore_next = false;
    integer index = -1;
    list<string> unknown = [];
    map<string,any> ret = (map<string,any>)listmap (string e, l, ``{
	index = index + 1;
	if (ignore_next)
	{
	    ignore_next = false;
	    return $[ e : (any)nil ];
	}
	ignore_next = false;
	if (contains (with_param, e))
	{
	    ignore_next = true;
	    return $[ e: l[index + 1]:""];
	}
	else if (contains (without_param, e))
	{
	    return $[ e : true ];
	}
	else
	{
	    unknown = add (unknown, e);
	    return $[ e : (any)nil];
	}
    });
    ret = (map<string,any>)filter (string k, any v, ret, ``(v != nil));
    ret = $[
	"parsed" : ret,
	"unknown" : mergestring (unknown, " "),
    ];
    return ret;
}

/**
 * Create options string from a map
 * @param options a map options represented as a map
 * @param other string other options that were set as string
 * @return string options represented as a string
 */
define string opts2string (map<string,any> options, string other) ``{
    string ret = other;
    foreach (string k, any v, options, ``{
	if (v == true)
	{
	    ret = sformat ("%1 %2", ret, k);
	}
	else if (v != false && v != "")
	{
	    ret = sformat ("%1 %2 %3", ret, k, v);
	}
    });
    return ret;
}

/**
 * If modified, ask for confirmation
 * @return true if abort is confirmed
 */
define boolean ReallyAbort() ``{
    return !NtpClient::modified || Popup::ReallyAbort(true);
}

/**
 * Check for pending Abort press
 * @return true if pending abort
 */
define boolean PollAbort() ``{
    return UI::PollInput() == `abort;
}

/**
  * Get the type of the clock from the address
  * @param address string the clock identification in the IP address form
  * @return integer the clock type
  */
define integer getClockType (string address) ``{
    if (address == "")
	return 0;
    if (! IP::Check4 (address))
    {
	y2error ("Invalid address: %1", address);
	return nil;
    }
    string cl_type = regexpsub (address,
	"[0-9]+\.[0-9]+\.([0-9]+)\.[0-9]+",
	"\\1");
    return tointeger (cl_type);
}

/**
 * Set the clock type into an IP address
 * @param address string the IP address to patch the clock number into
 * @param clock_type integer the clock type to be set
 * @return string IP address with clock type set correctly
 */
define string setClockType (string address, integer clock_type) ``{
    if (address == "")
	address = "127.127.0.0";
    if (! IP::Check4 (address))
    {
	y2error ("Invalid address: %1", address);
	return nil;
    }
    string ret = regexpsub (address,
	"([0-9]+\.[0-9]+\.)[0-9]+(\.[0-9]+)",
	sformat ("\\1%1\\2", clock_type));
    return ret;
}

/**
  * Get the unit number of the clock from the address
  * @param address string the clock identification in the IP address form
  * @return integer the unit number
  */
define integer getClockUnitNumber (string address) ``{
    if (address == "")
	return 0;
    if (! IP::Check4 (address))
    {
	y2error ("Invalid address: %1", address);
	return nil;
    }
    string cl_type = regexpsub (address,
	"[0-9]+\.[0-9]+\.[0-9]+\.([0-9]+)",
	"\\1");
    return tointeger (cl_type);
}

/**
 * Set the clock unit number into an IP address
 * @param address string the IP address to patch the clock number into
 * @param unit_number integer the unit number to be set
 * @return string IP address with unit number set correctly
 */
define string setClockUnitNumber (string address, integer unit_number) ``{
    if (address == "")
	address = "127.127.0.0";
    if (! IP::Check4 (address))
    {
	y2error ("Invalid address: %1", address);
	return nil;
    }
    string ret = regexpsub (address,
	"([0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+",
	sformat ("\\1%1", unit_number));
    return ret;
}


/**
  * Get entries for the clock type combo box
  * @return list of items for the combo box
  */
list<list<string> > getClockTypesCombo () {
    map<integer,string> clock_names = mapmap (integer k, map<string,string> v,
	clock_types, ``(
	    $[ k: v["name"]:"" ]
	)
    );
    list<list<string> > ret = maplist (integer k, string v, clock_names, {
	return [ sformat ("%1", k), v];
    });
    return ret;
}

/**
 * Propose the interface to be allowed for access in firewall
 * At the moment not used
 */
define list<string> proposeInterfacesToAllowAccess () ``{
    list<map<string,any> > recs = NtpClient::getSyncRecords ();
    recs = filter (map<string,any> r, recs, ``(
	r["type"]:"" == "peer" || r["type"]:"" == "broadcastclient"
    ));
    list<string> addresses = maplist (map<string,any> r, recs, ``(
	r["address"]:""
    ));
    addresses = filter (string a, addresses, ``(a != "" && a != nil));
    addresses = maplist (string a, addresses, ``{
	if (IP::Check4 (a))
	    return a;
	map m = (map)SCR::Execute (.target.bash_output,
	    sformat ("/usr/bin/host %1 | /bin/grep address", a));
	if (m["exit"]:0 != 0)
	    return nil;
	string out = m["stdout"]:"";
	out = regexpsub (out, "has address (.*)$", "\\1");
	return out;
    });
    addresses = filter (string a, addresses, ``(a != "" && a != nil));
    list<string> ifaces = maplist (string a, addresses, ``{
	map m = (map)SCR::Execute (.target.bash_output,
	    sformat ("/sbin/ip route get %1", a));
	if (m["exit"]:0 != 0)
	    return nil;
	string out = m["stdout"]:"";
	out = mergestring (splitstring (out, "\n"), " ");
	out = regexpsub (out, "dev[ ]+([^ ]+)[ ]+src", "\\1");
	return out;
    });
    ifaces = toset (ifaces);
    ifaces = filter (string i, ifaces, {return i != nil;});
    return ifaces;
}
/* EOF */
}
