##
## Here starts the experimental implementation of the MLM MIB. 
##
## Copyright (c) 1994
##
## J. Schoenwaelder
## TU Braunschweig, Germany
## Institute for Operating Systems and Computer Networks
##
## Permission to use, copy, modify, and distribute this
## software and its documentation for any purpose and without
## fee is hereby granted, provided that this copyright
## notice appears in all copies.  The University of Braunschweig
## makes no representations about the suitability of this
## software for any purpose.  It is provided "as is" without
## express or implied warranty.

mib load $scotty_lib/mibs/rfc1447.mib
mib load $scotty_lib/mibs/mlm.mib

snmp instance mlmLock.0 mlmLock	1

snmp instance mlmNextScript.0 mlmNextScript 1
trace variable mlmNextScript w mlmNextScript::set
proc mlmNextScript::set { vname idx operation } {
    upvar #0 $vname mlmNextScript
    incr mlmNextScript
}

##
## The script table contains currently only static script definitions.
## The MLM::RegisterProc procedure can be used to register new scripts.
##

proc MLM::RegisterProc {name descr} {

    global mlmNextScript
    global mlmScriptIndex mlmScriptName mlmScriptDescr mlmScriptStorageType
    global mlmSourceScript mlmSourceLine mlmSourceCode

    set i $mlmNextScript
    incr mlmNextScript 0

    snmp instance mlmScriptIndex.$i	mlmScriptIndex($i)	$i
    snmp instance mlmScriptName.$i	mlmScriptName($i)	$name
    snmp instance mlmScriptDescr.$i	mlmScriptDescr($i)	$descr
    snmp instance mlmScriptStorageType.$i mlmScriptStorageType($i) permanent
    snmp instance mlmScriptStatus.$i	mlmScriptStatus($i)     active
}

##
## Remove a complete row given by $idx from a table.
##

proc MLM::Destroy { table idx } {
    foreach elem [mib successor [mib successor $table]] {
	upvar #0 $elem var
	puts stderr "destroying $elem $idx!"
#	catch {unset var($idx)}
    }
}

##
## Handle script status changes.
##

trace variable mlmScriptStatus w mlmScriptStatus::set
proc mlmScriptStatus::set { vname idx operation } {
    upvar #0 $vname mlmScriptStatus
    global mlmScriptIndex mlmScriptName mlmScriptDescr mlmScriptStorageType
    global mlmSourceScript mlmSourceLine mlmSourceCode

    switch $mlmScriptStatus($idx) {
        active {
	}
        notInService {
	}
        notReady {
	}
        createAndGo {
	    set mlmScriptStatus notInService
	}
        createAndWait {
	    set mlmScriptStatus notReady
	}
        destroy {
	    MLM::Destroy mlmScriptTable $idx
	}
    }
}

##
## Handling of the mlm execution table.
##

proc MLM::Result {script result error} {
    global mlmResultLastIndex sysUpTime
    if {![info exists mlmResultLastIndex($script)]} {
	set mlmResultLastIndex($script) 0
    }
    set idx [incr mlmResultLastIndex($script)]
    snmp instance mlmResultExecution.$script.$idx \
	    mlmResultExecution($script,$idx) $script
    snmp instance mlmResultIndex.$script.$idx \
	    mlmResultIndex($script,$idx) $idx
    snmp instance mlmResultTimeStamp.$script.$idx \
            mlmResultTimeStamp($script,$idx) $sysUpTime
    snmp instance mlmResultType.$script.$idx \
	    mlmResultType($script,$idx) octetstring
    if {$result != ""} {
	snmp instance mlmOctetStringValue.$script.$idx \
		mlmOctetStringValue($script,$idx) [mib scan sysDescr $result]
	snmp instance mlmResultStatus.$script.$idx \
		mlmResultStatus($script,$idx) ok
    } else {
	snmp instance mlmOctetStringValue.$script.$idx \
		mlmOctetStringValue($script,$idx) [mib scan sysDescr $error]
	snmp instance mlmResultStatus.$script.$idx \
		mlmResultStatus($script,$idx) error
    }
}

proc MLM::Execute { idx } {
    global mlmExecutionScript mlmExecutionArguments
    global mlmScriptName
    puts stderr "MLM::Execute $idx"
    set sidx $mlmExecutionScript($idx)
    set cmd [list $mlmScriptName($sidx) $mlmExecutionArguments($idx)]
    if {[eval catch \"$cmd\" result]} {
	MLM::Result "" $result
    } else {
	MLM::Result $idx $result ""
    }
    puts stderr "MLM::Execute $cmd -> $result"
}

snmp instance mlmNextExecution.0 mlmNextExecution 1
trace variable mlmNextExecution w mlmNextExecution::set
proc mlmNextExecution::set { vname idx operation } {
    upvar #0 $vname mlmNextExecution
    incr mlmNextExecution
}

trace variable mlmExecutionStatus w mlmExecutionStatus::set
proc mlmExecutionStatus::set { vname idx operation } {
    upvar #0 $vname mlmExecutionStatus

    global mlmExecutionIndex
    global mlmExecutionScript mlmExecutionArguments
    global mlmExecutionInterval mlmExecutionRepetitions
    global mlmExecutionPermanence mlmExecutionStatus
    static mlmExecutionJob

    switch $mlmExecutionStatus($idx) {
        active {
	    set interval [expr $mlmExecutionInterval($idx) * 10]
	    set times $mlmExecutionRepetitions($idx)
	    set mlmExecutionJob($idx) \
		    [job create "MLM::Execute $idx" $interval $times]
	}
        notInService {
	}
        notReady {
	}
        createAndGo {
	}
        createAndWait {
	    snmp instance mlmExecutionIndex.$idx \
		    mlmExecutionIndex($idx) $idx
	    snmp instance mlmExecutionScript.$idx \
		    mlmExecutionScript($idx) "0"
	    snmp instance mlmExecutionArguments.$idx \
		    mlmExecutionArguments($idx) ""
	    snmp instance mlmExecutionInterval.$idx \
		    mlmExecutionInterval($idx) 0
	    snmp instance mlmExecutionRepetitions.$idx \
		    mlmExecutionRepetitions($idx) 1
	    snmp instance mlmExecutionPermanence.$idx \
		    mlmExecutionPermanence($idx) temporary
	    set mlmExecutionStatus($idx) notReady
	}
        destroy {
	    after 1 "MLM::Destroy mlmExecutionTable $idx"
	    unset mlmExecutionJob($idx)
	}
    }
}

##------------------------------------------------------------------------##
## SOME SAMPLE SCRIPTS -- JUST SOME TESTING AND DEBUGGING STUFF           ##
##------------------------------------------------------------------------##

proc "HelloWorld" { args } {
    join $args
}

proc "CheckICMP" {args} {
    join [icmp [join $args]]
}

proc CheckIfStatus {args} {
    set result ""
    foreach host [join $args] {
	catch {
	    set s [snmp session -address $host]
	    $s walk x "ifDescr ifAdminStatus ifOperStatus" {
		set descr [lindex [lindex $x 0] 2]
		set admin [lindex [lindex $x 1] 2]
		set oper  [lindex [lindex $x 2] 2]
		if {$oper != $admin} {
		    append result "$host: Interface $descr:"
		    append result " AdminStatus=$admin != OperStatus=$oper !\n"
		}
	    }
	    $s destroy
	}
    }
    return $result
}


MLM::RegisterProc "HelloWorld" "Print the arguments on stdout."
MLM::RegisterProc "CheckICMP" "Send an ICMP echo request to the arguments."
MLM::RegisterProc "CheckIfStatus" "Test the ifAdmin and ifOper status."
