ACC SHELL
/**
* File: clients/ldap/ldap_browser.ycp
* Package: Configuration of LDAP
* Summary: Simple browser and editor of LDAP tree
* Author: Jiri Suchomel <jsuchome@suse.cz>
*
* $Id: ldap_browser.ycp 55580 2009-02-18 12:56:30Z jsuchome $
*
*/
{
import "CommandLine";
import "Directory";
import "FileUtils";
import "Label";
import "Ldap";
import "LdapPopup";
import "Popup";
import "Wizard";
include "ldap/routines.ycp";
textdomain "ldap-client";
map cmdline = $[
"id" : "ldap_browser",
"mappings" : $[
]
];
if (size (WFM::Args()) > 0)
{
return CommandLine::Run( cmdline );
}
string root_dn = "";
string current_dn = "";
map data = $[];
map<string, any> tmp_data = $[];
// map of already read subtrees
map<string,boolean> dns = $[];
list<string> subdns = [];
list<term> tree_items = [];
map topdns = $[];
map open_items = $[];
string help_text =
// general help text for LDAP browser
_("<p>Browse the LDAP tree in the left part of the dialog.</p>") +
// help text for LDAP browser
_("<p>Once the LDAP object is selected in the tree, the table shows the object data. Use <b>Edit</b> to change the value of the selected attribute. Use <b>Save</b> to save your changes to LDAP.</p>");
// popup question (Continue/Cancel follows)
string unsaved = _("There are unsaved changes in the current entry.
Discard these changes?
");
term contents = `HBox (
`HWeight (1, `ReplacePoint (`id (`treeContents), `Top (`HBox ()))),
`HWeight (1, `ReplacePoint (`id (`entryContents), `Top (`HBox ())))
);
map display_info = UI::GetDisplayInfo ();
boolean textmode = display_info["TextMode"]:false;
// helper: data modified?
define boolean Modified () {
return size (tmp_data) > 0;
}
// helper: create the value that should be shown instead of whole DN in tree
define string show_dn (string dn) {
if (topdns[dn]:false)
return dn;
return get_rdn (dn);
}
// helper for set_tree_term function: create new items for subtrees
define list<term> update_items (list<term> its) {
return maplist (term it, its, {
string dn = it[0,0]:"";
if (dn == current_dn)
{
return `item (`id(dn), show_dn (dn), true,
maplist(string k, subdns, ``(
`item (`id(k), show_dn (k), false, []))));
}
integer last = size (it) - 1;
if (size (it[last]:[]) == 0)
return it;
// `OpenItems doesn't work in ncurses...
boolean open = haskey (open_items, dn) && !textmode;
return `item (
`id(dn), show_dn (dn), open, update_items (it[last]:[]));
});
}
// -----------------------------
// create the term with LDAP tree
define void set_tree_term () {
term cont = `HBox (`VSpacing (20), `VBox (`HSpacing(70),
`VSpacing (0.2),
`HBox (
`HSpacing (),
`ReplacePoint (`id (`reptree), `Tree (`id(`tree), root_dn, [])),
`ReplacePoint (`id (`repbuttons), `Empty ()),
`HSpacing ()
),
`HBox (
`HSpacing (1.5),
`HStretch (),
textmode ?
// button label
`PushButton (`id (`open), `opt (`key_F6),_("&Open")):
`Empty (),
// button label
`PushButton (`id(`reload),`opt(`key_F8), _("&Reload")),
`HSpacing (1.5)
),
`VSpacing (0.6)
));
UI::ReplaceWidget (`treeContents, cont);
if (size (tree_items) == 0)
{
list<string> out = (list<string>) SCR::Read (.ldap.search, $[
"base_dn" : root_dn,
"scope" : 1,
"dn_only" : true,
"not_found_ok" : true ]
);
if (size (out) > 0)
{
tree_items = maplist (string dn, out, {
dns [dn] = false;
topdns[dn] = true;
return `item (`id(dn), dn, false, []);
});
}
}
if (size (tree_items) > 0)
{
UI::ReplaceWidget (`id (`reptree), textmode ?
`Tree (`id(`tree), root_dn, tree_items) :
`Tree (`id(`tree), `opt(`notify), root_dn, tree_items));
// no item is selected
UI::ChangeWidget (`tree, `CurrentItem, nil);
}
else if (root_dn == "")
{
list bases = (list) SCR::Read (.ldap.search, $[
"base_dn" : "",
"scope" : 0,
"attrs" : [ "namingContexts" ]
]);
if (size (bases) > 0)
tree_items = maplist (string dn, bases[0,"namingContexts"]:[], {
topdns[dn] = true;
return `item(`id(dn), dn, false, []);
});
if (size (tree_items) > 0)
{
UI::ReplaceWidget (`id (`reptree), textmode ?
`Tree (`id(`tree), root_dn, tree_items) :
`Tree (`id(`tree), `opt(`notify), root_dn, tree_items));
UI::ChangeWidget (`tree, `CurrentItem, nil);
}
if (size (topdns) == 1)
root_dn = bases[0,"namingContexts",0]:"";
}
if (textmode)
UI::SetFocus (`id(`tree));
if (current_dn != "")
UI::ChangeWidget (`id(`tree), `CurrentItem, current_dn);
}
// -----------------------------
// create the term with LDAP entry data table
define void set_entry_term () {
list items = [];
// generate table items from already existing values
foreach (string attr, any val, (map<string,any>) data, {
if (is (val, map) || val == nil)
return;
list<string> value = [];
if (is (val, list))
{
value = (list<string>)val;
}
if (is (val, byteblock) ||
(is (val, list) && is (value[0]:nil, byteblock)))
{
y2warning ("binary value (%1) cannot be edited", attr);
return;
}
else if (is (val, integer))
{
value = [ sformat ("%1", val) ];
data [attr] = value;
}
else if (is (val, string))
{
value = [ (string)val ];
data [attr] = value;
}
items = add (items,`item (`id(attr), attr, mergestring(value,",")));
});
// generate table items with empty values
// (not set for this user/group yet)
// we need to read available attributes from Ldap
foreach (string class, (list<string>) sort (data["objectClass"]:[]), {
foreach (string at,(list<string>)Ldap::GetAllAttributes (class), {
if (!haskey (data, at))
{
data[at] = [];
items = add (items, `item (`id(at), at, ""));
}
});
});
term cont = `HBox(`HSpacing (1.5), `VBox(
`Left (`Label (current_dn)),
`Table(`id(`table), `opt (`notify, `immediate), `header(
// table header 1/2
_("Attribute") + " ",
// table header 2/2
_("Value")),
items),
`HBox (
`PushButton(`id(`edit), `opt(`key_F4), Label::EditButton()),
`HStretch(),
`PushButton(`id(`save), `opt(`key_F2), Label::SaveButton())
),
`VSpacing (0.5)
),
`HSpacing (1.5)
);
UI::ReplaceWidget (`entryContents, cont);
if (size (items) == 0)
UI::ChangeWidget (`id(`edit), `Enabled, false);
else
// no item is selected
UI::ChangeWidget (`table, `CurrentItem, nil);
UI::ChangeWidget (`id (`edit), `Enabled, false);
UI::ChangeWidget (`id (`save), `Enabled, false);
UI::SetFocus (`id(`table));
}
Wizard::CreateDialog ();
Wizard::SetDesktopIcon ("ldap_browser");
// dialog caption
Wizard::SetContentsButtons (_("LDAP Browser"),
contents, help_text, "", Label::CloseButton());
Wizard::HideBackButton ();
Wizard::HideAbortButton ();
// read current LDAP configuration
Ldap::Read ();
list configurations = [];
string configurations_file = Directory::vardir + "/ldap_servers.ycp";
// combobox item
string default_name = _("Current LDAP Client settings");
map configuration = $[
"server" : Ldap::GetFirstServer (Ldap::server),
"bind_dn" : Ldap::GetBindDN (),
"ldap_tls" : Ldap::ldap_tls,
"name" : default_name
];
// read configuration of LDAP browser
if (FileUtils::Exists (configurations_file))
{
configurations = (list) SCR::Read (.target.ycp, configurations_file);
if (configurations == nil || !is (configurations, list))
configurations = [];
}
if (configurations == [])
{
configurations = [ configuration ];
}
configuration = configurations[0]:$[];
// helper function: generate items for combo box
list connection_items (string selected) {
integer i = -1;
return maplist (map conf, (list<map>) configurations, {
i = i + 1;
return `item (`id (i), conf["name"]:"",conf["name"]:"" == selected);
});
}
// update the combo box with LDAP connections list
void update_connection_items (string selected) {
UI::ChangeWidget (`id (`delete), `Enabled, selected != default_name);
UI::ReplaceWidget (`id (`rpcombo),
`ComboBox (`id(`configs), `opt (`hstretch, `notify),
// combo box label
_("LDAP Connections"), connection_items (selected)
)
);
foreach (string s, [ "server", "bind_dn", "ldap_tls" ], {
UI::ChangeWidget (`id (s), `Enabled, selected != default_name);
UI::ChangeWidget (`id (s), `Value, s == "ldap_tls" ?
configuration[s]:false : configuration[s]:"");
});
}
// ask which LDAP connection to choose
UI::OpenDialog (`opt(`decorated), `HBox (`HSpacing (0.2), `VBox (
`VSpacing (0.2),
`HSpacing(40),
`HBox (
`ReplacePoint (`id (`rpcombo),
`ComboBox (`id(`configs), `opt (`hstretch, `notify),
// combo box label
_("LDAP Connections"), []
)
),
`VBox (
`Label (""),
`PushButton (`id (`add), Label::AddButton ())
),
`VBox (
`Label (""),
`PushButton (`id (`delete), Label::DeleteButton ())
)
),
// textentry label
`InputField (`id ("server"), `opt (`hstretch, `notify),_("LDAP Server"),
configuration["server"]:""),
`InputField (`id ("bind_dn"), `opt (`hstretch, `notify),
// textentry label
_("Administrator DN"), configuration["bind_dn"]:""),
// password entering label
`Password (`id("pw"), `opt (`hstretch), _("&LDAP Server Password")),
`VSpacing (0.2),
// check box label
`Left (`CheckBox (`id ("ldap_tls"), `opt (`notify), _("L&DAP TLS"),
configuration["ldap_tls"]:false)
),
`HBox(
`PushButton (`id(`ok),`opt(`key_F10, `default), Label::OKButton()),
// button label
`PushButton (`id(`anon), `opt(`key_F6), _("A&nonymous Access")),
`PushButton (`id(`cancel),`opt(`key_F9), Label::CancelButton())
),
`VSpacing (0.2)
), `HSpacing (0.2)));
string current_name = configuration["name"]:"";
update_connection_items (current_name);
any ret = nil;
while (true)
{
ret = UI::UserInput();
integer conf= (integer)UI::QueryWidget (`id (`configs), `Value);
// save configuration currently selected before switching to new one
if (ret == `ok || ret == `anon || is (ret, string))
{
configuration = configurations[conf]:$[];
current_name = configuration["name"]:"";
if (current_name != default_name)
{
foreach (string s, [ "server", "bind_dn", "ldap_tls" ], {
configuration[s] = UI::QueryWidget (`id (s), `Value);
});
integer i = -1;
configurations = maplist (map c, (list<map>) configurations, {
i = i + 1;
return i == conf ? configuration : c;
});
}
}
if (ret == `configs)
{
configuration = configurations[conf]:$[];
current_name = configuration["name"]:"";
UI::ChangeWidget (`id (`delete), `Enabled,
current_name != default_name);
foreach (string s, [ "server", "bind_dn", "ldap_tls" ], {
UI::ChangeWidget (`id (s), `Enabled,current_name!=default_name);
UI::ChangeWidget (`id (s), `Value, s == "ldap_tls" ?
configuration[s]:false : configuration[s]:"");
});
}
if (ret == `add)
{
UI::OpenDialog ( `opt(`decorated), `HBox (`HSpacing (0.2), `VBox (
`VSpacing (0.2),
`InputField (`id (`new),
// InputField label
_("Enter the name of the new LDAP connection")),
`HBox (
`PushButton (`id(`ok), `opt(`default), Label::OKButton ()),
`PushButton (`id(`cancel), Label::CancelButton ())
)
), `HSpacing(0.2)));
any r = UI::UserInput ();
string new = (string) UI::QueryWidget (`id (`new), `Value);
UI::CloseDialog ();
if (r == `cancel || new == "")
continue;
configuration = $[
"name" : new
];
configurations = add (configurations, configuration);
update_connection_items (new);
}
if (ret == `delete)
{
configurations = remove (configurations, conf);
update_connection_items (default_name);
}
if (ret == `ok || ret == `anon)
{
Ldap::server = (string) UI::QueryWidget (`id ("server"), `Value);
Ldap::bind_dn = (string) UI::QueryWidget (`id ("bind_dn"), `Value);
Ldap::bind_pass = (string) UI::QueryWidget(`id("pw"), `Value);
Ldap::ldap_tls = (boolean) UI::QueryWidget (`id("ldap_tls"),`Value);
Ldap::SetAnonymous (ret == `anon);
string error = Ldap::LDAPInitWithTLSCheck ($[]);
if (error != "")
{
Ldap::LDAPErrorMessage ("init", error);
continue;
}
error = Ldap::LDAPBind (Ldap::bind_pass);
if (error != "")
{
Ldap::LDAPErrorMessage ("bind", error);
continue;
}
error = Ldap::InitSchema ();
if (error != "")
{
Ldap::LDAPErrorMessage ("schema", error);
continue;
}
break;
}
if (ret == `cancel)
break;
}
UI::CloseDialog();
if (ret == `cancel)
{
Wizard::CloseDialog ();
return ret;
}
SCR::Write (.target.ycp, configurations_file, configurations);
// LDAP initialized, we can open the browser now
set_tree_term ();
current_dn = (string) UI::QueryWidget (`id(`tree), `CurrentItem);
if (current_dn == nil) current_dn = "";
set_entry_term ();
if (textmode)
UI::SetFocus (`id(`tree));
symbol result = `notnext;
symbol current = `ldaptree;
while (true) {
map event = UI::WaitForEvent ();
result = (symbol) event["ID"]:nil;
if (result == `cancel && !Popup::ReallyAbort (false))
result = `not_next;
if (result == `back || result == `cancel)
break;
if (result == `open)
result = `tree;
current_dn = (string) UI::QueryWidget (`id(`tree),`CurrentItem);
if (current_dn == nil)
current_dn = "";
// switch to different entry while current was modified
if (result == `tree && Modified ())
{
if (Popup::ContinueCancel (unsaved))
{
// discard the changes
tmp_data = $[];
}
else
{
result = `not_next;
continue;
}
}
// events in tree
if (result == `tree)
{
if (! dns[current_dn]:false)
{
UI::BusyCursor ();
subdns = (list<string>) SCR::Read (.ldap.search, $[
"base_dn" : current_dn,
"scope" : 1,
"dn_only" : true,
"not_found_ok" : true,
]);
if (subdns == nil)
{
y2warning ("the search for %1 returned nil...", current_dn);
continue;
}
else subdns = sort (subdns);
dns [current_dn] = true;
if (size (subdns) > 0)
// TODO if size (subdns) > 0) || dn has glyph
{
open_items = (map) UI::QueryWidget (`tree, `OpenItems);
tree_items = update_items (tree_items);
UI::ReplaceWidget (`id (`reptree), textmode ?
`Tree (`id(`tree), root_dn, tree_items) :
`Tree (`id(`tree), `opt(`notify), root_dn, tree_items));
UI::ChangeWidget (`id(`tree), `CurrentItem, current_dn);
open_items = $[];
}
current_dn = (string) UI::QueryWidget (`id(`tree),`CurrentItem);
if (current_dn == nil) current_dn = "";
}
data = Ldap::GetLDAPEntry (current_dn);
tmp_data = $[];
set_entry_term ();
UI::NormalCursor ();
if (textmode)
UI::SetFocus (`id(`tree));
}
if (result == `reload)
{
tree_items = [];
open_items = $[];
dns = $[];
topdns = $[];
subdns = [];
root_dn = "";
set_tree_term ();
}
// events in Edit Entry part
if (result == `edit)
result = `table;
if (result == `table && event["EventReason"]:"" == "SelectionChanged")
{
string attr = (string) UI::QueryWidget (`id(`table), `CurrentItem);
boolean enable = true;
if (size (attr) < size (current_dn) &&
substring (current_dn, 0, size (attr) + 1) == (attr + "="))
{
y2debug ("disabling %1 for editing...", attr);
enable = false;
}
if (attr == "objectClass")
enable = false;
UI::ChangeWidget (`id (`edit), `Enabled, enable);
}
else if (result == `table)
{
string attr = (string) UI::QueryWidget (`id(`table), `CurrentItem);
if (UI::QueryWidget (`id (`edit), `Enabled) == false)
{
y2milestone ("editing the value of attribute '%1' is not allowed", attr);
result = `notnext;
continue;
}
list<string> value = tmp_data [attr]:data[attr]:[];
value = LdapPopup::EditAttribute ($[
"attr" : attr,
"value" : value,
"single" : Ldap::SingleValued (attr)
]);
if (value == tmp_data [attr]:data[attr]:[])
{
result = `notnext;
continue;
}
UI::ChangeWidget(`id(`table),`Item(attr,1), mergestring(value,","));
UI::ChangeWidget (`id(`save), `Enabled, true);
tmp_data [attr] = value;
}
if (result == `save)
{
if (Modified ())
{
boolean cont = false;
foreach (string oc, data["objectClass"]:[], {
if (cont) return;
foreach (string attr, Ldap::GetRequiredAttributes (oc), {
any val = tmp_data[attr]:nil;
if (!cont && (val == [] || val == "")) {
//error popup, %1 is attribute name
Popup::Error (sformat (_("The \"%1\" attribute is mandatory.
Enter a value."), attr));
UI::SetFocus (`id(`table));
cont = true;
}
});
});
if (cont)
{
result = `not_next;
continue;
}
if (tmp_data["modified"]:"" == "")
tmp_data["modified"] = "edited";
if (Ldap::WriteLDAP ($[ current_dn : tmp_data ]))
{
tmp_data = $[];
UI::ChangeWidget (`id(`save), `Enabled, false);
}
}
}
// general events
if (result == `next)
{
if (Modified () && !Popup::ContinueCancel (unsaved))
{
result = `not_next;
continue;
}
break;
}
}
Wizard::CloseDialog ();
return `finish;
}
ACC SHELL 2018