Commit 2eb595db authored by Mika Havela's avatar Mika Havela

Status-info: Works and shows some information (not sure enabled/disabled should be there).

Config-tab: Only graphical layout is taking shape. No real data is shown. Data can't be changed.
Expert-tab: Works as it should (probably all done).

git-svn-id: svn://svn.alpinelinux.org/acf/fetchmail/trunk@687 ab2d0c66-481e-0410-8bed-d214d4d58bed
parent 1b659677
APP_NAME=fetchmail
PACKAGE=acf-$(APP_NAME)
VERSION=0.1
APP_DIST=\
fetchmail-controller.lua \
fetchmail-model.lua \
fetchmail-expert-html.lsp \
fetchmail-status-html.lsp \
fetchmail-config-html.lsp \
fetchmail.menu \
EXTRA_DIST=README Makefile config.mk
DISTFILES=$(APP_DIST) $(EXTRA_DIST)
TAR=tar
P=$(PACKAGE)-$(VERSION)
tarball=$(P).tar.bz2
install_dir=$(DESTDIR)/$(appdir)/$(APP_NAME)
all:
clean:
rm -rf $(tarball) $(P)
dist: $(tarball)
install:
mkdir -p "$(install_dir)"
cp -a $(APP_DIST) "$(install_dir)"
$(tarball): $(DISTFILES)
rm -rf $(P)
mkdir -p $(P)
cp $(DISTFILES) $(P)
$(TAR) -jcf $@ $(P)
rm -rf $(P)
# target that creates a tar package, unpacks is and install from package
dist-install: $(tarball)
$(TAR) -jxf $(tarball)
$(MAKE) -C $(P) install DESTDIR=$(DESTDIR)
rm -rf $(P)
include config.mk
.PHONY: all clean dist install dist-install
prefix=/usr
datadir=${prefix}/share
sysconfdir=${prefix}/etc
localstatedir=${prefix}/var
acfdir=${datadir}/acf
wwwdir=${acfdir}/www
cgibindir=${acfdir}/cgi-bin
appdir=${acfdir}/app
acflibdir=${acfdir}/lib
sessionsdir=${localstatedir}/lib/acf/sessions
<? local form = ... ?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
<?
function informationform(myform,tags)
io.write("<DL>")
for k,v in pairs(tags) do
if (myform[v]) then
local val = myform[v]
io.write("\t<DT")
if (#val.errtxt > 0) then io.write(" class='error'") end
io.write(">" .. val.label .. "</DT>\n")
io.write("\t\t<DD>" .. val.value .. "\n")
if (val.descr) and (#val.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>\n") end
if (#val.errtxt > 0) then io.write("\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>\n") end
io.write("\t\t</DD>\n")
end
end
io.write("</DL>")
end
?>
<?
function configform(myform,tags)
io.write("<DL>")
for k,v in pairs(tags) do
if (myform[v]) then
local val = myform[v]
io.write("\t<DT")
if (#val.errtxt > 0) then io.write(" class='error'") end
io.write(">" .. val.label .. "</DT>\n")
io.write("\t\t<DD>" .. html.form[val.type](val) .. "\n")
if (val.descr) and (#val.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>\n") end
if (#val.errtxt > 0) then io.write("\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>\n") end
io.write("\t\t</DD>\n")
end
end
io.write("</DL>")
end
?>
<H1>SYSTEM INFO</H1>
<?
local myform = form.status
local tags = { "status", "version", }
informationform(myform,tags)
?>
<H1>CONFIGURATION</H1>
<? local myform = form.config ?>
<form action="<?= form.option.script .. "/" .. form.option.prefix ..
form.option.controller .. "/" .. form.option.action ?>" method="POST">
<H2>GUIDED CONFIGURATION</H2>
<H3>FREQUENCY</H3>
<P>Select how often the mailboxes will be checked. For ETRN transfers (below) this specifies how often transfers are initiated</P>
<?
local tags = { "freq", }
configform(myform,tags)
?>
<H3>MAILBOXES</H3>
<P>In the boxes below, select up to 10 mailboxes to check for mail. You will need to specify the remote mailbox and password, as well as the local (internal) mailbox to forward the mail to. The SMTP host is the name or address of the SMTP server to send the mail to. For mail destined for the internal branch network, this should be <B>svcoutside</B> (the address of the outside interface of the services BSN component). This is then forwarded to the to the internal component of the BSN for sending on to the branch network.</P>
<P>For branches that use a POP3 account for the entire domain, selecting the <U>pop3domain</U> method will setup the appropriate configuration for retrieving and distributing the mail appropriately. The <B>domain</B> information should be your internet smtp domain. The <B>mailbox</B> field is ignored when this method is selected.</P>
<P>When selecting the <U>pop3</U> or <U>imap</U> methods, the <B>domain</B> field should be left blank.</P>
<? -- START - SPECIAL VIEW FOR SHOWING AVAILABLE MAILBOXES ?>
<?
local tags = "mailboxes"
local mailboxform = myform[tags]["value"]
?>
<DL>
<?
io.write("<CENTER><TABLE STYLE='width:90%;border:1px solid #ccc;background:#eee'><TR><TD CLASS='header' WIDTH='130px'>")
io.write("<CENTER>METHOD</CENTER></TD><TD CLASS='header' COLSPAN=2>")
io.write("<CENTER>REMOTE</CENTER></TD><TD CLASS='header' COLSPAN=2>")
io.write("<CENTER>LOCAL</CENTER></TD></TR>")
for i=1, table.maxn(mailboxform) do
leftpadd="30px"
rightpadd="5px"
io.write("<TR><TD>")
val = "method"
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD><TD style='padding-left:".. leftpadd .. ";padding-right:".. rightpadd .. ";' WIDTH='5%'>")
val = "remotehost"
io.write(mailboxform[i][val]["label"])
io.write(":</TD><TD>")
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD><TD style='padding-left:".. leftpadd .. ";padding-right:".. rightpadd .. ";' WIDTH='5%'>")
val = "localhost"
io.write(mailboxform[i][val]["label"])
io.write(":</TD><TD>")
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD></TR>")
io.write("<TR><TD>")
val = "disabled"
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write(" " .. mailboxform[i][val]["label"])
io.write("</TD><TD style='padding-left:".. leftpadd .. ";padding-right:".. rightpadd .. ";'>")
val = "remotemailbox"
io.write(mailboxform[i][val]["label"])
io.write(":</TD><TD>")
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD><TD style='padding-left:".. leftpadd .. ";padding-right:".. rightpadd .. ";'>")
val = "localmailbox"
io.write(mailboxform[i][val]["label"])
io.write(":</TD><TD>")
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD></TR>")
io.write("<TR><TD>")
io.write("</TD><TD style='padding-left:".. leftpadd .. ";padding-right:".. rightpadd .. ";'>")
val = "remotepassword"
io.write(mailboxform[i][val]["label"])
io.write(":</TD><TD>")
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD><TD style='padding-left:".. leftpadd .. ";padding-right:".. rightpadd .. ";'>")
val = "localdomain"
io.write(mailboxform[i][val]["label"])
io.write(":</TD><TD>")
io.write(html.form[mailboxform[i][val]["type"]](mailboxform[i][val]))
io.write("</TD></TR>")
io.write("<TR><TD COLSPAN=5><HR></TD></TR>")
end
io.write("</TABLE></CENTER>")
?>
<DL>
<? -- START - SPECIAL VIEW FOR SHOWING AVAILABLE MAILBOXES ?>
<H3>LAST RESORT</H3>
<P>The Postmaster address is the address of last resort when fetchmail cannot determine how to send a mail message. If left blank, undelieverable mail may be discarded.</P>
<?
local tags = { "postmaster", }
configform(myform,tags)
?>
<H3>ETRN</H3>
<P>This is for branches that have DNS mail domains hosted by an ISP that allows for ETRN dequeueing. ETRN dequeueing causes the SMTP mail exchanger at the ISP to forward mail to you via SMTP. You will need to make sure that DNS is setup appropriately and that your ISP supports ETRN. If you have not arranged with your ISP to have ETRN support, leave these fields blank.</P>
<?
local tags = { "etrnremote","etrnquedomain", }
configform(myform,tags)
?>
<? --[[ ?>
<H2>ADVANCED CONFIGURATION</H2>
<H3>GENERAL</H3>
<?
local tags = { "logfile", "loglevel", "smallerlogs", }
configform(myform,tags)
?>
<? --]] ?>
<H2>SAVE AND APPLY ABOVE SETTINGS</H2>
<?
local tags = { "cmdsave","cmdtest", }
configform(myform,tags)
?>
</form>
<?
local cmdform = form.management
local tags = { "start", "stop", "restart" }
if (cmdform) and (cmdform[tags[1]]) then
?>
<form name="management" action="" method="POST">
<H1>MANAGEMENT</H1>
<dl>
<dt><?= cmdform[tags[1]]["label"] ?></dt>
<dd>
<? for k,v in pairs(tags) do ?>
<? if (cmdform[v]) then ?>
<? io.write(html.form[cmdform[v].type](cmdform[v])) ?>
<? end ?>
<? end ?>
</dd>
<? if (form.cmdmanagement) and (#form.cmdmanagement.descr > 0) then ?>
<dt>Previous action result</dt>
<dd><pre><?= form.cmdmanagement.descr ?></pre></dd>
<? end ?>
</dl>
</form>
<? end ?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
module(..., package.seeall)
local list_redir = function (self)
self.conf.action = "status"
self.conf.type = "redir"
error (self.conf)
end
mvc = {}
mvc.on_load = function(self, parent)
if (self.worker[self.conf.action] == nil ) or ( self.conf.action == "init" ) then
self.worker[self.conf.action] = list_redir(self)
end
end
local function getstatus(self)
local status = self.model.getstatus()
if (#status.status.value > 0) then
status.status.value = "Enabled"
else
status.status.value = "Disabled"
end
return status
end
local function displaycmdsave(self)
-- Add a cmd button to the view
local cmdsave = cfe({ name="cmdsave",
label="Save/Apply above settings",
value="Save",
type="submit",
})
return cmdsave
end
local function displaycmdmanagement(disablestart,disablestop,disablerestart)
-- Add a management buttons
local management = {}
management.start = cfe({ name="cmdmanagement",
label="Program control-panel",
value="Start",
type="submit",
})
management.stop = cfe({ name="cmdmanagement",
label="Program control-panel",
value="Stop",
type="submit",
})
management.restart = cfe({ name="cmdmanagement",
label="Program control-panel",
value="Restart",
type="submit",
})
-- Disable management buttons based on if the process is running or not
if (disablestart) then management.start.disabled = "yes" end
if (disablestop) then management.stop.disabled = "yes" end
if (disablerestart) then management.restart.disabled = "yes" end
return management
end
function status(self)
return { status=getstatus(self) }
end
function config(self)
local cmdmanagement, cmdmanagementresult
local cmdsavereply = {}
local cmdsaveresult = {}
if ( self.clientdata.cmdmanagement) then
cmdmanagement = cfe({
name="cmdmanagement",
value=string.lower(self.clientdata.cmdmanagement),
})
cmdmanagementresult, cmdmanagement = self.model:startstop_service( cmdmanagement )
end
if ( self.clientdata.cmdsave) then
--[[
local variables="logfile loglevel smallerlogs maxsize numrotate localandnetworklog remotelogging" -- Advanced-config options
-- local variables="remotelogging" -- Guided-config options
for var in string.gmatch(variables, "%S+") do
-- Send nil instead of "" causes the parameter to be removed/deleted/empty/unset the variable in the config-file
if (self.clientdata[var] == "") then self.clientdata[var] = nil end
cmdsaveresult[var], cmdsavereply[var] = self.model:setconfigs( var,self.clientdata[var] )
end
--]]
end
local status = getstatus(self)
local config = self.model.getconfig()
-- Write out erros from previous cmdsave actions
for k,v in pairs(cmdsaveresult) do
if not (v) then
config[k]["errtxt"] = tostring(cmdsavereply[k]["errtxt"])
end
end
-- Display save button
config.cmdsave = displaycmdsave()
-- Add a test button to the view
config.cmdtest = cfe({ name="cmdtest",
label="Test saved settings",
value="Test",
type="submit",
})
-- FIXME: This is temporary disabling the buttons (until they work)
config.cmdsave["disabled"] = "yes"
config.cmdtest["disabled"] = "yes"
--[[
-- Management buttons
local disablestart,disablestop,disablerestart
-- Disable management buttons based on if the process is running or not
if (string.lower(status.status.value) == "enabled" ) then
disablestart = "yes"
else
disablestop = "yes"
end
-- Disable management buttons if there exist errors in the config
for k,v in pairs(config) do
if (config[k]["errtxt"] ~= "") then
disablestart = "yes"
disablestop = "yes"
disablerestart = "yes"
break
end
end
-- Display management buttons
local management = displaycmdmanagement(disablestart,disablestop,disablerestart)
--]]
return {
option={ script=ENV["SCRIPT_NAME"],
prefix=self.conf.prefix,
controller = self.conf.controller,
action = "config", },
status = status,
cmdmanagement = cmdmanagement,
management = management,
config = config,
debugclientdata = self.clientdata,
}
end
function expert(self)
local cmdmanagement, cmdmanagementresult
if ( self.clientdata.cmdmanagement) then
cmdmanagement = cfe({
name="cmdmanagement",
value=string.lower(self.clientdata.cmdmanagement),
})
cmdmanagementresult, cmdmanagement = self.model:startstop_service( cmdmanagement )
end
-- Save changes
local modifications = self.clientdata.filecontent or ""
if ( self.clientdata.cmdsave) then
modifications = self.model:update_filecontent(modifications)
end
local status = getstatus(self)
local config = self.model:get_filedetails()
-- Display save button
config.cmdsave = displaycmdsave()
--[[
-- Management buttons
local disablestart,disablestop,disablerestart
-- Disable management buttons based on if the process is running or not
if (string.lower(status.status.value) == "enabled" ) then
disablestart = "yes"
else
disablestop = "yes"
end
-- Disable management buttons if there exist errors in the config
for k,v in pairs(config) do
if (config[k]["errtxt"] ~= "") then
disablestart = "yes"
disablestop = "yes"
disablerestart = "yes"
break
end
end
-- Display management buttons
local management = displaycmdmanagement(disablestart,disablestop,disablerestart)
--]]
return {
option={ script=ENV["SCRIPT_NAME"],
prefix=self.conf.prefix,
controller = self.conf.controller,
action = "expert", },
cmdmanagement = cmdmanagement,
management = management,
config = config,
status = status,
startstop = startstop,
debugclientdata = self.clientdata,
}
end
<? local form = ... ?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
<?
function informationform(myform,tags)
io.write("<DL>")
for k,v in pairs(tags) do
if (myform[v]) then
local val = myform[v]
io.write("\t<DT")
if (#val.errtxt > 0) then io.write(" class='error'") end
io.write(">" .. val.label .. "</DT>\n")
io.write("\t\t<DD>" .. val.value .. "\n")
if (val.descr) and (#val.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>\n") end
if (#val.errtxt > 0) then io.write("\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>\n") end
io.write("\t\t</DD>\n")
end
end
io.write("</DL>")
end
?>
<?
function configform(myform,tags)
io.write("<DL>")
for k,v in pairs(tags) do
if (myform[v]) then
local val = myform[v]
io.write("\t<DT")
if (#val.errtxt > 0) then io.write(" class='error'") end
io.write(">" .. val.label .. "</DT>\n")
io.write("\t\t<DD>" .. html.form[val.type](val) .. "\n")
if (val.descr) and (#val.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>\n") end
if (#val.errtxt > 0) then io.write("\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>\n") end
io.write("\t\t</DD>\n")
end
end
io.write("</DL>")
end
?>
<H1>SYSTEM INFO</H1>
<?
local myform = form.status
local tags = { "status", "version", }
informationform(myform,tags)
?>
<H1>CONFIGURATION</H1>
<? local myform = form.config ?>
<form action="<?= form.option.script .. "/" .. form.option.prefix ..
form.option.controller .. "/" .. form.option.action ?>" method="POST">
<H2>EXPERT CONFIGURATION</H2>
<H3>FILE DETAILS</H3>
<?
local tags = { "filename", "filesize", "mtime", "sumerrors" }
informationform(myform,tags)
?>
<H3>FILE CONTENT</H3>
<?
io.write(html.form[form.config.filecontent.type](form.config.filecontent))
?>
<H2>SAVE AND APPLY ABOVE SETTINGS</H2>
<?
local tags = { "cmdsave", }
configform(myform,tags)
?>
</form>
<?
local cmdform = form.management
local tags = { "start", "stop", "restart" }
if (cmdform) and (cmdform[tags[1]]) then
?>
<form name="management" action="" method="POST">
<H1>MANAGEMENT</H1>
<dl>
<dt><?= cmdform[tags[1]]["label"] ?></dt>
<dd>
<? for k,v in pairs(tags) do ?>
<? if (cmdform[v]) then ?>
<? io.write(html.form[cmdform[v].type](cmdform[v])) ?>
<? end ?>
<? end ?>
</dd>
<? if (form.cmdmanagement) and (#form.cmdmanagement.descr > 0) then ?>
<dt>Previous action result</dt>
<dd><pre><?= form.cmdmanagement.descr ?></pre></dd>
<? end ?>
</dl>
</form>
<? end ?>
<?
--[[ DEBUG INFORMATION
io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>")
io.write(html.cfe_unpack(form))
io.write("</span>")
--]]
?>
module(..., package.seeall)
require("fs")
require("procps")
require("getopts")
require("format")
require("daemoncontrol")
require("validator")
local processname = "fetchmail"
local configfile = "/root/.fetchmailrc"
local config = {}
local function get_version()
local cmd = "/usr/bin/fetchmail --version 2>/dev/null"
local f = io.popen( cmd )
local cmd_output_result = f:read("*l")
f:close()
return cmd_output_result
end
local function getloglevels()
local loglevels = {}
for i=1,8 do
table.insert(loglevels,i)
end
return loglevels
end
local function getmethods()
local methods = {"pop3","imap","pop3domain", }
return methods
end
local function getmailboxes()
local mailboxes = {}
for i=1,2 do
local objects = cfe({})
objects.label = "Mailbox_" .. tostring(i)
objects.method = cfe({
name="method",
label = "Method",
type = "select",
value = "",
option = getmethods(),
})
objects.disabled = cfe({
name="disabled",
type="checkbox",
label = "Disabled",
checked = "yes",
})
objects.remotehost = cfe({
name="remotehost",
label = "RemoteHost",
value = "xxx_RemoteHost",
})
objects.remotemailbox = cfe({
name="remotemailbox",
label = "Mailbox",
value = "xxx_RemoteMailbox",
})
objects.remotepassword = cfe({
name="remotepassword",
label = "Password",
type = "text",
value = "xxx_password",
})
objects.localhost = cfe({
name="localhost",
label = "LocalHost",
value = "xxx_LocalHost",
})
objects.localmailbox = cfe({
name="localmailbox",
label = "LocalMailbox",
value = "xxx_LocalMailbox",
})
objects.localdomain = cfe({
name="localdomain",
label = "LocalDomain",
value = "xxx_LocalDomain",
})
table.insert(mailboxes, objects)
end
return mailboxes
end
-- ################################################################################
-- PUBLIC FUNCTIONS
-- action should be a CFE
function startstop_service ( self, action )
local cmd = action.value
local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, cmd)
action.descr=cmdmessage
action.errtxt=cmderror
-- Reporting back (true|false, the original acition)
return cmdresult,action
end
function getstatus()
local opts = getconfig()
local status = {}
status.version = cfe({ name = "version",
label="Program version",
value=get_version(),
})
status.status = cfe({ name="status",
label="Program status",
value=procps.pidof(processname),
})
status.configfile = cfe({ name="configfile",
label="Config file",
value=configfile,
})
--[[
if (opts["remotelogging"]) and not ((opts["remotelogging"]["value"] ~= "") and not (opts["localandnetworklog"]["value"])) then
status.logfile = cfe({ name="logfile",
label="Locally logging to",
value=opts["logfile"]["value"],
})
end
if (opts["SYSLOGD_OPTS"]) and (opts["SYSLOGD_OPTS"]["-R"]) and (opts["SYSLOGD_OPTS"]["-R"] ~= "") then
status.remote = cfe({ name="remotelogging",
label="Remote logging to",
value=opts["SYSLOGD_OPTS"]["-R"],
})
end
--]]
return status
end
function get_filedetails()
local path = configfile
local file = {}
local filedetails = {}
local config = {}
local filenameerrtxt
if (fs.is_file(path)) then
configcontent = getopts.getoptsfromfile(path) or config
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({