Project

General

Profile

Download (19.6 KB) Statistics
| Branch: | Tag: | Revision:
89d8bebc Marc Dequènes (Duck)
#!/usr/bin/ruby -Ku

#--
# LdapShadows, a Medium-level LDAP Access Library and Tool.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++

# to allow in-place run for test
$: << File.join(File.dirname(__FILE__), "..", "lib")

bf23ac8c Marc Dequènes (Duck)
# get locale from shell
locale = ENV['LANGUAGE'] || ENV['LC_ALL'] || ENV['LC_MESSAGES'] || ENV['LANG']

89d8bebc Marc Dequènes (Duck)
require 'ldap_shadows'
bbb82941 Marc Dequènes (Duck)
require 'ldap_shadows/display_utils'
89d8bebc Marc Dequènes (Duck)
require 'yaml'
require 'cmdparse2'

bbb82941 Marc Dequènes (Duck)
include LdapShadows

bf23ac8c Marc Dequènes (Duck)
set_locale(locale)
b0304d30 Marc Dequènes (Duck)
89d8bebc Marc Dequènes (Duck)
config_str = IO.read(File.join(LdapShadows::Config::CFG_DIR, "test.conf"))
1744c478 Marc Dequènes (Duck)
config = YAML.load(config_str)
config_str_prv_filelist = [
File.join(ENV['HOME'], ".shadowwalker"),
File.join(LdapShadows::Config::CFG_DIR, "private.conf")
]
config_str_prv_filelist.each do |file|
if File.exists?(file)
config_str_prv = IO.read(file)
config.merge!(YAML.load(config_str_prv))
break
end
end
config.recursive_symbolize_keys!
89d8bebc Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
bbb82941 Marc Dequènes (Duck)
$program_options = {}

89d8bebc Marc Dequènes (Duck)
cmdparser = CmdParse::CommandParser.new(true)
bbb82941 Marc Dequènes (Duck)
cmdparser.banner = PRODUCT
5ca3fa56 Marc Dequènes (Duck)
cmdparser.program_name = File.basename(__FILE__)
bbb82941 Marc Dequènes (Duck)
cmdparser.program_version = VERSION.split(".")
89d8bebc Marc Dequènes (Duck)
cmdparser.options = CmdParse::OptionParserWrapper.new do |opt|
opt.separator "Global options:"
97d3e6a1 Marc Dequènes (Duck)
opt.on("-d", "--debug", "Output debug info without being formated") {|t| $program_options[:debug] = true }
opt.on("-e", "--expert", "Output extra info for expert users") {|t| $program_options[:expert] = true }
opt.on("-H", "--handles", "Output with handles (objects/field/... keys used for manipulations)") {|t| $program_options[:handles] = true }
89d8bebc Marc Dequènes (Duck)
end

cmdparser.add_command(CmdParse::HelpCommand.new)
cmdparser.add_command(CmdParse::VersionCommand.new)

304a503d Marc Dequènes (Duck)
$ldapctl = Controller.new
$ldapctl.set_global_config(config[:presentation])
89d8bebc Marc Dequènes (Duck)
config[:aspects].each_pair do |aspect_name, aspect_data|
304a503d Marc Dequènes (Duck)
$ldapctl.set_aspect(aspect_name, aspect_data)
89d8bebc Marc Dequènes (Duck)
end
127edd07 Marc Dequènes (Duck)
begin
ActiveLdap::Base.setup_connection(config[:ldap])

config[:objects].each_pair do |obj_name, obj_data|
304a503d Marc Dequènes (Duck)
$ldapctl.load_object(obj_name, obj_data)
127edd07 Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
$ldapctl.load_relations
127edd07 Marc Dequènes (Duck)
rescue ActiveLdap::Error => e
bf23ac8c Marc Dequènes (Duck)
STDERR.puts _("LDAP connection error: %s") % e.to_s
exit 2
89d8bebc Marc Dequènes (Duck)
end


304a503d Marc Dequènes (Duck)
class Command < CmdParse::Command
attr_accessor :usages_params

def usage
if @usages_params
base_usage_str = super.sub("[ARGS]", "")
usages = @usages_params.collect {|params| base_usage_str + params }
usages.join("\n")
else
super
6089b33a Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
end
f4aab4ba Marc Dequènes (Duck)
protected

def params_shift_location(args)
bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("no location name given") if args.empty?
af19cdc5 Marc Dequènes (Duck)
location = args.shift.downcase
bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("bad location") unless location =~ /^([a-zA-Z]+)\/(.+)$/
loc_obj_hdl = $1
loc_item_hdl = $2
af19cdc5 Marc Dequènes (Duck)
split_args = [loc_obj_hdl, loc_item_hdl]
loc_obj_klass = params_shift_object(split_args)
loc_item = params_shift_item(loc_obj_klass, split_args)

[loc_obj_klass, loc_item]
end

def params_shift_object(args)
bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("no object name given") if args.empty?
af19cdc5 Marc Dequènes (Duck)
obj_hdl = args.shift.downcase.singularize
obj_klass = $ldapctl.find_klass(obj_hdl)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such object '%s'") % obj_hdl if obj_klass.nil?
af19cdc5 Marc Dequènes (Duck)
obj_klass
end

def params_shift_item(obj_klass, args, with_expert = false)
bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("no item name given") if args.empty?
af19cdc5 Marc Dequènes (Duck)
attr_list = ["*"]
attr_list << "+" if $program_options[:expert] and with_expert # add operational attributes if expert

item_hdl = args.shift.downcase
f4aab4ba Marc Dequènes (Duck)
begin
af19cdc5 Marc Dequènes (Duck)
item = obj_klass.find(item_hdl, :attributes => attr_list)
f4aab4ba Marc Dequènes (Duck)
rescue ActiveLdap::EntryNotFound
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such item '%s/%s'") % [obj_klass.handle, item_hdl]
f4aab4ba Marc Dequènes (Duck)
end
af19cdc5 Marc Dequènes (Duck)
item
f4aab4ba Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
end

class ListCommand < Command
def initialize
super('list', false)

a24bc5b1 Marc Dequènes (Duck)
self.short_desc = "list objects, and items/aspects/fields of an object"
self.usages_params = [
304a503d Marc Dequènes (Duck)
":objects",
a24bc5b1 Marc Dequènes (Duck)
"<object>",
"<object> :aspects",
"<object> :fields"
304a503d Marc Dequènes (Duck)
]
end

def execute (args)
bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("no object name given") if args.empty?
6089b33a Marc Dequènes (Duck)
a24bc5b1 Marc Dequènes (Duck)
obj_hdl = args.shift.downcase.singularize
304a503d Marc Dequènes (Duck)
case obj_hdl
when ':object'
26a3ca45 Marc Dequènes (Duck)
list = $ldapctl.objects
puts "=== List of LDAP objects (#{list.size}) ==="
list.each do |obj_name|
304a503d Marc Dequènes (Duck)
puts " - #{obj_name}"
end
else
af19cdc5 Marc Dequènes (Duck)
obj_klass = params_shift_object([obj_hdl])
89d8bebc Marc Dequènes (Duck)
a24bc5b1 Marc Dequènes (Duck)
if args.empty?
obj_human_name = Translator.translate_object_name(obj_hdl)
af19cdc5 Marc Dequènes (Duck)
Display.display_item_list("List of #{obj_human_name.pluralize}", obj_klass.find(:all), $program_options)
a24bc5b1 Marc Dequènes (Duck)
else
subobj_hdl = args.shift.downcase.singularize

obj_human_name = Translator.translate_object_name(obj_hdl)

case subobj_hdl
when ':aspect'
list = obj_klass.possible_aspects
puts "=== List of LDAP Aspects of #{obj_human_name.pluralize} (#{list.size}) ==="
list.each do |aspect|
str = Translator.translate_aspect_name(aspect)
str += " [#{aspect}]" if $program_options[:handles]
puts " - #{str}"
end
when ':field'
list = obj_klass.possible_attributes
puts "=== List of LDAP Fields of #{obj_human_name.pluralize} (#{list.size}) ==="
list.each do |field|
str = Translator.translate_field_name(field)
str += " [#{field}]" if $program_options[:handles]
puts " - #{str}"
end
obj_klass.possible_aspects.each do |aspect|
aspect_human_name = Translator.translate_aspect_name(aspect)
list = obj_klass.possible_attributes_for_aspect(aspect)
puts "--- Sublist of LDAP Fields for Aspect #{aspect_human_name} (#{list.size}) ---"
list.each do |field|
str = Translator.translate_field_name(field)
str += " [#{field}]" if $program_options[:handles]
puts " - #{str}"
end
end
else
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such subobject '%s'") % subobj_hdl
a24bc5b1 Marc Dequènes (Duck)
end
end
304a503d Marc Dequènes (Duck)
end
89d8bebc Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
end
cmdparser.add_command(ListCommand.new)

class ShowCommand < Command
def initialize
super('show', false)

self.short_desc = "show item information"
self.usages_params = [
"<object> <item>",
"<object> <item> <field>#?",
"<object> <item> <field>[#<index>]"
]
89d8bebc Marc Dequènes (Duck)
end

304a503d Marc Dequènes (Duck)
def execute (args)
af19cdc5 Marc Dequènes (Duck)
obj_klass = params_shift_object(args)
item = params_shift_item(obj_klass, args, true)
ca51664c Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
if args.empty?
$program_options[:skip_binary] = true
Display.display_item(item, $program_options)
ca51664c Marc Dequènes (Duck)
else
304a503d Marc Dequènes (Duck)
field_info = args.shift
field_name, file_no = field_info.split("#")
ca51664c Marc Dequènes (Duck)
5d28ad6e Marc Dequènes (Duck)
unless item.has_field?(field_name)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such field '%s' in object '%s'") % [field_name, obj_klass.handle]
ca51664c Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
unless item.attribute_present?(field_name)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Field '%s' in item '%s/%s' is not present") %
[field_name, obj_klass.handle, item.name]
ca51664c Marc Dequènes (Duck)
end

5d28ad6e Marc Dequènes (Duck)
field_data = item.send(field_name, true)
ca51664c Marc Dequènes (Duck)
11c9a6c9 Marc Dequènes (Duck)
result_is_binary = false
304a503d Marc Dequènes (Duck)
if file_no == "?"
result = field_data.size
else
file_no_i = file_no.to_i
file_no = (file_no_i.to_s == file_no) ? file_no_i : nil
ca51664c Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
attr_info = ActiveLdap::Base.schema.attribute(field_name)

field_single = attr_info.single_value?
if file_no.nil? and not field_single
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Field '%s' in object '%s' has multiple values, but you didn't select one") %
[field_name, obj_klass.handle]
ca51664c Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
file_no = 0 if file_no.nil?
if file_no > 0 and field_single
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Field '%s' in object '%s' has only a single value") %
[field_name, obj_klass.handle]
304a503d Marc Dequènes (Duck)
end
if file_no < 0 or file_no >= field_data.size
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Field '%s' in object '%s' doesn't have such file number '%s' (select in range [0, %s])") %
[field_name, obj_klass.handle, file_no, field_data.size - 1]
304a503d Marc Dequènes (Duck)
end

11c9a6c9 Marc Dequènes (Duck)
result = field_data[file_no]
result_is_binary = attr_info.binary?
ca51664c Marc Dequènes (Duck)
end

304a503d Marc Dequènes (Duck)
if args.empty?
11c9a6c9 Marc Dequènes (Duck)
if result_is_binary
# output binary data without newline, so it can be pipped or redirected easily
STDOUT.write result
else
puts result
end
304a503d Marc Dequènes (Duck)
else
file_name = args.shift
if File.exists?(file_name)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("File '%s' already exists, and i won't overwrite it") % file_name
304a503d Marc Dequènes (Duck)
end

begin
open(file_name, "w") do |fp|
fp.write result
end
rescue
bf23ac8c Marc Dequènes (Duck)
raise ProcessingError, _("Cannot save file: %s") % $!
304a503d Marc Dequènes (Duck)
end

puts "File saved."
end
ca51664c Marc Dequènes (Duck)
end
end
89d8bebc Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
cmdparser.add_command(ShowCommand.new)
89d8bebc Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
class TreeCommand < Command
def initialize
super('tree', false)
0d75a0b6 Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
self.short_desc = "show skeleton items tree"
self.usages_params = [
f4aab4ba Marc Dequènes (Duck)
"[<location>]"
304a503d Marc Dequènes (Duck)
]
f4aab4ba Marc Dequènes (Duck)
self.options = CmdParse::OptionParserWrapper.new do |opt|
opt.on( '-a', '--all', 'Display all objects in the tree.' ) { $program_options[:tree_all_objects] = true }
end
304a503d Marc Dequènes (Duck)
end

def execute (args)
puts "Tree:"

f4aab4ba Marc Dequènes (Duck)
search_base = nil
unless args.empty?
loc_obj_klass, loc_item = params_shift_location(args)
search_base = loc_item.dn
end
0d75a0b6 Marc Dequènes (Duck)
f4aab4ba Marc Dequènes (Duck)
if $program_options[:tree_all_objects]
dn_list = ActiveLdap::Base.search(:base => search_base, :scope => :sub, :attributes => ['']).collect do |entry|
ActiveLdap::DistinguishedName.parse(entry.first)
end
else
dn_list = []
gconfig = $ldapctl.get_global_config()
0d75a0b6 Marc Dequènes (Duck)
f4aab4ba Marc Dequènes (Duck)
(gconfig[:tree_objects] || []).each do |obj_hdl|
af19cdc5 Marc Dequènes (Duck)
obj_klass = $ldapctl.find_klass(obj_hdl.downcase)
f4aab4ba Marc Dequènes (Duck)
unless obj_klass
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Location object '%s' not defined") % obj_hdl
f4aab4ba Marc Dequènes (Duck)
end

obj_klass.find(:all, :base => search_base, :scope => :sub).each do |obj|
dn_list << obj.dn_obj
0d75a0b6 Marc Dequènes (Duck)
end
end
f4aab4ba Marc Dequènes (Duck)
end

base_dn = ActiveLdap::DistinguishedName.parse(LdapObject.base)
0d75a0b6 Marc Dequènes (Duck)
f4aab4ba Marc Dequènes (Duck)
tree = {}
dn_list.each do |dn|
ptree = tree
pdn = nil
(dn - base_dn).to_s.split(',').reverse.each do |pdn|
ptree[pdn] = {} unless ptree.has_key?(pdn)
ptree = ptree[pdn]
end
ptree = nil
304a503d Marc Dequènes (Duck)
end
f4aab4ba Marc Dequènes (Duck)
tree = {base_dn => tree}

Display.display_hash_tree(tree, 0)
0d75a0b6 Marc Dequènes (Duck)
end
end
304a503d Marc Dequènes (Duck)
cmdparser.add_command(TreeCommand.new)
b0304d30 Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
class ModCommand < Command
def initialize
super('mod', false)
b0304d30 Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
self.short_desc = "Modify attributes of an item"
self.usages_params = [
d9091cc0 Marc Dequènes (Duck)
"<object> <item> (<field>|<relation>|:aspects)(=|+=|-=)<value> [(<field>|<relation>|:aspects)(=|+=|-=)<value>] ..."
304a503d Marc Dequènes (Duck)
]
b0304d30 Marc Dequènes (Duck)
end

304a503d Marc Dequènes (Duck)
def execute (args)
af19cdc5 Marc Dequènes (Duck)
obj_klass = params_shift_object(args)
item = params_shift_item(obj_klass, args)
43bd8057 Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
modification_done = false
args.each do |mod_info|
bf23ac8c Marc Dequènes (Duck)
unless mod_info =~ /^([a-zA-Z]*(?::[a-zA-Z]+)?)(=|\+=|-=)(.*)$/
raise SyntaxError, _("modification parameter '%s' is invalid") % mod_info
end
304a503d Marc Dequènes (Duck)
key = $1
op = $2
val = $3
43bd8057 Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
if key.index(":")
type, field = key.split(":")
else
type = nil
field = key
43bd8057 Marc Dequènes (Duck)
end
0814bfc3 Marc Dequènes (Duck)
43bd8057 Marc Dequènes (Duck)
case type
when nil
5d28ad6e Marc Dequènes (Duck)
unless item.has_field?(field)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such field '%s' in object '%s'") % [field, obj_klass.handle]
43bd8057 Marc Dequènes (Duck)
end

304a503d Marc Dequènes (Duck)
attr_info = ActiveLdap::Base.schema.attribute(field)
if attr_info.read_only?
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The field '%s' cannot be modified (read only)") % field
304a503d Marc Dequènes (Duck)
end

11c9a6c9 Marc Dequènes (Duck)
if attr_info.binary?
unless File.exists?(val)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The field '%s' contains binary data, you must provide a filename instead of a direct value") % field
11c9a6c9 Marc Dequènes (Duck)
end

begin
val = File.read(val)
rescue
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The file for the binary field '%s' cannot be read: ") % [field, $!]
11c9a6c9 Marc Dequènes (Duck)
end
end
5d28ad6e Marc Dequènes (Duck)
old_val = item.send(field, true)
43bd8057 Marc Dequènes (Duck)
when 'rel'
304a503d Marc Dequènes (Duck)
unless item.relations.include?(field)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such relation '%s' for object '%s'") % [field, obj_klass.handle]
304a503d Marc Dequènes (Duck)
end

rel_info = item.info_for_relation(field)
if rel_info[:read_only]
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The relation '%s' cannot be modified (read only)") % field
43bd8057 Marc Dequènes (Duck)
end

304a503d Marc Dequènes (Duck)
# fetch remote object in relation, which will be the real 'val'
foreign_item_list = rel_info[:foreign_klass].find(:all, val)
if foreign_item_list.empty?
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Foreign item '%s' for relation '%s' not found") % [val, field]
304a503d Marc Dequènes (Duck)
end
if foreign_item_list.size > 1
bf23ac8c Marc Dequènes (Duck)
raise WeirdError, _("Ambiguous item '%s' for relation '%s' (%s possible items)") %
[val, field, foreign_item_list.size]
304a503d Marc Dequènes (Duck)
end
3d58e226 Marc Dequènes (Duck)
old_val = item.send(field)
304a503d Marc Dequènes (Duck)
val = foreign_item_list.first
d9091cc0 Marc Dequènes (Duck)
when ''
case field
when 'aspects'
unless item.class.possible_aspects.include?(val)
67b9f8b3 Marc Dequènes (Duck)
raise PreProcessingError, _("No such aspect '%s' for object '%s'") % [val, obj_klass.handle]
d9091cc0 Marc Dequènes (Duck)
end
else
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Unknown core field '%s'") % field
d9091cc0 Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
else
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Unknown type '%s' for field '%s'") % [type, field]
0814bfc3 Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
# if val is nil or the latest value is removed, then the atribute is removed from the object,
# or the association's attribute is removed from one side
case op
when '='
d9091cc0 Marc Dequènes (Duck)
if type == '' and field == 'aspects'
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The equality operator is not possible for aspects")
d9091cc0 Marc Dequènes (Duck)
end
3d58e226 Marc Dequènes (Duck)
val = [val] if old_val.is_a? Enumerable
item.send(field + "=", val)
304a503d Marc Dequènes (Duck)
when '+='
case type
when nil
if attr_info.single_value?
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The field '%s' cannot hold more than one value") % field
304a503d Marc Dequènes (Duck)
end
3d58e226 Marc Dequènes (Duck)
unless old_val.include?(val)
new_val = old_val << val
item.send(field + "=", new_val)
end
304a503d Marc Dequènes (Duck)
when 'rel'
if rel_info[:single_value]
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The relation '%s' cannot hold more than one foreign item") % field
304a503d Marc Dequènes (Duck)
end

3d58e226 Marc Dequènes (Duck)
unless old_val.include?(val)
item.send(field) << val
end
d9091cc0 Marc Dequènes (Duck)
when ''
case field
when 'aspects'
item.add_aspect(val)
end
304a503d Marc Dequènes (Duck)
end
when '-='
case type
when nil
new_val = old_val - [val]
11c9a6c9 Marc Dequènes (Duck)
item.send(field + "=", new_val)
304a503d Marc Dequènes (Duck)
when 'rel'
item.send(field).delete(val)
d9091cc0 Marc Dequènes (Duck)
when ''
case field
when 'aspects'
item.remove_aspect(val)
end
304a503d Marc Dequènes (Duck)
end
43bd8057 Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
modification_done = true
end

if modification_done
d9091cc0 Marc Dequènes (Duck)
missing_fields = item.missing_attributes
unless missing_fields.empty?
bf23ac8c Marc Dequènes (Duck)
miss_str = []
d9091cc0 Marc Dequènes (Duck)
missing_fields.each do |field|
str = Translator.translate_field_name(field)
str += " [#{field}]" if $program_options[:handles]
bf23ac8c Marc Dequènes (Duck)
miss_str << str
d9091cc0 Marc Dequènes (Duck)
end
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Cannot save the modifications; the following fields are missing: %s") %
miss_str.join(", ")
d9091cc0 Marc Dequènes (Duck)
end

304a503d Marc Dequènes (Duck)
puts "Modification done."
0814bfc3 Marc Dequènes (Duck)
else
304a503d Marc Dequènes (Duck)
puts "Nothing to do."
0814bfc3 Marc Dequènes (Duck)
end
b0304d30 Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
end
cmdparser.add_command(ModCommand.new)
0814bfc3 Marc Dequènes (Duck)
304a503d Marc Dequènes (Duck)
class DelCommand < Command
def initialize
super('del', false)

self.short_desc = "Delete an item"
self.usages_params = [
5d28ad6e Marc Dequènes (Duck)
"<object> <item>"
304a503d Marc Dequènes (Duck)
]
deb322cb Marc Dequènes (Duck)
self.options = CmdParse::OptionParserWrapper.new do |opt|
opt.on( '-r', '--recursive', 'Delete object and all children recursively.' ) { $program_options[:recursive_delete] = true }
end
304a503d Marc Dequènes (Duck)
end

def execute (args)
af19cdc5 Marc Dequènes (Duck)
obj_klass = params_shift_object(args)
item = params_shift_item(obj_klass, args)
b0304d30 Marc Dequènes (Duck)
deb322cb Marc Dequènes (Duck)
if $program_options[:recursive_delete]
item.class.delete_all(nil, :scope => :sub, :base => item.dn)
else
item.delete
end
304a503d Marc Dequènes (Duck)
puts "Deletion done."
34cb4054 Marc Dequènes (Duck)
end
b0304d30 Marc Dequènes (Duck)
end
304a503d Marc Dequènes (Duck)
cmdparser.add_command(DelCommand.new)

5d28ad6e Marc Dequènes (Duck)
class CreateCommand < Command
def initialize
super('create', false)

self.short_desc = "Create an item"
self.usages_params = [
e04ae9bc Marc Dequènes (Duck)
"<object> <new_item> <location> [<field>=<value>] ..."
5d28ad6e Marc Dequènes (Duck)
]
end

def execute (args)
af19cdc5 Marc Dequènes (Duck)
obj_klass = params_shift_object(args)

bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("no item name given") if args.empty?
af19cdc5 Marc Dequènes (Duck)
item_hdl = args.shift.downcase
e04ae9bc Marc Dequènes (Duck)
f4aab4ba Marc Dequènes (Duck)
loc_obj_klass, loc_item = params_shift_location(args)
e04ae9bc Marc Dequènes (Duck)
5d28ad6e Marc Dequènes (Duck)
item = obj_klass.new(item_hdl)
e04ae9bc Marc Dequènes (Duck)
item.base = loc_item.dn_obj - obj_klass.base_obj
5d28ad6e Marc Dequènes (Duck)
args.each do |param|
bf23ac8c Marc Dequènes (Duck)
raise SyntaxError, _("creation parameter '%s' is invalid") % param unless param =~ /^([a-zA-Z]+)=(.*)$/
5d28ad6e Marc Dequènes (Duck)
key = $1
val = $2

d9091cc0 Marc Dequènes (Duck)
val = nil if val == ''

5d28ad6e Marc Dequènes (Duck)
field = key

unless item.has_field?(field)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("No such field '%s' in object '%s'") % [field, obj_klass.handle]
5d28ad6e Marc Dequènes (Duck)
end

attr_info = ActiveLdap::Base.schema.attribute(field)
if attr_info.read_only?
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The field '%s' cannot be modified (read only)") % field
5d28ad6e Marc Dequènes (Duck)
end

if attr_info.binary?
unless File.exists?(val)
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The field '%s' contains binary data, you must provide a filename instead of a direct value") % field
5d28ad6e Marc Dequènes (Duck)
end

begin
val = File.read(val)
rescue
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("The file for the binary field '%s' cannot be read: %s") % [field, $!]
5d28ad6e Marc Dequènes (Duck)
end
end

item.send(field + "=", val)
end

d9091cc0 Marc Dequènes (Duck)
missing_fields = item.missing_attributes
unless missing_fields.empty?
bf23ac8c Marc Dequènes (Duck)
miss_str = []
d9091cc0 Marc Dequènes (Duck)
missing_fields.each do |field|
str = Translator.translate_field_name(field)
str += " [#{field}]" if $program_options[:handles]
bf23ac8c Marc Dequènes (Duck)
miss_str << str
d9091cc0 Marc Dequènes (Duck)
end
bf23ac8c Marc Dequènes (Duck)
raise PreProcessingError, _("Cannot save the new item; the following fields are missing: %s") %
miss_str.join(", ")
d9091cc0 Marc Dequènes (Duck)
end

5d28ad6e Marc Dequènes (Duck)
item.save!
end
end
cmdparser.add_command(CreateCommand.new)

b0304d30 Marc Dequènes (Duck)
127edd07 Marc Dequènes (Duck)
begin
cmdparser.parse
bf23ac8c Marc Dequènes (Duck)
rescue SyntaxError => e
STDERR.puts _("Syntax error: %s") % e.to_s
exit 1
rescue PreProcessingError => e
STDERR.puts _("Preprocessing error: %s") % e.to_s
exit 2
127edd07 Marc Dequènes (Duck)
rescue ActiveLdap::EntryInvalid => e
bf23ac8c Marc Dequènes (Duck)
# work around activeldap#26758 (for english output only :-/)
11c9a6c9 Marc Dequènes (Duck)
STDERR.puts e.to_s.sub(/invalid format: .*: required syntax:/, "invalid format. required syntax:")
127edd07 Marc Dequènes (Duck)
exit 3
rescue ActiveLdap::OperationNotPermitted => e
bf23ac8c Marc Dequènes (Duck)
STDERR.puts _("You don't have enough rights for this operation")
127edd07 Marc Dequènes (Duck)
exit 3
rescue ActiveLdap::Error => e
bf23ac8c Marc Dequènes (Duck)
STDERR.puts _("LDAP error: %s") % e.to_s
127edd07 Marc Dequènes (Duck)
exit 3
bf23ac8c Marc Dequènes (Duck)
rescue WeirdError =>e
STDERR.puts _("Weird error: %s") % e.to_s
exit 4
127edd07 Marc Dequènes (Duck)
end