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/mail/aliases" local path = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin " -- ################################################################################ -- LOCAL FUNCTIONS -- ################################################################################ -- PUBLIC FUNCTIONS function startstop_service(action) return modelfunctions.startstop_service(processname, action, {"start", "stop", "restart", "reload"}) end function getstatus() local status = modelfunctions.getstatus(processname, packagename, "Postfix Status") -- Enabled status is unique for postfix -- Look for pid file stored in queue_directory .. /pid/ local config = format.parse_ini_file(fs.read_file(baseurl.."main.cf") or "", "") or {} if config.queue_directory then local pidfiles = fs.find_files_as_array(".*\.pid", config.queue_directory.."/pid/") if pidfiles and pidfiles[1] then local file = pidfiles[1] -- check to see if there's a matching proc directory and that it was created slightly after the pid file -- this allows us to avoid the problem with proc numbers wrapping local tmp = string.match(fs.read_file(file) or "", "%d+") if tmp then local dir = "/proc/" .. tmp filetime = posix.stat(file, "ctime") dirtime = posix.stat(dir, "ctime") if dirtime and (tonumber(dirtime) - tonumber(filetime) < 100) then status.value.status.value = "Running" end end end end return 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) table.insert(listed_files, aliasesfile) return listed_files 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 = newfile.value.filename.value 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" 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 = format.parse_ini_file(fs.read_file("/etc/postfix/main.cf") or "", "") or {} for name,val in pairs(config) do -- run postmap on files local filename = string.match(val, "hash:(.*)") 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 -- 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