ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/SourceManagerSLP.ycp

/**
 * File:	modules/SourceManagerSLP.ycp
 * Package:	SLP Source Management
 * Summary:	SLP-related SourceManager settings
 * Authors:	Lukas Ocilka <locilka@suse.cz>
 * Status:      Work in Progress
 *
 * $Id: SourceManagerSLP.ycp 57028 2009-04-29 10:58:09Z lslezak $
 *
 * This module provides a complete set of functions that allows you to search
 * and select a new SLP repository.
 */
{
    import "SLP";
    import "Wizard";
    import "Directory";
    import "Stage";
    import "SuSEFirewall";
    import "Report";
    import "Label";
//    import "IP";
//    import "String";
//    import "FileUtils";

    textdomain "packager";
    module "SourceManagerSLP";

    term Icon (string icon_name) {
	map ui_info = UI::GetDisplayInfo();
	if ((boolean) ui_info["HasLocalImageSupport"]:false == false) return `Empty();

	return `Image (
	    sformat (
		"%1/22x22/apps/%2.png",
		Directory::icondir,
		icon_name
	    ),
	    "[x]"
	);
    }

    void CreateSearchUI () {
	UI::OpenDialog (
	    `VBox (
		`HBox (
		    `HSquash (`MarginBox (0.5, 0.2, Icon ("yast-you_server"))),
		    // translators: popup heading (progress popup)
		    `Left (`Heading(`id(`search_heading), _("SLP Search")))
		),
		`Left (
		    // progress information
		    `ReplacePoint(`id(`search_rp), `Label(_("Scanning network for installation services...")))
		)
	    )
	);
    }

    void CloseSearchUI () {
	UI::CloseDialog ();
    }

    void SetSearchUI (term content) {
	UI::ReplaceWidget(`id(`search_rp), content);
    }

    void SearchForSLPServices (list <map> & services) {
	// progress information
	SetSearchUI (`Label (_("Scanning network for installation services...")));
	y2milestone("scanning network: SLP::FindSrvs(\"install.suse\", \"\")");
	services = SLP::FindSrvs ("install.suse", "");
	y2milestone("Done, found %1 repositories", size(services));
    }

    void CreateSLPListFoundDialog (list <map> & services) {
	term filter_dialog = `Empty();
	boolean show_filter = false;

	// Show filter only for bigger amount of services
	if (size(services) > 15) {
	    show_filter = true;
	    filter_dialog = `MarginBox (0.5, 0.5, `Frame (
		// frame label
		_("Filter Form"),
		`VSquash (`HBox (
		    `HSquash(`MinWidth(
			22, `TextEntry (`id (`filter_text), "")
		    )),
		    // push button
		    `PushButton(`id(`filter), _("&Filter")),
		    `HStretch()
		))
	    ));
	}

	// bugzilla #209426
	// window size (in ncurses) based on currently available space
	map display_info = UI::GetDisplayInfo();
	integer min_size_x = 76;
	integer min_size_y = 19;
	if (display_info["TextMode"]:true) {
	    min_size_x = tointeger(display_info["Width"]:80)  * 3 / 4;
	    min_size_y = tointeger(display_info["Height"]:25) * 2 / 3 - 5;
	    if (min_size_x < 76) min_size_x = 76;
	    if (min_size_y < 18) min_size_y = 18;
	    y2milestone("X/x Y/y %1/%2 %3/%4",
		display_info["Width"]:80, min_size_x,
		display_info["Height"]:25, min_size_y);
	}

	UI::OpenDialog (
	    `VBox (
		`HBox (
		    `HSquash (`MarginBox (0.5, 0.2, Icon ("yast-you_server"))),
		    // translators: popup heading
		    `Left (`Heading(`id(`search_heading), _("Choose SLP Repository")))
		),
		filter_dialog,
		`MarginBox (0.5, 0, `MinSize(
		    min_size_x, min_size_y,
		    `Tree (
			`id (`tree_of_services),
			`opt (`notify),
			// tree label (tree of available products)
			_("Available Installation &Products"),
			[]
		    )
		)),
		`PushButton(`id(`details), _("&Details...")),
		`VSpacing (1),
		`HBox (
		    `PushButton (`id (`ok), `opt(`default), Label::SelectButton ()),
		    `VSpacing (1),
		    `PushButton (`id (`cancel), Label::CancelButton ())
		)
	    )
	);

	if (show_filter) {
	    UI::SetFocus(`filter_text);
	}
    }

    void InitDetailsButton () {
	integer current = (integer) UI::QueryWidget(`id(`tree_of_services), `CurrentItem);
	if (current == nil || current < 0) {
	    UI::ChangeWidget(`id(`details), `Enabled, false);
	} else {
	    UI::ChangeWidget(`id(`details), `Enabled, true);
	}
    }

    void ShowDetailsDialog (list <map> & services) {
	integer current = (integer) UI::QueryWidget(`id(`tree_of_services), `CurrentItem);
	if (current == nil || current < 0) {
	    y2error("No service selected, no details");
	    // error popup
	    Report::Error(_("No details are available."));
	} else {
	    map service_details = services[current]:$[];

	    if (service_details == $[]) {
		// message popup
		Report::Message(_("No details are available."));
	    } else {
		// maximal size allowed by UI (with a fallback)
		map display_information = UI::GetDisplayInfo();
		integer max_width = display_information["Width"]:1200;
		integer max_heigth = display_information["Height"]:500;
		// Graphical UI returns 1280x1024, textmode 80x25
		if (! display_information["TextMode"]:false) {
		    max_width = max_width / 15;
		    max_heigth = max_heigth / 18;
		}

		// maximal length of key and val found
		integer max_len_key = 0;
		integer max_len_val = 0;

		list <term> details = [];
		integer curr_len_key = 0;
		integer curr_len_val = 0;

		foreach (any key, any value, service_details, {
		    details = add (details, `item (`id (nil), tostring (key), tostring (value)));
		    curr_len_key = size (tostring (key));
		    curr_len_val = size (tostring (value));

		    if (curr_len_key != nil && curr_len_key > max_len_key) max_len_key = curr_len_key;
		    if (curr_len_val != nil && curr_len_val > max_len_val) max_len_val = curr_len_val;
		});
		// maximal key + maximal val (presented in table)
		integer max_len_total = max_len_key + max_len_val;

		// min X in UI
		integer min_size_x = max_len_total;
		if (min_size_x > max_width) min_size_x = max_width;
		if (min_size_x < 60) min_size_x = 60;

		// min Y in UI
		integer min_size_y = size (details) + 4;
		if (min_size_y > max_heigth) min_size_y = max_heigth;
		if (min_size_y < 14) min_size_y = 14;

		y2milestone ("Details min size: %1 x %2", min_size_x, min_size_y);

		UI::OpenDialog (
		    `VBox (
			`Left (`Heading(`id(`details_heading), _("Repository Details"))),
			`MinSize (
			    min_size_x, min_size_y,
			    `Table (
				`header(
				    // table header item
				    _("Key"),
				    // table header item
				    _("Value")
				),
				details
			    )
			),
			`VSpacing (1),
			`PushButton (`id(`ok), Label::OKButton())
		    )
		);
		UI::UserInput();
		UI::CloseDialog();
	    }
	}
    }

    /**
     * Initializes the listed SLP services.
     *
     * @param list <map> services (reference)
     * @param string regexp for services that should be visible (nil or "" for all)
     */
    void InitSLPListFoundDialog (list <map> & services, string regexp_string) {
	if (regexp_string == "") regexp_string = nil;

	map <string, list <integer> > inst_products = $[];
	string service_label = nil;

	// index in the list of 'services'
	integer service_counter = -1;

	foreach (map one_service, services, {
	    // always increase the service ID, must be consistent for all turns
	    service_counter = service_counter + 1;
	    
	    service_label = one_service["label"]:"";
	    
	    // bugzilla #219759
	    // service label can be empty (not defined)
	    if (service_label == "") {
		if (one_service["srvurl"]:"" != "") {
		    service_label = sformat (
			"%1: %2",
			_("Repository URL"),
			substring (one_service["srvurl"]:"", 21)
		    );
		} else {
		    y2error ("Wrong service definition: %1, key \"srvurl\" must not be empty.", one_service);
		}
	    }

	    // search works in "label" or in "srvurl" as a fallback
	    if (regexp_string != nil) {
		// filter out all services that don't match the regexp
		if (! regexpmatch (service_label, regexp_string)) return;
	    }

	    // define an empty list if it is not defined at all
	    if (inst_products[service_label]:nil == nil) inst_products[service_label] = [];
	    inst_products[service_label] = add (inst_products[service_label]:[], service_counter);
	});

	list <term> tree_of_services = [];
	list <term> urls_for_product = nil;
	integer product_counter = -1;
	string service_url = nil;

	// "SUSE Linux 10.2 x86_64":[10, 195]
	foreach (string one_product, list <integer> service_ids, inst_products, {
	    product_counter = product_counter + 1;

	    if (size(service_ids) == 1) {
		integer service_id = service_ids[0]:nil;
		tree_of_services[product_counter] = `item (`id(service_id), one_product);
	    } else {
		urls_for_product = [];
		foreach (integer service_id, service_ids, {
		    // removing "install.suse..."
		    service_url = substring(services[service_id, "srvurl"]:"", 21);

		    urls_for_product = add (
			urls_for_product,
			`item (`id (service_id), service_url)
		    );
		});
		// -1 for a product name without url (URLs are hidden below)
		tree_of_services[product_counter] = `item (`id (-1), one_product, urls_for_product);
	    }
	});

	UI::ChangeWidget (`id(`tree_of_services), `Items, tree_of_services);
	InitDetailsButton ();
    }

    string GetCurrentlySelectedURL (list <map> & services) {
	integer current = (integer) UI::QueryWidget(`id(`tree_of_services), `CurrentItem);

	if (current == nil || current < 0) {
	    // message popup
	    Report::Message (_("Please select one of offered options.
This product has more repositories available."));

	    return nil;
	} else {
	    string service_url = substring (services[current, "srvurl"]:"", 21);

	    if (service_url == nil || service_url == "") {
		y2error(
		    "An internal error occurred, service ID %1, %2 has no URL!",
		    current, services[current]:$[]
		);
		// popup error
		Report::Error (_("An internal error occurred.
The selected repository has no URL."));
		return nil;
	    } else {
		return service_url;
	    }
	}
    }

    string EscapeChars(string input, string escape)
    {
	string ret = input;

	if (escape != nil && size(escape) > 0)
	{
	    integer i = 0;
	    integer sz = size(escape);

	    while(i < sz)
	    {
		string ch = substring(escape, i, 1);
		y2debug("Escaping %1", ch);
		ret = mergestring(splitstring(ret, ch), "\\" + ch);
		i = i + 1;
	    };
	}

	return ret;
    }

    string HandleSLPListDialog (list <map> & services) {
	InitSLPListFoundDialog (services, nil);

	string dialog_ret = nil;
	any ret = nil;

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

	    if (ret == `cancel) {
		dialog_ret = nil;
		break;

	    } else if (ret == `ok) {
		dialog_ret = GetCurrentlySelectedURL (services);
		y2milestone("Selected URL: '%1'", dialog_ret);
		if (dialog_ret != "" && dialog_ret != nil) {
		    break;
		}

	    } else if (ret == `tree_of_services) {
		InitDetailsButton();

	    } else if (ret == `filter) {
		string regexp_string = (string) UI::QueryWidget (`id(`filter_text), `Value);
		y2milestone("original regexp_string: %1", regexp_string);
		// escape special character in the input string
		// \ must be the first character!
		regexp_string = EscapeChars(regexp_string, "\\(){}[]+^$|");
		y2milestone("escaped regexp_string: %1", regexp_string);

		InitSLPListFoundDialog (services, regexp_string);
	    } else if (ret == `details) {
		ShowDetailsDialog (services);

	    } else {
		y2error("Unknown ret: %1", ret);
	    }
	}

	return dialog_ret;
    }

    void CloseSLPListFoundDialog () {
	UI::CloseDialog();
    }

    void SearchForSLPServicesInfo (list <map> & services) {
	integer number_of_services = size (services);

	SetSearchUI (`Label (sformat (
	    // progress information, %1 stands for number of services
	    _("Collecting information of %1 services found..."),
	    number_of_services
	)));

	y2milestone("Collecting data about %1 services", number_of_services);

	list <map> new_services = [];

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

	integer counter = -1;
	foreach (map slp_service, services, {
	    counter = counter + 1;
	    string server_ip = slp_service["ip"]:"";
	    string service_url = slp_service["srvurl"]:"";

// bugzilla #219759
// /usr/bin/host not in inst-sys
// Anyway, it's not needed - key "ip" defines the server which has sent this reply
//
//	    if (!IP::Check4(server_ip))
//	    {
//		if (haskey(dns_cache, server_ip))
//		{
//		    server_ip = dns_cache[server_ip]:"";
//		}
//		else if (FileUtils::Exists ("/usr/bin/host"))
//		{
//		    string server_ip_quoted = "'" + String::Quote (server_ip) + "'";
//		    y2milestone ("Resolving host %1...", server_ip_quoted);
//		    map m = (map)SCR::Execute (.target.bash_output, sformat ("/usr/bin/host %1 | /bin/grep address", server_ip_quoted));
//
//		    if (m["exit"]:0 == 0)
//		    {
//			string out = m["stdout"]:"";
//			string ip = regexpsub (out, "has address (.*)$", "\\1");
//			if (ip != nil)
//			{
//			    y2milestone("...resolved to %1", ip);
//			    // cache the IP address
//			    dns_cache[server_ip] = ip;
//
//			    server_ip = ip;
//			}
//		    }
//		}
//	    }

	    // empty server_ip
	    if (service_url != "" && server_ip != "") {
		map attrs = SLP::GetUnicastAttrMap (service_url, server_ip);

		if (attrs != nil && attrs != $[]) {
		    slp_service = union (slp_service, attrs);
		}
	    }

	    new_services[counter] = slp_service;
	});

	y2milestone("Done");

	services = new_services;
    }

    /**
     * Function searches the SLP services on the current network.
     * If there are some SLP services, opens up a dialog containing
     * them and user has to select one or cancel the operation.
     * Selected URL is returned as string, otherwise a nil is returned.
     *
     * @return string service_URL
     */
    global string SelectOneSLPService () {

	CreateSearchUI();
	list <map> slp_services_found = [];
	SearchForSLPServices (slp_services_found);

	if (slp_services_found == nil || size(slp_services_found) == 0) {
	    y2warning("No SLP repositories found");
	} else {
	    SearchForSLPServicesInfo(slp_services_found);
	}
	CloseSearchUI();

	// no servers found
	if (slp_services_found == nil || size(slp_services_found) == 0) {
	    y2warning ("No SLP repositories were found");
	    if ((! Stage::initial ()) && SuSEFirewall::IsStarted ()) {
		Report::Message (
		    // error popup
		    _("No SLP repositories have been found on your network.
This could be caused by a running SuSEfirewall2,
which probably blocks the network scanning.")
		);
	    } else {
		Report::Message (
		    // error popup
		    _("No SLP repositories have been found on your network.")
		);
	    }
	    return nil;
	}

	CreateSLPListFoundDialog (slp_services_found);
	string selected_service = HandleSLPListDialog (slp_services_found);
	CloseSLPListFoundDialog ();

	return selected_service;
    }

    /**
     * Function scans for SLP installation servers on the network
     * @returns symbol one of `back, `next
     */
    global string AddSourceTypeSLP () {
	string url = SourceManagerSLP::SelectOneSLPService();
	y2milestone("Selected URL: %1", url);

	return url;
    }

/* EOF */
}

ACC SHELL 2018