home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / SourceManagerSLP.ycp < prev    next >
Text File  |  2006-11-29  |  13KB  |  485 lines

  1. /**
  2.  * File:    modules/SourceManagerSLP.ycp
  3.  * Package:    SLP Source Management
  4.  * Summary:    SLP-related SourceManager settings
  5.  * Authors:    Lukas Ocilka <locilka@suse.cz>
  6.  * Status:      Work in Progress
  7.  *
  8.  * $Id:$
  9.  *
  10.  * This module provides a complete set of functions that allows you to search
  11.  * and select a new SLP source.
  12.  */
  13. {
  14.     import "SLP";
  15.     import "Wizard";
  16.     import "Directory";
  17.     import "Stage";
  18.     import "SuSEFirewall";
  19.     import "Report";
  20.     import "Label";
  21. //    import "IP";
  22. //    import "String";
  23. //    import "FileUtils";
  24.  
  25.     textdomain "packager";
  26.     module "SourceManagerSLP";
  27.  
  28.     term Icon (string icon_name) {
  29.     map ui_info = UI::GetDisplayInfo();
  30.     if ((boolean) ui_info["HasLocalImageSupport"]:false == false) return `Empty();
  31.  
  32.     return `Image (
  33.         sformat (
  34.         "%1/current/icons/22x22/apps/%2.png",
  35.         Directory::themedir,
  36.         icon_name
  37.         ),
  38.         "[x]"
  39.     );
  40.     }
  41.  
  42.     void CreateSearchUI () {
  43.     UI::OpenDialog (
  44.         `VBox (
  45.         `HBox (
  46.             `HSquash (`MarginBox (0.5, 0.2, Icon ("yast-you_server"))),
  47.             // translators: popup heading (progress popup)
  48.             `Left (`Heading(`id(`search_heading), _("SLP Search")))
  49.         ),
  50.         `Left (
  51.             `ReplacePoint(`id(`search_rp), `Empty())
  52.         )
  53.         )
  54.     );
  55.     }
  56.  
  57.     void CloseSearchUI () {
  58.     UI::CloseDialog ();
  59.     }
  60.  
  61.     void SetSearchUI (term content) {
  62.     UI::ReplaceWidget(`id(`search_rp), content);
  63.     }
  64.  
  65.     void SearchForSLPServices (list <map> & services) {
  66.     // progress information
  67.     SetSearchUI (`Label (_("Scanning network for installation services...")));
  68.     y2milestone("scanning network: SLP::FindSrvs(\"install.suse\", \"\")");
  69.     services = SLP::FindSrvs ("install.suse", "");
  70.     y2milestone("Done, found %1 sources", size(services));
  71.     }
  72.  
  73.     void CreateSLPListFoundDialog (list <map> & services) {
  74.     term filter_dialog = `Empty();
  75.     boolean show_filter = false;
  76.  
  77.     // Show filter only for bigger amount of services
  78.     if (size(services) > 15) {
  79.         show_filter = true;
  80.         filter_dialog = `MarginBox (0.5, 0.5, `Frame (
  81.         // frame label
  82.         _("Filter Form"),
  83.         `VSquash (`HBox (
  84.             // Only some characters are valid 'A-Z a-z 0-9 .*-'
  85.             `HSquash(`TextEntry (`id (`filter_text), "")),
  86.             // push button
  87.             `PushButton(`id(`filter), `opt(`default), _("&Filter")),
  88.             `HStretch()
  89.         ))
  90.         ));
  91.     }
  92.  
  93.     // bugzilla #209426
  94.     // window size (in ncurses) based on currently available space
  95.     map display_info = UI::GetDisplayInfo();
  96.     integer min_size_x = 76;
  97.     integer min_size_y = 19;
  98.     if (display_info["TextMode"]:true) {
  99.         min_size_x = tointeger(display_info["Width"]:80)  * 3 / 4;
  100.         min_size_y = tointeger(display_info["Height"]:25) * 2 / 3 - 5;
  101.         if (min_size_x < 76) min_size_x = 76;
  102.         if (min_size_y < 18) min_size_y = 18;
  103.         y2milestone("X/x Y/y %1/%2 %3/%4",
  104.         display_info["Width"]:80, min_size_x,
  105.         display_info["Height"]:25, min_size_y);
  106.     }
  107.  
  108.     UI::OpenDialog (
  109.         `VBox (
  110.         `HBox (
  111.             `HSquash (`MarginBox (0.5, 0.2, Icon ("yast-you_server"))),
  112.             // translators: popup heading
  113.             `Left (`Heading(`id(`search_heading), _("Choose SLP Catalog")))
  114.         ),
  115.         filter_dialog,
  116.         `MarginBox (0.5, 0, `MinSize(
  117.             min_size_x, min_size_y,
  118.             `Tree (
  119.             `id (`tree_of_services),
  120.             `opt (`notify),
  121.             // tree label (tree of available products)
  122.             _("Available Installation Products"),
  123.             []
  124.             )
  125.         )),
  126.         `PushButton(`id(`details), _("Details...")),
  127.         `VSpacing (1),
  128.         `HBox (
  129.             `PushButton (`id (`ok), `opt(`default), Label::SelectButton ()),
  130.             `VSpacing (1),
  131.             `PushButton (`id (`cancel), Label::CancelButton ())
  132.         )
  133.         )
  134.     );
  135.  
  136.     if (show_filter) {
  137.         UI::SetFocus(`filter_text);
  138.     }
  139.     }
  140.  
  141.     void InitDetailsButton () {
  142.     integer current = (integer) UI::QueryWidget(`id(`tree_of_services), `CurrentItem);
  143.     if (current == nil || current < 0) {
  144.         UI::ChangeWidget(`id(`details), `Enabled, false);
  145.     } else {
  146.         UI::ChangeWidget(`id(`details), `Enabled, true);
  147.     }
  148.     }
  149.  
  150.     void ShowDetailsDialog (list <map> & services) {
  151.     integer current = (integer) UI::QueryWidget(`id(`tree_of_services), `CurrentItem);
  152.     if (current == nil || current < 0) {
  153.         y2error("No service selected, no details");
  154.         // error popup
  155.         Report::Error(_("No details are available."));
  156.     } else {
  157.         map service_details = services[current]:$[];
  158.  
  159.         if (service_details == $[]) {
  160.         // message popup
  161.         Report::Message(_("No details are available."));
  162.         } else {
  163.         list <term> details = [];
  164.         foreach (any key, any value, service_details, {
  165.             details = add (details, `item (`id(nil), tostring (key), tostring (value)));
  166.         });
  167.  
  168.         UI::OpenDialog (
  169.             `VBox (
  170.             `Left (`Heading(`id(`details_heading), _("Catalog Details"))),
  171.             `MinSize (
  172.                 60, 16,
  173.                 `Table (
  174.                 `header(
  175.                     // table header item
  176.                     _("Key"),
  177.                     // table header item
  178.                     _("Value")
  179.                 ),
  180.                 details
  181.                 )
  182.             ),
  183.             `VSpacing (1),
  184.             `PushButton (`id(`ok), Label::OKButton())
  185.             )
  186.         );
  187.         UI::UserInput();
  188.         UI::CloseDialog();
  189.         }
  190.     }
  191.     }
  192.  
  193.     /**
  194.      * Initializes the listed SLP services.
  195.      *
  196.      * @param list <map> services (reference)
  197.      * @param string regexp for services that should be visible (nil or "" for all)
  198.      */
  199.     void InitSLPListFoundDialog (list <map> & services, string regexp_string) {
  200.     if (regexp_string == "") regexp_string = nil;
  201.  
  202.     map <string, list <integer> > inst_products = $[];
  203.     string service_label = nil;
  204.  
  205.     // index in the list of 'services'
  206.     integer service_counter = -1;
  207.  
  208.     foreach (map one_service, services, {
  209.         // always increase the service ID, must be consistent for all turns
  210.         service_counter = service_counter + 1;
  211.         
  212.         service_label = one_service["label"]:"";
  213.         
  214.         // bugzilla #219759
  215.         // service label can be empty (not defined)
  216.         if (service_label == "") {
  217.         if (one_service["srvurl"]:"" != "") {
  218.             service_label = sformat (
  219.             "%1: %2",
  220.             _("Catalog URL"),
  221.             substring (one_service["srvurl"]:"", 21)
  222.             );
  223.         } else {
  224.             y2error ("Wrong service definition: %1, key \"srvurl\" must not be empty.", one_service);
  225.         }
  226.         }
  227.  
  228.         // search works in "label" or in "srvurl" as a fallback
  229.         if (regexp_string != nil) {
  230.         // filter out all services that don't match the regexp
  231.         if (! regexpmatch (service_label, regexp_string)) return;
  232.         }
  233.  
  234.         // define an empty list if it is not defined at all
  235.         if (inst_products[service_label]:nil == nil) inst_products[service_label] = [];
  236.         inst_products[service_label] = add (inst_products[service_label]:[], service_counter);
  237.     });
  238.  
  239.     list <term> tree_of_services = [];
  240.     list <term> urls_for_product = nil;
  241.     integer product_counter = -1;
  242.     string service_url = nil;
  243.  
  244.     // "SUSE Linux 10.2 x86_64":[10, 195]
  245.     foreach (string one_product, list <integer> service_ids, inst_products, {
  246.         product_counter = product_counter + 1;
  247.  
  248.         if (size(service_ids) == 1) {
  249.         integer service_id = service_ids[0]:nil;
  250.         tree_of_services[product_counter] = `item (`id(service_id), one_product);
  251.         } else {
  252.         urls_for_product = [];
  253.         foreach (integer service_id, service_ids, {
  254.             // removing "install.suse..."
  255.             service_url = substring(services[service_id, "srvurl"]:"", 21);
  256.  
  257.             urls_for_product = add (
  258.             urls_for_product,
  259.             `item (`id (service_id), service_url)
  260.             );
  261.         });
  262.         // -1 for a product name without url (URLs are hidden below)
  263.         tree_of_services[product_counter] = `item (`id (-1), one_product, urls_for_product);
  264.         }
  265.     });
  266.  
  267.     UI::ChangeWidget (`id(`tree_of_services), `Items, tree_of_services);
  268.     InitDetailsButton ();
  269.     }
  270.  
  271.     string GetCurrentlySelectedURL (list <map> & services) {
  272.     integer current = (integer) UI::QueryWidget(`id(`tree_of_services), `CurrentItem);
  273.  
  274.     if (current == nil || current < 0) {
  275.         // message popup
  276.         Report::Message (_("Please, select one of offered options.
  277. This product has more installation sources available."));
  278.  
  279.         return nil;
  280.     } else {
  281.         string service_url = substring (services[current, "srvurl"]:"", 21);
  282.  
  283.         if (service_url == nil || service_url == "") {
  284.         y2error(
  285.             "An internal error occurred, service ID %1, %2 has no URL!",
  286.             current, services[current]:$[]
  287.         );
  288.         // popup error
  289.         Report::Error (_("An internal error occurred.
  290. The selected source has no URL."));
  291.         return nil;
  292.         } else {
  293.         return service_url;
  294.         }
  295.     }
  296.     }
  297.  
  298.     string EscapeChars(string input, string escape)
  299.     {
  300.     string ret = input;
  301.  
  302.     if (escape != nil && size(escape) > 0)
  303.     {
  304.         integer i = 0;
  305.         integer sz = size(escape);
  306.  
  307.         while(i < sz)
  308.         {
  309.         string ch = substring(escape, i, 1);
  310.         y2debug("Escaping %1", ch);
  311.         ret = mergestring(splitstring(ret, ch), "\\" + ch);
  312.         i = i + 1;
  313.         };
  314.     }
  315.  
  316.     return ret;
  317.     }
  318.  
  319.     string HandleSLPListDialog (list <map> & services) {
  320.     InitSLPListFoundDialog (services, nil);
  321.  
  322.     string dialog_ret = nil;
  323.     any ret = nil;
  324.  
  325.     while (true) {
  326.         ret = UI::UserInput();
  327.  
  328.         if (ret == `cancel) {
  329.         dialog_ret = nil;
  330.         break;
  331.  
  332.         } else if (ret == `ok) {
  333.         dialog_ret = GetCurrentlySelectedURL (services);
  334.         y2milestone("Selected URL: '%1'", dialog_ret);
  335.         if (dialog_ret != "" && dialog_ret != nil) {
  336.             break;
  337.         }
  338.  
  339.         } else if (ret == `tree_of_services) {
  340.         InitDetailsButton();
  341.  
  342.         } else if (ret == `filter) {
  343.         string regexp_string = (string) UI::QueryWidget (`id(`filter_text), `Value);
  344.         y2milestone("original regexp_string: %1", regexp_string);
  345.         // escape special character in the input string
  346.         // \ must be the first character!
  347.         regexp_string = EscapeChars(regexp_string, "\\(){}[]+^$|");
  348.         y2milestone("escaped regexp_string: %1", regexp_string);
  349.  
  350.         InitSLPListFoundDialog (services, regexp_string);
  351.         } else if (ret == `details) {
  352.         ShowDetailsDialog (services);
  353.  
  354.         } else {
  355.         y2error("Unknown ret: %1", ret);
  356.         }
  357.     }
  358.  
  359.     return dialog_ret;
  360.     }
  361.  
  362.     void CloseSLPListFoundDialog () {
  363.     UI::CloseDialog();
  364.     }
  365.  
  366.     void SearchForSLPServicesInfo (list <map> & services) {
  367.     integer number_of_services = size (services);
  368.  
  369.     SetSearchUI (`Label (sformat (
  370.         // progress information, %1 stands for number of services
  371.         _("Collecting information of %1 services found..."),
  372.         number_of_services
  373.     )));
  374.  
  375.     y2milestone("Collecting data about %1 services", number_of_services);
  376.  
  377.     list <map> new_services = [];
  378.  
  379.     map<string,string> dns_cache = $[];
  380.  
  381.     integer counter = -1;
  382.     foreach (map slp_service, services, {
  383.         counter = counter + 1;
  384.         string server_ip = slp_service["ip"]:"";
  385.         string service_url = slp_service["srvurl"]:"";
  386.  
  387. // bugzilla #219759
  388. // /usr/bin/host not in inst-sys
  389. // Anyway, it's not needed - key "ip" defines the server which has sent this reply
  390. //
  391. //        if (!IP::Check4(server_ip))
  392. //        {
  393. //        if (haskey(dns_cache, server_ip))
  394. //        {
  395. //            server_ip = dns_cache[server_ip]:"";
  396. //        }
  397. //        else if (FileUtils::Exists ("/usr/bin/host"))
  398. //        {
  399. //            string server_ip_quoted = "'" + String::Quote (server_ip) + "'";
  400. //            y2milestone ("Resolving host %1...", server_ip_quoted);
  401. //            map m = (map)SCR::Execute (.target.bash_output, sformat ("/usr/bin/host %1 | /bin/grep address", server_ip_quoted));
  402. //
  403. //            if (m["exit"]:0 == 0)
  404. //            {
  405. //            string out = m["stdout"]:"";
  406. //            string ip = regexpsub (out, "has address (.*)$", "\\1");
  407. //            if (ip != nil)
  408. //            {
  409. //                y2milestone("...resolved to %1", ip);
  410. //                // cache the IP address
  411. //                dns_cache[server_ip] = ip;
  412. //
  413. //                server_ip = ip;
  414. //            }
  415. //            }
  416. //        }
  417. //        }
  418.  
  419.         // empty server_ip
  420.         if (service_url != "" && server_ip != "") {
  421.         map attrs = SLP::GetUnicastAttrMap (service_url, server_ip);
  422.  
  423.         if (attrs != nil && attrs != $[]) {
  424.             slp_service = union (slp_service, attrs);
  425.         }
  426.         }
  427.  
  428.         new_services[counter] = slp_service;
  429.     });
  430.  
  431.     y2milestone("Done");
  432.  
  433.     services = new_services;
  434.     }
  435.  
  436.     /**
  437.      * Function searches the SLP services on the current network.
  438.      * If there are some SLP services, opens up a dialog containing
  439.      * them and user has to select one or cancel the operation.
  440.      * Selected URL is returned as string, otherwise a nil is returned.
  441.      *
  442.      * @return string service_URL
  443.      */
  444.     global string SelectOneSLPService () {
  445.  
  446.     CreateSearchUI();
  447.     list <map> slp_services_found = [];
  448.     SearchForSLPServices (slp_services_found);
  449.  
  450.     if (slp_services_found == nil || size(slp_services_found) == 0) {
  451.         y2warning("No SLP catalogs found");
  452.     } else {
  453.         SearchForSLPServicesInfo(slp_services_found);
  454.     }
  455.     CloseSearchUI();
  456.  
  457.     // no servers found
  458.     if (slp_services_found == nil || size(slp_services_found) == 0) {
  459.         y2warning ("No SLP catalogs were found");
  460.         if ((! Stage::initial ()) && SuSEFirewall::IsStarted ()) {
  461.         Report::Message (
  462.             // error popup
  463.             _("No SLP catalogs have been found on your network.
  464. This could be caused by a running SuSEfirewall2,
  465. which probably blocks the network scanning.")
  466.         );
  467.         } else {
  468.         Report::Message (
  469.             // error popup
  470.             _("No SLP catalogs have been found on your network.")
  471.         );
  472.         }
  473.         return nil;
  474.     }
  475.  
  476.     CreateSLPListFoundDialog (slp_services_found);
  477.     string selected_service = HandleSLPListDialog (slp_services_found);
  478.     CloseSLPListFoundDialog ();
  479.  
  480.     return selected_service;
  481.     }
  482.  
  483. /* EOF */
  484. }
  485.