/**
 * File:	modules/NisServer.ycp
 * Package:	Configuration of NIS server
 * Summary:	NIS Server, input and output functions.
 * Authors:	Martin Vidner <mvidner@suse.cz>
 *              Dan Vesely <dan@suse.cz>
 *
 * $Id: NisServer.ycp 20792 2005-01-18 10:20:58Z jsuchome $
 *
 * Representation of the configuration of nisServer.
 * Input and output routines.
 */

{

module "NisServer";
textdomain "nis_server";

import "FileUtils";
import "NetworkDevices";
import "Progress";
import "Service";
import "Summary";
import "SuSEFirewall";

//TODO: make it work like Mail::Touch
/**
 * Data was modified?
 */
global boolean modified = false;

/**
 * Function sets internal variable, which indicates, that any
 * settings were modified, to "true"
 */
global define void SetModified () {
    modified = true;
}

/**
 * Functions which returns if the settings were modified
 * @return boolean  settings were modified
 */
global define boolean GetModified () {
    return modified;
}


//TODO: make this work
/**
 * Write only, used during autoinstallation.
 * Don't run services and SuSEconfig, it's all done at one place.
 */
global boolean write_only = false;

// ------------------------------------------------------------

/**
 * The domain we are serving.
 * (for simplicity, we assume a single domain)
 * US ".etc.defaultdomain"
 */
global string domain = "";

/**
 * For warning if the domain was changed.
 * TODO delegate to the client module?
 */
global string old_domainname = "";

/**
 * What kind of server to run: `master, `slave, `none
 */
global symbol ui_what = `none;

/**
 * If we are a slave, where is the master?
 *(it may actually be a hostname, TODO solve like in the client using nsswitch)
 */
global string ui_master_ip = "";

/**
 * Maps to be served
 */
global list<string> maps = [];

/**
 * Minimal UID to include in the user maps
 */
global integer minuid = 0;

/**
 * Minimal GID to include in the user maps
 */
global integer mingid = 0;

/**
 * Merge passwd and shadow to one map?
 * Makefile: string true|false
 */
global boolean merge_passwd = false;

/**
 * Merge group and gshadow to one map?
 * Makefile: string true|false
 */
global boolean merge_group = false;

/**
 * Don't push the changes to slave servers. (useful if there aren't any)
 * Makefile: string true|false
 */
global boolean nopush = false;

/**
 * Slave servers
 */
global list<string> ypservers = [];

/**
 * @struct securenet
 *  network: string
 *  netmask: string
 ** or
 *  hash: "#"
 *  (optional) comment: string
 */
global list<map> securenets = [];

/**
 * Start also the client? (only when client is configured locally)
 */
global boolean start_ypbind	= false;

/**
 * NIS client is configured localy (with current machine as server)
 */
global boolean nisclient_local	= true;

/**
 * Start also the map transfer daemon?
 */
global boolean start_ypxfrd = false;

/**
 * Start also the password daemon?
 */
global boolean start_yppasswdd = false;

/**
 * YPPWD_SRCDIR - source directory for passwd data
 */
global string pwd_srcdir = "/etc";

/**
 * YPPWD_CHFN - allow changing the full name?
 */
global boolean pwd_chfn = false;

/**
 * YPPWD_CHSH - allow changing the login shell?
 */
global boolean pwd_chsh = false;

/**
 * If DHCP client could change domain name (#28727)
 */
global boolean dhcp_changes_domain	= false;

/**
 * Packages to be installed for this module to operate
 */
global list<string> required_packages = ["ypserv"];


// ------------------------------------------------------------
define void YPMakefileVars ();
define void YPServerVars ();
define void YPSystemVars ();
define void YPSecurenets ();
define void YPServers ();
global define boolean isYPMaster ();
global define boolean isYPServerInstalled ();
global define string getMaster ();
global define list<map> GetSaveList (symbol workflow);


// ------------------------------------------------------------

/**
 * All tables that ypserv Makefile knows about
 */
global define list<string> GetAllMaps () {

    return ["passwd", "group", "hosts", "rpc", "services",
	"netid", "protocols", "netgrp", "mail", "shadow",
	"publickey", "networks", "ethers", "bootparams",
	"printcap", "amd.home", "auto.master",
	"auto.home", "auto.local", "passwd.adjunct",
	"timezone", "locale", "netmasks"];
}


/**
 * Read all NIS server settings.
 * @return true on success
 */
global define boolean Read() ``{

    // help text 1/1
    string help = _("<p>Please wait while reading the configuration.</p>");
    // dialog heading
    string title = _("Initializing NIS server setup");
    string progress_title = " ";

    list<string> files = [
	"/var/yp/Makefile",
	"/etc/sysconfig/ypserv",
	"/etc/defaultdomain",
	"/var/yp/securenets",
	"/var/yp/ypservers"
    ];

    list<void ()> vars = [
	YPMakefileVars,
	YPServerVars,
	YPSystemVars,
	YPSecurenets,
	YPServers
    ];

    Progress::New (title, progress_title, size (files) + 3,
		   // To translators: progress label %1 is filename
		   maplist (string file, files, ``(sformat (_("Load '%1' file"), file)))
		   + [
		       // Trans: progress label
		       _("Determine running services"),
		       // Trans: progress label
		       _("Determine server type"),
		       // progress stage label
		       _("Read firewall settings")
		       ],
		   // To translators: progress label %1 is filename
		   maplist (string file, files, ``(sformat (_("Loading '%1'..."), file)))
		   + [
		       // Trans: progress label
		       _("Determining running services..."),
		       // Trans: progress label
		       _("Determining server type..."),
		       // progress step label
		       _("Reading firewall settings..."),
		       // Trans: progress label
		       _("Done."),
		       ],
		   help);

    integer i = 0;
    while (i < size (files))
    {
	Progress::NextStage ();

	void () varfunc = vars[i]:nil;
	varfunc ();
	i = i + 1;
    }

    Progress::NextStage ();
    // "ypserv" is handled elsewhere
    start_ypbind = Service::Enabled ("ypbind");
    // Check if nis client is configured localy or not
    // -> client configuration should not be touched when it uses remote server
    if (start_ypbind)
    {
	import "Nis";
	import "DNS";
	Nis::Read ();
	boolean remote	= false;
	foreach (string server, splitstring (Nis::GetServers (), " "),
	{
	    if (!DNS::IsHostLocal (server))
	    {
		remote		= true;
	    }
	});
	if (remote || Nis::dhcp_wanted)
	{
	    start_ypbind	= false;
	    nisclient_local	= false;
	}
    }

    start_ypxfrd = Service::Enabled ("ypxfrd");
    start_yppasswdd = Service::Enabled ("yppasswdd");

    // TODOm: fix like the client (?)
    if (domain == "")
    {
	// a DHCP client may set the domainname too:
	// /etc/sysconfig/network/dhcp:DHCLIENT_SET_DOMAINNAME
	map out = (map) SCR::Execute (.target.bash_output, "/bin/ypdomainname");
	domain = deletechars (out["stdout"]:"", "\n");

    }
    old_domainname = domain;

    // Check if any device one is configured with DHCP, to know if domain name
    // won't be replaced by dhcp (#28727)
    NetworkDevices::Read ();
    if (size (NetworkDevices::Locate("BOOTPROTO", "dhcp")) > 0 &&
	SCR::Read (.sysconfig.network.dhcp.DHCLIENT_SET_DOMAINNAME) == "yes")
    {
	dhcp_changes_domain	= true;
    }

    Progress::NextStage ();
    if (!isYPServerInstalled ())
    {
	ui_what = `none;
    }
    else
    {
	ui_what = isYPMaster ()? `master: `slave;
	//FIXME: this will give a hostname. the label says IP.
	string master = getMaster();
	if (master != nil)
	{
	    ui_master_ip = master;
	}
    }

    Progress::NextStage ();

    boolean progress_orig = Progress::set (false);
    SuSEFirewall::Read ();
    Progress::set (progress_orig);

    Progress::NextStage ();

    modified = false;
    return true;
}

define any SCRGet (path p, any default) {
    any v = SCR::Read (p);
    return v != nil ? v : default;
}

define integer SCRGetInt (path p, integer default) {
    any v = SCR::Read (p);
    return (v != nil && v != "" && is (v,string))
	? tointeger ((string)v) : default;
}

define void YPMakefileVars () {
    maps = (list<string>) SCRGet (.var.yp.makefile.maps, ["passwd", "group", "rpc", "services", "netid"]);
    minuid = SCRGetInt (.var.yp.makefile.MINUID, 100);
    mingid = SCRGetInt (.var.yp.makefile.MINGID, 100);
    merge_passwd = (string) SCRGet (.var.yp.makefile.MERGE_PASSWD, "true") == "true";
    merge_group = (string) SCRGet (.var.yp.makefile.MERGE_GROUP, "true") == "true";
    nopush = (string) SCRGet (.var.yp.makefile.NOPUSH, "true") == "true";
}

define void YPServerVars () {

    if (FileUtils::Exists ("/etc/sysconfig/ypserv"))
    {
	pwd_srcdir = (string) SCRGet (.sysconfig.ypserv.YPPWD_SRCDIR, "/etc");
	pwd_chfn = SCRGet (.sysconfig.ypserv.YPPWD_CHFN, "no") == "yes";
	pwd_chsh = SCRGet (.sysconfig.ypserv.YPPWD_CHSH, "no") == "yes";
    }
}

define void YPSystemVars () {
    domain = (string) SCRGet (.etc.defaultdomain, "local");
}

define void YPSecurenets () {
    securenets	= [ $[
	"network" : "127.0.0.0",
	"netmask" : "255.0.0.0"
    ]];
    if (FileUtils::Exists ("/var/yp/securenets"))
    {
	securenets = (list<map>) SCRGet (.var.yp.securenets, securenets);
    }
}

define void YPServers () {
    if (FileUtils::Exists ("/var/yp/ypservers"))
    {
	ypservers = (list<string>) SCRGet (.var.yp.ypservers, []);
    }
}

// --------------------
// read-routines

    /**
     * Gets the master server (name or IP?) from any of this server's maps
     * @return	nil if no map is found or it has no YP_MASTER_NAME
     */
    global define string getMaster () ``{
	string dn = domain;
	if (dn == "")
	{
	    return nil;
	}
	string ddir = sformat ("/var/yp/%1", dn);
	string any_map = nil;
	if (SCR::Read (.target.size, ddir) >=0 )
	{
	    list dmaps = (list) SCR::Read (.target.dir, ddir);
	    any_map = (string) dmaps[0]:nil;
	}
	if (any_map == nil)
	{
	    return nil;
	}
	string command = sformat ("/usr/lib/yp/makedbm -u /var/yp/%1/%2 | grep ^YP_MASTER_NAME", dn, any_map);

	map out		= (map) SCR::Execute (.target.bash_output, command);
	list<string> l	= splitstring (out["stdout"]:"", " \n");
	return l[1]:nil;
    }

    /**
     * @return Determines if the current host is YP master or not
     */
    global define boolean isYPMaster () ``{
	string master = getMaster();
	if (master == nil)
	{
	    return false;	// can't decide
	}

	map output = (map) SCR::Execute (.target.bash_output, "/usr/lib/yp/yphelper --hostname");
	string yphelper_hostname = output["stdout"]:"";

	return master == deletechars (yphelper_hostname, "\n");
    }

    /**
     * @return Checks if the YP server software is installed
     * by querying RPM for ypserv
     */
    global define boolean isYPServerInstalled () ``{
	return SCR::Execute(.target.bash, "/bin/rpm -q ypserv") == 0;
    }


// ----------------------------------------

// plain text
global string error_msg = "";
// rich text
global string error_details = "";

/**
 * Adds an error to error_msg
 * @param s message, ending with a newline
 */
global define void addError (string s) ``{
    error_msg = error_msg + s;
}

/**
 * Adds an error to error_details
 * @param s message, ending with a newline
 */
global define void addErrorDetail (string s) ``{
    error_details = error_details + sformat ("<pre>%1</pre>", s);
}

/**
 * Kind-of-compatible replacement for term evaluation.
 * Either f[0] is void(),
 * or f[0] is void(any) and f[1] is any
 * Not called, bug #37146
 */
define void CallFunction01 (list<any> f) {
    typedef void () f0_t;
    typedef void (any) f1_t;
    any fp = f[0]:nil;
    if (is (fp, void ()))
    {
	void () fp0 = (void ()) fp;
	fp0 ();
    }
    else if (is (fp, void (any)))
    {
	void (any) fp1 = (void (any)) fp;
	fp1 (f[1]:nil);
    }
    else
    {
	y2error ("Bad function type: %1", fp);
    }
}

/**
 * Write all NIS server settings
 * @return true on success
 */
global define boolean Write() ``{
    // help text 1/1
    string help = _("<p>Please wait until the configuration is saved.</p>");
    // dialog heading
    string title = _("Saving NIS server setup");
    string progress_title = " ";

    list<map> save_list = GetSaveList (ui_what);
    integer step = 0;

    // To translators: dialog title
    Progress::New (title, progress_title, size (save_list) + 1,
		    maplist (map e, save_list, ``(e["save_label"]:""))
		    + [
			// progress bar stage
		        _("Save firewall settings"),
		    ],
		    maplist (map e, save_list, ``(e["progress_label"]:""))
		    + [
			// progress step
			_("Saving firewall settings..."),
			// progress step
			_("Done.")
		    ],
		    help);

    foreach (map save_item, save_list, ``{
	Progress::NextStage ();
	list<any> fl = save_item["function"]:[];
	y2debug ("Calling: %1", fl);
	if (size (fl) == 1)
	{
	    void () fp = (void ()) fl[0]:nil;
	    fp ();
	}
	else if (size (fl) == 2)
	{
	    void (any) fp = (void (any)) fl[0]:nil;
	    fp (fl[1]:nil);
	}
	else
	{
	    y2internal ("Bad save list item %1", fl);
	}
    });

    Progress::NextStage ();

    boolean progress_orig = Progress::set (false);
    SuSEFirewall::Write ();
    Progress::set (progress_orig);

    Progress::NextStage ();
    return true;
}

/**
 * Removes file or directory and log errors
 * @param file what to remove
 */
global define void Remove (any file) ``{
    if (SCR::Read (.target.size, file) != -1)
    {
	map output = (map) SCR::Execute (.target.bash_output,
				   sformat ("/bin/rm -rf %1", file));
	if (size (output["stderr"]:"") > 0)
	{
	    // To translators: message in the popup dialog
	    addError (sformat (_("Error while removing %1\n"), file));
	    addErrorDetail (output["stderr"]:"");
	}
    }
}

/**
 * Ensures that the domain directory exists.
 * @param	directory	the path
 * @return			false if not and cannot be created
 */
global define boolean EnsureDirectory (string directory) ``{
    map output = $[];

    if (SCR::Read (.target.size, directory) == -1)
    {
	output = (map) SCR::Execute (.target.bash_output,
			       sformat ("/bin/mkdir %1", directory));
	if (size (output["stderr"]:"") > 0)
	{
	    // To translators: message in the popup dialog
	    addError (sformat (_("Directory %1 cannot be created.\n"), directory));
	    addErrorDetail (output["stderr"]:"");
	    return false;
	}
    }
    return true;
}

/**
 * Gets the YP maps from master for slave
 */
global define void YPGetMaps () ``{

    map output = $[];
    string dn = domain;
    string dndir = sformat ("/var/yp/%1", dn);
    // first make sure that the directory exists
    if (! EnsureDirectory (dndir))
    {
	return;
    }

    // and get the maps
    string master = ui_master_ip;
    output = (map) SCR::Execute (.target.bash_output, sformat ("/usr/lib/yp/yphelper --maps %1 --domainname %2", master, dn));
    if (output["exit"]:1 != 0)
    {
	// To translators: message in the popup dialog
	addError (sformat (_("Cannot get list of maps.\n")));
	addErrorDetail (output["stderr"]:"");
    }
    list<string> running_maps = splitstring (output["stdout"]:"", "\n");
    // the element after the last newline is empty, remove it
    if (size (running_maps) > 0)
    {
	running_maps = remove (running_maps, size (running_maps) - 1);
    }

    maplist (string map_name, running_maps, ``{
	output = (map) SCR::Execute (.target.bash_output,
			       sformat ("/usr/lib/yp/ypxfr -f -h %1 -d %2 %3",
					master,
					dn,
					map_name));
	if (output["exit"]:1 != 0)
	{
	    // To translators: message in the popup dialog
	    addError (sformat (_("Error while retrieving %1 map from master.\n"), map_name));
	    addErrorDetail (output["stderr"]:"");
	}
    });


    if (!contains (running_maps, "ypservers"))
    {
	// To translators: message in the popup dialog
	addError (_("Could not get list with slaves.\n"));
    }
    else
    {
	output = (map) SCR::Execute (.target.bash_output, sformat (
				   "/usr/lib/yp/makedbm -u %1/ypservers",
				   dndir));
	string slaves = (string) output["stdout"]:nil;

	if (slaves != nil)
	{
	    output = (map) SCR::Execute (.target.bash_output,
				   "/usr/lib/yp/yphelper --hostname");
	    string hostname = output["stdout"]:"";
	    hostname = substring (hostname, 0, size (hostname) - 1);
	    string h2 = hostname + " " + hostname; // makedbm format
	    if (!contains (splitstring (slaves, "\n"), h2))
	    {
		// To translators: message in the popup dialog
		addError (_("Hostname of this host is not listed\nin the master's list.\n"));
	    }
	}
    }
}



/**
 * Save securenets list
 */

global define void SaveSecurenets () ``{
    SCR::Execute (.target.bash, sformat ("/bin/cp %1 %1.YaST2.save",
					 "/var/yp/securenets"));
    if (! SCR::Write (.var.yp.securenets, securenets))
    {
	// To translators: message in the popup dialog
	addError (sformat (_("Error saving file %1\n"), "/var/yp/securenets"));
    }
}


/**
 * Save list of slaves by calling appropriate any agent
 */
global define void SaveSlaves () ``{
    SCR::Execute (.target.bash, sformat ("/bin/cp %1 %1.YaST2.save",
					 "/var/yp/ypservers"));
    if (! SCR::Write (.var.yp.ypservers, ypservers))
    {
	// To translators: message in the popup dialog
	addError (sformat (_("Error saving file %1\n"), "/var/yp/ypservers"));
    }
}

/**
 * Saves config variables according to workflow
 * @param which workflow one of `slave, `master
 */
global define void SaveVariables (any which) ``{
    if (!SCR::Write (.etc.defaultdomain, domain))
    {
	// To translators: message in the popup dialog
	addError (_("Error setting up domain name\n"));
    }

    if (which == `master)
    {
	map<string,any> settings = $[
	    ".sysconfig.ypserv.YPPWD_SRCDIR": pwd_srcdir,
	    ".sysconfig.ypserv.YPPWD_CHFN": (pwd_chfn? "yes": "no"),
	    ".sysconfig.ypserv.YPPWD_CHSH": (pwd_chsh? "yes": "no"),
	    ".var.yp.makefile.maps": maps,
	    ".var.yp.makefile.MINUID": sformat ("%1", minuid),
	    ".var.yp.makefile.MINGID": sformat ("%1", mingid),
	    ".var.yp.makefile.MERGE_PASSWD": (merge_passwd? "true": "false"),
	    ".var.yp.makefile.MERGE_GROUP": (merge_group? "true": "false"),
	    ".var.yp.makefile.NOPUSH": (nopush? "true": "false"),
	    ];

	maplist (string var, any value, settings, ``{
	    if (!SCR::Write (topath (var), value))
	    {
		list var_parts = splitstring (var, ".");
		string var_name = var_parts[size (var_parts) - 1]:"";
		// To translators: message in the popup dialog
		addError (sformat (_("Error setting up variable %1\n"),
				   var_name));
	    }
	});

	if (!SCR::Write (.sysconfig.ypserv, nil))
	{
	    // To translators: message in the popup dialog
	    addError (sformat (_("Error saving file %1\n"),
			       "/etc/sysconfig/ypserv"));
	}
	if (!SCR::Write (.var.yp.makefile, nil))
	{
	    // To translators: message in the popup dialog
	    addError (sformat (_("Error saving file %1\n"),
			       "/var/yp/Makefile"));
	}
    }
}

/**
 * Starts or stop daemons
 * @param workflow what to start or save: `master, `slave, `none
 */
global define void YPDaemons (any workflow) ``{
    map output    = $[];
    list<string> to_stop  = [];
    list<string> to_start = [];

    if (workflow == `none)
    {
	to_stop = ["ypxfrd", "yppasswdd", "ypserv"];
    }
    else if (workflow == `slave)
    {
	to_stop  = ["ypxfrd", "yppasswdd", "ypserv"];
	to_start = ["portmap", "ypserv"];
    }
    else if (workflow == `master)
    {
	to_stop  = ["ypxfrd", "yppasswdd", "ypserv"];
	to_start = ["portmap", "ypserv"];

	if (start_yppasswdd)
	{
	    to_start = add (to_start, "yppasswdd");
	}

	if (start_ypxfrd)
	{
	    to_start = add (to_start, "ypxfrd");
	}
    }

    map<string,string> services = listmap (string s, to_stop, ``{
	return $[s : "disable"];
    });
    foreach (string s, to_start, ``{
	services[s] = "enable";
    });
    foreach (string s, string action, services, ``{
	Service::Adjust (s, action);
    });

    foreach (string d, to_stop, ``{
	y2milestone ("Stopping daemon %1", d);
	// $#@! broken by bug 9648
	integer ret = Service::RunInitScript (d, "stop");
	if (ret != 0)
	{
	    // To translators: message in the popup dialog
	    addError (sformat (_("Error while stopping %1 daemon\n"), d));
	}
    });

    foreach (string d, to_start, ``{
	y2milestone ("Starting daemon %1", d);
	// start only if not running. essential for portmap! (bug #9999)
	if (Service::Status (d) != 0) {
	    integer ret = Service::RunInitScript (d, "start");
	    if (ret != 0)
	    {
		// To translators: message in the popup dialog
		addError (sformat (_("Error while starting %1 daemon\n"), d));
	    }
	}
    });
}

/**
 * Creates initial database
 */
global define void YPMake () ``{
    map output = $[];

    // create the source directory, if it does not exist
    // (and passwd, shadow, group)

    if (! EnsureDirectory (pwd_srcdir))
    {
	return;
    }
    boolean create_ok = true;
    foreach (string s, ["passwd", "group"], ``{
	string p = pwd_srcdir + "/" + s;
	if (SCR::Read (.target.size, p) < 0)
	{
	    create_ok = create_ok && 0 == SCR::Execute (.target.bash, sformat ("/usr/bin/touch %1; /bin/chmod 0644 %1; /bin/chown root.root %1", p));
	}
    });
    string p = pwd_srcdir + "/shadow";
    if (SCR::Read (.target.size, p) < 0)
    {
	create_ok = create_ok && 0 == SCR::Execute (.target.bash, sformat ("/usr/bin/touch %1; /bin/chmod 0640 %1; /bin/chown root.shadow %1", p));
    }

    if (!create_ok)
    {
	// error popup
	addError (sformat (_("Error while creating an empty user database.\n")));
    }

    string dn = domain;
    if (! EnsureDirectory (sformat ("/var/yp/%1", dn)))	{
	return;
    }

    output = (map) SCR::Execute (.target.bash_output, sformat ("/usr/bin/make -C /var/yp/%1 -f ../Makefile NOPUSH=true ypservers", dn));

    if (size (output["stderr"]:"") > 0)
    {
	// To translators: message in the popup dialog
	addError (_("Error while creating the ypservers map.\n"));
	addErrorDetail (output["stderr"]:"");
    }

    output = (map) SCR::Execute (.target.bash_output, sformat ("/usr/bin/make -C /var/yp NOPUSH=true LOCALDOMAIN=%1", dn));

    if (size (output["stderr"]:"") > 0)
    {
	// To translators: message in the popup dialog
	addError (_("Error while creating database.\n"));
	addErrorDetail (output["stderr"]:"");
    }
}

/**
 * Calls NIS client configuration writing
 */
global define void Client () ``{
    import "Nis";

    map c = $[
	"start_nis":	start_ypbind,
	"nis_domain":	domain,
	"nis_servers":	[ "127.0.0.1" ],
	];

    boolean progress_orig = Progress::set (false);
    boolean ok =  Nis::Import (c) && Nis::Write ();
    Progress::set (progress_orig);
    if (!ok)
    {
	// To translators: message in the popup dialog
	addError (_("Error while configuring the client.\n"));
	addErrorDetail (Nis::YpbindErrors);
    }
}

/**
 * Returns a list of what to save
 * @param workflow what workflow was chosen (`none, `slave, `master)
 * @return a list of maps: <pre>$[
 *   "save_label": ...,
 *   "progress_label": ...,
 *   "function": @see CallFunction01
 * ]</pre>
 */
global define list<map> GetSaveList (symbol workflow) ``{

    list<map> result = [];

    // do this remove for all workflows
    if (domain != "")
    {
	result = [
	    $[
		// To translators: progress label
		"save_label"     : sformat (_("Remove /var/yp/%1"), domain),
		// To translators: progress label
		"progress_label" : sformat (_("Removing /var/yp/%1"), domain),
		"function"       : [Remove, sformat ("/var/yp/%1", domain)],
		]
	    ];
    }

    // *** none YP server flow
    if (workflow == `none)
    {
	result = result + [
	    // To translators: progress label
	    $["save_label"     : _("Stop running daemons."),
	      // To translators: progress label
	      "progress_label" : _("Stopping running daemons."),
	      "function"       : [YPDaemons, `none],
		]
	    ];
    }

    // *** slave YP server flow
    else if (workflow == `slave)
    {
	result = result + [
	    // To translators: progress label
	    $["save_label"     : _("Get maps from master."),
	      // To translators: progress label
	      "progress_label" : _("Getting maps from master."),
	      "function"       : [YPGetMaps],
		],
	    // To translators: progress label
	    $["save_label"     : _("Save hosts allowed to query server."),
	      // To translators: progress label
	      "progress_label" : _("Saving hosts allowed to query server."),
	      "function"       : [SaveSecurenets],
		],
	    // To translators: progress label
	    $["save_label"     : _("Set config variables."),
	      // To translators: progress label
	      "progress_label" : _("Setting config variables."),
	      "function"       : [SaveVariables, `slave],
		],
	    // To translators: progress label
	    $["save_label"     : _("Start daemon."),
	      // To translators: progress label
	      "progress_label" : _("Starting daemon."),
	      "function"       : [YPDaemons, `slave],
		]
	    ];
    }

    // *** master YP server flow
    else if (workflow == `master)
    {
	result = result + [
	    // To translators: progress label
	    $["save_label"     : _("Save hosts allowed to query server."),
	      // To translators: progress label
	      "progress_label" : _("Saving hosts allowed to query server."),
	      "function"       : [SaveSecurenets],
		]
	    ];

	if (!nopush && size (ypservers) > 0)
	{
	    result = result + [
		// To translators: progress label
		$["save_label"     : _("Save slaves."),
		  // To translators: progress label
		  "progress_label" : _("Saving slaves."),
		  "function"       : [SaveSlaves],
		    ]
		];
	}
	result = result + [
	    // To translators: progress label
	    $["save_label"     : _("Set config variables."),
	      // To translators: progress label
	      "progress_label" : _("Setting config variables."),
	      "function"       : [SaveVariables, `master],
		],
	    // To translators: progress label
	    $["save_label"     : _("Start daemons."),
	      // To translators: progress label
	      "progress_label" : _("Starting daemons."),
	      "function"       : [YPDaemons, `master],
		],
	    // To translators: progress label
	    $["save_label"     : _("Create initial database."),
	      // To translators: progress label
	      "progress_label" : _("Creating database."),
	      "function"       : [YPMake],
		],
	    ];
    }

    // slave or master is also client ?
    if (contains ([`slave, `master], workflow))
    {
	if (start_ypbind)
	{
	    result = result + [
		// To translators: progress label
		$["save_label"     : _("Start NIS client."),
		  // To translators: progress label
		  "progress_label" : _("Starting NIS client."),
		  "function"       : [Client],
		    ]
		];
	}
	else if (nisclient_local)
	{
	    result = result + [
		// To translators: progress label
		$["save_label"     : _("Stop NIS client."),
		  // To translators: progress label
		  "progress_label" : _("Stopping NIS client."),
		  "function"       : [Client],
		    ]
		];
	}

    }

    return result;
}

// ----------------------------------------
// autoyast

/**
 * Get all nisServer settings from the first parameter
 * (For use by autoinstallation.)
 * @param settings The YCP structure to be imported.
 * @return boolean True on success
 */
global define boolean Import (map settings) ``{

    // Get default variables


    string type = settings["server_type"]:"none";
    if (type == "master")
	ui_what = `master;
    else if (type == "slave")
	ui_what = `slave;
    else
	ui_what = `none;

    domain = settings["domain"]:"";
    minuid = settings["minuid"]:0;
    mingid = settings["mingid"]:0;

    merge_passwd = settings["merge_passwd"]:false;
    merge_group = settings["merge_group"]:false;

    ypservers = settings["slaves"]:[];
    if (ypservers == [])
	YPServers ();

    start_ypbind = settings["start_ypbind"]:false;

    start_ypxfrd = settings["start_ypxfrd"]:false;
    start_yppasswdd  = settings["start_yppasswdd"]:false;


    maps = settings["maps_to_serve"]:[];
    if (maps == [] )
	YPMakefileVars ();

    pwd_srcdir = settings["pwd_srcdir"]:"/etc";
    pwd_chsh =  settings["pwd_chsh"]:false;
    pwd_chfn =   settings["pwd_chfn"]:false;
    nopush = settings["nopush"]:false;

    securenets =  settings["securenets"]:[];
    if (securenets == [])
	YPSecurenets ();

    return true;
}

/**
 * Dump the nisServer settings to a single map
 * (For use by autoinstallation.)
 * @return map Dumped settings (later acceptable by Import ())
 */
global define map Export () ``{
    // TODO FIXME: your code here (return the above mentioned variables)...
    map settings = $[];
    settings["domain"] = domain;


    string type = "none";
    if (ui_what == `master)
	type = "master";
    else if (ui_what == `slave)
	type = "slave";

    settings["server_type"] = type;
    settings["minuid"]= minuid;
    settings["mingid"]= mingid;
    settings["merge_passwd"] =  merge_passwd;

    settings["merge_group"] = merge_group;

    list slaves = [];
    slaves = ypservers;

    // FIXME: NI
    // global boolean start_ypbind = false;

    settings["start_ypbind"] = start_ypbind;

    settings["start_ypxfrd"] = start_ypxfrd;
    settings["start_yppasswdd"] = start_yppasswdd;

    settings["maps_to_serve"] = maps;

    settings["pwd_srcdir"] =  pwd_srcdir;
    settings["slaves"] = slaves;
    settings["pwd_chsh"] = pwd_chsh;
    settings["pwd_chfn"] = pwd_chfn;
    settings["nopush"] = nopush;
    settings["securenets"] = securenets;
    return settings;
}

/**
 * Create a textual summary and a list of unconfigured cards
 * @param split split configured and unconfigured?
 * @return summary of the current configuration
 */
global define list Summary() ``{

    string summary = "";
    string nc = Summary::NotConfigured ();
    summary = Summary::AddHeader(summary, _("NIS Domain"));
    summary = Summary::AddLine(summary,	 ((domain != "") ? domain : nc));



    return [ summary, [] ];
}

/* EOF */
}
