##
## snmpd-mlm.tcl --
##
##	Here starts the experimental implementation of the TUBS
##	version of the MLM MIB. Some sample scripts for the 
##	are included at the end of this file.
##
## Copyright (c) 1994-1996 Technical University of Braunschweig.
##
## See the file "license.terms" for information on usage and redistribution
## of this file, and for a DISCLAIMER OF ALL WARRANTIES.

mib load tubs-mlm.mib

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

proc SNMP_MLMRegister {s name description {status active}} {

    global mlmNextScript
    global mlmScriptIndex mlmScriptName mlmScriptDescr mlmScriptStorageType
    global mlmSourceScript mlmSourceLine mlmSourceCode

    set i $mlmNextScript
    incr mlmNextScript

    set description [string trim $description]

    $s instance mlmScriptIndex.$i	mlmScriptIndex($i)	$i
    $s instance mlmScriptName.$i	mlmScriptName($i)	$name
    $s instance mlmScriptDescr.$i	mlmScriptDescr($i)	$description
    $s instance mlmScriptStorageType.$i mlmScriptStorageType($i) permanent
    $s instance mlmScriptStatus.$i	mlmScriptStatus($i)     $status
}

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

proc SNMP_MLMDestroyTable { table idx } {
    if {[mib syntax $table] == "SEQUENCE OF"} {
	set table [mib successor $table]
    }
    foreach elem [mib successor $table] {
	upvar #0 $elem var
	catch {unset var($idx)}
    }
}

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

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

proc SNMP_MLMExecute { s idx } {
    global mlmExecutionScript mlmExecutionArguments
    global mlmScriptName
    puts stderr "SNMP_MLMExecute $idx"
    set sidx $mlmExecutionScript($idx)
    set cmd [list $mlmScriptName($sidx) $mlmExecutionArguments($idx)]
    set cmd $mlmScriptName($sidx) ; append cmd " $mlmExecutionArguments($idx)"
    set cmd [concat $mlmScriptName($sidx) $mlmExecutionArguments($idx)]
    if {[eval [list catch $cmd result]]} {
	SNMP_MLMResult $s "" $result
    } else {
	SNMP_MLMResult $s $idx $result ""
    }
    puts stderr "SNMP_MLMExecute $cmd -> $result"
}

proc SNMP_MLMStartExecution {s idx {status active}} {

    global mlmExecutionIndex
    global mlmExecutionScript mlmExecutionArguments
    global mlmExecutionInterval mlmExecutionRepetitions
    global mlmExecutionPermanence mlmExecutionStatus

    $s instance mlmExecutionIndex.$idx mlmExecutionIndex($idx) $idx
    $s instance mlmExecutionScript.$idx mlmExecutionScript($idx) "0"
    $s instance mlmExecutionArguments.$idx mlmExecutionArguments($idx) ""
    $s instance mlmExecutionInterval.$idx mlmExecutionInterval($idx) 0
    $s instance mlmExecutionRepetitions.$idx mlmExecutionRepetitions($idx) 1
    $s instance mlmExecutionPermanence.$idx mlmExecutionPermanence($idx) temporary
    set mlmExecutionStatus($idx) $status
}

###
###

proc SNMP_MLMInit {s} {
    $s instance mlmLock.0 mlmLock 1

    $s instance mlmNextScript.0 mlmNextScript 1
    $s bind mlmNextScript.0 set {
	incr mlmNextScript
	break
    }

    $s bind mlmScriptStatus create {
	switch "%v" {
	    createAndGo {
		SNMP_MLMRegister "%S" "" "" active
	    }
	    createAndWait {
		SNMP_MLMRegister "%S" "" "" notReady
	    }
	    destroy {
	    }
	    default {
		error inconsistentValue
	    }
	}
    }

    $s bind mlmScriptStatus set {
	switch "%v" {
	    active {
	    }
	    notInService {
	    }
	    notReady {
	    }
	    createAndGo {
		error inconsistentValue
	    }
	    createAndWait {
		error inconsistentValue
	    }
	    destroy {
		SNMP_MLMDestroyTable mlmScriptTable "%i"
	    }
	}
    }

    $s instance mlmNextExecution.0 mlmNextExecution 1
    $s bind mlmNextExecution.0 set { 
	incr mlmNextExecution
	break
    }

    $s bind mlmExecutionStatus create {
	switch "%v" {
	    createAndGo {
		SNMP_MLMStartExecution "%S" "%i" active
	    }
	    createAndWait {
		SNMP_MLMStartExecution "%S" "%i" notReady
	    }
	    destroy {
	    }
	    default {
		error inconsistentValue
	    }
	}
    }

    $s bind mlmExecutionStatus set {
	global mlmExecutionInterval mlmExecutionRepetitions
	static mlmExecutionJob
	set idx "%i"
	switch "%v" {
	    active {
		set interval [expr $mlmExecutionInterval($idx) * 10]
		set times $mlmExecutionRepetitions($idx)
		set mlmExecutionJob($idx) \
		    [job create "SNMP_MLMExecute "%S" $idx" $interval $times]
	    }
	    notInService {
	    }
	    notReady {
	    }
	    createAndGo {
		error inconsistentValue
	    }
	    createAndWait {
		error inconsistentValue
	    }
	    destroy {
		after 1 "SNMP_MLMDestroyTable mlmExecutionTable $idx"
		unset mlmExecutionJob($idx)
	    }
	}
    }
}

##########################################################################
##########################################################################

proc SNMP_MLMScriptEcho {args} {
    return [join $args]
}

proc SNMP_MLMScriptCheckICMP {args} {
    return [join [icmp echo [join $args]]]
}

proc SNMP_MLMScriptCheckIfStatus {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
}

proc SNMP_MLMScriptCountTcpServiceUser {s port} {
    set count 0
    $s walk x "tcpConnState tcpConnLocalPort" {
        set tcpConnState     [lindex [lindex $x 0] 2]
        set tcpConnLocalPort [lindex [lindex $x 1] 2]
        if {$tcpConnState == "established" && $tcpConnLocalPort == $port} {
            incr count
        }
    }
    return $count
}

proc SNMP_MLMScriptTcpServiceUser {port args} {
    set result ""
    foreach host [join $args] {
        catch {
            set s [snmp session -address $host]
            lappend result "$host/[SNMP_MLMScriptCountTcpServiceUser $s $port]"
            $s destroy
        }
    }
    return $result
}

proc SNMP_MLMScriptRegisterSamples {s} {
    SNMP_MLMRegister $s SNMP_MLMScriptEcho {
	This procedure simply echos its arguments.
    }
    SNMP_MLMRegister $s SNMP_MLMSCriptCheckICMP {
	Send an ICMP echo request to the arguments.
    }
    SNMP_MLMRegister $s SNMP_MLMScriptCheckIfStatus {
	Test the ifAdmin and ifOper status.
    }
    SNMP_MLMRegister $s SNMP_MLMScriptTcpServiceUser {
	Count the number of established TCP connections to a given port.
    }
}

