# -*- Tcl -*-

# if the pol_fix result doesn't start with -, it's a flag
set pol_fix(maxlife) {-maxlife}
set pol_fix(minlife) {-minlife}
set pol_fix(minlength) {-minlength}
set pol_fix(minclasses) {-minclasses}
set pol_fix(oldkeys) {-history}

set pol_check(maxlife) check_lifetime_none
set pol_check(minlife) check_lifetime_none
set pol_check(minlength) check_decimal
set pol_check(minclasses) check_decimal
set pol_check(oldkeys) check_decimal

#
# policy modification fields
#
set policy_mod_fields {
    { "Policy:" {+-background #000} \
	    policy(name) "" \
	    label "+-relief flat -anchor w" }
    { "Min Lifetime:" default \
	    policy(minlife) save_policy(minlife) \
	    entry default check_lifetime_none }
    { "Max Lifetime:" default \
	    policy(maxlife) save_policy(maxlife) \
	    entry default check_lifetime_none }
    { "Min Character Classes:" default \
	    policy(minclasses) save_policy(minclasses) \
	    entry default check_decimal }
    { "Min Password Length:" default \
	    policy(minlength) save_policy(minlength) \
	    entry default check_decimal }
    { "Old Keys:" default \
	    policy(oldkeys) save_policy(oldkeys) \
	    entry default check_decimal }
    { "Principals Using Policy:" {+-background #000} \
	    policy(refcount) "" \
	    label "+-relief flat -anchor w" }
}

set policy_add_fields {
    { "Policy:" default \
	    policy(name) "" \
	    entry default check_policy_name }
    { "Min Lifetime:" default \
	    policy(minlife) "" \
	    entry default check_lifetime_none }
    { "Max Lifetime:" default \
	    policy(maxlife) "" \
	    entry default check_lifetime_none }
    { "Min Character Classes:" default \
	    policy(minclasses) "" \
	    entry default check_decimal }
    { "Min Password Length:" default \
	    policy(minlength) "" \
	    entry default check_decimal }
    { "Old Keys:" default \
	    policy(oldkeys) "" \
	    entry default check_decimal }
}

# Policy handling functions

proc load_policies { } {
    global policy_list
    
    # load list of policy names
    set policy_list [lsort [kadm5_getpols]]
}
 
proc populate_pols { } {
    global policy_list
    
    create_win_pols

    load_policies
    
    # populate the policies window
    .pols.lb delete 0 end
    foreach str $policy_list {
	.pols.lb insert end $str
    }
}

proc show_pol_info { pol } {
  global policy save_policy

  if {[winfo exists .policy]} {
      destroy .policy
  }
  create_win_pol_info edit
  
  if { [catch { set policy_info [kadm5_getpol $pol] } ] } {
      tk_dialog .dialog {Error} "Policy not found" {} 0 Ok
      load_policies
      catch { delete .policy }
  }

  # policy_info contains:
  # policy name, max life, min life, min length, min classes, old keys, ref

  set policy(name) [lindex $policy_info 0]
  set policy(maxlife) [kadm5_durtostr_none [lindex $policy_info 1]]
  set policy(minlife) [kadm5_durtostr_none [lindex $policy_info 2]]
  set policy(minlength) [lindex $policy_info 3]
  set policy(minclasses) [lindex $policy_info 4]
  set policy(oldkeys) [lindex $policy_info 5]
  set policy(refcount) [lindex $policy_info 6]

  # save the information 
  foreach k [array names policy] {
    set save_policy($k) $policy($k)
  }
}

proc create_win_pol_info { { type "edit" } } {
    global policy save_policy policy_mod_fields policy_add_fields

    # create the window for showing policy information
    toplevel .policy

    wm title .policy "Policy Information"
    set w .policy

    if { $type == "edit" } {
	create_entrylist $w.fields $policy_mod_fields
    } else {
	create_entrylist $w.fields $policy_add_fields
    }

    frame $w.bts
    button $w.bts.cancel -text "Cancel" -command "destroy $w"
    button $w.bts.revert -text "Revert All" \
	    -command [list revert_entrylist $w.fields $policy_mod_fields]
    button $w.bts.commit -text "Commit Changes" \
	    -command [list commit_pol_changes $type]
    pack $w.bts.cancel $w.bts.commit $w.bts.revert -side left
    
    pack $w.fields -side top -fill x
    pack $w.bts -side bottom -expand yes -anchor se
}

proc commit_pol_changes { type } {
    global debug policy save_policy pol_fix pol_check
    global policy_mod_fields policy_add_fields

    set policy(name) [string trim $policy(name)]

    if { $type == "edit" } {
	set ultimate_cmd "kadm5_modpol"
    } else {
	# must be add...
	foreach k [array names policy] {
	    set save_policy($k) "dummy-$k value"
	}
	set ultimate_cmd "kadm5_addpol"
    }


    if { $policy(name) == "" } {
	tk_dialog .dialog {Error} \
		"You must supply a name when adding a policy" {} 0 Ok
	return
    }

    if { [check_policy_name "" policy(name) 1] } {
	tk_dialog .dialog {Error} "Invalid policy name" {} 0 Ok
	return
    }

    set cmd ""
  
    # Step through other possible changes
    foreach k [list maxlife minlife minlength minclasses oldkeys] {
	if { $pol_check($k) != "" } {
	    if { [$pol_check($k) {} policy($k) 1] == 1 } {
		tk_dialog .dialog {Error} "\"$policy($k)\" is invalid." \
			{} 0 Ok
		return
	    }
	}
	if {$policy($k) != $save_policy($k)} {
	    if {$k == "maxlife" || $k == "minlife"} {
		lappend cmd $pol_fix($k) [kadm5_strtodur_none $policy($k)]
	    } else {
		lappend cmd $pol_fix($k) $policy($k)
	    }
	}
    }

    if { $cmd == "" } {
	destroy .policy
	return;
    }
    
    set cmd "$ultimate_cmd $cmd $policy(name)"
    
    # cross your fingers and run the command
    if { $debug || 1} {
	puts $cmd
    }
    if {[catch {eval $cmd} res] != 0} {
	tk_dialog .error {Error} \
		"Could not $type policy $policy(name): $res" {} 0 OK
	return
    }
    
    destroy .policy

    load_policies
    populate_pols
    
    refresh_principal_windows
}

proc create_win_pols { } {
    if {[winfo exists .pols]} {
	wm deiconify .pols
	raise .pols
	return
    }

    # create and open the policy window
    toplevel .pols
    wm title .pols "Policy List"
    
    scrollbar .pols.sb -orient vertical -relief sunken \
	    -command ".pols.lb yview"
    
    listbox .pols.lb -selectmode extended -width 25 -relief sunken \
	    -yscrollcommand ".pols.sb set"
    bind .pols.lb <Double-1> {
	show_pol_info [.pols.lb get [lindex [.pols.lb curselection] 0]]
    }
    
    frame .pols.menu

    menubutton .pols.menu.file -menu .pols.menu.file.m -text "File" \
	    -underline 0
    menu .pols.menu.file.m -tearoff 0
    .pols.menu.file.m add command -label "Refresh Policy List" -underline 0 \
	    -command "populate_pols"
    .pols.menu.file.m add command -label "Close" -underline 0 \
	    -command [list destroy .pols]

    menubutton .pols.menu.policy -menu .pols.menu.policy.m -text "Policy" \
	    -underline 1
    menu .pols.menu.policy.m -tearoff 0
    .pols.menu.policy.m add command -label "Add New" -underline 0 \
	    -command add_pol
    .pols.menu.policy.m add command -label "Delete" -underline 0\
	    -command delete_pol_sel
    .pols.menu.policy.m add command -label "Edit" -underline 0\
	    -command edit_pol_sel
    .pols.menu.policy.m add command -label "Copy" -underline 3\
	    -command copy_pol_sel

    pack .pols.menu.file .pols.menu.policy \
	    -side left
    
    pack .pols.menu -side top -expand yes -fill x

    pack .pols.sb -side right -fill y
    pack .pols.lb -side left -expand yes -fill both
    
    # read in the policies
    populate_pols
}

proc add_pol { { oldpol "" } } {
  global policy save_policy

  if {[winfo exists .policy]} {
      destroy .policy
  }
  create_win_pol_info add

  if { $oldpol == "" } {  
      set policy(name) ""
      set policy(minlife) "1 days"
      set policy(maxlife) "60 days"
      set policy(minlength) 1
      set policy(minclasses) 1
      set policy(oldkeys) 1
  } else {
      if { [catch { set policy_info [kadm5_getpol $oldpol] } ] } {
	  tk_dialog .dialog {Error} "Policy not found" {} 0 Ok
	  load_policies
	  catch { delete .policy }
      }
      set policy(name) ""
      set policy(maxlife) [kadm5_durtostr_none [lindex $policy_info 1]]
      set policy(minlife) [kadm5_durtostr_none [lindex $policy_info 2]]
      set policy(minlength) [lindex $policy_info 3]
      set policy(minclasses) [lindex $policy_info 4]
      set policy(oldkeys) [lindex $policy_info 5]
      set policy(refcount) [lindex $policy_info 6]
  }

  foreach k [array names policy] {
    set save_policy($k) $policy($k)
  }

  # force a new policy creation
  set save_policy(name) "dummy"
}

proc delete_pol_sel { } {
    # check the listbox
    set l [.pols.lb curselection]
    if {[llength $l] == 0} {
	tk_dialog .dialog {Error} "No policies selected" {} 0 Ok
	return
    } elseif {[llength $l] == 1} {
	set prompt "Are you sure you want to delete `[.pols.lb get $l]'?"
    } else {
	set prompt \
		"Are you sure you want to delete the [llength $l] selected policies?"
    }
    set result [tk_dialog .dialog {Policy Deletion} $prompt "" 0 No Yes]
    if {$result == 1} {
	foreach p $l {
	    global policy
	    set polname [.pols.lb get $p]
	    
	    if { [catch { kadm5_delpol $polname } res ] } {
		tk_dialog .dialog {Error} \
			"Cannot delete policy $polname: $res" {} 0 Ok
		continue
	    }
	    if { [winfo exists .policy] && \
		    $policy(name) == [.pols.lb get $p] } {
		destroy .policy
	    }
	}
	load_policies
	populate_pols
	refresh_principal_windows
    }
}

proc edit_pol_sel { } {
    # check the listbox
    set l [.pols.lb curselection]
    if {[llength $l] == 0} {
	tk_dialog .dialog {Error} "No policies selected" {} 0 Ok
	return
    } elseif {[llength $l] != 1} {
	tk_dialog .dialog {Error} "You must select exactly one policy to edit"\
		{} 0 Ok
	return
    }
    show_pol_info [.pols.lb get $l]
}

proc copy_pol_sel { } {
    # check the listbox
    set l [.pols.lb curselection]
    if {[llength $l] == 0} {
	tk_dialog .dialog {Error} "No policies selected" {} 0 Ok
	return
    } elseif {[llength $l] != 1} {
	tk_dialog .dialog {Error} "You must select exactly one policy to copy"\
		{} 0 Ok
	return
    }
    add_pol [.pols.lb get $l]
}

