#!/usr/bin/env ruby

require 'time'
require 'fileutils'

require 'active_samba_ldap'
require 'active_samba_ldap/command'

include ActiveSambaLdap::GetTextSupport

argv, opts, options = ActiveSambaLdap::Command.parse_options do |opts, options|
  options.computer_account = false
  options.gecos = nil
  options.home_directory = nil
  options.move_home_directory = false
  # options.inactive_days = nil
  options.new_user_name = nil
  options.uid = nil
  options.allow_non_unique_uid_number = false
  options.gid = nil
  options.merge_groups = true
  options.supplementary_groups = nil
  options.shell = nil
  options.given_name = nil
  options.common_name = nil
  options.surname = nil

  options.expire_date = nil
  options.can_change_password = nil
  options.must_change_password = nil
  options.samba_home_path = nil
  options.samba_home_drive = nil
  options.samba_logon_script = nil
  options.samba_profile_path = nil
  options.samba_account_flags = nil
  options.enable = nil
  options.mail_addresses = nil
  options.mail_to_addresses = nil


  opts.banner += " USER_NAME"

  opts.on("-c", "--[no-]computer-account",
          _("is a Windows Workstation"),
          _("(otherwise, Windows user)"),
          "(#{options.computer_account})") {|options.computer_account|}

  opts.on("--gecos=GECOS", _("gecos")) {|options.gecos|}
  opts.on("-d", "--home-directory=HOME_DIR",
          _("home directory")) {|options.home_directory|}
  opts.on("-m", "--[no-]move-home-directory",
          _("move home directory"),
          "(#{options.move_home_directory})") do |bool|
    options.move_home_directory = bool
  end
  opts.on("-r", "--rename=NEW_NAME",
          _("new user name (cn and dn are updated)")) do |name|
    options.new_user_name = name
  end
  opts.on("-u", "--uid=UID", Integer, _("uid")) {|options.uid|}
  opts.on("--[no-]allow-non-unique-uid",
          _("uid can be non unique "),
          "(#{options.allow_non_unique_uid_number})") do |bool|
    options.allow_non_unique_uid_number = bool
  end
  opts.on("-g", "--gid=GID", "gid") {|options.gid|}
  opts.on("-G", "--groups=GID1,GID2,GID3", Array,
          _("supplementary groups (comma separated)")) do |groups|
    options.supplementary_groups = groups
  end
  opts.on("--[no-]merge-groups",
          _("replace supplementary groups "),
          "(#{!options.merge_groups})") {|options.merge_groups|}
  opts.on("-s", "--shell=SHELL", _("shell")) {|options.shell|}
  opts.on("--given-name=NAME", _("given name")) {|options.given_name|}
  opts.on("-N", "--common-name=NAME",
          _("common name")) {|options.common_name|}
  opts.on("-S", "--surname=NAME", _("surname")) {|options.surname|}

  opts.separator("")
  opts.separator(_("For samba accounts:"))

  opts.on("-e", "--expire-date=DATE", _("expire date")) do |date|
    options.expire_date = Time.parse(date)
  end
  opts.on("-C", "--[no-]can-change-password",
          _("can change password")) do |bool|
    options.can_change_password = bool
  end
  opts.on("-M", "--[no-]must-change-password",
          _("must change password")) do |bool|
    options.must_change_password = bool
  end
  opts.on("--samba-home-path=PATH",
          _("sambaHomePath"),
          _("(SMB home share, like '\\\\PDC\\user'")) do |path|
    options.samba_home_path = path
  end
  opts.on("--samba-home-drive=DRIVE",
          _("sambaHomeDrive"),
          _("(letter associated with home share, like 'H:')")) do |drive|
    options.samba_home_drive = drive
  end
  opts.on("--samba-logon-script=SCRIPT",
          _("sambaLogonScript"),
          _("(DOS script to execute on login)")) do |script|
    options.samba_logon_script = script
  end
  opts.on("--samba-profile-path=PATH",
          _("sambaProfilePath"),
          _("(profile directory, " \
            "like '\\\\PDC\\profiles\\user')")) do |path|
    options.samba_profile_path = path
  end
  opts.on("--samba-account-flags=FLAGS",
          _("sambaAcctFlags"),
          _("(samba account control bits, " \
            "like '[NDHTUMWSLXI]')")) {|options.samba_account_flags|}
  opts.on("-D", "--[no-]disable-user", _("disable this user")) do |bool|
    options.enable = !bool
  end
  opts.on("-E", "--[no-]enable-user", _("enable this user")) do |bool|
    options.enable = bool
  end
#   opts.on("--mail-addresses=ADDRESS1,ADDRESS2,ADDRESS3",
#           Array,
#           _("mailAddresses (comma separated)")) {|options.mail_addresses|}
#   opts.on("--mail-to-addresses=ADDRESS1,ADDRESS2,ADDRESS3",
#           Array,
#           _("mailToAddresses (forward address)"),
#           _("(comma separated)")) do |addresses|
#     options.mail_to_addresses = addresses
#   end
end

name = nil
if argv.size == 1
  name = argv.first
else
  $stderr.puts opts
  exit 1
end

ActiveSambaLdap::Base.setup_connection("update")

class User < ActiveSambaLdap::User
  ldap_mapping
end

class Computer < ActiveSambaLdap::Computer
  ldap_mapping
end

class Group < ActiveSambaLdap::Group
  ldap_mapping
end

options.computer_account = true if /\$$/ =~ name

if options.computer_account
  member_class = Computer
  member_type = _("computer")
  name = name.chomp("$") + "$"
else
  member_class = User
  member_type = _("user")
end

unless member_class.exists?(name)
  $stderr.puts(_("%s doesn't exist: %s") % [member_type, name])
  exit 1
end
member = member_class.find(name)

unless Process.uid.zero?
  password = ActiveSambaLdap::Command.read_password(_("Enter your password: "))

  begin
    member.bind(password)
  rescue ActiveLdap::AuthenticationError
    $stderr.puts(_("password doesn't match."))
    exit 1
  end
  member.remove_connection
end

if options.uid
  begin
    member.change_uid_number(options.uid, options.allow_non_unique_uid_number)
  rescue ActiveSambaLdap::UidNumberAlreadyExists
    $stderr.puts $!.message
    exit 1
  end
end

if options.gid
  begin
    member.primary_group = Group.find_by_name_or_gid_number(options.gid)
  rescue ActiveSambaLdap::Error
    $stderr.puts $!.message
    exit 1
  end
end

if options.shell
  member.login_shell = options.shell
end

if options.gecos
  member.gecos = options.gecos
  member.description = options.gecos
  member.display_name = options.gecos
end

if options.home_directory
  if options.move_home_directory and !File.exist?(options.home_directory)
    FileUtils.mv(member.home_directory, options.home_directory)
  end
  member.home_directory = options.home_directory
end

if options.common_name
  member.cn = options.common_name
end

if options.surname
  member.sn = options.surname
end

if options.given_name
  member.given_name = options.given_name
end

if options.mail_addresses
  raise _("not implemented.")
end

if options.mail_to_addresses
  raise _("not implemented.")
end

if options.supplementary_groups
  member.groups = [] unless options.merge_groups
  member.groups = options.supplementary_groups.collect do |group|
    begin
      Group.find_by_name_or_gid_number(group)
    rescue ActiveSambaLdap::GidNumberDoesNotExist
      $stderr.puts $!
      exit 1
    end
  end
end

if options.expire_date
  member.samba_kickoff_time = options.expire_date.to_i.to_s
end

if options.samba_account_flags
  member.samba_acct_flags = options.samba_account_flags
end

unless options.can_change_password.nil?
  if options.can_change_password
    member.enable_password_change
  else
    member.disable_password_change
  end
end

unless options.must_change_password.nil?
  if options.must_change_password
    member.enable_forcing_password_change
  else
    member.disable_forcing_password_change
  end
end

if options.samba_home_path
  member.samba_home_path = options.samba_home_path
end

if options.samba_home_drive
  member.samba_home_drive = options.samba_home_drive.sub(/([^:])$/, "\\1:")
end

if options.samba_logon_script
  member.samba_logon_script = options.samba_logon_script
end

if options.samba_profile_path
  member.samba_profile_path = options.samba_profile_path
end

unless options.enable.nil?
  if options.enable
    member.enable
  else
    member.disable
  end
end

member.save!

if options.new_user_name
  if options.computer_account
    options.new_user_name = options.new_user_name.chomp("$") + "$"
  end
  if member_class.exists?(options.new_user_name)
    format = _("%s already exists: %s")
    $stderr.puts(format % [member_type, options.new_user_name])
    exit 1
  end
  new_member = member_class.new(options.new_user_name)

  new_member.cn = options.new_user_name
  new_member.attributes = member.attributes.reject do |key, value|
    %w(dn cn uid).include?(key)
  end
  new_member.save!
  member.groups.each do |group|
    if options.computer_account
      group.computers -= [member]
      group.computers << new_member
    else
      group.users -= [member]
      group.users << new_member
    end
  end

  member.destroy
end

ActiveSambaLdap::Base.restart_nscd

ActiveSambaLdap::Base.clear_active_connections!
