#
# File:    base-topology-license.prc
#
# Copyright 02/05/02 Sun Microsystems, Inc. All Rights Reserved.
# Author:  Ian Neal
#
# Version: 1.11 02/02/05 13:02:36
#

###########################################################
# Procedure to allow topology agent to subscribe to
# the topoLicRefresh trap that is sent with each module
# load/unload in SunMC 3.0
###########################################################
proc subscribeToLicenseTraps {} {

    set jobobject [ locate .services.snmp ]
    set trapobject [ locate .services.trap ]
    set lictrapoid [ toe_send $trapobject lookup trap topoLicRefresh ]
    ddl print info "Subscribing to license traps"
    toe_send $jobobject addNotifySubscription trapid1 trapOID $lictrapoid expiry 0

}

###########################################################
# Procedure to allow topology agent to subscribe to
# the topoLicRefresh trap that is sent with each module
# load/unload in SunMC 3.0
#
# lic_status = 1 | 100
# 1 - indicates licensable agents that must be re-requested
# 100 - indicates that the node is new and not licensed yet
#
#
###########################################################
proc updateDatabaseModuleList {lic_status} {

    ###################################################
    # Set the licensable trap server into the database"	
    ###################################################
    if { [ lookup -d "" licensing trapServerSet ] == "" } {
        subscribeToLicenseTraps
        set mytrapserver [ toe_send \
            [ locate .iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.info.system.trapaddr ] lookup -d "" data 0 ]
        ddl print info "Setting the trap server for topology = $mytrapserver"

        if { [ catch { topoDbLicTrapServer $mytrapserver } result ] } {
            if { [ string first "invalid command name" $result ] == 0 } {
                ddl print warning "Trap ignored as domain-config module not loaded"
                return ""
            } else {
                ddl print error "Error calling topoDbLicTrapServer $mytrapserver"
                ddl print error "result = $result"
            }
        }

        define licensing trapServerSet yes
    }

    ###########################################
    # retrieve the list of URLS to snmp query
    # for their module lists
    #########################################
    if { [ catch { topoDbGetAgents $lic_status } listurls ] } {
        if { [ string first "invalid command name" $listurls ] == 0 } {

            #
            # since domain config not loaded yet ignore this
            # trap and wait for the next one in order to license
            # the modules
            #
            ddl print warning "Trap ignored as domain-config module not loaded"
            return ""
        } else {
            ddl print error "Error calling topoDbGetAgents $lic_status"
            ddl print error "result = $listurls"
        }
    }

    foreach trapAddress $listurls {
	
    ###########################################
    # convert url from 1.1.1.1:1432 to
    # a form that can be stored in toe slice
    # i.e 1/1/1/1:1432
    ###########################################
        regsub -all "\\." $trapAddress / addr
        define remainingsnmp $addr ""
    }

    ##############################################
    # retrieve the first host to query and 
    # convert the 1/1/1/1:1432 back to
    # 1.1.1.1:1432 and callit
    #
    # all remaining entries in the 
    # remainingsnmp slice will be called at the
    # end of the snmpLicCallBackReceived
    ##############################################
    if { [ entries currentsnmp ] == "" } {
        set firstsnmp [lindex [entries remainingsnmp] 0]
        if { $firstsnmp != "" } {
            undefine remainingsnmp $firstsnmp
            define currentsnmp $firstsnmp 1
            regsub -all / $firstsnmp . addr
            refreshModuleListByPDU $addr
        }
    }

}

proc handleLicenseTrap { address } {

    set key [ dotstoslashes $address ]
    if { [ exists remainingsnmp $key ] ||   
         [ exists currentsnmp $key ] } {  
        return
    }
    if { [ entries currentsnmp ] != "" } {
        define remainingsnmp $key ""
        return
    }
    define currentsnmp $key 1
    refreshModuleListByPDU $address
}

proc refreshModuleListByPDU { trapAddress } {

	#ddl print info "@@@@ EXECUTING TRAPRECEIVED trapAddress=$trapAddress@@@@"

	#########################################
 	# trapaddress is in form of ip:port
	# extract ip and port info
	#########################################
	set poscolon [ string first : $trapAddress ]
	set ip [ string range $trapAddress 0 [ expr $poscolon - 1 ]]
	set port [ string range $trapAddress [ expr $poscolon + 1 ] [string length $trapAddress] ]

	set url1 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.info.system.trapaddr#0"
	set url2 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.info.system.trapaddr#0"

#	set url2 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.info.agent.general.component#0"

	set url3 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.operatingSystem.moduleTable.moduleEntry.modspec"
	set url4 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.operatingSystem.moduleTable.moduleEntry.version"
	set url5 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.hardware.moduleTable.moduleEntry.modspec"
	set url6 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.hardware.moduleTable.moduleEntry.version"
	set url7 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.localApplication.moduleTable.moduleEntry.modspec"
	set url8 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.localApplication.moduleTable.moduleEntry.version"
	set url9 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.remoteSystem.moduleTable.moduleEntry.modspec"
	set url10 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.remoteSystem.moduleTable.moduleEntry.version"
	set url11 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.serverSupport.moduleTable.moduleEntry.modspec"
	set url12 "sym/.iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.mibman.modules.serverSupport.moduleTable.moduleEntry.version"

	setParameters urls [list $url1 $url2 $url3 $url4 $url5 $url6 $url7 $url8 $url9 $url10 $url11 $url12]
	setParameters agentAddress $ip agentPort $port agentGetCommunity public

	################################################
	# Send the snmp request for the modules loaded
	# on the agent
	################################################
	set toeself [toe_self]
	set tidresult [triggerCommandOrMethod query "" [list $toeself {snmpLicCallBackReceived %result} ] ]

	##############################################################
	# Cache the ip:port info keyed on transaction id so that the 
	# callback function named "snmpLicCallBackReceived" 
	# can lookup the ip:port of the returning tid 
	##############################################################
	set tid [lindex $tidresult 1]
	define outstanding $tid [list $ip $port]

	clearParameters agentAddress agentPort agentGetCommunity urls
}

#############################################
# A procedure to take the ip:host name
# and return "ip port"
#############################################
proc moduleinstance { modulename } {
	set pos [string first + $modulename]
	if { $pos == -1 } {
		return [list $modulename {}]
	} else {
		set name [string range $modulename 0 [expr $pos - 1]]
		set inst [string range $modulename [expr $pos + 1] [string length $modulename]]
		return [list $name $inst]
	}
}

#############################################################################################
# This method is the call back procedure for the snmp request 
# for the list of modules
#
# there are 3 kinds of arc's that are received
# wait, data and error
# a wait means that instead of tid157 containing data then tid 167 will
# a data means that the list of modules has arrived
#
# eg's
#
# arc = data tid155 {{mib2-simple kernel-reader} {1.0 2.0} {} {} {} {} {} {} tools-adhocs 1.0}
# arc = wait tid157 tid161 {   }
#
#############################################################################################

proc snmpLicCallBackReceived { arc } {
    if { [ catch { _snmpLicCallBackReceived $arc } result ] } {
        ddl print error "snmpLicCallBackReceived: $result\n"
    } 
}

proc _snmpLicCallBackReceived { arc } {

	#ddl print info "snmpLicCallBackReceived: arc = $arc"

	set returncode 0
	set arctype [lindex $arc 0]
	set tidnumber [lindex $arc 1]
	set data [lindex $arc 2]
	set data1 [lindex $arc 3]

	#ddl print info "@@@@ EXECUTING CALLBACK @@@@ arctype = $arctype ; tidnumber = $tidnumber "
	#ddl print info "@@@@ EXECUTING CALLBACK @@@@ data = $data ; data1 = $data1"

	set toeself [ toe_self ]
	set result [ lookup -d "" outstanding $tidnumber] 
	if { $result == "" } {
		#ddl print error "Warning : snmpLicCallBackReceived tid = $tidnumber not cached"
		return ""
	}

	########################################
	# if tid found then extra ip port info
	########################################
	set ip [lindex $result 0]
	set port [lindex $result 1]

 	#ddl print info "Callback port = $port ; ip = $ip ; data = $data"

	if { $arctype == "data" } {

		########################################
		# snmp request is no longer outstanding 
		# so remove
		########################################
		undefine outstanding $tidnumber
	
		##############################################################
		# Cache the trap destination that topology is trapping from
		##############################################################
		set mytrapdest [ilookup -d "" value mytrapdest]
		if { $mytrapdest == "" } {
			set trapobj [ locate .iso.org.dod.internet.private.enterprises.sun.prod.sunsymon.agent.base.info.system.trapaddr ]
			set mytrapdest [toe_send $trapobj lookup data 0] 
			define value mytrapdest $mytrapdest
 		}

		# 
		# Delete the modules for this particular host
		# as we have received an updated list
		#
                if { [ catch { topoDbDeleteModuleByIpPort $ip $port } result ] } {
                        ddl print error "Error calling topoDbDeleteModuleByIpPort $ip $port"
                        ddl print error "result = $result"
                }

		#
		# Determine the leaf id base on ip and port
		#
                if { [ catch { topoDbGetLeafIdByIpPort $ip $port } leafid ] } {
                        ddl print error "Error calling topoDbGetLeafIdByIpPort $ip $port"
                        ddl print error "result = $leafid"
                }

		if { $leafid == "" || $leafid == 0 } {
			ddl print trace "Module list received for unloaded host.  Ignoring"
                        processRemainingSNMP
			return ""
		}

		set receivedtrapdest [ lindex $data 0]
#		set agenttype [ lindex $data 1]
		set agenttype "agent"

		if { $agenttype == "" } {
			set agenttype "invalidagentprocess"
		}

		if { [ catch { topoDbSetTrapDest $ip $port $receivedtrapdest $agenttype } result ] } {
                        ddl print error "Error calling topoDbSetTrapDest $ip $port $receivedtrapdest $agenttype"
                        ddl print error "result = $result"
		}

		list modulelist ""
		for { set i 0 } { $i < 5 } { incr i 1 } {
			set modname [expr $i * 2 + 2]
			set modver [expr $modname + 1]
			set modulenamelist [lindex $data $modname]
			set moduleversionlist [lindex $data $modver]
			set counter 0
			set module ""

			#############################################################
			# create the list of modules in the form
			# modname1 modinst1 modver1 modname2 modinst2 modver2 ... 
			#############################################################
			foreach module $modulenamelist {
				#ddl print info $module
				###############################################################
				# if module is not a topology+view then add to the database
				###############################################################
				if { [ string first "topology+view-" $module ] == -1 } {
					set moddata [moduleinstance $module]
					lappend modulelist [lindex $moddata 0]
					lappend modulelist [lindex $moddata 1]
					lappend modulelist [lindex $moduleversionlist $counter]
				}
				incr counter 1
			}
		}

		set functiontocall [ concat topoDbLicLoadModules $leafid $agenttype $receivedtrapdest $modulelist ] 
#		set returncode [ eval $functiontocall ]
		if { [ catch { eval $functiontocall } returncode ] } {
                        ddl print error "Error calling $functiontocall"
                        ddl print error "leafid = $leafid"
                        ddl print error "agenttype = $agenttype"
                        ddl print error "receivedtrapdest = $receivedtrapdest"
		}

                processRemainingSNMP

	} elseif { $arctype == "wait" } {
		if { $data != "" } {
			set result [lookup -d "unknowntid" outstanding $tidnumber]
			undefine outstanding $tidnumber
			define outstanding $data $result
		} else {
			undefine outstanding $tidnumber
		}
	} elseif { $arctype == "error" } {

		undefine outstanding $tidnumber
		
		#################################
		# host is likely down
		# unlicense modules accordingly
		#################################
		if { [ catch { topoDbDeleteModuleByIpPort $ip $port } result ] } {
			ddl print error "licensing snmpLicCallBackReceived error - topoDbDeleteModuleByIpPort call failed for machine $ip $port"
		}

		if { [ catch { topoDbSetTrapDest $ip $port 0.0.0.0 nonsunmc30agent } result ] } {
			ddl print error "licensing snmpLicCallBackReceived error - cannot change the licensing for machine $ip $port"
		}

                processRemainingSNMP
	} else {
		undefine outstanding $tidnumber
		ddl print error "snmpLicCallBackReceived : unknown type ignoring : $arc"
	}

	return $returncode
}

proc processRemainingSNMP {} {
    undefine currentsnmp
    set next [ lindex [entries remainingsnmp] 0 ]
    if { $next != "" } {
        define currentsnmp $next 1
        undefine remainingsnmp $next 
        refreshModuleListByPDU [ slashestodots $next ]
    }
}
