ACC SHELL
/**
* File: ProductLicense.ycp
*
* Module: ProductLicense
*
* Summary: Provide access / dialog for product license
*
* Author: Jiri Srain <jsrain@suse.cz>
* Lukas Ocilka <locilka@suse.cz>
*
*/
{
module "ProductLicense";
import "Directory";
import "InstShowInfo";
import "Language";
import "Popup";
import "Report";
import "Stage";
import "Wizard";
import "Mode";
import "FileUtils";
import "ProductFeatures";
import "String";
import "WorkflowManager";
import "Progress";
// IMPORTANT: maintainer of yast2-installation is responsible for this module
textdomain "packager";
// list of already accepted licenses
list <string> already_accepted_licenses = [];
list <string> license_patterns = [
"license\\.html", "license\\.%1\\.html",
"license\\.htm", "license\\.%1\\.htm",
"license\\.txt", "license\\.%1\\.txt"
];
// no more wildcard patterns here, UI can display only html and txt anyway
// All licenses have their own unique ID
list <string> license_ids = [];
/**
* License files by their eula_ID
* @struct $["ID":$[licenses]]
*/
map <string, map <string, string> > all_licenses = $[];
/**
* Checks the string that might contain ID of a license and
* eventually returns that id.
* See also GetIdPlease for a better ratio of successful stories.
*/
string GetId (string id_text) {
string id = nil;
if (regexpmatch (id_text, "^license_language_.+")) {
id = regexpsub (id_text, "^license_language_(.+)", "\\1");
} else {
y2error ("Cannot get ID from %1", id_text);
}
return id;
}
// Helper func. Cuts encoding suffix off the LANG
// env. variable i.e. foo_BAR.UTF-8 => foo_BAR
string EnvLangToLangCode ( string env_lang )
{
list <string> tmp = [];
if (env_lang != nil)
tmp = splitstring(env_lang, ".@");
return tmp[0]:"";
}
/**
* Creates a unique identification from filename
* (MD5sum + file size)
*
* @param string filename
* @return string unique ID
*/
string GetLicenseIdentString (string filename) {
if (! FileUtils::Exists (filename)) {
y2error ("License '%1' doesn't exist", filename);
return nil;
}
string filemd5 = FileUtils::MD5sum (filename);
if (filemd5 == nil) {
return nil;
}
string ret = sformat("%1-%2", filemd5, FileUtils::GetSize (filename));
y2milestone ("License ident for '%1' is '%2'", filename, ret);
return ret;
}
/**
* Checks whether the license (file) has been already accepted
*
* @param string filename
* @return boolean whether the license has been accepted before
*/
boolean IsLicenseAlreadyAccepted (string license_ident) {
if (license_ident == nil || license_ident == "") {
y2error ("Wrong license ID '%1'", license_ident);
return false;
}
return contains (already_accepted_licenses, license_ident);
}
/**
* Sets that the license (file) has been already accepted
*
* @param string filename
*/
void LicenseHasBeenAccepted (string license_ident) {
if (license_ident == nil || license_ident == "") {
y2error ("Wrong license ID '%1'", license_ident);
return;
}
y2milestone ("Adding License ID '%1' as already accepted", license_ident);
already_accepted_licenses = add (already_accepted_licenses, license_ident);
}
string WhichLicenceFile (string license_language, map <string, string> & licenses) {
string license_file = licenses[license_language]:"";
if (license_file == nil || license_file == "") {
y2error ("No license file defined for language '%1' in %2", license_language, licenses);
} else {
y2milestone ("Using license file: %1", license_file);
}
return license_file;
}
global term GetLicenseContent (string lic_lang, map <string, string> & licenses, string id) {
string license_file = WhichLicenceFile (lic_lang, licenses);
string license_text = (string) SCR::Read(.target.string, license_file);
if (license_text == nil)
{
Report::Error (sformat(_("Cannot read license file %1"), license_file));
license_text = "";
}
term rt = `Empty();
// License is HTML (or RichText)
if (regexpmatch(license_text, "</.*>"))
rt = `MinWidth (80, `RichText(`id (sformat("welcome_text_%1", id)),
license_text
));
// License is plain text
// details in BNC #449188
else
rt = `MinWidth (80, `RichText(`id (sformat("welcome_text_%1", id)),
"<pre>" + String::EscapeTags (license_text) + "</pre>"
));
return rt;
}
// filename printed in the license dialog
string license_file_print = nil;
term GetLicenseDialogTerm (list<string> languages, string license_language, map <string, string> & licenses, string id) {
string license_text = "";
term rt = GetLicenseContent (license_language, licenses, id);
// bug #204791, no more "languages.ycp" client
map<string,list> lang_names_orig = Language::GetLanguagesMap (false);
if (lang_names_orig == nil) {
y2error("Wrong definition of languages");
lang_names_orig = $[];
}
map<string,string> lang_names = $[];
// $[ "en" : "English (US)", "de" : "Deutsch" ]
lang_names = mapmap (string code, list descr,
lang_names_orig,
{
return $[ code : descr[4]:"" ];
});
/* for the default fallback */
if (lang_names[""]:nil == nil) {
// language name
lang_names[""] = lang_names_orig["en_US", 4]:"";
}
if (lang_names["en"]:nil == nil) {
// language name
lang_names["en"] = lang_names_orig["en_US", 4]:"";
}
list<list<string> > lang_pairs = maplist (string l, languages, {
string name_print = lang_names[l]:"";
if (name_print == "") {
string l_short = substring (l, 0, 2);
foreach (string k, string v, lang_names, {
if (substring (k, 0, 2) == l_short) {
name_print = v;
return true;
}
return false;
});
}
return [ l, name_print ];
});
// filter-out languages that don't have any name
lang_pairs = filter (list<string> lang_pair, lang_pairs, {
if (lang_pair[1]:"" == "") {
y2warning("Unknown license language '%1', filtering out...", lang_pair);
return false;
} else {
return true;
}
});
lang_pairs = sort (list<string> a, list<string> b, lang_pairs, {
// bnc#385172: must use < instead of <=, the following means:
// strcoll(x) <= strcoll(y) && strcoll(x) != strcoll(y)
list lsorted = lsort ([a[1]:"", b[1]:""]);
list lsorted_r = lsort ([b[1]:"", a[1]:""]);
return (lsorted[0]:"" == a[1]:"" && lsorted == lsorted_r);
});
list langs = maplist (list<string> descr, lang_pairs, {
return `item (`id (descr[0]:""), descr[1]:"", (descr[0]:"" == license_language));
});
term lang_selector_options = `opt (`notify);
// Disable in case there is no language to select
// bugzilla #203543
if (size (langs) <= 1) {
lang_selector_options = add (lang_selector_options, `disabled);
}
license_ids = toset (add (license_ids, id));
return `VBox (
// combo box
`Left (`ComboBox (`id (sformat("license_language_%1", id)), lang_selector_options, _("&Language"), langs)),
`ReplacePoint (`id (sformat("license_contents_rp_%1", id)), rt)
);
}
// BNC #448598
// no-acceptance-needed file in license.tar.gz means the license
// doesn't have to be accepted by user, just displayed
map <string, boolean> license_acceptance_needed = $[];
/**
* Returns whether accepting the license manually is requied.
*
* @see BNC #448598
* @return boolean if required
*/
global boolean AcceptanceNeeded (string id) {
return license_acceptance_needed[id]:true;
}
void SetAcceptanceNeeded (string id, boolean new_value) {
if (new_value == nil) {
y2error ("Undefined behavior (License ID %1), AcceptanceNeeded: %2", id, new_value);
return;
}
license_acceptance_needed[id] = new_value;
if (new_value == true) {
y2milestone ("License agreement (ID %1) WILL be required", id);
} else {
y2milestone ("License agreement (ID %1) will NOT be required", id);
}
}
term GetLicenseDialog (list<string> languages, string license_language, map <string, string> & licenses, string id, boolean spare_space) {
map display = UI::GetDisplayInfo();
integer space = display["TextMode"]:true ? 1 : 3;
term license_buttons = `VBox (
`VSpacing ((spare_space ? 0:2)),
`RadioButtonGroup(`id (sformat ("eula_%1", id)),
`HBox(
`HSpacing (2*space),
`VBox(
`Left(`RadioButton(`id (sformat("yes_%1", id)),
`opt(`notify),
// radio button
_("&Yes, I Agree to the License Agreement")
)),
`Left(`RadioButton(`id (sformat("no_%1", id)),
`opt(`notify),
// radio button
_("N&o, I Do Not Agree")
))
),
`HSpacing (2*space)
)
)
);
return `VBox (
`VSpacing ((spare_space ? 0:1)),
`HBox (
`HSpacing (2*space),
GetLicenseDialogTerm (languages, license_language, licenses, id),
`HSpacing (2*space)
),
// BNC #448598
// yes/no buttons exist only if needed
// if they don't exist, user is not asked to accept the license later
(AcceptanceNeeded (id) ?
license_buttons
:
`Empty()
),
`VSpacing((spare_space ? 0.5 : 1)),
`HBox (
`HSpacing (2*space),
(license_file_print != nil ?
`Left (
// FATE #302018
`Label (
// TRANSLATORS: addition license information
// %1 is replaced with the filename
sformat(_("If you want to print this EULA, you can find it
on the first media in the file %1"), license_file_print)
)
)
:
`Empty ()
),
`HSpacing (2*space)
),
`VSpacing ((spare_space ? 0:1))
);
}
string GetLicenseDialogHelp () {
// help text
return _("<p>Read the license agreement carefully and select
one of the available options. If you do not agree to the license agreement,
the configuration will be aborted.</p>
");
}
/**
* Displays License with Help and ( ) Yes / ( ) No radio buttons
* @param string file with the license
*/
void DisplayLicenseDialog (list<string> languages, boolean back, string license_language, map <string, string> & licenses, string id) {
// dialog caption
string caption = _("License Agreement");
term contents = GetLicenseDialog (languages, license_language, licenses, id, false);
// If acceptance is not needed, there's no need to disable the button
// by default
boolean default_next_button_state = (AcceptanceNeeded (id) ? false : true);
Wizard::SetContents(caption, contents, GetLicenseDialogHelp(),
back, default_next_button_state);
Wizard::SetTitleIcon ("yast-license");
Wizard::SetFocusToNextButton();
}
/**
* Removes the temporary directory for licenses
* @param string temporary directory path
*/
void CleanUpLicense (string tmpdir) {
if (tmpdir != nil && tmpdir != "/")
SCR::Execute (.target.bash_output,
sformat ("rm -rf '%1'", String::Quote(tmpdir))
);
}
/**
* Get all files with license existing in specified directory
* @param dir string directory to look into
* @param patterns a list of patterns for the files, regular expressions
* with %1 for the language
* @return a map $[ lang_code : filename ]
*/
map<string,string> LicenseFiles (string dir, list<string> patterns) {
map<string,string> ret = $[];
if (dir == nil) return ret;
list<string> files = (list<string>)SCR::Read (.target.dir, dir);
y2milestone ("All files in license directory: %1", files);
// no license
if (files == nil) return $[];
foreach (string p, patterns, {
if (! issubstring (p, "%"))
{
foreach (string file, files, {
//Possible license file names are regexp patterns
//(see list <string> license_patterns)
//so we should treat them as such (bnc#533026)
if ( regexpmatch(file,p) )
{
ret[""] = dir + "/" + file;
}
});
}
else
{
string regpat = sformat (p, "(.+)");
foreach (string file, files, {
if (regexpmatch (file, regpat))
{
string key = regexpsub (file, regpat, "\\1");
ret[key] = dir + "/" + file;
}
});
}
});
y2milestone ("Files containing license: %1", ret);
return ret;
}
string tmpdir = nil;
string license_dir = nil;
string info_file = nil;
// Functions for handling different locations of licenses -->
boolean UnpackLicenseTgzFileToDirectory (string unpack_file, string to_directory) {
// License file exists
if (FileUtils::Exists (unpack_file)) {
map out = (map) SCR::Execute (.target.bash_output,
sformat ("
rm -rf '%1' && \
mkdir -p '%1' && \
cd '%1' && \
tar -xzf '%2'
",
String::Quote (to_directory),
String::Quote (unpack_file)
)
);
// Extracting license failed, cannot accept the license
if (out["exit"]:0 != 0) {
y2error("Cannot untar license -> %1", out);
// popup error
Report::Error (_("An error occurred while preparing the installation system."));
CleanUpLicense (to_directory);
return false;
}
// Success
return true;
// Nothing to unpack
} else {
y2error ("No such file: %1", unpack_file);
return false;
}
}
void SearchForLicense_FirstStageBaseProduct (integer src_id, string fallback_dir) {
y2milestone ("Getting license from installation product");
string license_file = "/license.tar.gz";
if (FileUtils::Exists (license_file)) {
y2milestone("Installation Product has a license");
tmpdir = sformat ("%1/product-license/base-product/", (string) SCR::Read (.target.tmpdir));
if (UnpackLicenseTgzFileToDirectory (license_file, tmpdir)) {
license_dir = tmpdir;
license_file_print = "license.tar.gz";
} else {
license_file = nil;
}
} else {
y2milestone ("Installation Product doesn't have a license");
license_file = nil;
}
if (FileUtils::Exists ("/info.txt"))
info_file = "/info.txt";
}
void SearchForLicense_LiveCDInstallation (integer src_id, string fallback_dir) {
y2milestone ("LiveCD License");
// BNC #594042: Multiple license locations
list <string> license_locations = ["/usr/share/doc/licenses/", "/"];
license_dir = nil;
info_file = nil;
foreach (string license_location, license_locations, {
license_location = sformat ("%1/license.tar.gz", license_location);
if (FileUtils::Exists (license_location)) {
y2milestone ("Using license: %1", license_location);
tmpdir = sformat ("%1/product-license/LiveCD/", (string) SCR::Read (.target.tmpdir));
if (UnpackLicenseTgzFileToDirectory (license_location, tmpdir)) {
license_dir = tmpdir;
license_file_print = "license.tar.gz";
} else {
CleanUpLicense (tmpdir);
}
break;
}
});
if (license_dir == nil) {
y2milestone ("No license found in: %1", license_locations);
}
foreach (string info_location, license_locations, {
info_location = sformat ("%1/README.BETA", info_location);
if (FileUtils::Exists (info_location)) {
y2milestone ("Using info file: %1", info_location);
info_file = info_location;
break;
}
});
if (info_file == nil) {
y2milestone ("No info file found in: %1", license_locations);
}
}
void SearchForLicense_NormalRunBaseProduct (integer src_id, string fallback_dir) {
y2milestone ("Using default license directory %1", fallback_dir);
if (FileUtils::Exists (fallback_dir)) {
license_dir = fallback_dir;
} else {
y2warning ("Fallback dir doesn't exist %1", fallback_dir);
license_dir = nil;
}
if (FileUtils::Exists ("/info.txt"))
info_file = "/info.txt";
}
void SearchForLicense_AddOnProduct (integer src_id, string fallback_dir) {
y2milestone ("Getting license info from repository %1", src_id);
info_file = Pkg::SourceProvideDigestedFile (src_id, 1, "/media.1/info.txt", true /* optional */);
// using a separate license directory for all products
tmpdir = sformat ("%1/product-license/%2/", (string) SCR::Read(.target.tmpdir), src_id);
// FATE #302018 comment #54
string license_file_location = "/license.tar.gz";
string license_file = Pkg::SourceProvideDigestedFile (src_id, 1, license_file_location, true /* optional */);
if (license_file != nil) {
y2milestone ("Using file %1 with licenses", license_file);
if (UnpackLicenseTgzFileToDirectory (license_file, tmpdir)) {
license_dir = tmpdir;
license_file_print = "license.tar.gz";
} else {
license_dir = nil;
}
return;
}
y2milestone ("Licenses in %1... not supported", license_file_location);
// New format didn't work, try the old one 1stMedia:/media.1/license.zip
license_dir = tmpdir;
license_file = Pkg::SourceProvideDigestedFile (src_id, 1, "/media.1/license.zip", true /* optional */);
// no license present
if (license_file == nil) {
y2milestone ("No license present");
license_dir = nil;
tmpdir = nil;
// return from the function
return;
}
y2milestone("Product has a license");
map out = (map)SCR::Execute (.target.bash_output,
sformat (
"
rm -rf '%1' && \
mkdir -p '%1' && \
cd '%1' && \
unzip -qqo '%2'
",
String::Quote (tmpdir),
String::Quote (license_file)
)
);
// Extracting license failed, cannot accept the license
if (out["exit"]:0 != 0) {
y2error("Cannot unzip license -> %1", out);
// popup error
Report::Error (_("An error occurred while preparing the installation system."));
CleanUpLicense (tmpdir);
license_dir = nil;
} else {
license_dir = tmpdir;
license_file_print = "/media.1/license.zip";
}
}
// Functions for handling different locations of licenses <--
void GetSourceLicenseDirectory (integer src_id, string fallback_dir) {
y2milestone ("Searching for licenses... (src_id: %1, fallback_dir: %2, mode: %3, stage: %4)",
src_id, fallback_dir, Mode::mode(), Stage::stage());
license_file_print = nil;
// Bugzilla #299732
// Base Product - LiveCD installation
if (Mode::live_installation()) {
SearchForLicense_LiveCDInstallation (src_id, fallback_dir);
// Base-product - license not in installation
// * Stage is not initial
// * source ID is not defined
} else if (! Stage::initial() && src_id == nil) {
SearchForLicense_NormalRunBaseProduct (src_id, fallback_dir);
// Base-product - first-stage installation
// * Stage is initial
// * Source ID is not set
// bugzilla #298342
} else if (Stage::initial() && src_id == nil) {
SearchForLicense_FirstStageBaseProduct ((src_id == nil ? Pkg::SourceGetCurrent(true)[0]:0 : src_id), fallback_dir);
// Add-on-product license
// * Source ID is set
} else if (src_id != nil && src_id > -1) {
SearchForLicense_AddOnProduct (src_id, fallback_dir);
// Fallback
} else {
y2warning ("Source ID not defined, using fallback dir '%1'", fallback_dir);
license_dir = fallback_dir;
}
y2milestone ("ProductLicense settings: license_dir: %1, tmpdir: %2, info_file: %3", license_dir, tmpdir, info_file);
}
string lic_lang = "";
symbol InitLicenseData (integer src_id, string dir, map <string, string> & licenses,
list <string> & available_langs, boolean require_agreement, string & license_ident, string id) {
GetSourceLicenseDirectory (src_id, dir);
// License does not need to be accepted. Well, I mean, manually selected "Yes, of course, I agree..."
if (FileUtils::Exists (sformat ("%1/no-acceptance-needed", license_dir))) {
if (id == nil) {
y2error ("Parameter id not set");
} else {
SetAcceptanceNeeded (id, false);
}
}
licenses = LicenseFiles (license_dir,
license_patterns);
// all other 'licenses' could be replaced by this one
all_licenses[id] = licenses;
if (info_file == nil && size (licenses) == 0)
return `auto;
// Let's do getenv here. Language::language may not be initialized
// by now (see bnc#504803, c#28). Language::Language does only
// sysconfig reading, which is not too useful in cases like
// 'LANG=foo_BAR yast repositories'
string language = EnvLangToLangCode( getenv("LANG") );
// Preferencies how the client selects from available languages
list<string> langs = [
language,
substring (language, 0, 2), // "it_IT" -> "it"
"en_US",
"en_GB",
"en",
"" // license.txt fallback
];
available_langs = maplist (string lang, string fn,
licenses,
{
return lang;
});
// "en" is the same as "", we don't need to have them both
if (contains(available_langs, "en") && contains(available_langs, "")) {
y2milestone("Removing license fallback '' as we already have 'en'...");
available_langs = filter (string one_lang, available_langs, {
return one_lang != "en";
});
}
y2milestone ("Preffered lang: %1", language);
if (size (available_langs) == 0)
return `auto; // no license available
lic_lang = find (string l, langs, {
return haskey (licenses, l);
});
if (lic_lang == nil)
lic_lang = available_langs[0]:"";
y2milestone ("Preselected language: '%1'", lic_lang);
if (lic_lang == nil)
{
if (tmpdir != nil) CleanUpLicense (tmpdir);
return `auto;
}
// Check whether such license hasn't been already accepted
// Bugzilla #305503
string license_ident_lang = nil;
// We need to store the original -- not localized license ID (if possible)
foreach (string check_this, ["", "en", lic_lang], {
if (contains (available_langs, check_this)) {
license_ident_lang = check_this;
y2milestone ("Using localization '%1' (for license ID)", license_ident_lang);
break;
}
});
// fallback
if (license_ident_lang == nil) license_ident_lang = lic_lang;
string base_license = WhichLicenceFile (license_ident_lang, licenses);
license_ident = GetLicenseIdentString (base_license);
// agreement might be required even if license has been already accepted
// defined, properly ($md5sum(32)-(1)$size(1..n))
//
// see also BNC #448598
// Even if it it shown it sometimes doesn't need to be even accepted by
// selecting "yes, I agree"
if (require_agreement != true && tostring (license_ident) != nil && size (license_ident) > 33 && IsLicenseAlreadyAccepted (license_ident)) {
y2milestone ("License has been already accepted/shown");
CleanUpLicense (tmpdir);
return `accepted;
} else {
y2milestone ("License needs to be shown");
}
// bugzilla #303922
// src_id == nil (the initial product license)
if (src_id != nil) {
// use wizard with steps
if (Stage::initial()) {
// Wizard::OpenNextBackStepsDialog();
// WorkflowManager::RedrawWizardSteps();
y2milestone ("Initial stage, not opening any window...");
// use normal wizard
} else {
Wizard::OpenNextBackDialog();
}
}
return `cont;
}
// Should have been named 'UpdateLicenseContentBasedOnSelectedLanguage' :->
void UpdateLicenseContent (map <string, string> & licenses, string id) {
// read the selected language
lic_lang = (string) UI::QueryWidget (`id (sformat ("license_language_%1", id)), `Value);
term rp_id = `id (sformat ("license_contents_rp_%1", id));
if (licenses == $[]) {
licenses = all_licenses[id]:$[];
}
if (UI::WidgetExists (rp_id)) {
UI::ReplaceWidget (rp_id, GetLicenseContent (lic_lang, licenses, id));
} else {
y2error ("No such widget: %1", rp_id);
}
}
boolean AllLicensesAccepted () {
// BNC #448598
// If buttons don't exist, eula is automatically accepted
boolean accepted = true;
string eula_id = nil;
foreach (string one_license_id, license_ids, {
if (AcceptanceNeeded (one_license_id) != true) {
y2milestone ("License %1 does not need to be accepted", one_license_id);
return;
}
eula_id = sformat ("eula_%1", one_license_id);
if ((boolean) UI::WidgetExists (`id (eula_id)) != true) {
y2error ("Widget %1 does not exist", eula_id);
return;
}
// All licenses have to be accepted
string license_accepted = (string) UI::QueryWidget (`id (eula_id), `CurrentButton);
y2milestone ("License %1 accepted: %2", eula_id, license_accepted);
if (! regexpmatch (license_accepted, "^yes_")) {
accepted = false;
break;
}
});
return accepted;
}
boolean AllLicensesAcceptedOrDeclined () {
boolean ret = true;
string eula_id = nil;
foreach (string one_license_id, license_ids, {
if (AcceptanceNeeded (one_license_id) != true)
return;
eula_id = sformat ("eula_%1", one_license_id);
if ((boolean) UI::WidgetExists (`id (eula_id)) != true) {
y2error ("Widget %1 does not exist", eula_id);
}
string current_button = (string) UI::QueryWidget(`id (eula_id), `CurrentButton);
// license have to be accepted or declined
if (current_button == nil) {
y2warning ("License %1 hasn't been accepted or declined", eula_id);
ret = false;
break;
}
});
return ret;
}
symbol HandleLicenseDialogRet (map <string, string> & licenses, boolean base_product, string action) {
any ret = nil;
while (true) {
ret = UI::UserInput();
if (is (ret, string) && regexpmatch (tostring (ret), "^license_language_")) {
UpdateLicenseContent (licenses, GetId (tostring (ret)));
ret = `language;
// bugzilla #303828
// disabled next button unless yes/no is selected
} else if (is (ret, string) && (regexpmatch (tostring(ret), "^yes_") || regexpmatch (tostring(ret), "^no_"))) {
if (AllLicensesAcceptedOrDeclined())
Wizard::EnableNextButton();
// Aborting the license dialog
} else if (ret == `abort) {
// bugzilla #218677
if (base_product) {
if (Popup::ConfirmAbort (`painless)) {
y2milestone("Aborting...");
ret = `abort;
break;
}
} else {
// popup question
if (Popup::ContinueCancel(_("Really abort the add-on product installation?"))) {
y2milestone("Aborting...");
ret = `abort;
break;
}
}
} else if (ret == `next) {
// License declined
if (AllLicensesAccepted() != true)
{
// message is void in case not accepting license doesn't stop the installation
if (action == "continue")
{
y2milestone ("action in case of license refusal is continue, not asking user");
ret = `accepted;
break;
}
// text changed due to bug #162499
string refuse_popup_text = base_product
// text asking whether to refuse a license (Yes-No popup)
? _("Refusing the license agreement cancels the installation.
Really refuse the agreement?")
// text asking whether to refuse a license (Yes-No popup)
: _("Refusing the license agreement cancels the add-on
product installation. Really refuse the agreement?");
if (! Popup::YesNo(refuse_popup_text))
{
continue;
}
else
{
y2milestone("License has been declined.");
if (action == "abort")
{
ret = `abort;
break;
}
else if (action == "continue")
{
ret = `accepted;
break;
}
else if (action == "halt")
{
ret = `halt;
break;
// timed ok/cancel popup
if (!Popup::TimedOKCancel(_("The system is shutting down..."), 10))
{
continue;
}
else
{
ret = `halt;
break;
}
}
else
{
y2error ("Unknown action %1", action);
ret = `abort;
break;
}
}
}
// License accepted
else
{
y2milestone("All licenses have been accepted.");
ret = `accepted;
break;
}
} else if (ret == `back) {
ret = `back;
break;
} else {
y2error ("Unhandled input: %1", ret);
}
}
return (symbol) ret;
}
/**
* Generic cleanup
*/
void CleanUp() {
// BNC #581933: All license IDs are cached while the module is in memory.
// Removing them when leaving the license dialog.
license_ids = [];
}
/**
* Ask user to confirm license agreement
* @param src_id integer repository to get the license from.
* If set to 'nil', the license is considered to belong to a base product
* @param dir string directory to look for the license in if src_id is nil
* and not 1st stage installation
* @param patterns a list of patterns for the files, regular expressions
* with %1 for the language
* @param boolean enable_back sets the back_button status
* @param boolean base_product defines whether it is a base or add-on product
* true means base product, false add-on product
* @param require_agreement means that even if the license (or the very same license)
* has been already accepetd, ask user to accept it again (because of 'going back'
* in the installation proposal).
* @param string id, usually source id but it can be any unique id in UI. Well, of course
* it must be string.
*/
global symbol AskLicenseAgreement (integer src_id, string dir,
list<string> patterns, string action, boolean enable_back,
boolean base_product, boolean require_agreement, string id)
{
lic_lang = "";
map <string, string> licenses = $[];
list <string> available_langs = [];
string license_ident = "";
symbol init_ret = InitLicenseData (src_id, dir, licenses, available_langs, require_agreement, license_ident, id);
if (init_ret == `auto || init_ret == `accepted) {
y2milestone ("Returning %1", init_ret);
return init_ret;
}
boolean created_new_dialog = false;
// #459391
// If a progress is running open another dialog
if (Progress::IsRunning()) {
y2milestone ("Some progress is running, opening new dialog for license...");
Wizard::OpenNextBackDialog();
created_new_dialog = true;
}
DisplayLicenseDialog (available_langs, enable_back, lic_lang, licenses, id /* license id */);
// Display info as a popup if exists
if (info_file != nil)
InstShowInfo::show_info_txt (info_file);
// initial loop
symbol ret = nil;
// set timeout for autoinstallation
// bugzilla #206706
if (Mode::autoinst()) {
y2milestone("AutoYaST: License has been accepted automatically");
ret = `accepted;
} else {
ret = HandleLicenseDialogRet (licenses, base_product, action);
}
if (ret == `accepted && license_ident != nil) {
// store already accepted license ID
LicenseHasBeenAccepted (license_ident);
}
CleanUpLicense (tmpdir);
// bugzilla #303922
if (created_new_dialog || (!Stage::initial() && src_id != nil)) {
Wizard::CloseDialog();
}
CleanUp();
return ret;
}
/**
* Ask user to confirm license agreement
* @param src_id integer repository to get the license from.
* If set to 'nil', the license is considered to belong to a base product
* @param list <string> dirs - directories to look for the licenses
* @param patterns a list of patterns for the files, regular expressions
* with %1 for the language
* @param boolean enable_back sets the back_button status
* @param boolean base_product defines whether it is a base or add-on product
* true means base product, false add-on product
* @param require_agreement means that even if the license (or the very same license)
* has been already accepetd, ask user to accept it again (because of 'going back'
* in the installation proposal).
*/
global symbol AskLicensesAgreement (list <string> dirs,
list<string> patterns, string action, boolean enable_back,
boolean base_product, boolean require_agreement)
{
if (dirs == nil || dirs == []) {
y2error ("No directories: %1", dirs);
// error message
Report::Error ("Internal Error: No license to show");
return `auto;
}
symbol init_ret = nil;
if (init_ret == `auto || init_ret == `accepted) {
y2milestone ("Returning %1", init_ret);
return init_ret;
}
boolean created_new_dialog = false;
// #459391
// If a progress is running open another dialog
if (Progress::IsRunning()) {
y2milestone ("Some progress is running, opening new dialog for license...");
Wizard::OpenNextBackDialog();
created_new_dialog = true;
}
// dialog caption
string caption = _("License Agreement");
list <string> license_idents = [];
// initial loop
symbol ret = nil;
list <map <string, string> > licenses = [];
integer counter = -1;
term contents = `VBox();
// If acceptance is not needed, there's no need to disable the button
// by default
boolean default_next_button_state = true;
foreach (string dir, dirs, {
counter = counter + 1;
licenses[counter] = $[];
lic_lang = "";
list <string> available_langs = [];
string license_ident = "";
map <string, string> tmp_licenses = $[];
symbol init_ret = InitLicenseData (nil, dir, tmp_licenses, available_langs, require_agreement, license_ident, dir);
if (license_ident != nil)
license_idents = add (license_idents, license_ident);
term license_term = GetLicenseDialog (available_langs, lic_lang, tmp_licenses, dir, true);
if (license_term == nil) {
y2error ("Oops, license term is: %1", license_term);
} else {
contents = add (contents, license_term);
}
// Display info as a popup if exists
if (info_file != nil)
InstShowInfo::show_info_txt (info_file);
licenses[counter] = tmp_licenses;
if (AcceptanceNeeded (dir))
default_next_button_state = false;
});
SCR::Write (.target.ycp, "/tmp/a", contents);
Wizard::SetContents(caption, contents, GetLicenseDialogHelp(),
enable_back, default_next_button_state);
Wizard::SetTitleIcon ("yast-license");
Wizard::SetFocusToNextButton();
// set timeout for autoinstallation
// bugzilla #206706
if (Mode::autoinst()) {
y2milestone("AutoYaST: License has been accepted automatically");
ret = `accepted;
} else {
map <string, string> tmp_licenses = $[];
ret = HandleLicenseDialogRet (tmp_licenses, base_product, action);
y2milestone ("Dialog ret: %1", ret);
}
// store already accepted license IDs
if (ret == `accepted) {
foreach (string license_ident, license_idents, {
LicenseHasBeenAccepted (license_ident);
});
}
CleanUpLicense (tmpdir);
// bugzilla #303922
if (created_new_dialog || !Stage::initial()) {
Wizard::CloseDialog();
}
CleanUp();
return ret;
}
global symbol AskAddOnLicenseAgreement (integer src_id) {
return AskLicenseAgreement (src_id, "",
license_patterns,
"abort",
// back button is disabled
false, false, false,
tostring(src_id));
}
global symbol AskFirstStageLicenseAgreement (integer src_id, string action) {
// bug #223258
// disabling back button when the select-language dialog is skipped
//
boolean enable_back = true;
if (Language::selection_skipped)
enable_back = false;
return AskLicenseAgreement (nil /* base product */, "",
license_patterns,
action,
// back button is enabled
enable_back, true, true,
// unique id
tostring (src_id));
}
// FIXME: map <string, boolean> ...
map <string, boolean> info_file_already_seen = $[];
/**
* Called from the first stage Welcome dialog by clicking on a button
*/
global boolean ShowFullScreenLicenseInInstallation (any replace_point_ID, integer src_id) {
lic_lang = "";
map <string, string> licenses = $[];
list <string> available_langs = [];
string license_ident = "";
symbol init_ret = InitLicenseData (nil /* base product */, "", licenses, available_langs, true, license_ident, tostring (src_id));
// Replaces the dialog content with Languages combo-box
// and the current license text (richtext)
UI::ReplaceWidget (
`id (replace_point_ID),
GetLicenseDialogTerm (available_langs, lic_lang, licenses, tostring(src_id))
);
any ret = nil;
while (true)
{
ret = UI::UserInput();
if (is (ret, string) && regexpmatch (tostring (ret), "^license_language_[[:digit:]]+")) {
UpdateLicenseContent (licenses, GetId (tostring (ret)));
} else {
break;
}
}
CleanUp();
return true;
}
/**
* Used in the first-stage Welcome dialog
*/
global boolean ShowLicenseInInstallation (any replace_point_ID, integer src_id) {
lic_lang = "";
map <string, string> licenses = $[];
list <string> available_langs = [];
string license_ident = "";
symbol init_ret = InitLicenseData (nil /* base product */, "", licenses, available_langs, true, license_ident, tostring (src_id));
term rt = GetLicenseContent (lic_lang, licenses, tostring (src_id));
UI::ReplaceWidget (`id (replace_point_ID), rt);
string id = tostring (src_id);
// Display info as a popup if exists
if (info_file != nil && info_file_already_seen[id]:false != true) {
if (Mode::autoinst()) {
y2milestone ("Autoinstallation: Skipping info file...");
} else {
InstShowInfo::show_info_txt (info_file);
info_file_already_seen[id] = true;
}
}
CleanUp();
return true;
}
global symbol AskInstalledLicenseAgreement (string directory, string action) {
// patterns are hard-coded
return AskLicenseAgreement (nil, directory, [], action, false, true, false, directory);
}
// FATE #306295: More licenses in one dialog
global symbol AskInstalledLicensesAgreement (list <string> directories, string action) {
// patterns are hard-coded
return AskLicensesAgreement (directories, [], action, false, true, false);
}
} // EOF
ACC SHELL 2018