fetchmail-model.lua 9.09 KB
Newer Older
1 2
module(..., package.seeall)

Mika Havela's avatar
Mika Havela committed
3
-- Load libraries
4 5 6 7 8
require("fs")
require("procps")
require("format")
require("daemoncontrol")
require("validator")
Mika Havela's avatar
Mika Havela committed
9
require("processinfo")
10

Mika Havela's avatar
Mika Havela committed
11 12
-- Set variables
local packagename = "fetchmail"
13 14 15 16
local processname = "fetchmail"
local configfile = "/root/.fetchmailrc"
local config = {}

Mika Havela's avatar
Mika Havela committed
17 18
-- ################################################################################
-- LOCAL FUNCTIONS
19 20 21 22 23 24 25 26

local function getloglevels()
	local loglevels = {}
	for i=1,8 do
		table.insert(loglevels,i)
	end
	return loglevels
end
Mika Havela's avatar
Mika Havela committed
27

28 29 30 31 32
local function getmethods()
	local methods = {"pop3","imap","pop3domain", }
	return methods
end

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
local function getmailboxes(t)
	local objects = cfe({})
	objects.label = "Mailbox " .. tostring(t["RBOX"])
	objects.method = cfe({ 
		name="method",
		label = "Method",
		type = "select",
		value = t["METHOD"],
		option = getmethods(),
		})
	objects.disabled = cfe({ 
		name="disabled",
		type="checkbox",
		label = "Disabled",
		checked = t["DISABLED"],
		})
	objects.remotehost = cfe({ 
		name="remotehost",
		label = "RemoteHost",
		value = t["RHOST"],
		})
	objects.remotemailbox = cfe({ 
		name="remotemailbox",
		label = "Mailbox",
		value = t["RBOX"],
		})
	objects.remotepassword = cfe({ 
		name="remotepassword",
		label = "Password",
		type = "passwd",
		value = t["PASSWD"],
		})
	objects.localhost = cfe({ 
		name="localhost",
		label = "LocalHost",
		value = t["LHOST"],
		})
	objects.localmailbox = cfe({ 
		name="localmailbox",
		label = "LocalMailbox",
		value = t["LBOX"],
		})
	objects.localdomain = cfe({ 
		name="localdomain",
		label = "LocalDomain",
		value = t["DOMAIN"],
		})
	return objects
81 82
end

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
local function read_config()
--[[
imap/pop3 lines are:
1    2      3        4       5  6   7        8       9        10
poll <host> protocol <proto> no dns username <uname> password <passwd>
11 12             13       14         15 16      17
is <localmailbox> smtphost <desthost> no rewrite fetchall

pop3domain lines are:
1    2      3             4        5        6    7  8   9        10      11       12
poll <host> localdomainst <domain> protocol pop3 no dns username <uname> password <passwd>
13 14 15   16       17         18          19       20 21      22
to *  here smtphost <desthost> smtpaddress <domain> no rewrite fetchall

etrn is:
1    2      3        4    5          6
pool <host> protocol etrn smtpdomain <mydomain>
--]]
101
	local mailboxes = {}
102 103 104 105 106 107
	local configcontent_postmaster = {}
	local configcontent_etrn = {}
	local path = configfile
	local valid = nil
	configcontenttable = fs.read_file_as_array(path) or {}
	for k,v in pairs(configcontenttable) do
108
		if (string.match(v, "^%s*#Begin Fetchmail")) then valid=1 end
109
		if (valid) then
110
			-- 
111 112 113 114 115 116
			local DISABLED = string.match(v, "^%s*(#)")

			-- Set parameters for POP3 or IMAP
			local val = {RHOST=2, CHECK=9 ,METHOD=4, RBOX=8, PASSWD=10, LBOX=12, LHOST=14}
			local configcontent = {}
			configcontent[k] = {}
117
			configcontent[k]["DISABLED"] = DISABLED
118 119 120 121 122 123 124 125 126
			for kk,vv in pairs(val) do
				configcontent[k][kk] = tostring(string.match(v,"^%s*" .. string.rep("%S*%s*",vv-1) .. "(%S*)%s*"))
			end
			-- Remove quotes from passwords
			if (configcontent[k]["PASSWD"]) then
				configcontent[k]["PASSWD"] = string.match(configcontent[k]["PASSWD"], "^\"(.-)\"")
			end
			-- Check if row is valid config
			if (configcontent[k]["CHECK"]) and (string.lower(configcontent[k]["CHECK"]) == "password") then 
127
				table.insert(mailboxes,getmailboxes(configcontent[k])) 
128 129 130 131 132 133
			end

			-- Set parameters for POP3domain
			local val = {RHOST=2, METHOD=6, RBOX=10, CHECK=11, PASSWD=12, LHOST=17, DOMAIN=19,}
			local configcontent = {}
			configcontent[k] = {}
134
			configcontent[k]["DISABLED"] = DISABLED
135 136 137
			for kk,vv in pairs(val) do
				configcontent[k][kk] = tostring(string.match(v,"^%s*" .. string.rep("%S*%s*",vv-1) .. "(%S*)%s*"))
			end
138 139
			-- Display this config as Method=pop3domain (as the current options in the view)
			configcontent[k]["METHOD"] = "pop3domain"
140 141 142 143 144 145
			-- Remove quotes from passwords
			if (configcontent[k]["PASSWD"]) then
				configcontent[k]["PASSWD"] = string.match(configcontent[k]["PASSWD"], "^\"(.-)\"")
			end
			-- Check if row is valid config
			if (configcontent[k]["CHECK"]) and (string.lower(configcontent[k]["CHECK"]) == "password") then 
146
				table.insert(mailboxes,getmailboxes(configcontent[k])) 
147 148 149 150 151 152
			end

			-- Set parameters for etrn
			local val = {ETRNSMTPHOST=2, CHECK=4, ETRNDOMAIN=6}
			local configcontent = {}
			configcontent[k] = {}
153
			configcontent[k]["DISABLED"] = DISABLED
154 155 156 157 158 159 160 161 162 163 164 165
			for kk,vv in pairs(val) do
				configcontent[k][kk] = tostring(string.match(v,"^%s*" .. string.rep("%S*%s*",vv-1) .. "(%S*)%s*"))
			end
			-- Check if row is valid config
			if (configcontent[k]["CHECK"]) and (string.lower(configcontent[k]["CHECK"]) == "etrn") then 
				configcontent_etrn=configcontent[k]
			end

			-- Set parameters for postmaster
			local val = {CHECK=2, POSTMASTER=3}
			local configcontent = {}
			configcontent[k] = {}
166
			configcontent[k]["DISABLED"] = DISABLED
167 168 169 170 171 172 173 174 175
			for kk,vv in pairs(val) do
				configcontent[k][kk] = tostring(string.match(v,"^%s*" .. string.rep("%S*%s*",vv-1) .. "(%S*)%s*"))
			end
			-- Check if row is valid config
			if (configcontent[k]["CHECK"]) and (string.lower(configcontent[k]["CHECK"]) == "postmaster") then 
				configcontent_postmaster=configcontent[k]
			end

		end
176
		if (string.match(v, "^%s*#End Fetchmail")) then valid=nil end
177
	end
178 179
	-- Create one empty record so that user can add settings
	table.insert(mailboxes,getmailboxes({})) 
180
	return mailboxes,configcontent_postmaster,configcontent_etrn
181 182

end
Mika Havela's avatar
Mika Havela committed
183

Mika Havela's avatar
Mika Havela committed
184 185 186 187
local function process_status_text(procname)
	local t = procps.pidof(procname)
	if (t) and (#t > 0) then
		return "Enabled"
Mika Havela's avatar
Mika Havela committed
188
	else
Mika Havela's avatar
Mika Havela committed
189 190
		return "Disabled"
	end
Mika Havela's avatar
Mika Havela committed
191 192
end

193 194 195 196 197 198 199 200 201 202 203 204 205 206
-- ################################################################################
-- PUBLIC FUNCTIONS

function startstop_service ( self, action )
	local cmd = action.value
	local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, cmd)
	action.descr=cmdmessage
	action.errtxt=cmderror
	return cmdresult,action
end

function getstatus()
	local opts = getconfig()
	local status = {}
Mika Havela's avatar
Mika Havela committed
207

Mika Havela's avatar
Mika Havela committed
208
	local value, errtxt = processinfo.package_version(packagename)
209 210
	status.version = cfe({ name = "version",
		label="Program version",
Mika Havela's avatar
Mika Havela committed
211 212
		value=value,
		errtxt=errtxt,
213
		 })
Mika Havela's avatar
Mika Havela committed
214

215 216
	status.status = cfe({ name="status",
		label="Program status",
Mika Havela's avatar
Mika Havela committed
217
		value=process_status_text(processname),
218
		})
Mika Havela's avatar
Mika Havela committed
219

Mika Havela's avatar
Mika Havela committed
220
	local autostart_sequense, autostart_errtxt = processinfo.process_botsequence(processname)
Mika Havela's avatar
Mika Havela committed
221 222 223 224 225 226
	status.autostart = cfe({ name="autostart",
		label="Autostart sequence",
		value=autostart_sequense,
		errtxt=autostart_errtxt,
		})

Mika Havela's avatar
Mika Havela committed
227 228 229 230 231
	status.configfile = cfe({ name="configfile",
		label="Config file",
		value=configfile,
		})

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	return status
end

function get_filedetails()
	local path = configfile
	local file = {}
	local filedetails = {}
	local config = {}
	local filenameerrtxt
	if (fs.is_file(path)) then
		filedetails = fs.stat(path)
		config = getconfig(path)
	else
		config = {}
		config.filename = {}
		config["filename"]["errtxt"]="Config file '".. path .. "' is missing!"
	end

	file["filename"] = cfe({ 
		name="filename",
		label="File name",
		value=path,
		errtxt=filenameerrtxt
		})
	file["filesize"] = cfe({ 
		name="filesize",
		label="File size",
		value=filedetails.size or 0,
		})
	file["mtime"] = cfe({ 
		name="mtime",
		label="File date",
		value=filedetails.mtime or "---",
		})
	file["filecontent"] = cfe({ 
		type="longtext",
		name="filecontent",
		label="File content",
		value=fs.read_file(path),
		})

	-- Sum all errors into one cfe
	local sumerrors = ""
	for k,v in pairs(config) do
Mika Havela's avatar
Mika Havela committed
276
		if (config[k]) and (config[k]["errtxt"]) and (config[k]["errtxt"] ~= "") then	
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
			sumerrors = sumerrors .. config[k]["errtxt"] .. "\n"
		end
	end
	if (sumerrors ~= "") then
		file["sumerrors"] = cfe ({ 
			name="sumerrors",
			label = "Configuration errors",
			errtxt = string.match(sumerrors, "(.-)\n$"),
			})
	end

	return file
end
function getconfig()
	local config = {}
292
	local mailboxes,configcontent_postmaster,configcontent_etrn = read_config()
293
	if not (fs.is_file(configfile)) then
294 295 296
		config["configfile"] = "Config file '".. configfile .. "' is missing!"
	end
	
297 298 299 300 301 302 303
	config["debug"] = cfe({ 
		name="debug",
		label = "Debug info",
		type = "longtext",
		value = configcontent,
		})

304 305 306 307 308 309 310 311 312 313 314
	-- Next section selects which configurations we should show to the user
	config["freq"] = cfe({ 
		name="freq",
		label = "Check mail once every",
		type = "select",
		value = "123",
		option = {"15min", "hour","day",},
		})
	config["mailboxes"] = cfe({ 
		name="mailboxes",
		label = "Mailboxes",
315
		value = mailboxes,
316 317 318 319
		})
	config["postmaster"] = cfe({ 
		name="postmaster",
		label = "Postmaster",
320
		value = configcontent_postmaster["POSTMASTER"],
321 322 323 324
		})
	config["etrnremote"] = cfe({ 
		name="etrnremote",
		label = "Remote server",
325
		value = configcontent_etrn["ETRNSMTPHOST"],
326 327 328 329
		})
	config["etrnquedomain"] = cfe({ 
		name="etrnquedomain",
		label = "Queued domain",
330
		value = configcontent_etrn["ETRNDOMAIN"],
331 332 333 334 335 336 337 338 339 340 341 342
		})

	return config
end

-- modifications should be a CFE
function update_filecontent (self, modifications)
	local path = configfile
	local file_result,err = fs.write_file(path, format.dostounix(modifications))
	return file_result, err
end