aboutsummaryrefslogtreecommitdiff
path: root/plugins/nut.lua
blob: c42fa6077a1b7418f5dd26d16ff6f72a8892ce47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
--
-- nut.lua: Network UPS Tools service detection plugin
--
-- Copyright (c) 2017, Přemysl Janouch <p@janouch.name>
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--

ponymap.check_api_version (1)

local NUT = {}
NUT.__index = NUT

function NUT.new (unit)
	unit:write ("LIST UPS\n")
	return setmetatable ({ unit = unit, buf = "", in_list = false }, NUT)
end

-- Bare words and quoted strings with escape sequences, separated by spaces;
-- unfortunately Lua patterns are too weak to use them for this trivial task
function NUT.parse (line)
	local result, state, field, c = {}, 0, ""
	for c in (line .. " "):gmatch (".") do
		if state == 0 then
			if c == "\"" then state = 2
			elseif c ~= " "  then field = c state = 1 end
		elseif state == 1 then
			if c == " " then table.insert (result, field) field = "" state = 0
			elseif c == "\"" then state = 2
			else field = field .. c end
		elseif state == 2 then
			if c == "\\" then state = 3
			elseif c == "\"" then state = 1
			else field = field .. c end
		elseif state == 3 then field = field .. c state = 2 end
	end
	return result
end

function NUT:process (line)
	if not self.in_list then
		if line:match ("^BEGIN LIST UPS$") then
			self.unit:add_info ("no authentication required")
			self.unit:set_success (true)
			self.in_list = true
			return true
		elseif line:match ("^ERR ACCESS-DENIED") then
			self.unit:set_success (true)
		end
	else
		local fields = self.parse (line)
		if #fields == 3 and fields[1] == "UPS" then
			self.unit:add_info ("UPS: " .. fields[2] .. " - " .. fields[3])
			return true
		end
	end
end

function NUT:on_data (data)
	self.buf = self.buf .. data
	repeat
		local line, rest = self.buf:match ("([^\n]*)\n(.*)")
		if not line then return end
		self.buf = rest
	until not self:process (line)
	self.unit:stop ()
end

ponymap.register_service { name="NUT", flags=0, new_scan=NUT.new }