#!/usr/bin/env lua

local json = require "luci.jsonc"
local fs   = require "nixio.fs"
local sys = require "luci.sys"
local ut = require "luci.util"

local function readfile(path)
	local s = fs.readfile(path)
	return s and (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

local methods = {
	setScepCertAction = {
		args = { name = "", action = "" },
		call = function(args)
			local sys = require "luci.sys"
			local name = args.name
			local action = args.action
			luci.sys.exec("rm -rf /tmp/scepstatus")
			local comd = "/sbin/scep "..action.." "..name
			luci.sys.exec(comd)
			return { result = "OK" }
		end
	},

	getScepCertInfo = {
		call = function()
			local sys = require "luci.sys"
			local uci = require "uci"
			local data = {}
			local x = uci.cursor()

			x:foreach('scep', 'cert', function(s)
				local name = s.name
				local enroll = s.enroll_status
				if enroll ~= '0' then
					data[name] = {}
					data[name]['start'] = luci.sys.exec("cat /etc/scep/%q/startDate 2>/dev/null | xargs echo -n" %name)
					data[name]['end'] = luci.sys.exec("cat /etc/scep/%q/endDate 2>/dev/null | xargs echo -n" %name)
				end
			end
			)
			return { result = data }
		end
	},

	getScepEnrollStatus = {
		call = function()
			local sys = require "luci.sys"
			local file
			local data = {}
			local res = {}
			file = io.open('/tmp/scepstatus', 'r')

			if file then
				for line in file:lines() do
					if string.find(line,"SUCCESS") ~= nil then
						data["found"] = "success"
					elseif string.find(line, "already enrolled") ~= nil then
						data["found"] = "enrolled"
					elseif string.find(line, "Connection refused") ~= nil then
						data["found"] = "refused"
					elseif string.find(line, "Transaction not permitted") ~= nil then
						data["found"] = "notpermit"
					elseif string.find(line, "Host is unreachable") ~= nil then
						data["found"] = "unreachable"
					elseif string.find(line, "incorrect server url") ~= nil then
						data["url"] = "incorrectURL"
					elseif string.find(line, "incorrect password") ~= nil then
						data["pw"] = "incorrectpwd"
					elseif string.find(line, "error while sending message") ~= nil then
						data["unsupport"] = "unsupported"
					end
				end
			end
			file:close()

			if data.found == "success" then
				res.status = "Certificate enrolled successfully!"
				res.color = "#008000"
			elseif data.found == "enrolled" then
				res.status = "Certificate is already Enrolled!"
				res.color = "#008000"
			elseif (data.found == "refused") and (data.url == "incorrectURL") then
				res.status = "Certificate enroll Failed! <br>Please check the server and make sure its running"
				res.color = "#FF0000"
			elseif (data.found == 'unreachable') or (data.url == 'incorrectURL') then
				res.status = "Certificate enroll Failed! <br>Given URL is unreachable"
				res.color = "#FF0000"
			elseif data.found == "notpermit" then
				res.status = "Certificate enroll Failed! <br>Please give a valid Password <br>If certificate enroll failed with valid URL and password, it means certificate was already enrolled to another device with the same subject name. <br>So please give unique subject name and try"
				res.color = "#FF0000"
			elseif data.url == "incorrectURL" then
				res.status = "Certificate enroll Failed! <br>Please check the URL"
				res.color = "#FF0000"
			elseif data.unsupport == "unsupported" then
				res.status = "Given Key type is not supported by the server"
				res.color = "#FF0000"
			end
			return { result = res }
		end
	},

	getScepRenewStatus = {
		call = function()
			local file;
			local res = {};
			file = io.open('/tmp/scepstatus', 'r');

			if file then
				for line in file:lines() do
					if string.find(line, "success") then
						res.status = "Certificate renewal successfully Done!"
						res.color = "#008000"
					elseif string.find(line, "notpermit") then
						res.status = "Certificate renewal Failed! \nServer may not be supported renewal"
						res.color = "#FF0000"
					elseif string.find(line, "failed") then
						res.status = "Certificate renewal Failed! \nNo certificate found to renewal. Please Enroll certificate"
						res.color = "#FF0000"
					end
				end
			end
			file:close()

			return { result = res }
		end
	},

	getScepDeleteStatus = {
		call = function()
			local sys = require "luci.sys"
			local res = luci.sys.exec("cat /tmp/scepstatus 2>/dev/null | xargs echo -n")

			return { result = res }
		end
	}
}

local function parseInput()
	local parse = json.new()
	local done, err

	while true do
		local chunk = io.read(4096)
		if not chunk then
			break
		elseif not done and not err then
			done, err = parse:parse(chunk)
		end
	end

	if not done then
		print(json.stringify({ error = err or "Incomplete input" }))
		os.exit(1)
	end

	return parse:get()
end

local function validateArgs(func, uargs)
	local method = methods[func]
	if not method then
		print(json.stringify({ error = "Method not found" }))
		os.exit(1)
	end

	if type(uargs) ~= "table" then
		print(json.stringify({ error = "Invalid arguments" }))
		os.exit(1)
	end

	uargs.ubus_rpc_session = nil

	local k, v
	local margs = method.args or {}
	for k, v in pairs(uargs) do
		if margs[k] == nil or
		   (v ~= nil and type(v) ~= type(margs[k]))
		then
			print(json.stringify({ error = "Invalid arguments" }))
			os.exit(1)
		end
	end

	return method
end

if arg[1] == "list" then
	local _, method, rv = nil, nil, {}
	for _, method in pairs(methods) do rv[_] = method.args or {} end
	print((json.stringify(rv):gsub(":%[%]", ":{}")))
elseif arg[1] == "call" then
	local args = parseInput()
	local method = validateArgs(arg[2], args)
	local result, code = method.call(args)
	print((json.stringify(result):gsub("^%[%]$", "{}")))
	os.exit(code or 0)
end
