#
#   File:    base-init.toe
#   Author:  Halcyon Inc.
#   Version: 1.80 03/05/23 16:32:03
#
#   Copyright (c) 1993-1997 Halcyon Inc.
#
#   OpenAgent Base Initialization (TOE)
#

#
# rename exit to _exit
#
rename exit _exit
#
# display usage
#
proc usage { } {
    set opt "<component> -h <host> -p <port> -m <modspec> -s <session> -c <console> -dir <dir> -x <params> -u <url> -i -q"
    puts stderr "Usage: es-start.sh $opt" 
    _exit
}

#
# determine component to be started
#
set component [ lindex $argv 0 ]
if { $component == "unknown" } {
    puts stderr "no component specified"
    usage 
}

#
# set argv0 to component name
#
set argv0 $component

#
# get command line arguments
#
set env(INTERACTIVE)     0 
set env(QUIET)     0 
set env(TARGET_CONFIG)   {}
set env(TARGET_TEMPLATE) {}
set env(TARGET_URL) {}
set env(PARAMS) {}
set env(UNUSED_ARGS) {}

set i 1

while { $i < $argc } {
    switch -- [ lindex $argv $i ] \
	{-h} {
	    incr i
            #
            # ignore host argument
            #
	} \
	{-p} {
	    incr i
	    set env(AGENTPORT) [ lindex $argv $i ] 
	} \
	{-i} {
	    set env(INTERACTIVE) 1 
	} \
	{-q} {
	    set env(QUIET) 1 
	} \
	{-s} {
	    incr i
            lappend env(TARGET_CONFIG) [ lindex $argv $i ] 
	} \
	{-c} {
	    incr i
            lappend env(TARGET_TEMPLATE) [ lindex $argv $i ] 
	} \
	{-m} {
	    incr i
            lappend env(TARGET_MODULE) [ lindex $argv $i ] 
	} \
	{-x} {
	    incr i
            lappend env(PARAMS) [ lindex $argv $i ] 
	} \
	{-u} {
	    incr i
            lappend env(TARGET_URL) [ lindex $argv $i ] 
	} \
	{-dir} {
		incr i
	} \
	{-display} {
		incr i
		set env(DISPLAY) [ lindex $argv $i ]
	} \
	default {
        lappend env(UNUSED_ARGS) [ lindex $argv $i ] 
	}
    incr i
}


#
# Check that the DISPLAY variable is not :0 because 
# this causes the console to spin on Solaris 2.4.
# 
if { [ info exists env(DISPLAY) ] == 1 } {
	if { $env(DISPLAY) == ":0" } {
		set env(DISPLAY) ":0.0"
	}
}

#
# Wrapper proc for host2ip 
#
proc resolveHostName { arghostname } {
	return [ host2ip $arghostname ]
}

proc getSubagentService {} {
    if { [ catch { locate .services.subagents } object ] } {
        set object ""
    }
    return $object
}

#
# define Event Mananger shutdown proc (to close database)
#
proc shutdownEventMgr {} {
 
    if { [ catch { closeEventDatabase } result ] } {
        ddl print warning "shutdown: could not close Event Management database : $result \n" 
    } else {
        ddl print info "shutdown: Event Management database closed successfully \n"
    }
    return
}

#
# define exit proc
#
proc exit { args } {
    set object [ getSubagentService ]
    if { $object != "" } {
        toe_send $object shutdownSubagents info 
    }

    if { [ getComponent ] == "event" } {
       shutdownEventMgr
    }

    foreach reason $args { 
	ddl print info "$reason\n" 
	ddl print syslog "$reason\n"
    }
    #foreach reason $args { catch { puts stderr "$reason" } }
 
    ddl print info "*** terminating execution ***\n"
    ddl print syslog "*** terminating execution ***\n"
    #catch { puts stderr "*** terminating execution ***" }
    # send SIGTERM ( 15 ) signal to everyone in the process group
    sendsignal 15 0
    _exit 0
}

#
# define quit proc
#
proc quit { args } {
    exit $args
}

#
# define abort proc
#
proc abort { args } {
    set object [ getSubagentService ]
    if { $object != "" } {
        toe_send $object shutdownSubagents info 
    }

    if { [ getComponent ] == "event" } {
       shutdownEventMgr
    }

    foreach reason $args { 
	ddl print error "$reason\n"
	ddl print syslog "$reason\n"
    }
    ddl print error "*** aborting execution ***\n"
    ddl print syslog "*** aborting execution ***\n"
    #foreach reason $args { catch { puts stderr "$reason" } }
    #catch { puts stderr "*** aborting execution ***" }
    _exit 1
}

proc printBadAddressMessageAndExit {} {
     set comp [ getComponent ]
     set host [ lookup -d "" value .config.${comp}.${comp}Server ]
     set msg "${comp}Server parameter ($host) is not a valid local hostname\n"
     abort "$msg"
}

#
# define trap proc
#
proc trap { numbers command } {
    foreach number $numbers {
	signal $number [ list after 0 $command ]
    }
}

#
# define error reporting proc
#
proc bgerror { args } {
    if { $args != "" } {
        ddl print error "$args\n"
    }
    global errorInfo
    foreach line [ split $errorInfo "\n" ] {
        ddl print debug "|    $line\n"
    }
}

#
# get current component
#
proc getComponent {} {
    toe_send [ locate .config.current ] ilookup -d "" value component
}


#
# enable basic diagnostics
#
if { $env(INTERACTIVE) } {
    set interface "desc://localhost/stdout"
} else {
    set interface "syslog://localhost/LOG_ALERT;app=$component;facility=LOG_DAEMON;logopt=LOG_PID"
  # close file0
  # close file1
  # close file2
}
foreach channel "error warning info syslog" {
    ddl open $channel $interface
    ddl enable $channel
}
unset channel
unset interface

#
# set process to be process group leader
#
#pkgload unix
catch setpgrp

#
# set signal handlers
#
trap 1 { ddl print info "received HUP signal - ignoring\n" }
trap 3 { abort "received QUIT signal" }
trap 6 { abort "received ABORT signal" }
trap 2 { quit "received interrupt signal" }
trap 15 { quit "received software termination signal" }
#trap 24 { puts "received control-Z" }

#
# user-level inheritance wrapper
#
proc use { args } {
    foreach name $args {
	inherit [ resolvealias $name ]
    }
}

proc resolvealias { name } {
    #
    # see if name corresponds to actual object
    #
    if { ! [ catch { locate $name } ] } {
        return $name
    }

    #
    # try alias slice, then aliases object
    #
    set p [ lookup -d "" alias $name ]
    if { $p == "" } {
        set p [ lookup -d "" value ..templates.aliases.$name ]
        if { $p == "" } {
	    return $name
        }
    }

    #
    # re-resolve to allow aliases to reference aliases
    #
    return [ resolvealias $p ]
}

##############################################################################
# Method:	getParentTree
# 
# Abstract:	Development/debugging proc to recursively list the parents
#		of the current object, and, if specified, the parent tree of
#		all the current object's superior objects as well.
#
# Arguments:	args		Arg list, containing
#				- optional indent string (for recursion)
#				- optional '-s' to scope superiors
#
# Returns:	The parent tree.
##############################################################################
proc getParentTree { args } {

    set args [ join $args ]
    set length [ llength $args ]
    set scope 0

#   Arg check.
#   ----------
    for { set badargs 0 } { 1 } { 1 } {

    	if { $length > 2 } {
	    set badargs 1
	    break
	}
	
	for { set i 0 } { $i < $length } { incr i } {
	    switch -- [ lindex $args $i ] \
		{-s} {
		    set scope 1
		    set newargs [ lreplace $args $i $i ]
		} \
		default {
		    if { ![ catch { set indent } ] } {
		    	set badargs 1
			break
		    } else {
			set indent [ lindex $args $i ]
		    }
		}
	}
	break
    }

    if { $badargs == 1 } {
	error "Usage: getParentTree ?indentstring? ?-s?"
    }

    if { [ catch { set indent } ] } {
	set indent ""
    }
 
#   Current object.
#   ---------------
    set result "[ toe_name -full ] \[[ toe_self ]\]\n"
    set origindent $indent
    append indent "."
    foreach parent [ toe_parents ] {

#	Current object's parents.
#	-------------------------
	append result "$indent"
	append result "[ toe_send $parent getParentTree $indent ]"
    }

    if { $scope == 1 } {

#	Current object's superior.
#	--------------------------
	append result "\n"
	set superior [ toe_superior ]
	if { $superior != "" } {
	    append result "[ toe_send $superior getParentTree $origindent -s ]"
	}
    }
	
    return $result
}

##############################################################################
# Method:	locateKeyVal
# 
# Abstract:	Development/debugging proc to locate the specified slice-key
#		pair in the current object and its parent tree and, if 
#		specified, its superior object tree as well.
#
# Arguments:	slice		Slice name.
#		key		Key name.
#		args		Arg list, containing:
#				- optional '-a' to locate ALL pairs in the
#				  tree (i.e. don't stop when first found)
#				- optional '-s' to scope superiors
#
# Returns:	The slice, key and value, along with the object in which
#		it was found (or all objects, if desired).  Throws the
#		usual error (same as lookup) if not found.
##############################################################################
proc locateKeyVal { slice key args } {
    
    set badargs 0
    set scope 0
    set doall 0

    set args [ join $args ]
    set newargs $args
    set length [ llength $args ]

#   Arg check.
#   ----------
    for { set badargs 0 } { 1 } { 1 } {

    	if { $length > 4 } {
	    set badargs 1
	    break
	}
	
	for { set i 0 } { $i < $length } { incr i } {
	    switch -- [ lindex $args $i ] \
		{-s} {
		    set scope 1
		    set newargs [ lreplace $args $i $i ]
		} \
		{-a} {
		    set doall 1
		} \
		default {
		    
		    set badargs 1
		    break
		}
	}
	break
    }

    if { $badargs == 1 } {
	error "Usage: locateKeyVal slice key ?-s? ?-a?"
    }

    set found 0
    set result ""

#   Check current object.
#   ---------------------
    set catchval [ catch { ilookup $slice $key } value ]
    if { $catchval == 0 } {
    	append result "\[[ toe_name -full ]\] \[[ toe_self ]\]: $slice:$key = $value\n"
	set found 1 
    }
	
    if { $catchval == 1 || $doall == 1 } {

#	Check object's parents.
#	-----------------------
	foreach parent [ toe_parents ] {
	    if { ![ catch { toe_send $parent locateKeyVal $slice $key $newargs } value ] } {
		set found 1
		append result $value
		if { $doall == 0 } break
	    }
	}

    	if { $scope == 1 } {

#	    Check object's superior.
#	    ------------------------
	    set superior [ toe_superior ]
	    if { $superior != "" } {
	    	if { ![ catch { toe_send $superior locateKeyVal $slice $key $args } value ] } {
		    set found 1
		    append result $value
	    	}
	    }
	}
    }

    if { $found == 0 } {
	error $value
    }

    return $result
}


##############################################################################
# Method:	updateKeyValTree
#		updateKeyVal
# 
# Abstract:	Procs to traverse through the tree rooted at the current
#		object and consisting of the object and all its inferiors
#		(recursively), updating the specified key-value pair in the
#		specified slice (creating it, if specified).
#
# Arguments:	slice		Slice name.
#		key		Key name.
#		value		Value.
#		args		Arg list, containing
#				- optional '-c' to create the slice entry
#				  if it doesn't already exist
#
# Returns:	Nothing.
##############################################################################
proc updateKeyValTree { slice key value args } {

    set args [ join $args ]
    set length [ llength $args ]

#   Arg check.
#   ----------
    for { set badargs 0 } { 1 } { 1 } {

    	if { $length > 1 } {
	    set badargs 1
	    break
	}
	
	for { set i 0 } { $i < $length } { incr i } {
	    switch -- [ lindex $args $i ] \
		{-c} {
		} \
		default {
		    set badargs 1
		    break
		}
	}
	break
    }

    if { $badargs == 1 } {
	error "Usage: updateKeyValTree slice key value ?-c?"
    }

    toe_recurse pre { updateKeyVal $slice $key $value $args }
}

proc updateKeyVal { slice key value args } {

    set args [ join $args ]
    set length [ llength $args ]
    set create 0

#   Arg check.
#   ----------
    for { set badargs 0 } { 1 } { 1 } {

    	if { $length > 1 } {
	    set badargs 1
	    break
	}
	
	for { set i 0 } { $i < $length } { incr i } {
	    switch -- [ lindex $args $i ] \
		{-c} {
		    set create 1
		} \
		default {
		    
		    set badargs 1
		    break
		}
	}
	break
    }

    if { $badargs == 1 } {
	error "Usage: updateKeyVal slice key value ?-c?"
    }

    if { $create == 1 || ![ catch { ilookup $slice $key } result ] } {
	define $slice $key $value
    }
}

#
# Define error handler used when a file being imported encounters an error
#
proc parse_error { args } {
    if { [ catch { toe_name -full } name ] } {
        ddl print debug "parse_error: in root object context\n"
    } else { 
        ddl print debug "parse_error: in object context $name\n"
    }
    set length [ llength $args ]
    if { $length == 4 } {
        set file [ lindex $args 0 ]
        set line [ lindex $args 1 ]
        set err  [ lindex $args 2 ]
        set tok  [ lindex $args 3 ]

	if { $tok == "" } {
            ddl print debug "file not found: ${file}\n"
	} elseif { $tok != {]} } {
	    abort "${err} in ${file}($line) at token '$tok'"
	} else {
	    abort "parsing error in ${file}($line): ${err}"
	}
    } elseif { $length == 5 } {
        set file [ lindex $args 0 ]
        set line [ lindex $args 1 ]
        set err  [ lindex $args 2 ]
        set info [ lindex $args 3 ]
        set tok  [ lindex $args 4 ]
	abort "${err}: $info" "in ${file}($line) at token '$tok'"
    } else {
	eval [ concat [ list abort "general parsing error" ] $args ]
    }
} 

proc getGeneralUser {} {
    return [ lookup -d "public" value .config.current.generaluser ]
}
 
proc getSuperUser {} {
    return [ lookup -d "private" value .config.current.superuser ]
}
 
proc promoteUser { user logicalType } {
    if { $user != "" } {
        set userlist [ lookup -d "" value .config.current._${logicalType} ]
        if { [ lsearch -exact $userlist $user ] == -1 } {
            lappend userlist $user
            define value .config.current._${logicalType} $userlist
        }
    }
}

proc isIpAddress { ip } {
    return [ regexp {^[1-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$} $ip ]
}

proc getCurrentHostname {} {
    return [ lookup value .config.current.hostname ]
}

proc getCurrentIpAddress {} {
    return [ lookup value .config.current.ipaddress ]
}

proc getCurrentSnmpPort {} {
    return [ lookup value .config.current.snmpPort ]
}

proc getCurrentAddress {} {
    return [ lookup value .config.current.address ]
}

proc getCurrentFullHostname {} {
    return [ lookup value .config.current.fullhostname ]
}

proc sysinfo { option } {

    switch $option \
        {hostname} {
            return [ getCurrentHostname ]
        } \
        {ip} - {address} {
            return [ getCurrentIpAddress ]
        } \
        {systemname} {
            return [ getCurrentFullHostname ]
        } \
        {unamehostname} {
            return [ _sysinfo hostname ]
        } \
        {unameip} - {unameaddress} {
            return [ _sysinfo ip ]
        } \
        {unamesystemname} {
            return [ _sysinfo systemname ]
        } \
        default {
            return [ _sysinfo $option ]
        }
}

toe_send $root {

    if { $env(QUIET) != "1" } {
    	ddl print info "Sun Management Center [ sysinfo swverstring ]\n"
    	ddl print info "registering import actions\n"
    }

    #
    # define app-specific import actions
    #
    import register parse_error
    import register ddl
    import register pkgload
    import register source
    import register requires
    import register locate
    import register lookup
    import register slookup
    import register construct
    import register activate
    import register use
    import register exit

    if { $env(QUIET) != "1" } {
    	ddl print info "loading standard services\n"
    }
    if { [ catch {
	import interface value base-init.x
    } error ] } {
	bgerror
	abort $error
    }

    import string value ".config.current = { \[ inherit $component \] }"
    define value .config.current.component $component

    if { $component == "subagent" } {
        if { [ info exists env(AGENTPORT) ] } {
            define value .config.subagent.snmpPort $env(AGENTPORT)
        } else {
            set msg "Subagent must specify SNMP port using -p option" 
            abort $msg
        }
    }

    #
    # get the current component host and port
    #
    set hostname [ lookup -d "" value .config.${component}.${component}Server ]
    set port     [ lookup -d "" value .config.${component}.snmpPort ]

    if { $port == "" } {
        set msg "Must specify SNMP port in configuration file"
        abort $msg
    }

    #
    # if hostname is not defined, use uname hostname of local host
    # and determine the ip address
    #
    if { $hostname == "" } {
        set hostname [ sysinfo unamehostname ]
        set ipaddress [ host2ip $hostname ]

    } elseif { [ isIpAddress $hostname ] } {
        set ipaddress $hostname
        if { [ catch { ip2host $ipaddress } hostname ] } {
            ddl print error "$hostname\n" 
            printBadAddressMessageAndExit
        }

    } else {
        if { [ catch { host2ip $hostname } ipaddress ] } {
            ddl print error "$ipaddress\n" 
            printBadAddressMessageAndExit
        }
    }
    
    #
    # strip off the domain name if the hostname is fully qualified 
    # or generate the full name based on the default domain name
    #
    set parts [ split $hostname . ]  
    if { [ llength $parts ] > 1 } {
        set fullname $hostname 
        set hostname [ lindex $parts 0 ]
    } else {
        set fullname ${hostname}.[ sysinfo domainname ]
    }

    define value .config.current.hostname      $hostname
    define value .config.current.fullhostname  $fullname
    define value .config.current.ipaddress     $ipaddress
    define value .config.current.address       ${ipaddress}:${port}

    #
    # promote the superuser and generaluser
    #
    promoteUser [ getSuperUser ] adminUsers
    promoteUser [ getGeneralUser ] generalUsers

    set parts [ split $component "" ]
    set parts [ lreplace $parts 0 0 [ string toupper [ lindex $parts 0 ] ] ]
    define value .config.$component.banner "Starting SyMON v[ sysinfo swversion ] [ join $parts "" ]"

    if { $env(QUIET) != "1" } {
    	ddl print info "standard services load complete\n"

	#
	# component host name and snmp port
	#
        set trapServer [ lookup value .config.trap.trapServer ]
        set trapPort [ lookup value .config.trap.snmpPort ]

        set eventTrapServer [ lookup value .config.event.eventServer ]
        set eventTrapPort [ lookup value .config.event.snmpPort ]

	#
	# print agent host and port
	#
	if { $component == "agent" } {
	    set currentMsg "agent host and port: $hostname:$port"
	} else {
	    set currentMsg "$component agent host and port: $hostname:$port"
	}
	ddl print info "$currentMsg\n"

	#
	# print trap handler host and port
	#
	set trapMsg "trap handler destination host and port: $trapServer:$trapPort"
	ddl print info "$trapMsg\n"

	#
	# print event server host and port
	#
	set eventMsg "event trap destination host and port: $eventTrapServer:$eventTrapPort"
	ddl print info "$eventMsg\n"
    }

    #
    # disable basic diagnostics
    #
    foreach channel "error warning info" {
    	ddl disable $channel
    	ddl close $channel 
    }
    unset channel

    #
    # enable component diagnostics
    #
    set activeChannels [
	lookup -d "error warning info" value .config.${component}.activeChannels
    ]
 
    set defaultInterface [
        lookup -d "desc://localhost/stderr" value .config.${component}.defaultOutput
    ]

    foreach channel $activeChannels {
    	set interface [
            lookup -d $defaultInterface value .config.${component}.${channel}Output
     	]
    	ddl open $channel $interface
    	ddl enable $channel
    }
 
    unset interface
    unset defaultInterface
    unset activeChannels
    unset channel

    #
    # if subagent, redefine trap configuration to point to master agent
    #
    if { $component == "subagent" } {
        set agentServer [ getCurrentHostname ] 
        set agentPort [ lookup value .config.agent.snmpPort ]

        define value .config.trap.trapServer $agentServer 
        define value .config.trap.snmpPort $agentPort
    }

    #
    # define agent address
    #
    define value .config.agent.agentAddress [ lookup value .config.current.ipaddress ]

    #
    # define the trap daemon address in the trap configuration object
    #
    set trapServer [ lookup value .config.trap.trapServer ]
    if { [ catch { host2ip $trapServer } trapServerAddress ] } {
	set error "*** Unable to resolve trapServer host: $trapServer"
	ddl print error "$error\n"
	abort $error
    } elseif { [ catch { ip2host $trapServerAddress } ] } {
        set error "*** Unable to resolve trapServer IP address: $trapServerAddress"
        ddl print error "$error\n"
        abort $error
    }
    define value .config.trap.trapServerAddress $trapServerAddress

    #
    # define the event trap daemon address in the trap configuration object
    #
    set eventTrapServer [ lookup value .config.event.eventServer ]
    if { [ catch { host2ip $eventTrapServer } eventTrapServerAddress ] } {
        set error "*** Unable to resolve eventTrapServer host: $eventTrapServer"
        ddl print error "$error\n"
        abort $error
    } elseif { [ catch { ip2host $eventTrapServerAddress } ] } {
        set error "*** Unable to resolve eventServer IP address: $eventTrapServerAddress"
        ddl print error "$error\n"
        abort $error
    }
    define value .config.trap.eventTrapServerAddress $eventTrapServerAddress
    
    #
    # set the process file limit if specified in the configuration file
    #
    set filelimit [ lookup -d "" value .config.${component}.numFileLimit ]
    if { $filelimit != "" } {
	if { $filelimit == "max" } {
	    set filelimit [ getsyslimit file max ]
	}
	catch { setsyslimit file $filelimit }
    }
    
    #
    # print the OpenAgent version
    #
    if { $env(QUIET) != "1" } {
    	ddl print info "Sun Management Center [ sysinfo swverstring ]\n"

	#
	# log agent, trap, and event server hosts and traps
	#
	ddl print info "$currentMsg\n"
	ddl print info "$trapMsg\n"
	ddl print info "$eventMsg\n"
    }

    if { ![ catch {lookup -d "on" value .config.current.SNMPv1} result ] } {
	if { [string tolower $result] == "off" } { 
		ddl if info { ddl print info "SNMPv1 has been turned off" } 
	} 
    }

    if { ![ catch {lookup -d "on" value .config.current.SNMPv2c} result ] } {
	if { [string tolower $result] == "off" } { 
		ddl if info { ddl print info "SNMPv2c has been turned off" } 
	}
    } 

    #
    # load component-specific services
    #
    if { $env(QUIET) != "1" } {
    	ddl print info "loading $component services\n"
    }
    if { [ catch { import interface value base-$component.x } error ] } {
		bgerror
		abort $error
    }
	
    if { $env(QUIET) != "1" } {
    	ddl print info "$component service load complete\n"
    }
}

#
# set up interactive session
#
if { $env(INTERACTIVE) } {
    ddl print info "setting up interactive session\n"
    set prompt "$component:> "
    set context [ toe_context create ]
    toe_context send $context proc TTYEVAL {} {
	set done 0
	set exit 0
	set buffer ""
	while { ! $done } {
    	    if { [ gets stdin data ] < 0 } {
	        quit
    	    }
	    if { $buffer == "" } {
		set buffer $data
	    } else {
		append buffer "\n" $data
	    }
	    append buffer
	    if { [ info complete $buffer ] } {
		set done 1
		if { $buffer != "" } {
    	    	    catch { uplevel #0 $buffer } result
    	    	    puts stdout $result
		}
	    }

	    if { $done } {
    	        global prompt
    	        global component
    	        if { [ catch toe_name location ] } { set location "" }
    	        set prompt "$component:$location> "
    	        puts -nonewline stdout $prompt
    	        flush stdout
	    } else {
    	        puts -nonewline stdout "> "
    	        flush stdout
	    }
	}
    }
    toe_context send $context {
    	toe_begin $root
    	toe_send [ locate services.mel ] registerDescriptor stdin read \
            [ list $root "toe_context send $context TTYEVAL" ]
    }
    unset context

    puts -nonewline stdout $prompt
    flush stdout

    #
    # define "ls -a" slices
    #
    set lsSlices "object data"

    #
    # define "data", "status" and "dumpall" procs
    #
    proc data {} {
   	export interface data desc://localhost/stderr -dot
    }
    proc status {} {
   	export interface status desc://localhost/stderr -dot
    }
    proc dumpall {} {
   	export interface "" desc://localhost/stderr -dot
    }
}

#
# define dump proc
#
if { $env(INTERACTIVE) } {
    ddl open dump desc://localhost/stderr
    ddl enable dump
}

proc dump { args } {
    global env
    if { $env(INTERACTIVE) } {
        ddl print dump "$args\n"
    }
}

#
# enter event loop
#
toe_context send [ toe_context create ] {
    toe_begin $root
    toe_send [ locate services.mel ] processEvents
}
