module(..., package.seeall) -- Load libraries require("modelfunctions") require("posix") require("fs") require("format") require("validator") -- Set variables local processname = "postfix" local packagename = "postfix" local baseurl = "/etc/postfix/" local aliasesfile = "/etc/postfix/aliases" local path = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin " -- ################################################################################ -- 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 startstop_service(action) return modelfunctions.startstop_service(processname, action, {"Start", "Stop", "Restart", "Reload"}) end function getstatus() return modelfunctions.getstatus(processname, packagename, "Postfix Status") end function 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 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 getfiledetails(filename) return modelfunctions.getfiledetails(filename, geteditablefilelist()) end function updatefiledetails(filedetails) return modelfunctions.setfiledetails(filedetails, geteditablefilelist()) end function getnewfile() local options = {} options.filename = cfe({ label="File Name" }) return cfe({ type="group", value=options, label="New File" }) end function createfile(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 deletefile(filename) local result = cfe({ value="Failed to delete file", label="Delete file result" }) if not validator.is_valid_filename(filename, baseurl) then result.errtxt = "Not a valid filename!" elseif not fs.is_file(filename) then result.errtxt = "File doesn't exist!" else os.remove(filename) result.value = "File Deleted" end return result end function rebuild_databases() local result = cfe({ value={"Rebuilding databases"}, label="Rebuild Databases result" }) table.insert(result.value, " See logfile for possible errors") local cmd,f,cmdresult -- 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 cmd = "postmap "..filename table.insert(result.value, "Running: "..cmd) f = io.popen(format.escapespecialcharacters(path..cmd)) table.insert(result.value, f:read("*a")) f:close() end end end -- finally, run newaliases cmd = "newaliases" table.insert(result.value, "Running: "..cmd) f = io.popen(format.escapespecialcharacters(path..cmd)) table.insert(result.value, f:read("*a")) f:close() result.value = table.concat(result.value, "\n") return result end