ACC SHELL

Path : /usr/share/YaST2/include/nfs/
File Upload :
Current File : //usr/share/YaST2/include/nfs/ui.ycp

/**
 * File:
 *   ui.ycp
 *
 * Module:
 *   Configuration of nfs
 *
 * Summary:
 *   Network NFS client dialogs
 *
 * Authors:
 *   Jan Holesovsky <kendy@suse.cz>
 *   Dan Vesely <dan@suse.cz>
 *   Martin Vidner <mvidner@suse.cz>
 *
 * $Id: ui.ycp 62074 2010-05-27 13:24:03Z mvidner $
 *
 * Network NFS client dialogs
 *
 */

{
    textdomain "nfs";

    import "CWMFirewallInterfaces";
    import "Hostname";
    import "FileUtils";
    import "Label";
    import "Nfs";
    import "Popup";
    import "SuSEFirewall";
    import "Wizard";
    include "nfs/routines.ycp";

    /**
     * Read settings dialog
     * @return `abort if aborted and `next otherwise
     */
    symbol ReadDialog() {
	boolean ret = nil;
	ret = Nfs::Read ();
	return ret ? `next : `abort;
    }

    /**
     * Write settings dialog
     * @return `abort if aborted and `next otherwise
     */
    symbol WriteDialog() {
	boolean ret = Nfs::Write ();
	return ret ? `next : `abort;
    }

    /**
     * Caches names of nfs servers for GetFstabEntry
     */

    list<string> hosts = nil;

    /**
     * Let the user choose one of a list of items
     * @param title	selectionbox title
     * @param items	a list of items
     * @return		one item or nil
     */
    define string ChooseItem (string title, list<string> items) ``{
	string item = nil;

	UI::OpenDialog (
	    `VBox (
		`HSpacing (40),
		`HBox (
		    `SelectionBox (`id (`items), title, items),
		    `VSpacing(10)
		    ),
		`ButtonBox (
		    `PushButton (`id (`ok), `opt (`default, `key_F10),
				 Label::OKButton ()),
		    `PushButton (`id (`cancel), `opt (`key_F9),
				 Label::CancelButton())
		    )
		));
	UI::SetFocus (`id (`items));
	any ret = nil;
	do
	{
	    ret = UI::UserInput();
	}
	while (ret != `cancel && ret != `ok);

	if (ret == `ok)
	{
	    item = (string) UI::QueryWidget (`id (`items), `CurrentItem);
	}
	UI::CloseDialog();

	return item;
    }

    /**
     * Find out whether this nfs host really exists
     * @param hname	hostname
     * @return true if it exists, false otherwise
     */
    define boolean HostnameExists( string hname ){
	string prog_name = "/usr/bin/host";
	boolean ret = false;

	if (FileUtils::Exists( prog_name ))
	{
	    map out = (map) SCR::Execute(.target.bash_output,
			   sformat("%1 %2",prog_name, hname ));

	    ret = (out["exit"]: -1 == 0);
	    y2debug("DNS lookup of %1 returned %2", hname, ret );
	}
	else
	{
	   y2warning("Cannot DNS lookup %1, will not propose default hostname", hname);
	}

	return ret;
    }

    /* Return convenient hostname (FaTE #302863) to be proposed
     * i.e. nfs + current domain (nfs. + suse.cz)
     * @return string 	proposed hostname
     */
    define string ProposeHostname() {
	string ret = "";
	string cur_domain = Hostname::CurrentDomain();

	if (cur_domain != nil || cur_domain != "")
        {
	    ret = "nfs." + cur_domain;
	}
	return ret;
    }

    /**
     * Give me one name from the list of hosts
     * @param hosts	a list of hostnames
     * @return		a hostname
     */
    define string ChooseHostName(list<string> hosts) ``{
	Wizard::SetScreenShotName ("nfs-client-1aa-hosts");
	// selection box label
	// changed from "Remote hosts" because now it shows
	// NFS servers only
	string ret = ChooseItem (_("&NFS Servers"), hosts);
	Wizard::RestoreScreenShotName ();
	return ret;
    }

    /**
     * Give me one name from the list of exports
     * @param exports	a list of exports
     * @return		an export
     */
    define string ChooseExport (list<string> exports) ``{
	Wizard::SetScreenShotName ("nfs-client-1ab-exports");
	// selection box label
	string ret = ChooseItem (_("&Exported Directories"), exports);
	Wizard::RestoreScreenShotName ();
	return ret;
    }

    /**
     * Nicely put a `TextEntry and its helper `PushButton together
     * @param text   textentry widget
     * @param button pushbutton widget
     * @return a HBox
     */
    define term TextAndButton (term text, term button) ``{
	return `HBox (
	    `Bottom (text),
	    `HSpacing(0.5),
	    `Bottom (button)
	    );
    }
    /**
     * Ask user for an entry.
     * @param fstab_ent	$["spec": "file": "mntops":] or nil
     * @param existing	list of fstab entries for duplicate mount-point checking
     * @return		a nfs_entry or nil
     */
    define map<string,any> GetFstabEntry(map<string,any> fstab_ent, list<map> existing) ``{
	Wizard::SetScreenShotName ("nfs-client-1a-edit");

	string server = "";
	string pth = "";
	string mount = "";
	boolean nfs4 = false;
	string options = "defaults";
	list <string> servers = [ ];
	string old = "";

	if (fstab_ent != nil)
	{
	    term couple = SpecToServPath(fstab_ent["spec"]:"");
	    server = couple[0]:"";
	    pth = couple[1]:"";
	    mount = fstab_ent["file"]:"";
	    nfs4 = fstab_ent["vfstype"]:"" == "nfs4";
	    options = fstab_ent["mntops"]:"";
	    servers = [ server ];
	    old = fstab_ent["spec"]:"";
	}
        else
	{
	    string proposed_server = ProposeHostname();
	    if ( HostnameExists( proposed_server ) )
	        servers = [ proposed_server ];
	}

	UI::OpenDialog(
	    `opt(`decorated),
	    `HBox(
		`HSpacing(1),
		`VBox(
		    `VSpacing(0.2),
		    `HBox(
		        TextAndButton (
			`ComboBox(
			    `id(`serverent),`opt(`editable),
			    // text entry label
			    _("&NFS Server Hostname"), servers ),
			// pushbutton label
			// choose a host from a list
			// appears in help text too
			`PushButton (`id (`choose), _("Choo&se"))
			),
			`HSpacing(0.5),
			TextAndButton (
			    `TextEntry(`id(`pathent),
				       // textentry label
				       _("&Remote Directory"), pth),
			    // pushbutton label,
			    // select from a list of remote filesystems
			    // make it short
			    // appears in help text too
			    `PushButton (`id (`pathent_list), _("&Select"))
			    )
		    ),
		    `Left( `CheckBox(`id(`nfs4),  _("NFS&v4 Share"), nfs4)),
		    `Left(
			TextAndButton (
			    `TextEntry(`id(`mountent),
				       // textentry label
				       _("&Mount Point (local)"), mount),
			    // button label
			    // browse directories to select a mount point
			    // appears in help text too
			    `PushButton(`id(`browse), _("&Browse"))
			    )
			),
		    // textentry label
		    `VSpacing(0.2),
		    `TextEntry(`id(`optionsent), _("O&ptions"), options),
		    `VSpacing(0.2),
		    `ButtonBox(
			`PushButton(`id(`ok), `opt(`default, `key_F10), Label::OKButton()),
			`PushButton(`id(`cancel), `opt (`key_F9), Label::CancelButton()),
			`PushButton(`id(`help), `opt (`key_F1), Label::HelpButton())),
		    `VSpacing(0.2)),
		`HSpacing(1)
		));
	UI::ChangeWidget(`id(`serverent), `Value, server);
	UI::SetFocus (`id (`serverent));

	any ret = nil;
	do
	{
	    ret = UI::UserInput();

	    if (ret == `choose)
	    {
		if (hosts == nil)
		{
		    //newer, shinier, better rpcinfo from rpcbind (#450056)
		    string prog_name = "/sbin/rpcinfo";
		    string delim = "";

		    //fallback from glibc (uses different field separators, grr :( )
		    if( !FileUtils::Exists(prog_name) )
		    {
			prog_name = "/usr/sbin/rpcinfo";
			delim = "-d ' ' ";
		    }

		    // label message
		    UI::OpenDialog(`Label(_("Scanning for hosts on this LAN...")));
		    // #71064
		    // this works also if ICMP broadcasts are ignored
		    string cmd = prog_name + " -b mountd 1 | cut " + delim + "-f 2 | sort -u";
		    map out = (map) SCR::Execute (.target.bash_output, cmd);
		    hosts = filter (string s, splitstring (out["stdout"]:"", "\n"), ``( s != ""));
		    UI::CloseDialog();

		}
		if( hosts == [] || hosts == nil )
		{
		    //Translators: 1st part of error message
		    string error_msg = _("No NFS server has been found on your network.");

		    if ( SuSEFirewall::GetStartService() )
		    {
			//Translators: 2nd part of error message (1st one is 'No nfs servers have been found ...)
		        error_msg = error_msg + _("\nThis could be caused by a running SuSEfirewall2,
which probably blocks the network scanning.");
		    }
		    Report::Error(error_msg);
		 }
		 else
		 {
		     string host = ChooseHostName(hosts);
		     if (host != nil)
		     {
		        UI::ChangeWidget(`id(`serverent), `Value, host);
		     }
		 }
	    }
	    else if (ret == `pathent_list)
	    {
		string server = (string) UI::QueryWidget(`id(`serverent), `Value);
		boolean v4 = (boolean) UI::QueryWidget(`id(`nfs4), `Value);

		if (!CheckHostName (server))
		{
		    UI::SetFocus (`id (`serverent));
		    continue;
		}

		UI::OpenDialog (
		    `Label (
			// Popup dialog, %1 is a host name
			sformat (_("Getting directory list for \"%1\"..."),
				 server)
			));
		list<string> dirs = [];

		// showmounts does not work for nfsv4 (#466454)
		if (v4)
		{
		    string tmpdir = Nfs::Mount(server, "/", nil, "ro", "nfs4");

		    // This is completely stupid way how to explore what can be mounted
		    // and I even don't know if it is correct. Maybe 'find tmpdir -xdev -type d'
		    // should be used instead. No clue :(
		    dirs = maplist( string dirent, (list <string> ) SCR::Read(.target.dir, tmpdir), {
			return "/" + dirent;
		    });
		    dirs = prepend(dirs, "/");
		    Nfs::Unmount( tmpdir );
		}
		else
		{
		    dirs = (list<string>) SCR::Read (.net.showexports, server);
		}

		if (dirs == nil)
		{
		    dirs = ["internal error"];
		}
		UI::CloseDialog ();
		string dir = ChooseExport (dirs);
		if (dir != nil)
		{
		    UI::ChangeWidget (`id (`pathent), `Value, dir);
		}
	    }
	    else if (ret == `browse)
	    {
		string dir = (string) UI::QueryWidget(`id (`mountent), `Value);
		if (dir == nil || size (dir) == 0)
		{
		    dir = "/";
		}

		// heading for a directory selection dialog
		dir = UI::AskForExistingDirectory(dir, _("Select the Mount Point"));

		if (dir != nil && size(dir) > 0)
		{
		    UI::ChangeWidget (`id (`mountent), `Value, dir);
		}
	    }
	    else if (ret == `ok)
	    {
		server = (string) UI::QueryWidget(`id(`serverent), `Value);
		pth = StripExtraSlash ((string) UI::QueryWidget(`id(`pathent), `Value));
		mount = StripExtraSlash ((string) UI::QueryWidget(`id(`mountent), `Value));
		nfs4 = (boolean) UI::QueryWidget(`id(`nfs4), `Value);
		options = deletechars ((string) UI::QueryWidget(`id(`optionsent), `Value), " ");

		ret = nil;
		string options_error = check_options (options);
		if (!CheckHostName (server))
		{
		    UI::SetFocus (`id (`serverent));
		}
		else if (! CheckPath (pth))
		{
		    UI::SetFocus (`id (`pathent));
		}
		else if (! CheckPath (mount) || IsMpInFstab (existing, mount))
		{
		    UI::SetFocus (`id (`mountent));
		}
		else if (size (options_error) > 0)
		{
		    Popup::Error(options_error);
		    UI::SetFocus (`id (`optionsent));
		}
		else
		{
		    fstab_ent = $[
			"spec"    : server+":"+pth,
			"file"    : mount,
			"vfstype" : nfs4 ? "nfs4" : "nfs",
			"mntops"  : options,
			];
		    if (old != (server+":"+pth))
			fstab_ent = add(fstab_ent, "old", old);
		    ret = `ok;
		}
	    }
	    else if (ret == `help)
	    {
		//help text 1/4
		// change: locally defined -> servers on LAN
		string helptext = _("<p>Enter the <b>NFS Server Hostname</b>.  With
<b>Choose</b>, browse through a list of
NFS servers on the local network.</p>
");
		// help text 2/4
		// added "Select" button
		helptext = helptext + _("<p>In <b>Remote File System</b>,
enter the path to the directory on the NFS server.  Use
<b>Select</b> to select one from those exported by the server.
</p>");
		// help text 3/4
		helptext = helptext + _("<p>		
For <b>Mount Point</b>, enter the path in the local file system where the directory should be mounted. With
<b>Browse</b>, select your mount point
interactively.</p>");
		// help text 4/4
		helptext = helptext + _("<p>For a list of <b>Options</b>,
read the man page mount(8).</p>");
		// popup heading
		Popup::LongText (_("Help"), `RichText (helptext), 50, 18);
	    }
	}
	while (ret != `ok && ret != `cancel);

	UI::CloseDialog();
	Wizard::RestoreScreenShotName ();

	if (ret == `ok)
	    return fstab_ent;
	return nil;
    }

    // firewall widget using CWM
    map<string, any> fw_settings = $[
        "services": [ "service:nfs-client" ],
	"display_details": true,
    ];
    map<string,any> fw_cwm_widget = CWMFirewallInterfaces::CreateOpenFirewallWidget (fw_settings);

    list< map <string,any> > nfs_entries = Nfs::nfs_entries;
    map <string, any> modify_line = $[];

    // Help, part 1 of 3
    string help_text1 = _("<p>The table contains all directories 
exported from remote servers and mounted locally via NFS (NFS shares).</p>") +

    // Help, part 2 of 3
 _("<p>Each NFS share is identified by remote NFS server address and
exported directory, local directory where the remote directory is mounted, 
NFS type (either plain nfs or nfsv4) and mount options. For further information 
about mounting NFS and mount options, refer to <tt>man nfs.</tt></p>") +

    // Help, part 3 of 3
_("<p>To mount a new NFS share, use <B>Add</B> button. To change the configuration of
currently mounted share, use <B>Edit</B> button. Remove and unmount selected share by 
<B>Delete</B> button.</p>");


    string help_text2 = _("<p>If you need to access NFSv4 shares (NFSv4 is a newer version
of NFS protocol), check <b>Enable NFSv4</b> option. In that case, you might need to supply
specific <b>NFSv4 Domain Name</b>, required for correct setting of file/directory access
rights.</p>") + fw_cwm_widget["help"]:"";

    void EnableDisableButtons()
    {
	UI::ChangeWidget(`id(`editbut), `Enabled, ( nfs_entries != [] ) );
	UI::ChangeWidget(`id(`delbut), `Enabled, ( nfs_entries != [] ) );
    }

    term FstabTab()
    {
	term fstab_content =
	    `VBox(
		`Table(`id(`fstable), `opt(`notify, `immediate),
		       `header(
			   // table header
			   _("Server")+"  ",
			   _("Remote Directory")+"  ",
			   // table header
			   _("Mount Point")+"  ",
			   // table header
			   _("NFS Type"),
			   // table header
			   _("Options")+"  "),
		       FstabTableItems(nfs_entries)),
		`HBox(`PushButton(`id(`newbut), `opt (`key_F3),
				  Label::AddButton ()),
		      `PushButton(`id(`editbut), `opt (`key_F4),
				  Label::EditButton ()),
		      `PushButton(`id(`delbut), `opt (`key_F5),
				  Label::DeleteButton ()),
		      // #211570
		      `HStretch ())
	    );

	return fstab_content;

    }

    term SettingsTab()
    {
	term settings_content =
	    `VBox(
	        //`VSpacing (1),
	        `HBox(
	            `Left(`CheckBox(`id(`enable_nfs4), `opt(`notify), _("Enable NFSv4"))),
	            `Left(`InputField(`id(`nfs4_domain), _("NFSv4 Domain Name"))),
	            `HStretch()
	        ),
	        `VSpacing (1),
	        fw_cwm_widget["custom_widget"]:`Empty (),
		`VStretch()
	    );

	return settings_content;
    }

    term MainDialogLayout()
    {
	term contents =
	    `VBox(
		`DumbTab(
		    [ `item(`id(`overview),_("&NFS Shares")),
		      `item(`id(`settings), _("NFS &Settings")) ],
	            `ReplacePoint(`id(`rp), FstabTab())
		)
	    );

	return contents;
    }

    void InitFstabEntries( )
    {
        UI::ChangeWidget (`id(`fstable), `Items, FstabTableItems (nfs_entries));
	EnableDisableButtons();

    }
    
    void InitSettings( )
    {
        CWMFirewallInterfaces::OpenFirewallInit (fw_cwm_widget, "");
        UI::ChangeWidget(`id(`enable_nfs4), `Value, Nfs::nfs4_enabled);
	UI::ChangeWidget( `id(`nfs4_domain), `Enabled, Nfs::nfs4_enabled);
	UI::ChangeWidget(`id(`nfs4_domain), `Value, Nfs::idmapd_domain);
    }
    
    void SaveFstabEntries( )
    {
        Nfs::nfs_entries = nfs_entries;
    }
    
    void SaveSettings( map event )
    {
        CWMFirewallInterfaces::OpenFirewallStore (fw_cwm_widget, "", event);
        Nfs::nfs4_enabled = (boolean) UI::QueryWidget(`id(`enable_nfs4),`Value); 
	Nfs::idmapd_domain = (string) UI::QueryWidget(`id(`nfs4_domain),`Value);
    }

    void HandleEvent( any widget )
    {
	integer entryno = -1;
        // handle the events, enable/disable the button, show the popup if button clicked
	if ( UI::WidgetExists(`id("_cwm_firewall_details")) && UI::WidgetExists(`id("_cwm_open_firewall")) )
	    CWMFirewallInterfaces::OpenFirewallHandle (fw_cwm_widget, "", $[ "ID" : widget ]);
	/*changed =
	    true ||		// TODO: fw changed, #44106
	    true;		// TODO: nfs changed*/
	if ( UI::WidgetExists(`id(`fstable)) )
	    entryno = (integer) UI::QueryWidget(`id(`fstable), `CurrentItem);

	if (widget == `newbut)
	{
	    map<string,any> entry = GetFstabEntry (nil, (list<map>) union (Nfs::non_nfs_entries, nfs_entries));

	    if (entry != nil)
	     {
	        nfs_entries = add (nfs_entries, entry);
		modify_line = entry;
	        EnableDisableButtons();

		Nfs::SetModified();
	     }

	    UI::ChangeWidget (`id(`fstable), `Items, FstabTableItems (nfs_entries));
	}
	else if (widget == `editbut)
	{
	        integer count = 0;
	        map<string,any> entry = GetFstabEntry (nfs_entries[entryno]:$[], // Default values
				      (list<map>) union (Nfs::non_nfs_entries, remove (nfs_entries, entryno)));
	        if (entry != nil)
	        {
	           integer count = 0;
	           nfs_entries = maplist(map<string,any> ent, nfs_entries, ``{
		       count = count+1;
		       if (count-1 != entryno)
		           return ent;
		       return entry;
	            });

		    modify_line = entry;
	            UI::ChangeWidget (`id(`fstable), `Items, FstabTableItems (nfs_entries));
		    Nfs::SetModified();
	        }
	}
	else if (widget == `delbut && size (nfs_entries) > 0)
	{
		map <string, any> share = nfs_entries[entryno]: $[];
		if ( Popup::YesNo( sformat( _("Really delete %1?"), share["spec"]:"")) )
		{
		    modify_line = share;
	            nfs_entries = remove (nfs_entries, entryno);
	            UI::ChangeWidget (`id(`fstable), `Items, FstabTableItems (nfs_entries));
	            EnableDisableButtons();

	 	    Nfs::SetModified();
		}
	}
	else if (widget == `enable_nfs4)
	{
	    boolean enabled = (boolean) UI::QueryWidget(`id(`enable_nfs4), `Value);
	    UI::ChangeWidget( `id(`nfs4_domain), `Enabled, enabled);
	    Nfs::SetModified();
	}
	else if ( widget == `settings )
	{
	     SaveFstabEntries( );
	     UI::ReplaceWidget(`id(`rp), SettingsTab() );
	     InitSettings();
	     Wizard::SetHelpText( help_text2 );
	}
	else if ( widget == `overview )
	{
	     SaveSettings( $[ "ID" : widget ] );
	     UI::ReplaceWidget(`id(`rp), FstabTab() );
	     InitFstabEntries();
	     Wizard::SetHelpText( help_text1 );
	}
    }

    /**
     * NFS client dialog itselfs
     * @return `back, `abort or `next
     */
    define symbol FstabDialog () ``{
	Wizard::SetScreenShotName ("nfs-client-1-fstab");

        nfs_entries = Nfs::nfs_entries;

	// dialog heading
	Wizard::SetContents(_("NFS Client Configuration"),
				   MainDialogLayout(), help_text1,
				   false,
				   true);
	//Wizard::HideBackButton();
	//Wizard::SetAbortButton(`abort, Label::CancelButton());

	InitFstabEntries();

	// Kludge, because a `Table still does not have a shortcut.
	// Simple to solve here: there's only the table and buttons,
	// so it is OK to always set focus to the table
	UI::SetFocus (`id (`fstable));

	map event = nil;
	any ret = nil;
	integer entryno = -1;

	do
	{
	   event = UI::WaitForEvent ();	   
	   ret = event["ID"]:nil;
	   if (ret == `ok)
	   {
	       ret = `next;
	   }
	   else if (ret == `cancel)
	   {
	       ret = `abort;
	   }
	   else if (ret == `abort && Nfs::GetModified() && !Popup::ReallyAbort (true))
	   {
	       ret = `again;
	   }
	   else
		HandleEvent( ret );
	}
	while (ret != `back && ret != `next && ret != `abort);

	if (ret == `next)
	{
	    // grab current settings, store them to SuSEFirewall::
	    if( UI::WidgetExists(`id(`fstable)) )
		SaveFstabEntries( );
	    if( UI::WidgetExists(`id(`enable_nfs4)) )
		SaveSettings( event );

	}

	Wizard::RestoreScreenShotName ();
	return (symbol) ret;
    }

}

ACC SHELL 2018