- Fix ADO cursor issue where reading rs("description") twice caused
empty values (IsNull check consumed the field value)
- Change all device pages to read description field once using
`description = rs("description") & ""` pattern
- Add deviceDescription variable in displaydevice.asp
- Fix machinetypeid mapping: IDF=17, Camera=18 (was swapped)
- Add model dropdown fix to include currently assigned model
- Add server application tracking feature
- Various other improvements and fixes
Files affected:
- displaydevice.asp, displaylocationdevice.asp
- deviceaccesspoint.asp, deviceserver.asp, deviceswitch.asp
- devicecamera.asp, deviceidf.asp
- savenetworkdevice.asp, networkdevices.asp
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
381 lines
13 KiB
Plaintext
381 lines
13 KiB
Plaintext
<%
|
|
' Zabbix API Configuration - uses ZABBIX_URL and ZABBIX_API_TOKEN from config.asp
|
|
' NOTE: config.asp must be included by the calling page (via sql.asp) before this file
|
|
|
|
' Function to make HTTP POST request to Zabbix API with Bearer token
|
|
Function ZabbixAPICall(jsonRequest)
|
|
On Error Resume Next
|
|
Dim http, responseText, httpStatus
|
|
Set http = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
|
|
|
|
' Set aggressive timeouts (in milliseconds): resolve, connect, send, receive
|
|
' 2 seconds to resolve DNS, 3 seconds to connect, 3 seconds to send, 5 seconds to receive
|
|
http.setTimeouts 2000, 3000, 3000, 5000
|
|
|
|
http.Open "POST", ZABBIX_URL, False
|
|
http.setRequestHeader "Content-Type", "application/json-rpc"
|
|
http.setRequestHeader "Authorization", "Bearer " & ZABBIX_API_TOKEN
|
|
http.Send jsonRequest
|
|
|
|
If Err.Number <> 0 Then
|
|
ZabbixAPICall = "{""error"":""HTTP Error: " & Err.Description & " (Code: " & Err.Number & ")""}"
|
|
Err.Clear
|
|
Exit Function
|
|
End If
|
|
|
|
httpStatus = http.Status
|
|
responseText = http.responseText
|
|
|
|
' Check HTTP status code
|
|
If httpStatus <> 200 Then
|
|
ZabbixAPICall = "{""error"":""HTTP Status: " & httpStatus & " - " & responseText & """}"
|
|
Else
|
|
ZabbixAPICall = responseText
|
|
End If
|
|
|
|
Set http = Nothing
|
|
On Error Goto 0
|
|
End Function
|
|
|
|
' Function to verify API token works (returns 1 if successful, empty string if failed)
|
|
Function ZabbixLogin()
|
|
' With API tokens, we just verify the token works by making a simple API call
|
|
' Use hostgroup.get instead of apiinfo.version (which doesn't allow auth header)
|
|
Dim jsonRequest, response
|
|
|
|
jsonRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""hostgroup.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""groupid""]," & _
|
|
"""limit"":1" & _
|
|
"}," & _
|
|
"""id"":1" & _
|
|
"}"
|
|
|
|
response = ZabbixAPICall(jsonRequest)
|
|
|
|
' Check if we got a valid response or error
|
|
If InStr(response, """result"":[") > 0 Or InStr(response, """result"":[]") > 0 Then
|
|
ZabbixLogin = "1" ' Success - got valid result (even if empty array)
|
|
ElseIf InStr(response, """error""") > 0 Then
|
|
ZabbixLogin = "ERROR: " & response ' Return error details
|
|
Else
|
|
ZabbixLogin = "UNKNOWN: " & response ' Return response for debugging
|
|
End If
|
|
End Function
|
|
|
|
' Function to get hostgroup ID by name
|
|
Function GetHostGroupID(groupName)
|
|
Dim jsonRequest, response, groupID
|
|
|
|
jsonRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""hostgroup.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""groupid""]," & _
|
|
"""filter"":{" & _
|
|
"""name"":[""" & groupName & """]" & _
|
|
"}" & _
|
|
"}," & _
|
|
"""id"":2" & _
|
|
"}"
|
|
|
|
response = ZabbixAPICall(jsonRequest)
|
|
|
|
' Parse response to get groupid
|
|
If InStr(response, """groupid"":""") > 0 Then
|
|
groupID = Mid(response, InStr(response, """groupid"":""") + 12)
|
|
groupID = Left(groupID, InStr(groupID, """") - 1)
|
|
GetHostGroupID = groupID
|
|
Else
|
|
GetHostGroupID = ""
|
|
End If
|
|
End Function
|
|
|
|
' Function to get all hosts in a hostgroup
|
|
Function GetHostsInGroup(groupID)
|
|
Dim jsonRequest
|
|
|
|
jsonRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""host.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""hostid"",""host"",""name""]," & _
|
|
"""groupids"":[""" & groupID & """]," & _
|
|
"""selectInterfaces"":[""ip""]" & _
|
|
"}," & _
|
|
"""id"":3" & _
|
|
"}"
|
|
|
|
GetHostsInGroup = ZabbixAPICall(jsonRequest)
|
|
End Function
|
|
|
|
' Function to get items (toner levels) for a specific host by IP address
|
|
Function GetPrinterTonerLevels(hostIP)
|
|
Dim jsonRequest, response
|
|
|
|
' First, find the host by IP
|
|
jsonRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""host.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""hostid""]," & _
|
|
"""filter"":{" & _
|
|
"""host"":[""" & hostIP & """]" & _
|
|
"}" & _
|
|
"}," & _
|
|
"""id"":4" & _
|
|
"}"
|
|
|
|
response = ZabbixAPICall(jsonRequest)
|
|
|
|
' Check if result array is empty
|
|
If InStr(response, """result"":[]") > 0 Then
|
|
GetPrinterTonerLevels = "{""error"":""Host not found in Zabbix"",""ip"":""" & hostIP & """}"
|
|
Exit Function
|
|
End If
|
|
|
|
' Extract hostid from result array
|
|
' Look for "hostid":" and then extract the value between quotes
|
|
Dim hostID, startPos, endPos
|
|
startPos = InStr(response, """hostid"":""")
|
|
If startPos > 0 Then
|
|
' Move past "hostid":" to get to the opening quote of the value
|
|
startPos = startPos + 10 ' Length of "hostid":"
|
|
' Find the closing quote
|
|
endPos = InStr(startPos, response, """")
|
|
' Extract the value
|
|
hostID = Mid(response, startPos, endPos - startPos)
|
|
Else
|
|
GetPrinterTonerLevels = "{""error"":""Could not extract hostid"",""response"":""" & Left(response, 200) & """}"
|
|
Exit Function
|
|
End If
|
|
|
|
' Debug: Check hostID value
|
|
If hostID = "" Or IsNull(hostID) Then
|
|
GetPrinterTonerLevels = "{""error"":""HostID is empty"",""hostid"":""" & hostID & """}"
|
|
Exit Function
|
|
End If
|
|
|
|
' Now get items for this host with component:supplies AND type:level tags
|
|
' Build the item request using the extracted hostID
|
|
Dim itemRequest
|
|
itemRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""item.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""itemid"",""name"",""lastvalue"",""lastclock"",""units"",""status"",""state""]," & _
|
|
"""hostids"":[""" & hostID & """]," & _
|
|
"""selectTags"":""extend""," & _
|
|
"""evaltype"":0," & _
|
|
"""tags"":[" & _
|
|
"{""tag"":""component"",""value"":""supplies"",""operator"":0}," & _
|
|
"{""tag"":""type"",""value"":""level"",""operator"":0}" & _
|
|
"]," & _
|
|
"""sortfield"":""name""," & _
|
|
"""monitored"":true" & _
|
|
"}," & _
|
|
"""id"":5" & _
|
|
"}"
|
|
|
|
' Make the item.get call
|
|
Dim itemResponse
|
|
itemResponse = ZabbixAPICall(itemRequest)
|
|
|
|
' Return the item response
|
|
GetPrinterTonerLevels = itemResponse
|
|
End Function
|
|
|
|
' Function to get ICMP ping status for a printer
|
|
Function GetPrinterPingStatus(hostIP)
|
|
Dim jsonRequest, response
|
|
|
|
' First, find the host by IP
|
|
jsonRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""host.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""hostid""]," & _
|
|
"""filter"":{" & _
|
|
"""host"":[""" & hostIP & """]" & _
|
|
"}" & _
|
|
"}," & _
|
|
"""id"":6" & _
|
|
"}"
|
|
|
|
response = ZabbixAPICall(jsonRequest)
|
|
|
|
' Check if result array is empty
|
|
If InStr(response, """result"":[]") > 0 Then
|
|
GetPrinterPingStatus = "-1" ' Host not found
|
|
Exit Function
|
|
End If
|
|
|
|
' Extract hostid from result array
|
|
Dim hostID, hostidPos
|
|
hostidPos = InStr(response, """hostid"":""")
|
|
If hostidPos > 0 Then
|
|
hostID = Mid(response, hostidPos + 10)
|
|
' Find the closing quote
|
|
Dim endPos
|
|
endPos = InStr(1, hostID, """")
|
|
hostID = Mid(hostID, 1, endPos - 1)
|
|
Else
|
|
GetPrinterPingStatus = "-1" ' Could not extract hostid
|
|
Exit Function
|
|
End If
|
|
|
|
' Get ICMP ping item
|
|
jsonRequest = "{" & _
|
|
"""jsonrpc"":""2.0""," & _
|
|
"""method"":""item.get""," & _
|
|
"""params"":{" & _
|
|
"""output"":[""lastvalue""]," & _
|
|
"""hostids"":[""" & hostID & """]," & _
|
|
"""search"":{" & _
|
|
"""key_"":""icmpping""" & _
|
|
"}" & _
|
|
"}," & _
|
|
"""id"":7" & _
|
|
"}"
|
|
|
|
response = ZabbixAPICall(jsonRequest)
|
|
|
|
' Extract ping status (1 = up, 0 = down)
|
|
Dim valuePos
|
|
valuePos = InStr(response, """lastvalue"":""")
|
|
If valuePos > 0 Then
|
|
Dim pingStatus, pingStart, pingEnd
|
|
pingStart = valuePos + 13 ' Length of "lastvalue":"
|
|
pingEnd = InStr(pingStart, response, """")
|
|
pingStatus = Mid(response, pingStart, pingEnd - pingStart)
|
|
GetPrinterPingStatus = pingStatus
|
|
Else
|
|
GetPrinterPingStatus = "-1" ' Item not found
|
|
End If
|
|
End Function
|
|
|
|
' Simple JSON parser for toner data (extracts color and level from tags)
|
|
Function ParseTonerData(jsonResponse)
|
|
Dim tonerArray()
|
|
Dim resultStart, itemStart, itemEnd
|
|
Dim validItems, i, searchPos
|
|
|
|
' Check if we have a valid result
|
|
resultStart = InStr(jsonResponse, """result"":[")
|
|
If resultStart = 0 Then
|
|
ParseTonerData = tonerArray
|
|
Exit Function
|
|
End If
|
|
|
|
' First pass: count valid toner items (exclude drums and unsupported)
|
|
validItems = 0
|
|
searchPos = resultStart
|
|
Do While True
|
|
itemStart = InStr(searchPos, jsonResponse, """name"":""")
|
|
If itemStart = 0 Then Exit Do
|
|
|
|
' Check if this is a toner (not drum) and status is not unsupported
|
|
Dim itemBlock
|
|
itemEnd = InStr(itemStart, jsonResponse, "},")
|
|
If itemEnd = 0 Then itemEnd = InStr(itemStart, jsonResponse, "}]")
|
|
If itemEnd = 0 Then Exit Do
|
|
|
|
itemBlock = Mid(jsonResponse, itemStart, itemEnd - itemStart)
|
|
|
|
' Only count if status is active (0) and NOT a drum
|
|
If InStr(itemBlock, """status"":""0""") > 0 And InStr(LCase(itemBlock), "drum") = 0 Then
|
|
validItems = validItems + 1
|
|
End If
|
|
|
|
searchPos = itemEnd + 1
|
|
If searchPos > Len(jsonResponse) Then Exit Do
|
|
Loop
|
|
|
|
If validItems = 0 Then
|
|
ParseTonerData = tonerArray
|
|
Exit Function
|
|
End If
|
|
|
|
ReDim tonerArray(validItems - 1, 2) ' name, value, color
|
|
|
|
' Second pass: extract toner data
|
|
i = 0
|
|
searchPos = resultStart
|
|
Do While i < validItems
|
|
itemStart = InStr(searchPos, jsonResponse, """name"":""")
|
|
If itemStart = 0 Then Exit Do
|
|
|
|
itemEnd = InStr(itemStart, jsonResponse, "},")
|
|
If itemEnd = 0 Then itemEnd = InStr(itemStart, jsonResponse, "}]")
|
|
If itemEnd = 0 Then Exit Do
|
|
|
|
itemBlock = Mid(jsonResponse, itemStart, itemEnd - itemStart)
|
|
|
|
' Only process items with active status (exclude drums)
|
|
If InStr(itemBlock, """status"":""0""") > 0 And InStr(LCase(itemBlock), "drum") = 0 Then
|
|
Dim itemName, itemValue, itemColor
|
|
Dim nameStart, nameEnd, valueStart, valueEnd, colorStart, colorEnd
|
|
|
|
' Extract name (find position after "name":")
|
|
nameStart = InStr(itemBlock, """name"":""")
|
|
If nameStart > 0 Then
|
|
nameStart = nameStart + 8 ' Length of "name":"
|
|
nameEnd = InStr(nameStart, itemBlock, """")
|
|
itemName = Mid(itemBlock, nameStart, nameEnd - nameStart)
|
|
Else
|
|
itemName = ""
|
|
End If
|
|
|
|
' Extract lastvalue (find position after "lastvalue":")
|
|
valueStart = InStr(itemBlock, """lastvalue"":""")
|
|
If valueStart > 0 Then
|
|
valueStart = valueStart + 13 ' Length of "lastvalue":"
|
|
valueEnd = InStr(valueStart, itemBlock, """")
|
|
itemValue = Mid(itemBlock, valueStart, valueEnd - valueStart)
|
|
Else
|
|
itemValue = "0"
|
|
End If
|
|
|
|
' Extract color from tags array
|
|
itemColor = ""
|
|
colorStart = InStr(itemBlock, """tag"":""color"",""value"":""")
|
|
If colorStart > 0 Then
|
|
colorStart = colorStart + 26
|
|
colorEnd = InStr(colorStart, itemBlock, """")
|
|
itemColor = Mid(itemBlock, colorStart, colorEnd - colorStart)
|
|
End If
|
|
|
|
' Normalize color tag (handle variations like matte_black, photo_black)
|
|
If itemColor <> "" Then
|
|
If InStr(itemColor, "black") > 0 Then itemColor = "black"
|
|
If itemColor = "gray" Or itemColor = "grey" Then itemColor = "gray"
|
|
End If
|
|
|
|
' If no color tag, try to determine from name
|
|
If itemColor = "" Then
|
|
Dim lowerName
|
|
lowerName = LCase(itemName)
|
|
If InStr(lowerName, "cyan") > 0 Then itemColor = "cyan"
|
|
If InStr(lowerName, "magenta") > 0 Then itemColor = "magenta"
|
|
If InStr(lowerName, "yellow") > 0 Then itemColor = "yellow"
|
|
If InStr(lowerName, "black") > 0 Then itemColor = "black"
|
|
If InStr(lowerName, "gray") > 0 Or InStr(lowerName, "grey") > 0 Then itemColor = "gray"
|
|
End If
|
|
|
|
tonerArray(i, 0) = itemName
|
|
tonerArray(i, 1) = itemValue
|
|
tonerArray(i, 2) = itemColor
|
|
|
|
i = i + 1
|
|
End If
|
|
|
|
searchPos = itemEnd + 1
|
|
If searchPos > Len(jsonResponse) Then Exit Do
|
|
Loop
|
|
|
|
ParseTonerData = tonerArray
|
|
End Function
|
|
%>
|