ACC SHELL
/**
* File: clients/ntp-client_proposal.ycp
* Summary: Installation client for ntp configuration
* Author: Bubli <kmachalkova@suse.cz>
*
* This is used as the general interface between yast2-country
* (time,timezone) and yast2-ntp-client.
*/
{
textdomain "ntp-client";
import "Address";
import "NetworkService";
import "NtpClient";
import "Service";
import "String";
import "Stage";
import "PackageSystem";
import "Popup";
import "Progress";
import "Report";
import "Wizard";
/*
API:
Usual *_proposal functions: MakeProposal, AskUser, Write.
(but not Description; see, it just *looks* like *_proposal)
Additionally:
GetNTPEnabled (queries Service::Enabled)
SetUseNTP [ntp_used]
*/
any ret = nil;
string func = "";
map param = $[];
if(size(WFM::Args()) > 0 && is(WFM::Args(0), string)) {
func = (string)WFM::Args(0);
if(size(WFM::Args()) > 1 && is(WFM::Args(1), map))
param = (map)WFM::Args(1);
}
y2milestone("ntp-client_proposal called func %1 param %2",func,param);
string ui_help_text() {
// help text
string tmp = _("<p>Press <b>Synchronize Now</b>, to get your system time set correctly using the selected NTP server. If you want to make use of NTP permanently, enable the <b>Save NTP Configuration</b> option</p>");
tmp = tmp + _("<p>Enabling <b>Run NTP as daemon</b> option, the NTP service will be started as deamon. Otherwise the system time will be synchronized periodicaly. The default interval is 15 min. You can change it after installation with the <b>yast2 ntp-client module</b>.</p>");
// help text, cont.
if( ! Stage::initial() )
tmp = tmp + _("<p>Using the <b>Configure</b> button, open the advanced NTP configuration.</p>");
// help text, cont.
tmp = tmp + _("<p>Synchronization with the NTP server can be done only when the network is configured.</p>");
return tmp;
}
// FIXME must go to module to preserve value
boolean ntp_was_used = false;
void ui_enable_disable_widgets (boolean enabled) {
UI::ChangeWidget (`id (`ntp_address), `Enabled, enabled);
UI::ChangeWidget (`id (`run_service), `Enabled, enabled);
UI::ChangeWidget (`id (`ntp_now), `Enabled, enabled);
UI::ChangeWidget (`id (`ntp_save), `Enabled, enabled);
if (UI::WidgetExists (`id (`ntp_configure))) // bnc#483787
UI::ChangeWidget (`id (`ntp_configure), `Enabled, enabled);
}
void handle_invalid_hostname( string server ) {
// translators: error popup
Popup::Error( sformat(_("Invalid NTP server hostname %1"), server) );
}
boolean GetNTPEnabled () {
return Service::Enabled (NtpClient::service_name);
}
boolean ValidateSingleServer( string ntp_server )
{
if (!Address::Check(ntp_server) )
{
UI::SetFocus(`id(`ntp_address));
return false;
}
return true;
}
void AddSingleServer( string server )
{
integer idx = NtpClient::findSyncRecord("server", server);
// -1 means adding new server
if (idx == -1)
{
NtpClient::selected_record["address"] = server;
NtpClient::selected_record["type"] = "server";
}
else
NtpClient::selectSyncRecord(idx);
NtpClient::storeSyncRecord();
}
// @param cc country code
void MakeProposal(string cc)
{
list ntp_items = [];
//on the running system, read all the data, otherwise firewall
//and other stuff outside ntp.conf may not be initialized correctly
//(#375877)
if (!Stage::initial())
{
boolean progress_orig = Progress::set (false);
NtpClient::Read();
Progress::set (progress_orig);
}
// ntp_selected is true if NTP was proposed during installation (fate#303520)
else if (!NtpClient::ntp_selected)
NtpClient::ProcessNtpConf();
if( NtpClient::config_has_been_read || NtpClient::ntp_selected)
{
y2milestone("ntp_items will be filled from /etc/ntp.conf");
// grr, GUNS means all of them are used and here we just pick one
ntp_items = maplist(string server, NtpClient::GetUsedNtpServers(),{
return `item(`id(server), server);
});
// avoid calling Read again (bnc #427712)
NtpClient::config_has_been_read = true;
}
/*
FIXME: does MakeProposal have sense?
would it have sense if implemented properly?
real proposal starts here, it is ui_read before...
*/
y2milestone("ntp_items :%1", ntp_items);
if( ntp_items == [])
{
y2milestone("Nothing found in /etc/ntp.conf, proposing current language-based NTP server list");
ntp_items = NtpClient::GetNtpServersByCountry( cc, true );
NtpClient::config_has_been_read = true;
}
ntp_items = add(ntp_items, "");
UI::ChangeWidget(`id(`ntp_address), `Items, ntp_items);
}
/**
@param first_time when asking for first time, we check if service is running
@return should our radio button be selected
*/
boolean ui_init(term rp, string country, boolean first_time) {
term cont = `VBox (`VSpacing (0.5), `HBox (
`HSpacing (3),
`HWeight (1, `VBox (
`Left (`ComboBox (`id (`ntp_address), `opt (`editable, `hstretch),
// combo box label
_("&NTP Server Address")
)),
`VSpacing (0.3),
`HBox (
`HSpacing (0.5),
// check box label
`Left (`CheckBox (`id (`run_service), _("&Run NTP as daemon")))
),
`HBox (
`HSpacing (0.5),
// check box label
`Left (`CheckBox (`id (`ntp_save), _("&Save NTP Configuration"), true ))
)
)),
`HWeight (1, `VBox (
`Label (""),
`VSpacing (0.3), // try to line up the widgets horizontally
// push button label
`Left (`PushButton (`id (`ntp_now), _("S&ynchronize now"))),
`VSpacing (0.3),
// push button label
// bnc#449615: only simple config for inst-sys
Stage::initial() ? `Label("") : `Left (`PushButton (`id (`ntp_configure), _("&Configure..."))),
`Label("")
))
));
UI::ReplaceWidget(rp, cont);
if (!NetworkService::isNetworkRunning())
{
y2warning("Network is not running, NTP synchronization will not be available");
// If network not running we have to be able to configure ntp nevertheless
// UI::ChangeWidget(`id(`ntp_content), `Enabled, false); // FIXME it is outside
}
// ^ createui0
// FIXME is it correct? move out?
boolean ntp_used = (first_time && !Stage::initial ()) ?
GetNTPEnabled () : NtpClient::ntp_selected;
MakeProposal (country);
return ntp_used;
}
symbol AskUser () {
symbol ret = nil;
string ntp_server = (string) UI::QueryWidget(`id(`ntp_address), `Value);
if ( !ValidateSingleServer( ntp_server ) )
ret = `invalid_hostname;
else
{
string ntp_server = (string) UI::QueryWidget(`id(`ntp_address), `Value);
AddSingleServer(ntp_server);
boolean retval = (boolean) WFM::CallFunction("ntp-client");
if (retval)
ret = `next;
string cc = NtpClient::GetCurrentLanguageCode();
MakeProposal(cc);
}
return ret;
}
boolean WriteNtpSettings (string ntp_server,boolean run_service) {
NtpClient::modified = true;
AddSingleServer(ntp_server);
if( ! run_service )
{
NtpClient::synchronize_time=true;
NtpClient::run_service=false;
NtpClient::sync_interval=15;
}
//OK, so we stored the server address
//In inst-sys we don't need to care further
//ntp-client_finish will do the job
//In installed system we must write the settings
if (!Stage::initial()) {
Wizard::OpenAcceptDialog(); // FIXME so that the progress does not disturb the dialog to be returned to
NtpClient::Write();
Wizard::CloseDialog();
}
return true;
}
/*
params:
server (taken from UI if empty)
servers (intended to use all of opensuse.pool.ntp.org,
but I did not have time to make it work)
write_only (bnc#589296)
ntpdate_only (TODO rename to onetime)
return:
`success, `invalid_hostname or `ntpdate_failed
*/
symbol Write(map param) {
symbol ret = nil;
string ntp_server = param["server"]:"";
boolean run_service = param["run_service"]:true;
if (ntp_server == "")
// get the value from UI only when it wasn't given as a parameter
ntp_server = (string) UI::QueryWidget(`id(`ntp_address), `Value);
if ( !ValidateSingleServer( ntp_server ) )
return `invalid_hostname;
if (param["write_only"]:false)
{
WriteNtpSettings (ntp_server,run_service);
return `success;
}
// One-time adjusment without running the ntp daemon
// Meanwhile, ntpdate was replaced by sntp
boolean ntpdate_only = param["ntpdate_only"]:false;
string required_package = "ntp";
//In 1st stage, schedule packages for installation
//but not in case user wants to set the time only (F#302917)
//(ntpdate is in inst-sys so we don't need the package)
if (Stage::initial() && !ntpdate_only)
{
import "Packages";
Packages::addAdditionalPackage(required_package);
// bugzilla #327050
// Agent for writing /etc/ntp.conf needs to be installed
// to write the settings at the end of the installation
Packages::addAdditionalPackage("yast2-ntp-client");
}
//Otherwise, prompt user for confirming pkg installation
else if (!Stage::initial ())
{
if (!PackageSystem::CheckAndInstallPackages([ required_package ]))
{
Report::Error(sformat( _("Synchronization with NTP server is not possible
without having package %1 installed"), required_package));
}
}
Popup::ShowFeedback("", _("Synchronizing with NTP server..."));
y2milestone("Running sntp to sync with %1", ntp_server);
// -r: do set the system time
// -P no: do not ask if time difference is too large
// -c 1 -d 15: delay 15s, only one try (bnc#442287)
integer r = (integer) SCR::Execute (.target.bash, sformat ("/usr/sbin/sntp -c 1 -d 15 -r -P no '%1'", String::Quote(ntp_server)));
y2milestone ("'sntp %1' returned %2", ntp_server, r);
Popup::ClearFeedback();
if (r != 0)
return `ntpdate_failed;
// User wants to more than running sntp (synchronize on boot)
if (!ntpdate_only)
{
WriteNtpSettings (ntp_server,run_service);
}
return `success;
}
// ui = UI::UserInput
symbol ui_handle(any ui) {
boolean redraw = false;
if (ui == `ntp_configure)
{
symbol rv = AskUser ();
if( rv == `invalid_hostname)
{
handle_invalid_hostname (
(string) UI::QueryWidget (`id (`ntp_address), `Value));
}
else if (rv == `next && !Stage::initial ())
{
// show the 'save' status after configuration
UI::ChangeWidget (`id(`ntp_save), `Value, GetNTPEnabled ());
}
}
if (ui == `ntp_now)
{
symbol rv = Write ($["ntpdate_only" : true]);
if( rv == `invalid_hostname)
{
handle_invalid_hostname (
(string) UI::QueryWidget (`id (`ntp_address), `Value));
}
else if (rv == `success)
{
redraw = true; // update time widgets
}
}
return redraw? `redraw : nil;
}
boolean ui_try_save() {
map argmap = $[];
argmap["ntpdate_only"] = false;
argmap["run_service"] = false;
if (UI::QueryWidget (`id (`ntp_save), `Value) == false)
argmap["ntpdate_only"] = true;
if (UI::QueryWidget (`id (`run_service), `Value) == true)
argmap["run_service"] = true;
symbol rv = Write (argmap);
string server = (string) UI::QueryWidget (`id(`ntp_address),`Value);
if (rv == `invalid_hostname)
{
handle_invalid_hostname( server );
return false; // loop on
}
else if ( rv == `ntpdate_failed)
{
// Translators: yes-no popup,
// ntpdate is a command, %1 is the server address
if (Popup::YesNo( sformat(_("'ntpdate %1' failed. Revisit NTP server configuration?"), server) ))
{
return false; // loop on
}
else if (!argmap["ntpdate_only"]:false)
{
WriteNtpSettings (server,argmap["run_service"]:false); //may be the server is realy not accessable
}
}
// success, exit
return true;
}
if (false)
{
return;
}
else if (func == "GetNTPEnabled")
{
ret = GetNTPEnabled ();
}
else if (func == "SetUseNTP")
{
NtpClient::ntp_selected = param["ntp_used"]:false;
ret = true;
}
else if (func == "MakeProposal")
{
string cc = param["country"]:NtpClient::GetCurrentLanguageCode();
ret = MakeProposal(cc);
}
else if (func == "Write")
{
ret = Write (param);
}
else if (func == "ui_help_text")
{
ret = ui_help_text();
}
else if (func == "ui_init")
{
term rp = param["replace_point"]:`id(`rp);
string cc = param["country"]:NtpClient::GetCurrentLanguageCode();
boolean ft = param["first_time"]:false;
ret = ui_init(rp, cc, ft);
}
else if (func == "ui_try_save")
{
ret = ui_try_save();
}
else if (func == "ui_enable_disable_widgets")
{
ret = ui_enable_disable_widgets(param["enabled"]:false);
}
else if (func == "ui_handle")
{
ret = ui_handle(param["ui"]:nil);
}
return ret;
}
ACC SHELL 2018