#!/usr/sgitcl/bin/sgitcl -n
# This program is the gui for the dhcp_bootp server program. It allows the
# user to set up the configuration and options to run the server
#
#most Widgets have a capital W at end

dlopen libsautil.so init SAUtil_Init

#falback resources get these from the app-defaults/Dhcp file
set fbacks {
    {*sgiMode:       true}
    {*useSchemes:    all}
    {Dhcp*title:	Proclaim Server}
}

#
#constants for printing lease info.
#
set SECSPERDAY [expr 3600*24]
set SECSPERHOUR 3600
set SECSPERMIN 60
#
#constants to define the frequency at which to update lease info.
#
set MINUPDFREQ 5000
set INITUPDFREQ [expr $SECSPERMIN*1000]
#
# error messages
#
set ILLEGAL_OPTIONS_MSG "Illegal Option in File"
set Y_NOT_SUPPORTED "-y option is ignored"
set FILE_EXISTS "Configuration exists"
set FILE_NOT_EXISTS "Configuration does not exist"
set SELECT_FILE "Select a configuration from the list"
set WRONG_CONFIG_FORMAT "This configuration is badly formatted"
set SAVE_FILE_QTN "Changes mades, Save?"
set DELETE_FILE_QTN "Confirm Delete"
#
#global defines
#
set defaultOptionsDir /etc/config
set defaultOptionsFile $defaultOptionsDir/dhcp_bootp.options
set defaultProclaimConfigDir /var/dhcp/config
set defaultProclaimConfigFile config.Default
set etherToIPFile /var/tmp/etherToIP
set defaultHostsMap /etc/hosts
set defaultEthersMap /etc/ethers
set defaultSysName /unix


set defaultProclaimMask config.*

#
#global variables
#
set optionsFile $defaultOptionsFile
set hostsMap		""	;# -w
set ethersMap		""	;# -e
set sysName		""	;# -u
set proclaimConfigDir	$defaultProclaimConfigDir	;# -c
set otherOptions	""

set updFreq $INITUPDFREQ ; # frequency of updating lease information
set timer 0 ; # handle for the timer
set lastModTime ""

set mapsOnOffStatus 0
#
#matrix Widget values
#
set colLabels "Host, Domain, IP\nAddress, Expiration\nDate     Time"
set colMaxLengths  "64, 20, 30, 50"
set colWidths "12, 15, 15, 20"
#
#global widgets
#
set dialW	""; #is a global used for small popup messages
set qdialW	""; #is a global used for questions
set fileSDWokCB "" ; # callback for file selection widget
set qdialOkCB ""
set qdialCanCB ""
#
# table of labels for the optios
# the app-defaults file contains the actual labels
# this array holds the widget names for the labels
# We do this in order to allow the label strings to be 
# configured as per the users needs
#
set optionLabel(Serve_This_Network:) lbl68	;# 1
set optionLabel(pro_address_counter:) lbl0	;# 1
set optionLabel(pro_host_pfx_counter:) lbl1	;# 1
set optionLabel(pro_netmask:) lbl2		;# 1
set optionLabel(pro_lease:) lbl3		;# 1
set optionLabel(pro_host_prefix:) lbl5		;# 1
set optionLabel(pro_choose_name:) lbl6		;# 1
set optionLabel(pro_ipaddress_range:) lbl7	;# 1
set optionLabel(pro_router_addr:) lbl8  	;# 1
set optionLabel(pro_timeserver_addr:) lbl9	;# 2
set optionLabel(pro_nameserver_addr:) lbl10	;# 2
set optionLabel(pro_dnsserver_addr:) lbl11	;# 2
set optionLabel(pro_nisserver_addr:) lbl12	;# 4
set optionLabel(pro_dns_domain:) lbl13		;# 1
set optionLabel(pro_nis_domain:) lbl14		;# 4
set optionLabel(pro_mtu:) lbl15			;# 6
set optionLabel(pro_allnets_local:) lbl16	;# 6
set optionLabel(pro_broadcast:) lbl17		;# 6
set optionLabel(pro_domask_disc:) lbl18		;# 6
set optionLabel(pro_resp_mask_req:) lbl19	;# 6
set optionLabel(pro_static_routes:) lbl20	;# 6
set optionLabel(pro_do_router_disc:) lbl21	;# 6
set optionLabel(pro_router_solicit_addr:) lbl22 ;# 6
set optionLabel(pro_logserver_addr:) lbl23	;# 2
set optionLabel(pro_cookieserver_addr:) lbl24	;# 2
set optionLabel(pro_LPRserver_addr:) lbl25	;# 2
set optionLabel(pro_resourceserver_addr:) lbl26	;# 2
set optionLabel(pro_bootfile_size:) lbl27	;# 1
set optionLabel(pro_swapserver_addr:) lbl28	;# 2
set optionLabel(pro_IPforwarding:) lbl29	;# 5
set optionLabel(pro_source_routing:) lbl30	;# 5
set optionLabel(pro_policy_filter:) lbl31	;# 5
set optionLabel(pro_max_reassy_size:) lbl32	;# 5
set optionLabel(pro_IP_ttl:) lbl33		;# 5
set optionLabel(pro_pathmtu_timeout:) lbl34	;# 5
set optionLabel(pro_pathmtu_table:) lbl35	;# 5
set optionLabel(pro_trailer_encaps:) lbl36	;# 7
set optionLabel(pro_arpcache_timeout:)  lbl37	;# 7
set optionLabel(pro_ether_encaps:) lbl38	;# 7
set optionLabel(pro_TCP_ttl:) lbl39		;# 8
set optionLabel(pro_TCP_keepalive_intrvl:) lbl40;# 8
set optionLabel(pro_TCP_keepalive_garbage:) lbl41;# 8
set optionLabel(pro_NetBIOS_nameserver_addr:) lbl42	;# 4
set optionLabel(pro_NetBIOS_distrserver_addr:) lbl43	;# 4
set optionLabel(pro_NetBIOS_nodetype:) lbl44	;# 4
set optionLabel(pro_NetBIOS_scope:) lbl45	;# 4
set optionLabel(pro_X_fontserver_addr:) lbl46	;# 3
set optionLabel(pro_X_displaymgr_addr:) lbl47	;# 3
set optionLabel(pro_nisplus_domain:) lbl48	;# 4
set optionLabel(pro_nisplusserver_addr:) lbl49	;# 4
set optionLabel(pro_mobileIP_homeagent_addr:) lbl50	;# 3
set optionLabel(pro_SMTPserver_addr:) lbl51	;# 3
set optionLabel(pro_POP3server_addr:) lbl52	;# 3
set optionLabel(pro_NNTPserver_addr:) lbl53	;# 3
set optionLabel(pro_WWWserver_addr:) lbl54	;# 3
set optionLabel(pro_fingerserver_addr:) lbl55	;# 3
set optionLabel(pro_IRCserver_addr:) lbl56	;# 3
set optionLabel(pro_StreetTalkserver_addr:) lbl57	;# 3
set optionLabel(pro_STDAserver_addr:) lbl58	;# 3
set optionLabel(pro_time_offset:) lbl59		;# 1
set optionLabel(pro_nameserver116_addr:) lbl60  ;# 2
set optionLabel(pro_impressserver_addr:) lbl61  ;# 2
set optionLabel(pro_meritdump_pathname:) lbl62  ;# 1
set optionLabel(pro_root_pathname:) lbl63	;# 1
set optionLabel(pro_extensions_pathname:) lbl64 ;# 1
set optionLabel(pro_NTPserver_addr:) lbl65	;# 2
set optionLabel(pro_TFTPserver_name:) lbl66	;# 1
set optionLabel(pro_bootfile_name:) lbl67	;# 1

#
#table of callbacks to verify entries in configurations
#It is an array indexed by the option that is being validated
#
set verifyEntryProc(Serve_This_Network:) entryBlankBoolean
set verifyEntryProc(pro_address_counter:) entryBlankInt
set verifyEntryProc(pro_host_pfx_counter:) entryBlankInt
set verifyEntryProc(pro_netmask:) entryBlankAddr
set verifyEntryProc(pro_lease:) entryBlankLong
set verifyEntryProc(pro_host_prefix:) entryBlankString
set verifyEntryProc(pro_choose_name:) entryBlankBoolean
set verifyEntryProc(pro_ipaddress_range:) entryIntRanges
set verifyEntryProc(pro_router_addr:) entryBlankAddrList
set verifyEntryProc(pro_timeserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_nameserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_dnsserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_nisserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_dns_domain:) entryBlankString
set verifyEntryProc(pro_nis_domain:) entryBlankString
set verifyEntryProc(pro_mtu:) entryBlankInt
set verifyEntryProc(pro_allnets_local:) entryBlankBoolean
set verifyEntryProc(pro_broadcast:) entryBlankAddr
set verifyEntryProc(pro_domask_disc:) entryBlankBoolean
set verifyEntryProc(pro_resp_mask_req:) entryBlankBoolean
set verifyEntryProc(pro_static_routes:) entryBlankAddrPair
set verifyEntryProc(pro_do_router_disc:) entryBlankBoolean
set verifyEntryProc(pro_router_solicit_addr:) entryBlankAddr
set verifyEntryProc(pro_logserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_cookieserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_LPRserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_resourceserver_addr:) entryBlankAddrList 
set verifyEntryProc(pro_bootfile_size:) entryBlankInt
set verifyEntryProc(pro_swapserver_addr:) entryBlankAddr
set verifyEntryProc(pro_IPforwarding:) entryBlankBoolean
set verifyEntryProc(pro_source_routing:) entryBlankBoolean
set verifyEntryProc(pro_policy_filter:) entryBlankAddrList
set verifyEntryProc(pro_max_reassy_size:) entryBlankInt
set verifyEntryProc(pro_IP_ttl:) entryBlankInt
set verifyEntryProc(pro_pathmtu_timeout:) entryBlankLong
set verifyEntryProc(pro_pathmtu_table:) entryBlankInt ; # should be INtList
set verifyEntryProc(pro_trailer_encaps:) entryBlankBoolean
set verifyEntryProc(pro_arpcache_timeout:) entryBlankLong
set verifyEntryProc(pro_ether_encaps:) entryBlankBoolean
set verifyEntryProc(pro_TCP_ttl:) entryBlankInt
set verifyEntryProc(pro_TCP_keepalive_intrvl:) entryBlankLong
set verifyEntryProc(pro_TCP_keepalive_garbage:) entryBlankBoolean
set verifyEntryProc(pro_NetBIOS_nameserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_NetBIOS_distrserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_NetBIOS_nodetype:) entryBlankInt
set verifyEntryProc(pro_NetBIOS_scope:) entryBlankString ; # check this
set verifyEntryProc(pro_X_fontserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_X_displaymgr_addr:) entryBlankAddrList
set verifyEntryProc(pro_nisplus_domain:) entryBlankString
set verifyEntryProc(pro_nisplusserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_mobileIP_homeagent_addr:) entryBlankAddrList
set verifyEntryProc(pro_SMTPserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_POP3server_addr:) entryBlankAddrList
set verifyEntryProc(pro_NNTPserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_WWWserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_fingerserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_IRCserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_StreetTalkserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_STDAserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_time_offset:) entryBlankInt
set verifyEntryProc(pro_nameserver116_addr:) entryBlankAddrList
set verifyEntryProc(pro_impressserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_meritdump_pathname:) entryBlankString
set verifyEntryProc(pro_root_pathname:) entryBlankString
set verifyEntryProc(pro_extensions_pathname:) entryBlankString
set verifyEntryProc(pro_NTPserver_addr:) entryBlankAddrList
set verifyEntryProc(pro_TFTPserver_name:) entryBlankString
set verifyEntryProc(pro_bootfile_name:) entryBlankString
#
# groups of fields for display
#
# General group and Servers group Section 3 of RFC 1533
#
set genOptions1 {Serve_This_Network: pro_address_counter: \
	pro_host_pfx_counter: pro_netmask: pro_lease: pro_host_prefix: \
	pro_choose_name: pro_ipaddress_range: pro_router_addr: \
	pro_bootfile_size: pro_time_offset: pro_meritdump_pathname: \
	pro_root_pathname: pro_extensions_pathname: \
	pro_TFTPserver_name: pro_bootfile_name: }

set serverOptions2 {pro_dns_domain: pro_dnsserver_addr:\
	pro_timeserver_addr:\
	pro_logserver_addr: pro_cookieserver_addr: pro_LPRserver_addr:\
	pro_resourceserver_addr: pro_swapserver_addr: pro_nameserver116_addr:\
	pro_impressserver_addr: pro_NTPserver_addr: }

#
# section 8 of RFC 1533
#
set applOptions3 {pro_X_fontserver_addr: pro_X_displaymgr_addr:\
	pro_mobileIP_homeagent_addr: pro_SMTPserver_addr:\
	pro_POP3server_addr: pro_NNTPserver_addr: pro_WWWserver_addr:\
	pro_fingerserver_addr: pro_IRCserver_addr:\
	pro_StreetTalkserver_addr: pro_STDAserver_addr:}
	
set serviceOptions4 { pro_NetBIOS_nameserver_addr:\
	pro_NetBIOS_distrserver_addr:\
	pro_NetBIOS_nodetype: pro_NetBIOS_scope:\
	pro_nis_domain: pro_nisserver_addr:\
	pro_nisplus_domain: pro_nisplusserver_addr:}
	

#
#section 4 of RFC 1533
#
set ipperhostOptions5 {pro_IPforwarding: pro_source_routing:\
	pro_policy_filter: pro_max_reassy_size: pro_IP_ttl:\
	pro_pathmtu_timeout: pro_pathmtu_table:}

#
#setion 5 of RFC 1533
#
set ipperinterfaceOptions6 {pro_mtu: pro_allnets_local: pro_broadcast:\
	pro_domask_disc: pro_resp_mask_req: pro_do_router_disc:\
	pro_router_solicit_addr: pro_static_routes: }
#
# section 6 
#
set linkperinterfaceOptions7 {pro_trailer_encaps: pro_arpcache_timeout:\
	pro_ether_encaps:}

#
# section 7
set tcpOptions8 {pro_TCP_ttl: pro_TCP_keepalive_intrvl:\
	pro_TCP_keepalive_garbage:}

#
# this procedure calls the appropriate procedure for validating
# options entries depending on the entry index in the verifyEntryProc
# array
#
set errorW ""
set currentEntryW ""
proc verifyEntry {w} {
    global editedForm oldValue
    global verifyEntryProc currentEntryW errorW

    set currentEntryW $w
    set index [string range $w [expr [string last txt_ $w]+4] end]
    $w getValues -value t
    if {[string compare $oldValue($index) $t]} {
	set editedForm 1
    }
    if {[catch {set verifyEntryProc($index)}]} {
	entryBlankString $index $t
    } else {
	if {[info exists verifyEntryProc($index)]} {
		$verifyEntryProc($index) $index $t 
	}
    }
    if {![string compare $errorW $w]} {
	set errorW ""
    }
}

#
# validates a range of integers
#
proc entryIntRanges {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [string trimright $t]]
    if {![string compare $t ""]} {
	return
    }
    if {[regexp {^(([0-9]+ *- *[0-9]+ *, *)*(([0-9]+ *- *[0-9]+ *)|( *[0-9]+)))$} $t]} {
	return
    }
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, e.g. 1-3, 5-7, 9"
    }
}

#
# validates address pairs
#
proc entryBlankAddrPair {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [string trimright $t]]
    if {![string compare $t ""]} {
	return
    }
    if {[regexp {^((([0-9]+.[0-9]+.[0-9]+.[0-9]+) *- *([0-9]+.[0-9]+.[0-9]+.[0-9]+) *, *)*(([0-9]+.[0-9]+.[0-9]+.[0-9]+) *- *([0-9]+.[0-9]+.[0-9]+.[0-9]+)))$} $t]} { 
	return
    }
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, e.g. addr1 - addr2, addr3 - addr4"
    }
}

#
# validates address list
#
proc entryBlankAddrList {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [string trimright $t]]
    if {![string compare $t ""]} {
	return
    }
    if {[regexp {^((([0-9]+.[0-9]+.[0-9]+.[0-9]+)( )*,( )*)*([0-9]+.[0-9]+.[0-9]+.[0-9]+))$} $t]} {
	return
    }
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, e.g. addr1, addr2, addr3"
    }
}

#
# validate a boolean
#
proc entryBlankBoolean {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [ string trimright $t]]
    if {![string compare $t ""]} {
	return
    }
    if {($t == "Y") || ($t == "N") || ($t == "y") || ($t == "n") || \
	    ($t == 0) || ($t == 1) ||\
	    ($t == "No") || ($t == "no") || \
	    ($t == "Yes") || ($t == "yes")} {
	return
    } 
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, enter 0 or 1"
    }
}

#
#validate integer
#
proc entryBlankInt {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [ string trimright $t]]
    if {![string compare $t ""]} {
	return
    }
    if {[regexp {^((\ )*)?((0x)[0-9a-fA-F]+|[0-9]+)$} $t]} {
	return
    }
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, enter integer"
    }
}

#
# validate ip address
#
proc entryBlankAddr {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [ string trimright $t]]
    if {![string compare $t ""]} {
	return
    }
    if {[scan $t "0x%x" a]} {
	return
    }
    if {[scan $t " %d.%d.%d.%d" a b c d] >= 4} {
	if {($a < 0) || ($a > 255)} {
	    if {[string compare $errorW $currentEntryW]} {
		set errorW $currentEntryW
		postDialog $dialW dialog_error "$entry error, enter address a.b.c.d"
	    }
	    return
	}
	if {($b < 0) || ($b > 255)} {
	    if {[string compare $errorW $currentEntryW]} {
		set errorW $currentEntryW
		postDialog $dialW dialog_error "$entry error, enter address a.b.c.d"
	    }
	    return
	}
	if {($c < 0) || ($c > 255)} {
	    if {[string compare $errorW $currentEntryW]} {
		set errorW $currentEntryW
		postDialog $dialW dialog_error "$entry error, enter address a.b.c.d"
	    }
	    return
	}
	if {($d < 0) || ($a > 255)} {
	    if {[string compare $errorW $currentEntryW]} {
		set errorW $currentEntryW
		postDialog $dialW dialog_error "$entry error, enter address a.b.c.d"
	    }
	    return
	}
	return
    }
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, enter address a.b.c.d"
    }
}
 
#
# validates long integer
#   
proc entryBlankLong {entry t} {
    global dialW errorW currentEntryW
    set t [string trimleft [ string trimright $t]]
 
    if {![string compare $t ""]} {
	return
    }
    if {[regexp {^((\ )*)?((0x)[0-9a-fA-F]+|[0-9]+)$} $t]} {
	return
    }
    if {[string compare $errorW $currentEntryW]} {
	set errorW $currentEntryW
	postDialog $dialW dialog_error "$entry error, enter integer"
    }
}

#
# string entry
#
proc entryBlankString {entry t} {
#    puts "entryBlankString called:$entry value: $t"
}

#
#general routines used in several places 	    
#
# this routine creates a control panel for a dialog
# the parent should be a pane and the number of buttons and callback list 
# is passed as parameter
#
proc createCPanel {parent nbuttons whichDef cbList } {
    xmForm $parent.cpForm
    $parent.cpForm setValues -fractionBase [expr 20*$nbuttons-1]\
	    -leftOffset 10 -rightOffset 10
    set retW $parent.cpForm
    set oldw 0
    for {set i 0} {$i < $nbuttons} {set i [expr $i+1]} {
	xmPushButton $retW.btn$i managed
	$retW.btn$i getValues -width w
	if {$w > $oldw} {
	    set oldw $w
	}
	$retW.btn$i activateCallback [lindex $cbList $i]
	$retW.btn$i setValues -topAttachment attach_form\
		-bottomAttachment attach_form\
		-showAsDefaults [expr $i==$whichDef]\
		-defaultButtonShadowThickness 1
	if {$i == [expr $nbuttons-1]} {
	    $retW.btn$i setValues -rightAttachment attach_form
	} 
	if {$i != 0} {
	    if {$i != [expr $nbuttons-1]} {
		$retW.btn$i setValues -leftAttachment attach_position -leftPosition [expr 20*$i]
	    }
	} else {
	    $parent.cpForm.btn$i getValues -height ht
	    $retW.btn$i setValues -leftAttachment attach_form
	}
    }
    $retW manageChild
    $parent.cpForm getValues -marginHeight h
    set ht [expr $ht + 2*$h]
    if {$whichDef == -1} {
	$parent.cpForm setValues -paneMaximum $ht -paneMinimum $ht
    } else {
	$parent.cpForm setValues -paneMaximum $ht -paneMinimum $ht\
		-defaultButton $retW.btn$whichDef
    }
    for {set i 0} {$i < $nbuttons} {incr i} {
	$retW.btn$i setValues -width [expr $oldw + 30]
    }
    return $retW
}

#
# general dialog posting the type parameter can be any of the dialog types
#
proc postDialog {widget type msg} {
    global dialW

    if {![string compare $widget ""]} {
	xmMessageDialog .dialW
	set dialW dialW
	set widget dialW
	.$widget.Cancel unmanageChild
	.$widget.Help unmanageChild
    }
    .$widget setValues -dialogType $type -messageString $msg
    .$widget manageChild
}

#
# question dialog
#
proc ask {widget msg okCB canCB} {
    global stillModal answer qdialOkCB qdialCanCB qdialW
    if {![string compare $widget ""]} {
	xmQuestionDialog .qdialW\
		-dialogStyle dialog_full_application_modal
	set qdialW qdialW
	set widget qdialW
	.$widget.Help unmanageChild
    }
    if {[string compare $qdialOkCB ""]} {
	.$widget removeCallback okCallback $qdialOkCB
    }
    if {[string compare $qdialOkCB ""]} {
	.$widget removeCallback cancelCallback $qdialCanCB
    }
    set qdialOkCB $okCB
    set qdialCanCB $canCB
    .$widget okCallback $qdialOkCB
    .$widget cancelCallback $qdialCanCB
    
    .$widget setValues -messageString $msg
    .$widget manageChild
    set stillModal 1
    while {$stillModal} {
	. processEvent
    }
    .$widget unmanageChild
}

#
# this procedure creates an entry form, a entry for each item in the the
# second parameter is created
#
proc createEntryW {parent configList index} {
    global optionLabel

    set rowcolW [xmRowColumn $parent.rcW$index \
	    -isAligned true -numColumns 2 -orientation vertical\
	    -packing pack_column]
    set n {}
    foreach i $configList {
	xmLabel $rowcolW.$optionLabel($i) managed \
		-marginLeft 20
	lappend n $i
    }
    foreach in $n {
	xmText $rowcolW.txt_$in managed
	$rowcolW.txt_$in losingFocusCallback {verifyEntry %w }
	$rowcolW.txt_$in activateCallback {verifyEntry %w }
    }
    $rowcolW manageChild
    return $rowcolW
}

#
# this routine unmanages all labels and text widget that were part of an
# older entry form
#
proc destroyEntryW {parent} {
    $parent getValues -children ch
    foreach ich $ch {
	[string trim $ich " ,"] unmanageChild
    }
}
#
# Options File Selection 
#
proc doFile {Dir FileMask File okcb} {
    global fileSDWokCB 
    .fileSDW setValues -dirMask $FileMask -directory $Dir 
    if { ![lempty $File] } {
	    .fileSDW setValues -dirSpec $File
    }
    if {[string compare $fileSDWokCB ""]} {
	.fileSDW removeCallback okCallback $fileSDWokCB
    } else {
	.fileSDW cancelCallback {.fileSDW unmanageChild}
    }
    .fileSDW okCallback $okcb
    set fileSDWokCB $okcb

    .fileSDW manageChild
}
#
# Options Form selections
#
proc doOptions {} {
    global fileSDWokCB
    global optionsFile
    .optionsFormW manageChild
    readOptionsFile
}
#
# read and update the Options Form
#
proc readOptionsFile {} {
    global optionsFile defaultSysName defaultProclaimConfigDir
    global hostsMap ethersMap \
	    sysName proclaimConfigDir otherOptions
    global dialW ILLEGAL_OPTIONS_MSG Y_NOT_SUPPORTED
    if {[catch {set fd [open $optionsFile r]} msg]} {
	postDialog $dialW dialog_error [list $msg]
	return
    }
    setMapsOn
    set otherOptions ""
    while {[gets $fd line] >= 0} {
	if {![cequal [cindex $line 0] #]} {
	    set len [llength $line]
	    for {set index 0} {$index < $len} {set index [expr $index+1]} {
		switch -- [lindex $line $index] {
		    -y {
		        postDialog $dialW dialog_error $Y_NOT_SUPPORTED
		    }
		    -w { 
			setMapsOn
			set hostsMap [lindex $line [set index [expr $index+1]]]
			.optionsFormW.paneW.rcW.hostsTextW setValues -value $hostsMap
		    }
		    -e { 
			setMapsOn
			set ethersMap [lindex $line [set index [expr $index+1]]]
			.optionsFormW.paneW.rcW.ethersTextW setValues -value $ethersMap
		    }
		    -u { 
			set sysName [lindex $line [set index [expr $index+1]]]
			.optionsFormW.paneW.rcW.sysnameTextW setValues -value $sysName
		    }
		    -c { 
			set proclaimConfigDir [lindex $line [set index [expr $index+1]]]
			.optionsFormW.paneW.rcW.proclaimConfDirTextW setValues -value $proclaimConfigDir
		    }
		    -x {
			set otherOptions [format "%s -x" $otherOptions]
		    }
		    -t {
			set buf [lindex $line [set index [expr $index + 1]]]
			set otherOptions [format "%s -t %s" $otherOptions $buf]
		    }
		    -n {
			set otherOptions [format "%s -n" $otherOptions]
                    }
		    -m {
			set buf [lindex $line [set index [expr $index + 1]]]
			set otherOptions [format "%s -m %s" $otherOptions $buf]
		    }
		    -r {
 			set buf [lindex $line [set index [expr $index+1]]]
			set otherOptions [format "%s -r %s" $otherOptions $buf]
		    }
		    -W {
			set otherOptions [format "%s -W" $otherOptions]
		    }
		    -E {
			set otherOptions [format "%s -E" $otherOptions]
		    }
		    -pn {
			set otherOptions [format "%s -pn" $otherOptions]
		    }
		    -pt {
 			set buf [lindex $line [set index [expr $index+1]]]
			set otherOptions [format "%s -pt %s" $otherOptions $buf]
		    }
		    -pl {
 			set buf [lindex $line [set index [expr $index+1]]]
			set otherOptions [format "%s -pl %s" $otherOptions $buf]
		    }
		    -pd {
			set otherOptions [format "%s -pd" $otherOptions]
		    }
		    -dn {
			set otherOptions [format "%s -dn" $otherOptions]
		    }
		    -da {
			set otherOptions [format "%s -da" $otherOptions]
		    }
		    -db {
			set otherOptions [format "%s -db" $otherOptions]
		    }
		    -dc {
			set otherOptions [format "%s -dc" $otherOptions]
		    }
		    -ds {
			set otherOptions [format "%s -ds" $otherOptions]
		    }
		    -dt {
 			set buf [lindex $line [set index [expr $index+1]]]
			set otherOptions [format "%s -dt %s" $otherOptions $buf]
		    }
		    -l {
 			set buf [lindex $line [set index [expr $index+1]]]
			set otherOptions [format "%s -l %s" $otherOptions $buf]
		    }
		    default { 
			postDialog $dialW dialog_error $ILLEGAL_OPTIONS_MSG
		    }
		}
	    }
	}
    }
    close $fd
    .optionsFormW.paneW.rcW.otherOptionsTextW setValues -value $otherOptions
    if {![string compare [string trim $proclaimConfigDir] ""]} {
	set proclaimConfigDir $defaultProclaimConfigDir
	.optionsFormW.paneW.rcW.proclaimConfDirTextW setValues\
		-value $proclaimConfigDir
    }
    if {![string compare [string trim $sysName] ""]} {
	set sysName $defaultSysName
	.optionsFormW.paneW.rcW.sysnameTextW setValues -value $sysName
    }
}


#
#define some callbacks used in the options form
#
proc optionsUpdCB {} {
    set error [optionsAppCB]
    if {$error == 0} {
	.optionsFormW unmanageChild
    }
}

proc optionsAppCB {} {
    global dialW mapsOnOffStatus
    global optionsFile defaultProclaimConfigDir defaultEthersMap\
	defaultSysName defaultHostsMap 
    global  hostsMap ethersMap sysName\
	    proclaimConfigDir otherOptions
    set buf ""
    set error 0
    .optionsFormW.paneW.rcW.hostsTextW getValues -value hostsMap
    if {[string compare [string trim $hostsMap] ""]} {
	if {[string compare $hostsMap $defaultHostsMap]} {
	    set buf [format "%s-w %s " $buf $hostsMap]
	}
    }
    .optionsFormW.paneW.rcW.ethersTextW getValues -value ethersMap
    if {[string compare [string trim $ethersMap] ""]} {
	if {[string compare $ethersMap $defaultEthersMap]} {
	    set buf [format "%s-e %s " $buf $ethersMap]
	}
    }
    .optionsFormW.paneW.rcW.sysnameTextW getValues -value sysName
    if {[string compare [string trim $sysName] ""]} {
	if {[string compare $sysName $defaultSysName]} {
	    set buf [format "%s-u %s " $buf $sysName]
	}
    }
    .optionsFormW.paneW.rcW.proclaimConfDirTextW getValues -value proclaimConfigDir
    if {[string compare [string trim $proclaimConfigDir] ""]} {
	if {[string compare $proclaimConfigDir $defaultProclaimConfigDir]} {
	    set buf [format "%s-c %s " $buf $proclaimConfigDir]
	}
    } else {
	set proclaimConfigDir $defaultProclaimConfigDir
    }
    .optionsFormW.paneW.rcW.otherOptionsTextW getValues -value otherOptions
    if {[string compare [string trim $otherOptions] ""]} {
	if {[string compare [string trim $buf] ""]} {
	    set buf [format "%s %s" $buf $otherOptions]
	} else {
	    set buf [format "%s" [string trim $otherOptions]]
	}
    } 
    
    if {!($error)} {
	if {[catch {set fd [open $optionsFile w]} msg]} {
	    postDialog $dialW dialog_error [list $msg]
	    return
	}
	puts $fd $buf
	close $fd
    }
    return $error
}

proc optionsCanCB {} {
    .optionsFormW unmanageChild
}


#
# Interface Configuration callbacks
#
# Menu Button on Configuration Pulldown menu pressed
#
proc doConfiguration {} {
    global proclaimConfigDir
    .configFormW.paneW.rc1W.dirTextW setValues -value $proclaimConfigDir
    set cFiles [getConfigFiles]
    .configFormW.paneW.listW setValues -items $cFiles\
	    -itemCount [llength $cFiles]
    .configFormW manageChild
}

#
# find all the config files in the configuration directory
# return the list of files
#
proc getConfigFiles {} {
    global proclaimConfigDir defaultProclaimConfigDir
    if {![string compare $proclaimConfigDir ""]} {
	set proclaimConfigDir $defaultProclaimConfigDir
    }
    set configFiles [glob -nocomplain $proclaimConfigDir/config.*]
    set cFiles {}
    foreach l $configFiles {
	lappend cFiles [string range [file tail $l] 7 end]
    }
    return $cFiles
}

#
# read config file and update values in all windows
#
proc updEditConfigForm {configFile} {
    global configEntryW forms noForms configList editedForm oldValue
    global dialW WRONG_CONFIG_FORMAT proclaimConfigDir\
	    editConfigFile verifyEntryProc curFormIndex newFormIndex
    $configEntryW($curFormIndex) unmanageChild
    set editedForm 0
    set curFormIndex $newFormIndex
    set editConfigFile $configFile
    if {[catch {set fd [open $editConfigFile r]} msg]} {
	postDialog $dialW dialog_error [list $msg]
	return
    }
    while {[gets $fd line] >= 0} {
	if {![cequal [cindex $line 0] #]} {
	    if {[set index [string first : $line]] == -1} {
		postDialog $dialW dialog_error $WRONG_CONFIG_FORMAT
	    } else {
		set in [string range $line 0 $index]
		lappend configList $in
		set x [string trim [string range $line [expr $index+1] end]]
		if {! [info exists verifyEntryProc($in)]} {
		    continue
		}
		if {($verifyEntryProc($in) == "entryBlankBoolean")} {
		    if {($x == 0)} {
			set x N
		    } elseif {($x == 1)} {
			set x Y
		    }
		}
		for {set i 0} {$i < $noForms} {incr i} {
		    set whichList [lsearch [lindex $forms $i] $in]
		    if {$whichList != -1} {
			$configEntryW($i).txt_$in setValues -value $x
			set oldValue($in) $x
			break
		    }
		}
	    }
	}
    }
    set i [string last / $editConfigFile]
    if {$i == -1} {
	set fileName $editConfigFile
    } else {
	set fileName [string range $editConfigFile [incr i] end]
    }
    [.editConfigFormW parent] setValues -title\
	    [format "Proclaim: Configuration - %s" $fileName]
    close $fd
    .fileSDW unmanageChild
    $configEntryW($curFormIndex) manageChild
    .editConfigFormW manageChild
}

proc showEntryW {w} {
    global configEntryW newFormIndex curFormIndex
    
    regexp {[0-9]+} $w newFormIndex 
    $configEntryW($curFormIndex) unmanageChild
    $configEntryW($newFormIndex) manageChild
    set curFormIndex $newFormIndex
}

#
# when the configuration directory is changed 
# set the config files correctly in the window
#
proc updateConfigDir {} {
    global proclaimConfigDir
    .configFormW.paneW.rc1W.dirTextW getValues -value proclaimConfigDir
    set cFiles [getConfigFiles]
    .configFormW.paneW.listW setValues -items $cFiles\
	    -itemCount [llength $cFiles]
    .configFormW.paneW.formW.textW setValues -value ""
}
 
# 
# when a configuration is selected from the list
# update it in the selected text window
#   
proc doSelectFromList {} {
    .configFormW.paneW.listW getValues -selectedItems items
    .configFormW.paneW.formW.textW setValues -value $items
}

#
# The apply button was pressed - do either add/del
# update the directory and the list
#
proc configAddCB {} {
    global dialW proclaimConfigDir defaultProclaimConfigDir\
	    defaultProclaimConfigFile
    global FILE_EXISTS FILE_NOT_EXISTS SELECT_FILE
    set error 0
    .configFormW.paneW.formW.textW getValues -value entry
    if {[string compare $entry ""]} {
	set entry [format "config.%s" $entry]
	if {[file exists $proclaimConfigDir/$entry]} {
	    postDialog $dialW dialog_error $FILE_EXISTS
	    set error 1
	} else {
	    .configFormW.paneW.listW getValues -selectedItems items
	    if {[string compare $items ""]} {
		set items [format "config.%s" $items]
		if {[catch {exec cp $proclaimConfigDir/$items $proclaimConfigDir/$entry} msg]} {
		    postDialog $dialW dialog_error [list $msg]
		    return
		}
	    } else {
		if {[catch {exec cp $defaultProclaimConfigDir/$defaultProclaimConfigFile $proclaimConfigDir/$entry} msg]} {
		    postDialog $dialW dialog_error [list $msg]
		    return
		}
	    }		    
	    updateConfigDir
	    .configFormW.paneW.formW.textW setValues -value ""
	}
    } else {
	postDialog $dialW dialog_error $SELECT_FILE
    }
}

proc deleteConfigOkCB {} {
    global dialW proclaimConfigDir defaultProclaimConfigDir\
	    defaultProclaimConfigFile editConfigFile stillModal answer\
	    editedForm
    global FILE_EXISTS FILE_NOT_EXISTS SELECT_FILE
    set stillModal 0
    set answer 1
    set error 0
    set entry $editConfigFile
    if {[string compare $entry ""]} {
	if {[file exists $entry]} {
	    if {[catch {exec rm $entry} msg]} {
		postDialog $dialW dialog_error [list $msg]
		return
	    }
	    .editConfigFormW unmanageChild
	    set editedForm 0
	    return
	} else {
	    postDialog $dialW dialog_error $FILE_NOT_EXISTS
	}
    } else {
	postDialog $dialW dialog_error $SELECT_FILE
    }
}

proc deleteConfigCanCB {} {
    global stillModal answer
    set stillModal 0
    set answer 0
    return
}

#
# edit button was pressed - bring up the form and load the values form file
# by calling updEditConfigForm
#

proc configEdtCB {} {
    global proclaimConfigDir dialW SELECT_FILE editedForm qdialW SAVE_FILE_QTN\
	    oldValue
    .fileSDW getValues -dirSpec items 

    if {$editedForm} {
	ask $qdialW $SAVE_FILE_QTN editConfigOkCB editConfigCanCB
    } 
    set editedForm 0
    if {[string compare $items ""]} {
	updEditConfigForm $items 
    } else {
	postDialog $dialW dialog_error $SELECT_FILE
    }		
    
}

proc configSavCB {} {
    global proclaimConfigDir dialW SELECT_FILE  editConfigFile
    .fileSDW getValues -dirSpec items
    set editConfigFile $items
    if {[string compare $items ""]} {
	editConfigAppCB 
    } else {
	postDialog $dialW dialog_error $SELECT_FILE
    }		    
}
    
proc configClrCB {} {
    .configFormW.paneW.formW.textW setValues -value ""
}

proc configCanCB {} {
    .configFormW unmanageChild
}

#
#functions and callbacks for edit config
#
#
# update the values in the text fields to the file on disk
#
proc editConfigOkCB {} {
    global stillModal answer editedForm
    set stillModal 0
    set answer 1
    editConfigAppCB
    .editConfigFormW unmanageChild
    set editedForm 0
}
    
proc editConfigAppCB {} {
    global configList configEntryW dialW editConfigFile verifyEntryProc\
	    noForms forms oldValue editedForm proclaimConfigDir
    set i [string last / $editConfigFile]
    if {$i == -1} {
	set fileName $proclaimConfigDir/$editConfigFile
    } else {
	set fileName $editConfigFile
    }

    if {[catch {set fd [open $fileName w]} msg]} {
	postDialog $dialW dialog_error [list $msg]
	return
    }

    for {set j 0} {$j < $noForms} {incr j} {
	set form [lindex $forms $j] 
	foreach i $form {
	    $configEntryW($j).txt_$i getValues -value entry
	    if {($verifyEntryProc($i) == "entryBlankBoolean")} {
		if {[string compare $entry ""]} {
		    if {($entry == "Yes") || ($entry == "Y") || \
		      ($entry == "yes") || ($entry == "y") } {
			set entry 1
		    } elseif {($entry == "No") || ($entry == "no") ||\
			    ($entry == "N") || ($entry == "n")} {
			set entry 0
		    }
		}
	    }
	    puts $fd "$i $entry"
	    set oldValue($i) $entry
	}
    }
    .fileSDW unmanageChild
    close $fd
    set editedForm 0
    set i [string last / $editConfigFile]
    if {$i == -1} {
	set fileName $editConfigFile
    } else {
	set fileName [string range $editConfigFile [incr i] end]
    }
    [.editConfigFormW parent] setValues -title\
	    [format "Proclaim: Configuration - %s" $fileName]
}

proc editConfigCanCB {} {
    global stillModal answer editedForm
    set stillModal 0
    set answer 0
    .editConfigFormW unmanageChild
    set editedForm 0
}

#
# lease callbacks
#
proc getRelTime {end begin} {
    global SECSPERHOUR SECSPERMIN
    if {($end < $begin)} {
	return ""
    }
    set reltime [expr $end - $begin]
    set hours [expr $reltime/$SECSPERHOUR]
    set mins [expr [set tmp [expr ($reltime - $hours*$SECSPERHOUR)]]/$SECSPERMIN]
    set secs [expr $tmp%$SECSPERMIN]
    if {($hours != 0)} {
	set x [format "In %d hours %d mins %d secs" $hours $mins $secs]
    } elseif {($mins != 0)} {
	set x [format "In %d mins %d secs" $mins $secs]
    } else {
	set x [format "In %d secs" $secs]
    }
    return $x
}
proc showLeases {} {
    global etherToIPFile SECSPERDAY dialW updFreq timer \
	    lastModTime
    set curtime [getclock]
    catch {. removeTimer $timer}
    set timer [. addTimer $updFreq showLeases]
    set leases {}
    set nrows 0
    catch {exec /usr/sbin/dbmToEthIP > $etherToIPFile}
    if {[file exists $etherToIPFile]} {
	set newModTime [file mtime $etherToIPFile]
	if {$lastModTime == $newModTime} {
		    return
	}
	set lastModTime $newModTime 
	if {[catch {set fd [open $etherToIPFile r]} msg]} {
		    postDialog $dialW dialog_error [list $msg]
		    return
	}
		
	while {[gets $fd line] >= 0} {
	    if {![cequal [cindex $line 0] #]} {
		  set conv [scan $line "%s\t%s\t%s\t%d" ether ip hostName expiry]
		  if {$conv == 4} {
		      set dot [string first . $hostName]
		      if {$dot == -1} {
			  set host $hostName
			  set domain ""
		      } else {
			  set host [string range $hostName 0 [expr $dot-1]]
			  set domain [string range $hostName [expr $dot+1]  end]
		      }
		      if {$expiry == 0} {
			  lappend leases $host $domain $ip  Negotiating
                      } elseif {$expiry == -1} {
                          lappend leases $host $domain $ip  Infinite
                      } elseif {$expiry == -2} {
                          lappend leases $host $domain $ip  STOLEN
                      } elseif {$expiry == -3} {
                          lappend leases $host $domain $ip  STATIC
		      } else {
			  lappend leases $host $domain $ip \
			      [fmtclock $expiry "%D %R"]
		      }
		      incr nrows
		  }
	    }
	}
	close $fd
    }
    .main.mPaneW.leaseMatrixW getValues -rows orows
    if {$orows > 1} {
	.main.mPaneW.leaseMatrixW deleteRows 0 [expr $orows-1]
    }
    if {$nrows} {
	.main.mPaneW.leaseMatrixW addRows 0 $nrows $leases
    }
}

proc restoreMatrixCell {} {
    .main.mPaneW.leaseMatrixW cancelEdit 1
}

#
# Frequency Related procedures
#
proc doPromptFreqCB {} {
    global updFreq
    .main.freqDialogW setValues -textString [expr $updFreq/1000]
    .main.freqDialogW manageChild
}

proc updFreqCB {} {
    global dialW ENTER_SECS updFreq MINUPDFREQ timer
    .main.freqDialogW getValues -textString updFreq
    if {[string compare $updFreq ""]} {
	set updFreq [expr $updFreq*1000]
	if {$updFreq < $MINUPDFREQ} {
	    set updFreq $MINUPDFREQ
	}
	catch {. removeTimer $timer}
	set timer [. addTimer $updFreq showLeases]
	.main.freqDialogW unmanageChild
    } else {
	postDialog $dialW dialog_error $ENTER_SECS
    }
}

proc canFreqCB {} {
    .main.freqDialogW unmanageChild
}

#
# runtime callbacks
#
proc setServerOnOff {} {
    global dialW

    .main.mPaneW.formW.chkconfigOnOffW getValues -set serverOnOffStatus 
    if {$serverOnOffStatus} {
	if {[catch {exec chkconfig -f proclaim_server on} msg]} {
	    postDialog $dialW dialog_error [list $msg]
	    .main.mPaneW.formW.chkconfigOnOffW setValues -set False
	} else {
	    catch {exec chkconfig -f proclaim_relayagent off}
	}
    } else {
	catch {exec chkconfig -f proclaim_server off}
    }
}

proc setMapsOn {} {
    global mapsOnOffStatus fg bg hostsMap ethersMap\
	    defaultHostsMap defaultEthersMap
    if {$mapsOnOffStatus} {
	return
    }
    #.optionsFormW.paneW.rcW.mapsW setValues -set 1
    set mapsOnOffStatus 1
    if {![string compare [string trim $hostsMap] ""]} {
	set hostsMap $defaultHostsMap
    }
    if {![string compare [string trim $ethersMap] ""]} {
	set ethersMap $defaultEthersMap
    }
    .optionsFormW.paneW.rcW.hostsTextW setValues -editable true\
	    -foreground $fg -background $bg -value $hostsMap\
	    -traversalOn true
    .optionsFormW.paneW.rcW.ethersTextW setValues -editable true\
	    -foreground $fg -background $bg -value $ethersMap\
	    -traversalOn true
    showLeases
}

proc checkSave {} {
    global editedForm SAVE_FILE_QTN qdialW editConfigFile
    if {$editedForm} {
	set msg [format "%s: %s" $SAVE_FILE_QTN $editConfigFile]
	ask $qdialW $msg editConfigOkCB editConfigCanCB
    } else {
	editConfigCanCB
    }
    set editedForm 0
}

proc checkDelete {} {
    global  DELETE_FILE_QTN qdialW editConfigFile
    set msg [format "%s: %s" $DELETE_FILE_QTN $editConfigFile]
    ask $qdialW $msg deleteConfigOkCB deleteConfigCanCB
}

#############################################################
# main program begins here
#
xtAppInitialize -class ProclaimServer\
	-fallbackResources $fbacks

xmMainWindow .main


xmFileSelectionDialog .fileSDW
.fileSDW.Help unmanageChild
#
# create a menu bar
#
xmMenuBar .main.barW managed 

#
#create a matrix to hold the leases in the main window
#
xmPanedWindow .main.mPaneW managed\
	-sashWidth 1 -sashHeight 1 -separatorOn false

xbaeMatrix .main.mPaneW.leaseMatrixW managed\
	-boldLabels true -visibleRows 14 -columns 4 -columnWidths $colWidths\
	-columnLabels $colLabels -columnMaxLengths $colMaxLengths\
	-cellMarginHeight 2 -cellMarginWidth 2 -cellHighlightThickness 0\
	-cellShadowThickness 0

#avoid editing
.main.mPaneW.leaseMatrixW modifyVerifyCallback {restoreMatrixCell}

set serverOnOffStatus [expr ![catch {exec chkconfig proclaim_server}]]
xmForm .main.mPaneW.formW managed 
xmToggleButton .main.mPaneW.formW.chkconfigOnOffW managed\
	-highlightThickness 0\
	-alignment alignment_beginning -set $serverOnOffStatus\
	-leftAttachment attach_form\
	-bottomAttachment attach_form

.main.mPaneW.formW.chkconfigOnOffW valueChangedCallback {setServerOnOff}

.main.mPaneW.formW.chkconfigOnOffW getValues -height h 
.main.mPaneW.formW getValues -marginHeight mh
.main.mPaneW.formW setValues -paneMinimum [expr $h+2*$mh]\
	-paneMaximum [expr $h+2*$mh]

# 
# arrange to make the pane the main window
#
.main setValues -menuBar .main.barW\
	-workWindow .main.mPaneW

.main manageChild


#
# create "file" pull-down menu
#
xmPulldownMenu .main.barW.fileMenuW
xmPushButton .main.barW.fileMenuW.optionsW managed
xmPushButton .main.barW.fileMenuW.configW managed
xmPushButton .main.barW.fileMenuW.syslogW managed
xmPushButton .main.barW.fileMenuW.quitW managed


.main.barW.fileMenuW.optionsW activateCallback {doOptions}
.main.barW.fileMenuW.configW activateCallback {doFile $proclaimConfigDir $defaultProclaimMask "" configEdtCB}
.main.barW.fileMenuW.syslogW activateCallback {catch {exec sysmon &}}
.main.barW.fileMenuW.quitW	activateCallback {exit 0}

#
# create cascade buttons on the menu bar 
#
xmCascadeButton .main.barW.fileW managed \
	-subMenuId .main.barW.fileMenuW
xmCascadeButton .main.barW.helpW managed 
.main.barW setValues -menuHelpWidget .main.barW.helpW

.main.barW.helpW activateCallback {catch {exec /usr/sbin/insight -v IA_NetwkMail -a 'query(DHCP)' > /dev/null 2>&1 &}}

#############################################################
#create options form
#
xmFormDialog .optionsFormW\
	-noResize true -fractionBase 3

xmPanedWindow .optionsFormW.paneW managed\
	-sashWidth 1 -sashHeight 1 -separatorOn false\
	-leftAttachment attach_form\
	-rightAttachment attach_form -topAttachment attach_form\
	-bottomAttachment attach_form

xmRowColumn .optionsFormW.paneW.rcW \
	-radioBehavior true\
	-isAligned true -numColumns 2 -orientation vertical\
	-packing pack_column 

xmLabel .optionsFormW.paneW.rcW.hostsLabelW managed
xmLabel .optionsFormW.paneW.rcW.ethersLabelW managed

xmLabel .optionsFormW.paneW.rcW.sysnameLabelW managed
xmLabel .optionsFormW.paneW.rcW.proclaimConfDirLabelW managed
xmLabel .optionsFormW.paneW.rcW.otherOptionsLabelW managed

xmLabel .optionsFormW.paneW.rcW.l2W managed\
	-labelString ""
xmText .optionsFormW.paneW.rcW.hostsTextW managed\
	-value $defaultHostsMap
xmText .optionsFormW.paneW.rcW.ethersTextW managed\
	-value $defaultEthersMap

xmText .optionsFormW.paneW.rcW.sysnameTextW managed\
	-value $defaultSysName
xmText .optionsFormW.paneW.rcW.proclaimConfDirTextW managed\
	-value $defaultProclaimConfigDir
xmText .optionsFormW.paneW.rcW.otherOptionsTextW managed\
        -value $otherOptions
.optionsFormW.paneW.rcW.proclaimConfDirTextW getValues\
	-foreground fg -background bg
.optionsFormW.paneW.rcW manageChild
xmSeparator .optionsFormW.paneW.sepW managed
#
# create the control panel for the options dialog
#
set cpanel [createCPanel .optionsFormW.paneW 2 0 {optionsUpdCB optionsCanCB}]

.optionsFormW.paneW manageChild


#
# read options to set the global values
#
readOptionsFile

#
# end of options form
#

#############################################################
#create edit the config form
#
xmFormDialog .editConfigFormW\
	-noResize true


xmPanedWindow .editConfigFormW.paneW managed\
	-sashWidth 1 -sashHeight 1\
	-leftAttachment attach_form -rightAttachment attach_form \
	-topAttachment attach_form -bottomAttachment attach_form\
	-separatorOn false
xmMenuBar .editConfigFormW.paneW.barW managed 

#
# create "file" pull-down menu
#
xmPulldownMenu .editConfigFormW.paneW.barW.fileMenuW
xmPushButton .editConfigFormW.paneW.barW.fileMenuW.openW managed
xmPushButton .editConfigFormW.paneW.barW.fileMenuW.saveW managed
xmPushButton .editConfigFormW.paneW.barW.fileMenuW.saveasW managed
xmPushButton .editConfigFormW.paneW.barW.fileMenuW.deleteW managed
xmPushButton .editConfigFormW.paneW.barW.fileMenuW.closeW managed

.editConfigFormW.paneW.barW.fileMenuW.openW activateCallback\
	{doFile $proclaimConfigDir $defaultProclaimMask "" configEdtCB}
.editConfigFormW.paneW.barW.fileMenuW.saveW activateCallback\
	{editConfigAppCB}
.editConfigFormW.paneW.barW.fileMenuW.saveasW activateCallback\
	{doFile $proclaimConfigDir $defaultProclaimMask "" configSavCB}
.editConfigFormW.paneW.barW.fileMenuW.deleteW activateCallback\
	{checkDelete}
.editConfigFormW.paneW.barW.fileMenuW.closeW activateCallback \
	{checkSave}
	
#
# create cascade buttons on the menu bar 
#
xmCascadeButton .editConfigFormW.paneW.barW.fileW managed \
	-subMenuId .editConfigFormW.paneW.barW.fileMenuW
xmCascadeButton .editConfigFormW.paneW.barW.helpW managed 
.editConfigFormW.paneW.barW setValues -menuHelpWidget .editConfigFormW.paneW.barW.helpW
.editConfigFormW.paneW.barW.helpW activateCallback {catch {exec /usr/sbin/insight -v IA_NetwkMail -a 'query(DHCP)' &}}

set forms [list $genOptions1 $serverOptions2 $applOptions3 $serviceOptions4\
	$ipperhostOptions5 $ipperinterfaceOptions6 $linkperinterfaceOptions7\
	$tcpOptions8]
set noForms [llength $forms]

# create the options buttons
xmRowColumn .editConfigFormW.paneW.rcW managed\
	-orientation horizontal

xmPulldownMenu .editConfigFormW.paneW.rcW.menuW
for {set i 0} {$i < $noForms} {incr i} {
    xmPushButton .editConfigFormW.paneW.rcW.menuW.btn$i managed
    .editConfigFormW.paneW.rcW.menuW.btn$i activateCallback {showEntryW %w}
}
xmOptionMenu .editConfigFormW.paneW.rcW.oMenuW managed\
	-subMenuId .editConfigFormW.paneW.rcW.menuW

.editConfigFormW.paneW.rcW.menuW.btn0 getValues -height h
.editConfigFormW.paneW.rcW.menuW getValues -marginHeight mh
.editConfigFormW.paneW.rcW setValues -paneMaximum [expr 2*$h+2*$mh]\
	-paneMinimum [expr 2*$h+2*$mh]

xmScrolledWindow .editConfigFormW.paneW.scrW managed


for {set i 0} {$i < $noForms} {incr i} {
    set configEntryW($i)  [createEntryW .editConfigFormW.paneW.scrW \
	    [lindex $forms $i] $i]
    $configEntryW($i) unmanageChild
    foreach item [lindex $forms $i] {
	set oldValue($item) ""
    }
}

set curFormIndex 0
set newFormIndex 0
set editedForm   0

.editConfigFormW.paneW manageChild

showLeases

#
# all forms created GO!
#
. realizeWidget
. mainLoop

