ACC SHELL

Path : /usr/share/YaST2/clients/
File Upload :
Current File : //usr/share/YaST2/clients/inst_upgrade_urls.ycp

{
    // FATE #301785: Distribution upgrade should offer
    // existing extra installation sources as Add-On

    import "Installation";
    import "FileUtils";
    import "Stage";
    import "GetInstArgs";
    import "FileUtils";
    import "Mode";
    import "Wizard";
    import "Progress";
    import "Label";
    import "NetworkService";
    import "Popup";
    import "AddOnProduct";
    import "Report";
    import "PackageCallbacks";

    textdomain "installation";

    symbol ret = `next;
    if (GetInstArgs::going_back())
	ret = `back;

    boolean test_mode = false;

    integer do_not_remove = 0;

    if (size (WFM::Args()) > 0 && is (WFM::Args(0), string)) {
	y2milestone ("Args: %1", WFM::Args());
	if (WFM::Args(0) == "test")
	    test_mode = true;
    }

    if (test_mode) {
	y2milestone ("Test mode");
    } else {
	if (! Stage::initial()) {
	    y2milestone ("Not an initial stage");
	    return ret;
	}
	if (! Mode::update()) {
	    y2milestone ("Not an udpate mode");
	    return ret;
	}
    }

    string dir_old = sformat ("%1/var/lib/zypp/db/sources/", Installation::destdir);
    list <map <string, any> > old_urls = [];

    string dir_new = sformat ("%1/etc/zypp/repos.d/", Installation::destdir);
    list <map> new_urls = [];

    list <map> already_registered_repos = [];

    void ReadOldTypeURLs () {
	// Old-type URLs
	list <string> all_source_files = (list <string>) SCR::Read (.target.dir, dir_old);

	if (all_source_files == nil || all_source_files == []) {
	    y2milestone ("No old zypp sources on the target");
	} else {
	    integer counter = -1;

	    foreach (string one_source_file, all_source_files, {
		one_source_file = sformat ("%1/%2", dir_old, one_source_file);

		if (! FileUtils::Exists (one_source_file)) {
		    y2error ("File doesn't exist: %1", one_source_file);
		    return;
		}

		map xmlcontent = (map) SCR::Read (.anyxml, $[
		    "file" : one_source_file,
		    "args" : $[
			"ForceArray" : 0,
			"ForceContent" : 0,
			"KeepRoot" : 0,
		    ]
		]);

		if (xmlcontent == nil || xmlcontent == $[]) {
		    y2error ("Can't read %1, SCR returned erroneous data: %2", one_source_file, xmlcontent);
		    return;
		}

		// bnc #300901
		boolean enabled = nil;

		if (is (xmlcontent["enabled"]:nil, boolean)) {
		    enabled = xmlcontent["enabled"]:false;
		} else if (is (xmlcontent["enabled"]:nil, string)) {
		    enabled = (xmlcontent["enabled"]:"false" == "true");
		}

		boolean auto_refresh = nil;

		if (is (xmlcontent["auto-refresh"]:nil, boolean)) {
		    auto_refresh = xmlcontent["auto-refresh"]:false;
		} else if (is (xmlcontent["auto-refresh"]:nil, string)) {
		    auto_refresh = (xmlcontent["auto-refresh"]:"false" == "true");
		}

		map <string, any> one_old_url = $[
		    "url" :	xmlcontent["url"]:nil,
		    "enabled" :	enabled,
		    "auto-refresh" : auto_refresh,
		    "name" :	xmlcontent["alias"]:nil,
		];

		foreach (string key, ["alias", "product-dir", "type"], {
		    if (haskey (xmlcontent, key)) {
			one_old_url[key] = xmlcontent[key]:"";
		    }
		});

		counter = counter + 1;
		old_urls[counter] = one_old_url;
	    });

	    y2milestone ("URLs: %1", old_urls);
	}
    }

    void ReadNewTypeURLs () {
	// New-type URLs
	new_urls = (list <map>) SCR::Read (.zypp_repos, dir_new);

	if (new_urls == nil || new_urls == []) {
	    y2milestone ("No new zypp sources on the target");
	} else {
	    y2milestone ("URLs: %1", new_urls);
	}
    }

    void CreateListTableUI () {
	Wizard::SetContents (
	    // TRANSLATORS: dialog caption
	    _("Previously Used Repositories"),
	    `VBox (
		// TRANSLATORS: dialog text, possibly multiline,
		// Please, do not use more than 50 characters per line.
		`Left (`Label (_("These repositories were found on the system
you are upgrading:"))),
		`Table (
		    `id ("table_of_repos"),
		    `opt (`notify, `keepSorting),
		    `header (
			// TRANSLATORS: Table header item
			_("Current Status"),
			// TRANSLATORS: Table header item
			_("Repository"),
			// TRANSLATORS: Table header item
			_("URL")
		    ),
		    []
		),
		`Left (`HBox (
		    // TRANSLATORS: Push button
		    `PushButton (`id (`edit), _("&Change...")),
		    `HSpacing (1),
		    // TRANSLATORS: Push button
		    `PushButton (`id (`toggle), _("&Toggle Status")),
		    `HStretch()
		))
	    ),
	    // TRANSLATORS: help text 1/3
	    _("<p>Here you see all software repositories found
on the system you are upgrading. Enable the ones you want to include in the upgrade process.</p>") +
	    // TRANSLATORS: help text 2/3
	    _("<p>To enable, remove or disable an URL, click on the
<b>Toggle Status</b> button or double-click on the respective table item.</p>") +
	    // TRANSLATORS: help text 3/3
	    _("<p>To change the URL, click on the <b>Change...</b> button.</p>"),
	    true,
	    true
	);
	Wizard::SetTitleIcon ("yast-sw_source");
    }

    list <map> urls = [];

    map <string, string> id_to_name = $[];

    map <string, string> status_map = $[
	// TRANSLATORS: Table item status (repository)
	"removed"	: _("Removed"),
	// TRANSLATORS: Table item status (repository)
	"enabled"	: _("Enabled"),
	// TRANSLATORS: Table item status (repository)
	"disabled"	: _("Disabled"),
    ];

    void RedrawListTableUI () {
	integer currentitem = (integer) UI::QueryWidget (`id ("table_of_repos"), `CurrentItem);

	integer counter = -1;
	list <term> items = maplist (map one_url, urls, {
	    counter = counter + 1;

	    id_to_name[sformat ("ID: %1", counter)] = one_url["name"]:_("Unknown");

	    return `item (
		`id (counter),
		status_map[one_url["new_status"]:"removed"]:_("Unknown"),
		// TRANSLATORS: Fallback name for a repository
		one_url["name"]:_("Unknown"),
		one_url["url"]:""
	    );
	});

	// bnc #390612
	items = sort (term a, term b, items, ``(a[2]:"" < b[2]:""));

	UI::ChangeWidget (`id ("table_of_repos"), `Items, items);

	if (currentitem != nil) {
	    UI::ChangeWidget (`id ("table_of_repos"), `CurrentItem, currentitem);
	}

	boolean enable_buttons = (size (items) > 0);
	UI::ChangeWidget (`id (`edit), `Enabled, enable_buttons);
	UI::ChangeWidget (`id (`toggle), `Enabled, enable_buttons);
    }

    // 'removed'	-> currently not enabled
    // 'enabled'	-> currently added as enabled
    // 'disabled'	-> currently added as disabled
    string FindCurrentRepoStatus (string alias) {
	if (alias == "" || alias == nil) {
	    y2error ("alias URL not defined!");
	    return "removed";
	}

	string ret = "removed";

	foreach (map one_url, already_registered_repos, {
	    if (alias == one_url["alias"]:"-A-") {
		ret = (one_url["enabled"]:false == true ? "enabled" : "disabled");
		break;
	    }
	});

	return ret;
    }

    string FindURLName (string id) {
	if (id == "" || id == nil) {
	    y2error ("Base URL not defined!");
	    return nil;
	}

	string ret = nil;

	foreach (map one_url, urls, {
	    if (id == one_url["id"]:"-A-" && one_url["name"]:"" != "") {
		ret = one_url["name"]:"";
		break;
	    }
	});

	return ret;
    }

    string FindURLType (string id) {
	if (id == "" || id == nil) {
	    y2error ("Base URL not defined!");
	    return "";
	}

	string ret = "";

	foreach (map one_url, urls, {
	    if (id == one_url["id"]:"-A-" && one_url["type"]:"" != "") {
		ret = one_url["type"]:"";
		break;
	    }
	});

	return ret;
    }

    void EditItem (integer currentitem) {
	if (currentitem == nil || currentitem < 0) {
	    y2error ("Cannot edit item: %1", currentitem);
	    return;
	}

	string url = urls[currentitem, "url"]:"";
	integer min_width = size (url);

	UI::OpenDialog (
	    `VBox (
		// TRANSLATORS: textentry
		`MinWidth (min_width, `TextEntry (`id (`url), _("&Repository URL"), url)),
		`VSpacing (1),
		`ButtonBox (
		    `PushButton (`id (`ok), `opt (`default, `okButton, `key_F10), Label::OKButton()),
		    `PushButton (`id (`cancel), `opt (`cancelButton, `key_F9), Label::CancelButton())
		)
	    )
	);
	
	any ret = UI::UserInput ();
	url = (string) UI::QueryWidget (`id (`url), `Value);
	UI::CloseDialog();

	if (ret == `cancel) {
	    return;
	}
	
	urls[currentitem, "url"] = url;
    }

    void UseOldOrNewURLs () {
	urls = [];

	// If some new (since 10.3 Alpha?) URLs found, use only them
	if (new_urls != nil && new_urls != []) {
	    foreach (map one_url_map, new_urls, {
		// bnc #300901
		boolean enabled = nil;

		// mapping url (zypp-based) keys to keys used in pkg-bindings
		if (is (one_url_map["enabled"]:0, integer)) {
		    enabled = (one_url_map["enabled"]:0 == 1);
		} else if (is (one_url_map["enabled"]:"0", string)) {
		    enabled = (one_url_map["enabled"]:"0" == "1");
		} else if (is (one_url_map["enabled"]:false, boolean)) {
		    enabled = one_url_map["enabled"]:false;
		}

		// bnc #387261
		boolean autorefresh = true;

		// mapping url (zypp-based) keys to keys used in pkg-bindings
		if (is (one_url_map["autorefresh"]:0, integer)) {
		    autorefresh = (one_url_map["autorefresh"]:0 == 1);
		} else if (is (one_url_map["autorefresh"]:"0", string)) {
		    autorefresh = (one_url_map["autorefresh"]:"0" == "1");
		} else if (is (one_url_map["autorefresh"]:false, boolean)) {
		    autorefresh = one_url_map["autorefresh"]:false;
		}

		boolean keeppackages = true;

		// mapping url (zypp-based) keys to keys used in pkg-bindings
		if (is (one_url_map["keeppackages"]:0, integer)) {
		    keeppackages = (one_url_map["keeppackages"]:0 == 1);
		} else if (is (one_url_map["keeppackages"]:"0", string)) {
		    keeppackages = (one_url_map["keeppackages"]:"0" == "1");
		} else if (is (one_url_map["keeppackages"]:false, boolean)) {
		    keeppackages = one_url_map["keeppackages"]:false;
		}

		map <string, any> new_url_map = $[
		    "autorefresh" : autorefresh,
		    "alias" : one_url_map["id"]:one_url_map["baseurl"]:"",
		    "url" : one_url_map["baseurl"]:nil,
		    "name" : (one_url_map["name"]:"" == "" ? one_url_map["id"]:"" : one_url_map["name"]:""),
		    "enabled" : enabled,
		    "keeppackages" : keeppackages,
		];

		if (haskey (one_url_map, "priority")) {
		    new_url_map["priority"] = one_url_map["priority"]:99;
		}

		// store the repo-type as well
		if (one_url_map["type"]:"" != "") {
		    new_url_map["type"] = one_url_map["type"]:"";
		}

		urls = add (urls, new_url_map);
	    });
	// Fallback, old URLs found
	// ... 10.1, 10.2
	} else if (old_urls != nil && old_urls != []) {
	    urls = old_urls;
	}

	integer id = -1;
	string url_alias = "";

	urls = maplist (map one_url, urls, {
	    id = id + 1;

	    // unique ID
	    one_url["id"] = sformat ("ID: %1", id);

	    // BNC #429059
	    if (haskey (one_url, "alias") && one_url["alias"]:nil != nil) {
		url_alias = sformat ("%1", one_url["alias"]:"");
		one_url["new_status"] = FindCurrentRepoStatus (url_alias);
	    } else {
		y2warning ("No 'alias' defined: %1", one_url);
		one_url["new_status"] = "removed";
	    }

	    one_url["initial_url_status"]  = one_url["new_status"]:"removed";
	    return one_url;
	});
    }

    /**
     * Function removes repositories already registered by the installation
     * from list of urls found on the system.
     */
    void RemoveInstallationReposFromUpgrededSystemOnes () {
	// Works only for the very first registered (installation) repo
	boolean found = false;

	// All already registered repos
	foreach (map one_registered_repo, already_registered_repos, {
	    if (one_registered_repo["enabled"]:true == false) {
		return;
	    }

	    if (found == true) {
		break;
	    }
	    found = true;

	    // if an installation repository is disabled, skip it
	    if (one_registered_repo["enabled"]:true == false) {
		y2milestone ("Repo %1 is not enabled, skipping", one_registered_repo["url"]:one_registered_repo["media"]:nil);
		return;
	    }

	    string registered_url  = one_registered_repo["url"]:"-A-";
	    string registered_name = one_registered_repo["name"]:"-A-";
	    string registered_dir  = one_registered_repo["path"]:"/";

	    // Remove them from repos being offered to user to enable/disable them
	    // Don't handle them at all, they have to stay untouched
	    // See bnc #360109
	    urls = filter (map one_from_urls, urls, {
		string one_url  = one_from_urls["url"]:"-B-";
		string one_name = one_from_urls["name"]:"-B-";
		string one_dir  = one_from_urls["path"]:"/";

		if (registered_url == one_url && registered_name == one_name && registered_dir == one_dir) {
		    y2milestone ("The same product (url) already in use, not handling it %1", one_registered_repo);
		    return false;
		} else {
		    return true;
		}
	    });
	});
    }

    // BNC #583155: Removed/Enabled/Disabled
    // Toggled this way: R/E/D/R/E/D/...
    string ToggleStatus (map repo_map) {
	string status = repo_map["new_status"]:"removed";

	if (status == "removed") {
	    status = "enabled";
	} else if (status == "enabled") {
	    status = "disabled";
	// disabled
	} else {
	    status = "removed";
	}

	return status;
    }

    symbol HandleOldSources () {
	y2milestone ("Offering: %1", urls);
	y2milestone ("Already registered: %1", already_registered_repos);

	CreateListTableUI();
	RedrawListTableUI();

	symbol ret = `next;
	any ui_ret = nil;

	while (true) {
	    ui_ret = UI::UserInput();

	    if (ui_ret == "table_of_repos") ui_ret = `toggle;

	    if (ui_ret == `toggle) {
		integer currentitem = (integer) UI::QueryWidget (`id ("table_of_repos"), `CurrentItem);
		if (currentitem != nil) {
		    // BNC #583155: Removed/Enabled/Disabled
		    urls[currentitem, "new_status"] = ToggleStatus (urls[currentitem]:$[]);
		    RedrawListTableUI();
		}
		continue;
	    } else if (ui_ret == `next) {
		ret = `next;
		break;
	    } else if (ui_ret == `back) {
		ret = `back;
		break;
	    } else if (ui_ret == `abort) {
		ret = `abort;
		break;
	    } else if (ui_ret == `edit) {
		integer currentitem = (integer) UI::QueryWidget (`id ("table_of_repos"), `CurrentItem);
		EditItem (currentitem);
		RedrawListTableUI();
	    } else {
		y2error ("Unknown UI input: %1", ui_ret);
	    }
	}

	return ret;
    }

    boolean NetworkRunning () {
	boolean ret = false;
	
	while (true) {
	    if (NetworkService::isNetworkRunning()) {
		ret = true;
		break;
	    }
	
	    // Network is not running
	    if (! Popup::AnyQuestion (
		// TRANSLATORS: popup header
		_("Network is not Configured"),
		// TRANSLATORS: popup question
		_("Remote repositories require an Internet connection.
Configure it?"),
		Label::YesButton(),
		Label::NoButton(),
		`yes
	    )) {
		y2milestone ("User decided not to setup the network");
		ret = false;
		break;
	    }

	    y2milestone ("User wants to setup the network");
	    // Call network-setup client
	    any netret = WFM::call("inst_network_setup");

	    if (netret == `abort) {
		y2milestone ("Aborting the network setup");
		break;
	    }
	}

	return ret;
    }

    void SetAddRemoveSourcesUI () {
	Wizard::SetContents (
	    // TRANSLATORS: dialog caption
	    _("Previously Used Repositories"),
	    `VBox (
		// TRANSLATORS: Progress text
		`Label (_("Adding and removing repositories..."))
	    ),
	    // TRANSLATORS: help text
	    _("<p>Please wait while repositories are being added and removed.</p>"),
	    false,
	    false
	);
	Wizard::SetTitleIcon ("yast-sw_source");
    }

    void SetAddRemoveSourcesProgress (
	list <integer> & sources_to_remove,
	list <string> & sources_to_add,
	list <string> & sources_to_add_disabled
    ) {
	list <string> actions_todo  = [];
	list <string> actions_doing = [];

	integer steps_nr = 0;

	if (size (sources_to_remove) > 0) {
	    y2milestone ("Remove %1 repos", sources_to_remove);
	    actions_todo	= add (actions_todo,  _("Remove unused repositories"));
	    actions_doing	= add (actions_doing, _("Removing unused repositories..."));
	    steps_nr		= steps_nr + size (sources_to_remove);
	}

	if (size (sources_to_add) > 0) {
	    y2milestone ("Add %1 enabled repos", sources_to_add);
	    actions_todo	= add (actions_todo,  _("Add enabled repositories"));
	    actions_doing	= add (actions_doing, _("Adding enabled repositories..."));
	    steps_nr		= steps_nr + size (sources_to_add);
	}

	if (size (sources_to_add_disabled) > 0) {
	    y2milestone ("Add %1 disabled repos", sources_to_add_disabled);
	    actions_todo	= add (actions_todo,  _("Add disabled repositories"));
	    actions_doing	= add (actions_doing, _("Adding disabled repositories..."));
	    steps_nr		= steps_nr + size (sources_to_add_disabled);
	}

	Progress::New (
	    // TRANSLATORS: dialog caption
	    _("Previously Used Repositories"),
	    _("Adding and removing repositories..."),
	    steps_nr,
	    actions_todo,
	    actions_doing,
	    // TRANSLATORS: help text
	    _("<p>Please wait while repositories are being added and removed.</p>")
	);
    }

    // See bnc #309317
    string GetUniqueAlias (string alias_orig) {
        if (alias_orig == nil) alias_orig = "";

        // all current aliases
        list <string> aliases = maplist (integer i, Pkg::SourceGetCurrent(false), {
            map info = Pkg::SourceGeneralData (i);
            return info["alias"]:"";
        });

        // default
        string alias = alias_orig;

        // repository alias must be unique
        // if it already exists add "_<number>" suffix to it
        integer idx = 1;
        while (contains (aliases, alias)) {
            alias = sformat("%1_%2", alias_orig, idx);
            idx = idx + 1;
        }

        if (alias_orig != alias) {
            y2milestone ("Alias '%1' changed to '%2'", alias_orig, alias);
        }

        return alias;
    }

    void AdjustRepoSettings (map & new_repo, string id) {
	if (id == nil || id == "") {
	    y2error ("Undefined ID: %1", id);
	    return;
	}

	foreach (map one_url, urls, {
	    if (one_url["id"]:"" == id) {
		y2milestone ("Matching: %1", one_url);

		// alias needs to be unique
		// bnc #309317
		//
		// alias is taken from the system first
		// bnc #387261
		//
		new_repo["alias"] = GetUniqueAlias (one_url["alias"]:"");

		foreach (string key, ["autorefresh", "gpgcheck", "keeppackages"], {
		    if (haskey (one_url, key))
			new_repo[key] = one_url[key]:true;
		});

		if (haskey (one_url, "priority"))
		    new_repo["priority"] = one_url["priority"]:99;

		break;
	    }
	});
    }

    void IUU_RemoveRepositories (list <integer> sources_to_remove) {
	if (size (sources_to_remove) == 0) {
	    return;
	}

	Progress::Title (_("Removing unused repositories..."));
	Progress::NextStage ();

	y2milestone ("Deleting repos: %1", sources_to_remove);
	foreach (integer one_id, sources_to_remove, {
	    Progress::NextStep ();
	    Pkg::SourceDelete (one_id);

	    AddOnProduct::add_on_products = (list <map <string, any> >) filter (
	        map one_addon, AddOnProduct::add_on_products, {
		    return one_addon["media"]:-42 != one_id;
		}
	    );
	     
	});
    }

    boolean InsertCorrectMediaHandler (string url, string name) {
	if (! regexpmatch (url, "^cd:/") && ! regexpmatch (url, "^dvd:/")) {
	    y2milestone ("URL is not a CD/DVD");
	    return true;
	}

	// true - OK, continue
	if (Popup::AnyQuestion (
	    _("Correct Media Requested"),
	    sformat(_("Make sure that media with label %1
is in the CD/DVD drive.

If you skip it, repository will not be added."), name),
	    Label::OKButton(),
	    Label::SkipButton(),
	    `yes
	) == true) {
	    Pkg::SourceReleaseAll();
	    return true;
	}

	// false - skip
	return false;
    }

    void IUU_AddEnabledRepositories (list <string> sources_to_add, map <string, string> & id_to_url) {
	if (size (sources_to_add) == 0) {
	    return;
	}

	Progress::Title (_("Adding enabled repositories..."));
	Progress::NextStage ();

	// Adding sources in a disabled state, then enable them
	// for the system upgrade
	    foreach (string one_id, sources_to_add, {
		y2milestone ("Adding repository: %1", one_id);
		Progress::NextStep ();
		string one_url = id_to_url[one_id]:"";
		string repo_name = id_to_name[one_id]:"";
		string pth = "/";

		if (InsertCorrectMediaHandler (one_url, repo_name) != true) {
		    y2warning ("Skipping source %1", one_id);
		    return;
		}

		string repo_type = Pkg::RepositoryProbe (one_url, "/");
		y2milestone ("Probed repository: %1 type: %2", one_url, repo_type);
		
		if (repo_type == nil || repo_type == "NONE") {
		    y2error ("Cannot add repository");
		    Report::Error (sformat(_("Cannot add repository %1
URL: %2"), repo_name, one_url));
		    return;
		}

		// see bnc #310209
		// Adding repositories with their correct names
		map <string, any> repoadd = $[
		    "enabled" : false,
		    "name" : repo_name,
		    "base_urls" : [one_url],
		    "prod_dir" : pth,
		    "type" : repo_type,
		    // bnc #543468, do not check aliases of repositories stored in Installation::destdir
		    "check_alias" : false,
		];
		AdjustRepoSettings (repoadd, one_id);
		y2milestone ("Adding repo (enabled): %1", repoadd);

		integer new_id = Pkg::RepositoryAdd (repoadd);
		if (new_id == nil || new_id == -1) {
		    y2error ("Error adding repository: %1", repoadd);
		    Report::Error (sformat(
			_("Cannot add enabled repository
Name: %1
URL: %2"),
			repo_name,
			one_url
		    ));
		    return;
		}

		if (new_id > -1) {
		    boolean repo_refresh = Pkg::SourceRefreshNow (new_id);
		    y2milestone ("Repository refreshed: %1", repo_refresh);

		    if (repo_refresh != true) {
			Report::Error (sformat (
			    // TRANSLATORS: error report
			    // %1 is replaced with repo-name, %2 with repo-URL
			    _("An error occurred while refreshing repository
Name: %1
URL: %2"),
			    repo_name,
			    one_url
			));
			return;
		    }

		    boolean repo_enable = Pkg::SourceSetEnabled (new_id, true);
		    y2milestone ("Repository enabled: %1", repo_enable);

		    if (repo_enable != true) {
			Report::Error (sformat (
			    // TRANSLATORS: error report
			    // %1 is replaced with repo-name, %2 with repo-URL
			    _("An error occurred when enabling repository
Name: %1
URL: %2"),
			    repo_name,
			    one_url
			));
			return;
		    }

		    AddOnProduct::Integrate (new_id);

		    map <string, string> prod = (map <string, string>) Pkg::SourceProductData (new_id);
		    y2milestone ("Product Data: %1", prod);

		    AddOnProduct::add_on_products = add (AddOnProduct::add_on_products, $[
			"media" : new_id,
			"media_url" : one_url,
			"product_dir" : pth,
			"product" : repo_name,
			"autoyast_product" : repo_name,
		    ]);
		}
	    });
    }

    void IUU_AddDisabledRepositories (list <string> sources_to_add_disabled, map <string, string> & id_to_url) {
	if (size (sources_to_add_disabled) == 0) {
	    return;
	}

	Progress::Title (_("Adding disabled repositories..."));
	Progress::NextStage ();

	// Adding the rest of sources in a disabled state
	// bnc #326342
	    y2milestone ("Adding DISABLED repos: %1", sources_to_add_disabled);

	    foreach (string one_id, sources_to_add_disabled, {
		Progress::NextStep ();
		string one_url = id_to_url[one_id]:"";
		string repo_name = id_to_name[one_id]:"";
		string pth = "/";

		if (InsertCorrectMediaHandler (one_url, repo_name) != true) {
		    y2warning ("Skipping source %1", one_id);
		    return;
		}

		// see bnc #310209
		// Adding repositories with their correct names
		map <string, any> repoadd = $[
		    "enabled" : false,
		    "name" : repo_name,
		    "base_urls" : [one_url],
		    "prod_dir" : pth,
		    // bnc #543468, do not check aliases of repositories stored in Installation::destdir
		    "check_alias" : false,
		];
		AdjustRepoSettings (repoadd, one_id);

		// do not probe! adding as disabled!
		string repo_type = FindURLType (one_url);
		if (repo_type != nil && repo_type != "") {
		    repoadd["type"] = repo_type;
		}
		
		y2milestone ("Adding repo (disabled): %1", repoadd);

		integer new_id = Pkg::RepositoryAdd (repoadd);
		if (new_id == nil || new_id == -1) {
		    y2error ("Error adding repository: %1", repoadd);
		    Report::Error (sformat(
			_("Cannot add disabled repository
Name: %1
URL: %2"),
			repo_name,
			one_url
		    ));
		}
	    });
    }

    boolean SourceIsRemote (string url) {
	if (regexpmatch (url, "^cd://"))	return false;
	if (regexpmatch (url, "^dvd://"))	return false;
	if (regexpmatch (url, "^disk://"))	return false;

	return true;
    }

    integer FindMediaNr (string alias, string url) {
	if (alias == "" || alias == nil) {
	    y2error ("alias not defined!");
	    return nil;
	}

	if (url == "" || url == nil) {
	    y2error ("URL not defined!");
	    return nil;
	}

	integer ret = nil;

	foreach (map one_url, already_registered_repos, {
	    if (alias == one_url["alias"]:"-A-" && url == one_url["url"]:"-A-") {
		ret = one_url["media"]:-1;
		break;
	    }
	});

	return ret;
    }

    symbol AddOrRemoveSources () {
	list <integer> sources_to_remove = [];

	list <string>  sources_to_add    = [];

	map <string, string> id_to_url = $[];

	// bnc #308763
	list <string> sources_to_add_disabled = [];

	// bnc #400823
	do_not_remove = Pkg::SourceGetCurrent(false)[0]:0;

	boolean some_sources_are_remote = false;

	foreach (map one_source, urls, {
	    string url = one_source["url"]:"";
	    string id = one_source["id"]:"";

	    if (SourceIsRemote (url)) {
		some_sources_are_remote = true;
	    }

	    id_to_url[id] = url;

	    // bnc #400823
	    integer current_medianr = FindMediaNr (tostring(one_source["alias"]:nil), tostring(one_source["url"]:nil));

	    if (do_not_remove == current_medianr) {
		y2milestone ("Skipping source: %1 (installation repository)", do_not_remove);
		return;
	    }

	    y2milestone ("Checking repo: %1", one_source);

	    // Source should be enabled at the end
	    if (one_source["new_status"]:"" == "enabled") {
		if (one_source["initial_url_status"]:"" == "enabled") {
		    y2milestone ("Source has been already enabled");
		} else {
		    // It's not yet enabled, add it
		    sources_to_add = add (sources_to_add, id);
		    y2milestone ("Source to add: %1", id);

		    // It's been already added but in disabled state
		    if (one_source["initial_url_status"]:"" == "disabled") {
			sources_to_remove = add (sources_to_remove, current_medianr);
			y2milestone ("Source to remove: %1", current_medianr);
		    }
		}

	    // Source should be removed (not added)
	    } else if (one_source["new_status"]:"" == "removed") {
		if (one_source["initial_url_status"]:"" == "removed") {
		    y2milestone ("Repository has been already removed");
		} else {
		    sources_to_remove = add (sources_to_remove, current_medianr);
		    y2milestone ("Source to remove: %1", current_medianr);
		}

	    // Source will be added in disabled state
	    // BNC #583155
	    } else if (one_source["new_status"]:"" == "disabled") {
		// It's been already added in enabled state
		if (one_source["initial_url_status"]:"" == "enabled") {
		    sources_to_remove = add (sources_to_remove, current_medianr);
		    y2milestone ("Source to remove: %1", current_medianr);
		}

		sources_to_add_disabled = add (sources_to_add_disabled, id);
		y2milestone ("Source to add disabled: %1", id);
	    }
	});

	if (size(sources_to_remove) > 0 || size (sources_to_add) > 0) {
	    SetAddRemoveSourcesUI();
	}

	// BNC #478024: Remote repositories need a running network
	if ((size (sources_to_add) > 0) && ! NetworkRunning()) {
	    y2milestone ("No network is running, trying inst_network_check fallback");
	    any ret = WFM::CallFunction ("inst_network_check", []);
	    y2milestone ("Called inst_network_check returned: %1", ret);
	}

	// Remote repositories without running network are registered
	// as disabled
	if ((size (sources_to_add) > 0) && ! NetworkRunning()) {
	    y2warning ("Network is not running, sources will be added in DISABLED state");
	    sources_to_add_disabled = (list <string>) union (sources_to_add_disabled, sources_to_add);
	    sources_to_add = [];
	}

	sources_to_remove = filter (integer one_source, sources_to_remove, {
	    return (one_source != do_not_remove);
	});

	sources_to_add_disabled = filter (string one_source, sources_to_add_disabled, {
	    return (one_source != sformat ("ID: %1", do_not_remove));
	});

	SetAddRemoveSourcesProgress (sources_to_remove, sources_to_add, sources_to_add_disabled);

	PackageCallbacks::RegisterEmptyProgressCallbacks();

	IUU_RemoveRepositories (sources_to_remove);

	// Add repositories in enabled state
	IUU_AddEnabledRepositories (sources_to_add, id_to_url);

	// Add repositories in disabled state
	IUU_AddDisabledRepositories (sources_to_add_disabled, id_to_url);

	Progress::Finish();

	PackageCallbacks::RestorePreviousProgressCallbacks();

	return `next;
    }

    void SetProgressUI () {
	Progress::New (
	    // TRANSLATORS: dialog caption
	    _("Reading Repositories Used on the System"),
	    " ",
	    2,
	    [
		// TRANSLATORS: progress step
		_("Read previously used repositories"),
		_("Initialize package manager"),
	    ],
	    [
		// TRANSLATORS: progress step
		_("Reading previously used repositories..."),
		_("Initializing package manager..."),
	    ],
	    // TRANSLATORS: dialog help
	    _("<p>Reading repositories. Please wait...</p>")
	);
	Wizard::SetTitleIcon ("yast-sw_source");
    }

    // for testing purpose
    if (Mode::normal()) Wizard::CreateDialog();

    SetProgressUI();
    Progress::NextStage();

    // Read the old repos (old type)
    if (FileUtils::Exists (dir_old))
	ReadOldTypeURLs ();
    else
	y2milestone ("Skipping ReadOldTypeURLs()");

    // Read the old repos (new type)
    if (FileUtils::Exists (dir_new))
	ReadNewTypeURLs ();
    else
	y2milestone ("Skipping ReadNewTypeURLs()");
    Progress::NextStage();

    boolean continue_processing = false;

    if ((old_urls != nil && old_urls != []) || (new_urls != nil && new_urls != [])) {
	continue_processing = true;
	// initialize zypp
	Pkg::TargetInitialize (Installation::destdir);
	// bnc #429080
	Pkg::TargetLoad();
	Pkg::SourceStartManager (false);

	list <integer> current_repos_list = Pkg::SourceGetCurrent (false /* not only enabled */);
	y2milestone ("Currently registered repos: %1", current_repos_list);

	foreach (integer one_id, current_repos_list, {
	    map source_data = Pkg::SourceGeneralData (one_id);
	    source_data["media"] = one_id;

	    already_registered_repos = add (already_registered_repos, source_data);
	});
    }

    // bnc #400823 
    do_not_remove = Pkg::SourceGetCurrent(false)[0]:0;

    UseOldOrNewURLs();
    RemoveInstallationReposFromUpgrededSystemOnes();

    Progress::NextStage();
    Progress::Finish();

    if (already_registered_repos == nil || size (already_registered_repos) < 1) {
	y2milestone ("No sources found");
	continue_processing = false;
    } else if (urls == nil || size (urls) < 1) {
	y2milestone ("No sources to offer");
	continue_processing = false;
    }

    if (continue_processing) {
	ret = HandleOldSources();
	if (ret == `next)
	    ret = AddOrRemoveSources();
    }

    // for testing purpose
    if (Mode::normal()) {
	if (ret == `next) Pkg::SourceSaveAll();
	Wizard::CloseDialog();
    }

    y2milestone ("Returning %1", ret);
    return ret;
}

ACC SHELL 2018