/**
 * File:
 *   modules/Mail.ycp
 *
 * Package:
 *   Configuration of mail aliases
 *
 * Summary:
 *   Data for configuration of mail aliases, input and output functions.
 *
 * Authors:
 *   Martin Vidner <mvidner@suse.cz>
 *
 * $Id: MailAliases.ycp 12978 2003-12-05 14:46:46Z jsuchome $
 *
 * Representation of the configuration of mail aliases.
 * Input and output routines.
 * Separated from Mail.ycp because yast2-users need us.
 * Virtusertable/virtual users are not included, arbitrarily.
 *
 */

{
    // Set the name of the module
    module "MailAliases";

    // no translatable strings, no textdomain.

    /* ---------------------------------------------------------------- */

    /**
     * List of maps: $[comment:, alias:, destinations:] (all are strings)
     * Except root.
     */
    global list<map> aliases = [];
    /**
     * Separated/joined with aliases by read/write/set/export
     */
    global string root_alias = "";
    /**
     * Separated/joined with aliases by read/write/set/export
     */
    string root_alias_comment = "";

    /**
     * Useful for autoinstall: the provided aliases will be (with
     * higher priority) merged with existing ones (presumably system defaults).
     */
//    global boolean merge_aliases = false;

    /* ---------------------------------------------------------------- */

    /**
     * Separates aliases into aliases, root_alias and root_alias_comment
     */
    global define void FilterRootAlias () ``{
	root_alias = "";
	root_alias_comment = "";
	aliases = filter (map e, aliases, ``{
	    if (e["alias"]:"" == "root" )
	    {
		root_alias = e["destinations"]:"";
		root_alias_comment = e["comment"]:"";
		return false;
	    }
	    return true;
	});
    }

    /**
     * Read the aliases table (and separate the root alias)
     * @return success?
     */
    global define boolean ReadAliases () ``{
	list<map> a_raw = (list<map>) SCR::Read (.mail.aliases.table);
	aliases =  maplist (map e, a_raw,
			    ``($[
				   "comment"		: e["comment"]: "",
				   "alias"		: e["key"]: "",
				   "destinations"	: e["value"]: "",
				   ]));
	FilterRootAlias ();
	return true;
    }

    /**
     * @param	aliases an alias table
     * @return prepend root alias data to aliases, if set
     */
    global define list<map> MergeRootAlias (list<map> aliases) ``{
	list<map> ret = aliases;
	if (root_alias != "")
	{
	    ret = prepend (ret, $[
				 "alias": "root",
				 "destinations": root_alias,
				 "comment": root_alias_comment,
				 ]);
	}
	return ret;
    }

    /* ---------------------------------------------------------------- */

    /**
     * Merges mail tables, which are order-preserving maps.
     * First are the entries of the old map, with values updated
     * from the new one, then the rest of the new map.
     * @param new	new table
     * @param old	old table
     * @return		merged table
     */
    define list<map> mergeTables (list<map> new, list<map> old) ``{
	// make a true map
	map new_m = listmap (map e, new,
			     ``($[
				    e["key"]:"" :
				    [ e["comment"]:"", e["value"]:"" ]
				]));
	// update old values
	list<map> replaced = maplist (map e, old, ``{
	    string k = e["key"]:"";
	    list cv = new_m[k]:[];
	    if (size (cv) > 0)
	    {
		new_m[k] = []; // ok, newly constructed
		return $["key": k, "comment": cv[0]:"", "value": cv[1]:""];
	    }
	    else
	    {
		return $["key": k, "comment": e["comment"]:"", "value": e["value"]:""];
	    }
	});
	// remove already updated values
	list<map> filtered = filter (map e, new, ``(
					 size (new_m[ e["key"]:"" ]:[]) > 0)
	    );
	return flatten ([replaced, filtered]);
    }

    /**
     * Part of Write.
     * @return success
     * @see SetRootAlias
     */
    global define boolean WriteAliases () ``{
	// aliases
	path alias_path = .mail.aliases.table;
	list<map> a_raw = maplist (map e, MergeRootAlias (aliases),
				   ``($[
					  "comment"	: e["comment"]:"",
					  "key"		: e["alias"]:"",
					  "value"	: e["destinations"]:"",
					  ]));
//	if (merge_aliases)
//	{
//	    a_raw = mergeTables (a_raw, SCR::Read (alias_path));
//	}
	SCR::Write (alias_path, a_raw);
	return true;
    }


    /* ---------------------------------------------------------------- */

    /**
     * For use by the Users package.
     * Does not rely on the internal state, first calls the agent.
     * @return eg. "joe, \\root", "" if not defined
     */
    global define string GetRootAlias () ``{
	if (!ReadAliases ())
	{
	    return "";
	}
	return root_alias;
    }


    /**
     * For use by the Users package.
     * Does not use the internal state, just calls the agent.
     * SuSEconfig or newaliases is NOT called!
     * (TODO: what if it is called while the main module is running?)
     * Errors are reported via Report::Error.
     * @param destinations The new alias. If "", it is removed.
     * @return true on success
     */
    global define boolean SetRootAlias (string destinations) ``{
	if (!ReadAliases ())
	{
	    return false;
	}

	root_alias = destinations;
	root_alias_comment = ""; // TODO: "created by the ... yast2 module"?

	if (!WriteAliases ())
	{
	    return false;
	}

	if (! SCR::Write (.mail.aliases, nil))
	{
	    return false;
	}
	return true;
    }

}
