summaryrefslogtreecommitdiffstats
path: root/postfix-model.lua
blob: 06436e51c8bfdae6e376665831793b59d1a406ed (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
local mymodule = {}

-- Load libraries
modelfunctions = require("modelfunctions")
posix = require("posix")
fs = require("acf.fs")
format = require("acf.format")
validator = require("acf.validator")

-- Set variables
local processname = "postfix"
local packagename = "postfix"
local baseurl = "/etc/postfix/"
local aliasesfile = "/etc/postfix/aliases"

-- ################################################################################
-- LOCAL FUNCTIONS

local getconfig = function()
	-- the postfix config is like an ini file, but it allows multi-line entries
	-- so, we convert and then parse like ini file
	local content = fs.read_file(baseurl.."main.cf") or ""
	-- lines that begin with whitespace and first non-whitespace character is not '#'
	-- are continuations, so delete the carriage return
	-- have to delete blank and comment lines first, because could be before continuation line
	-- I've seen no documentation on inline comments, so user beware
	content = string.gsub(content, "\n+", "\n")
	content = string.gsub(content, "\n%s*#[^\n]*", "")
	content = string.gsub(content, "\n[^%S\n]+([^#])", " %1")

	return format.parse_ini_file(content, "") or {}, content
end

-- ################################################################################
-- PUBLIC FUNCTIONS

function mymodule.get_startstop(self, clientdata)       
        return modelfunctions.get_startstop(processname)
end

function mymodule.startstop_service(self, startstop, action)        
        return modelfunctions.startstop_service(startstop, action)
end

function mymodule.getstatus()
	return modelfunctions.getstatus(processname, packagename, "Postfix Status")
end

function mymodule.getstatusdetails()
	return cfe({ type="longtext", value="", label="Postfix Status Details" })
end

local function geteditablefilelist()
	local listed_files = fs.find_files_as_array("[^%.].*", baseurl)
	-- remove .db files
	local result = {}
	for i,name in ipairs(listed_files) do
		if not string.find(name, "%.db$") then
			result[#result+1] = name
		end
	end
	return result
end

function mymodule.getfilelist()
	local listed_files = {}

	for i,name in ipairs(geteditablefilelist()) do
		local filedetails = fs.stat(name) or {}
		table.insert ( listed_files , {filename=name, mtime=filedetails.mtime or "---", filesize=filedetails.size or "0"} )
	end

	table.sort(listed_files, function (a,b) return (a.filename < b.filename) end )

	return cfe({ type="list", value=listed_files, label="Postfix File List" })
end

function mymodule.getfiledetails(filename)
	return modelfunctions.getfiledetails(filename, geteditablefilelist())
end

function mymodule.updatefiledetails(self, filedetails)
	return modelfunctions.setfiledetails(self, filedetails, geteditablefilelist())
end

function mymodule.getnewfile()
	local options = {}
	options.filename = cfe({ label="File Name" })
	return cfe({ type="group", value=options, label="New File" })
end

function mymodule.createfile(self, newfile)
	newfile.errtxt = "Failed to create file"
	local path = string.match(newfile.value.filename.value, "^%s*(.*%S)%s*$") or ""
	if not string.find(path, "/") then
		path = baseurl..path
	end
	if validator.is_valid_filename(path, baseurl) then
		if posix.stat(path) then
			newfile.value.filename.errtxt = "File already exists"
		elseif string.find(path, "%.db$") then
			newfile.value.filename.errtxt = "Cannot create .db files"
		else
			fs.create_file(path)
			newfile.errtxt = nil
		end
	else
		newfile.value.filename.errtxt = "Invalid filename"
	end

	return newfile
end

function mymodule.getdeletefile(self, clientdata)
	local retval = {}
	retval.filename = cfe({ value=clientdata.filename or "", label="File Name" })
	return cfe({ type="group", value=retval, label="Delete File" })
end

function mymodule.deletefile(self, delfile)
	local filename = delfile.value.filename.value
	delfile.errtxt = "Failed to delete file"
	if not validator.is_valid_filename(filename, baseurl) then
		delfile.value.filename.errtxt = "Not a valid filename!"
	elseif not fs.is_file(filename) then
		delfile.value.filename.errtxt = "File doesn't exist!"
	else
		os.remove(filename)
		delfile.errtxt = nil
	end
	return delfile
end

function mymodule.get_rebuild_databases()
	local retval = {}
	return cfe({ type="group", value=retval, label="Rebuild Databases" })
end

function mymodule.rebuild_databases(self, rebuild)
	local result = {"Rebuilding databases"}
	local errresult = false
	local cmd,f,cmdresult,errtxt
	-- parse main.cf looking for hash files
	local config, content = getconfig()
	for i,db in ipairs({"btree", "cdb", "dbm", "hash", "sdbm"}) do
		for filename in string.gmatch(content, "[%s=]("..db..":%S+)") do
			filename = string.gsub(filename, ",$", "")
			-- run postmap on file
			if filename and not string.find(filename, aliasesfile) then
				table.insert(result, "Running: postmap"..filename)
				cmdresult, errtxt = modelfunctions.run_executable({"postmap", filename}, true)
				if errtxt then
					errresult = true
					table.insert(result, errtxt)
				end
				table.insert(result, cmdresult)
			end
		end
	end
	-- finally, run newaliases
	table.insert(result, "Running: newaliases")
	cmdresult, errtxt = modelfunctions.run_executable({"newaliases"}, true)
	if errtxt then
		errresult = true
		table.insert(result, errtxt)
	end
	table.insert(result, cmdresult)

	if errresult then
		rebuild.errtxt = table.concat(result, "\n")
	else
		rebuild.descr = table.concat(result, "\n")
	end
	return rebuild
end

function mymodule.getmailqueue()
	local result, errtxt = modelfunctions.run_executable({"mailq"})
	return cfe({ type="longtext", value=result, label="Postfix Mail Queue", errtxt=errtxt })
end

function mymodule.getflushqueue()
	local retval = {}
	return cfe({ type="group", value=retval, label="Flush Queue" })
end

function mymodule.flushqueue(self, flush)
	flush.descr, flush.errtxt = modelfunctions.run_executable({"postqueue", "-f"})
	if not flush.errtxt and flush.descr == "" then flush.descr = "Queue Flushed" end
	return flush
end

return mymodule