summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile48
-rw-r--r--README0
-rw-r--r--config.mk10
-rw-r--r--fetchmail-config-html.lsp205
-rw-r--r--fetchmail-controller.lua207
-rw-r--r--fetchmail-expert-html.lsp113
-rw-r--r--fetchmail-model.lua353
-rw-r--r--fetchmail-status-html.lsp44
-rw-r--r--fetchmail.menu2
9 files changed, 982 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5aa1149
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,48 @@
+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
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..45f4d21
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,10 @@
+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
diff --git a/fetchmail-config-html.lsp b/fetchmail-config-html.lsp
new file mode 100644
index 0000000..9ae4af1
--- /dev/null
+++ b/fetchmail-config-html.lsp
@@ -0,0 +1,205 @@
+<? 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>")
+--]]
+?>
+
+
+
diff --git a/fetchmail-controller.lua b/fetchmail-controller.lua
new file mode 100644
index 0000000..cf30d9b
--- /dev/null
+++ b/fetchmail-controller.lua
@@ -0,0 +1,207 @@
+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
+
diff --git a/fetchmail-expert-html.lsp b/fetchmail-expert-html.lsp
new file mode 100644
index 0000000..0a36abb
--- /dev/null
+++ b/fetchmail-expert-html.lsp
@@ -0,0 +1,113 @@
+<? 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>")
+--]]
+?>
diff --git a/fetchmail-model.lua b/fetchmail-model.lua
new file mode 100644
index 0000000..2be471b
--- /dev/null
+++ b/fetchmail-model.lua
@@ -0,0 +1,353 @@
+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({
+ 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
+ if (config[k]["errtxt"] ~= "") then
+ 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 = {}
+ if (fs.is_file(configfile)) then
+ configcontent = getopts.getoptsfromfile(configfile) or config
+ else
+ config["configfile"] = "Config file '".. configfile .. "' is missing!"
+ end
+
+
+
+ -- 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",
+ value = getmailboxes(),
+ })
+ config["postmaster"] = cfe({
+ name="postmaster",
+ label = "Postmaster",
+ value = "xxx@xxx.xx",
+ })
+ config["etrnremote"] = cfe({
+ name="etrnremote",
+ label = "Remote server",
+ value = "xxx",
+ })
+ config["etrnquedomain"] = cfe({
+ name="etrnquedomain",
+ label = "Queued domain",
+ value = "xxx",
+ })
+
+--[[
+
+ -- Next section is to print errormessages when configs are wrong
+ if (configcontent["SYSLOGD_OPTS"]["-l"]) and
+ ((tonumber(configcontent["SYSLOGD_OPTS"]["-l"]) == nil) or (tonumber(configcontent["SYSLOGD_OPTS"]["-l"]) > 8)) then
+ config["loglevel"]["errtxt"] = "Log value is out of range!\nCurrent value in config is '" ..
+ configcontent["SYSLOGD_OPTS"]["-l"] ..
+ "' - This is invalid!\nPlease select one of the above and save your changes."
+ table.insert(config["loglevel"]["option"], tonumber(configcontent["SYSLOGD_OPTS"]["-l"]))
+ end
+
+ if (configcontent["SYSLOGD_OPTS"]["-L"] ~= nil) and ((configcontent["SYSLOGD_OPTS"]["-R"] == nil) or (configcontent["SYSLOGD_OPTS"]["-R"] == "")) then
+ config["localandnetworklog"]["errtxt"] = "Logging to local and network (-L) is not possible unless you define a host (-R) for remote logging or remove this option."
+ end
+
+ -- Sum all errors into one cfe
+ local sumerrors = ""
+ for k,v in pairs(config) do
+ if (config[k]["errtxt"] ~= "") then
+ sumerrors = sumerrors .. config[k]["errtxt"] .. "\n"
+ end
+ end
+ if (sumerrors ~= "") then
+ config["sumerrors"] = cfe ({
+ name="sumerrors",
+ label = "Configuration errors",
+ errtxt = sumerrors,
+ })
+ end
+
+--]]
+
+ return config
+end
+
+-- IMPORTANT! This function is a exception! It's not fed with CFE's
+-- Parameter should be one of the ones defined in the variable 'variabletranslator'.
+-- value should be whatever the new value should be.
+function setconfigs(self,parameter,value)
+ -- Set variables
+--[[
+ local variable = "SYSLOGD_OPTS"
+ local variabletranslator = ({
+ logfile = "-O",
+ loglevel = "-l",
+ smallerlogs = "-S",
+ maxsize = "-s",
+ numrotate = "-b",
+ localandnetworklog = "-L",
+ remotelogging = "-R",
+ })
+ cmdparameter = variabletranslator[parameter]
+
+ -- Report a error if someone tryes to use a invalid parameter
+ if not (cmdparameter) then
+ local availablevariables = ""
+ for k,v in pairs(variabletranslator) do
+ availablevariables = k .. ", " .. availablevariables
+ end
+ parameter = parameter or ""
+ return false, cfe({
+ name="syslog.model.setconfigs()",
+ errtxt="'" .. parameter .. "' is not a valid parameter!\nValid options are: " .. availablevariables,
+ })
+ end
+
+ --TODO: Validate so that user cant add values with '-' (could cause major breakage next time you do getopts)
+
+ -- This config-file only accepts one type of parameters (report error if someone uses wrong parameter)
+ if not (string.find(cmdparameter, "-%a$")) then
+ return false, cfe({
+ name="syslog.model.setconfigs()",
+ errtxt="Parameter must be formated '-a' (where a is one upper/lowercase letter [a-z])",
+ })
+ end
+
+ -- Validate userinput (if valid path/filename)
+ if (value) and (cmdparameter == "-O") then
+ local cmdresult, cmdmessage = validator.is_valid_filename(value, "/var/log" )
+ if not (cmdresult) then
+ return false, cfe({
+ name="syslog.model.setconfigs()",
+ errtxt=cmdmessage,
+ })
+ end
+ end
+
+ -- Validate userinput (Has the user entered a valid hostname and/or port)
+ if (value) and (cmdparameter == "-R") then
+ local hostport = format.string_to_table(value, ":")
+ local host = hostport[1]
+ local port = hostport[2]
+ if (port) and not (validator.is_port(port)) then
+ return false, cfe({
+ name="syslog.model.setconfigs.getopts.setoptsinfile()",
+ errtxt="You entered '" .. tostring(port) .. "' as port - This is not valid!",
+ })
+ end
+ end
+
+ -- Set/Unset checkbox variables
+ if (value) and ((cmdparameter == "-S") or (cmdparameter == "-L")) then value = "" end
+
+ local cmdresult, cmdmessage, cmderror = getopts.setoptsinfile(configfile,variable,cmdparameter,value)
+ if (cmderror) then
+ return false, cfe({
+ name="syslog.model.setconfigs.getopts.setoptsinfile()",
+ errtxt=cmderror,
+ })
+ end
+ return true, cfe({
+ name="syslog.model.setconfigs()",
+ value=cmdmessage,
+ })
+--]]
+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
+
diff --git a/fetchmail-status-html.lsp b/fetchmail-status-html.lsp
new file mode 100644
index 0000000..780abb3
--- /dev/null
+++ b/fetchmail-status-html.lsp
@@ -0,0 +1,44 @@
+<? local form = ... ?>
+
+<?
+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
+?>
+
+<H1>SYSTEM INFO</H1>
+<?
+local myform = form.status
+local tags = { "status", "version", }
+informationform(myform,tags)
+?>
+
+<H2>PROGRAM SPECIFIC OPTIONS/INFORMATION</H2>
+<?
+local myform = form.status
+local tags = { "configfile", }
+informationform(myform,tags)
+?>
+
+<?
+--[[ 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>")
+--]]
+?>
+
diff --git a/fetchmail.menu b/fetchmail.menu
new file mode 100644
index 0000000..a2caced
--- /dev/null
+++ b/fetchmail.menu
@@ -0,0 +1,2 @@
+#CAT GROUP/DESC TAB ACTION
+Networking 30Fetchmail status status