diff options
author | Ted Trask <ttrask01@yahoo.com> | 2008-06-18 20:07:55 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2008-06-18 20:07:55 +0000 |
commit | 151f597ce365349add8c21fff63902be0084645f (patch) | |
tree | fdfa505adeaea2d4bb0e8c604a0439b211016111 | |
parent | f0dcd211ed5fca855655d8b60b588b1d193e92fd (diff) | |
download | acf-tinydns-151f597ce365349add8c21fff63902be0084645f.tar.bz2 acf-tinydns-151f597ce365349add8c21fff63902be0084645f.tar.xz |
Rewrite of tinydns to simplify code and use new cfe model.
Added js to filter records.
git-svn-id: svn://svn.alpinelinux.org/acf/tinydns/trunk@1219 ab2d0c66-481e-0410-8bed-d214d4d58bed
-rw-r--r-- | tinydns-basicstatus-html.lsp | 16 | ||||
-rwxr-xr-x | tinydns-config-html.lsp | 86 | ||||
-rw-r--r-- | tinydns-confirmaction-html.lsp | 20 | ||||
-rw-r--r-- | tinydns-controller.lua | 454 | ||||
-rw-r--r-- | tinydns-edit-html.lsp | 62 | ||||
-rw-r--r-- | tinydns-expert-html.lsp | 73 | ||||
-rw-r--r-- | tinydns-listfiles-html.lsp | 49 | ||||
-rw-r--r-- | tinydns-model.lua | 668 | ||||
-rw-r--r-- | tinydns-newfile-html.lsp | 17 | ||||
-rw-r--r-- | tinydns-startstop-html.lsp | 26 | ||||
-rw-r--r-- | tinydns-status-html.lsp | 183 | ||||
-rw-r--r-- | tinydns.menu | 4 | ||||
-rw-r--r-- | tinydns.roles | 4 |
13 files changed, 516 insertions, 1146 deletions
diff --git a/tinydns-basicstatus-html.lsp b/tinydns-basicstatus-html.lsp new file mode 100644 index 0000000..d0eae68 --- /dev/null +++ b/tinydns-basicstatus-html.lsp @@ -0,0 +1,16 @@ +<? local data = ... ?> +<? require("viewfunctions") ?> +<? --[[ +io.write(html.cfe_unpack(data)) +--]] ?> + +<H1>SYSTEM INFO</H1> +<DL> +<? +displayitem(data.value.status) +displayitem(data.value.version) +displayitem(data.value.autostart) +displayitem(data.value.configdir) +displayitem(data.value.listen) +?> +</DL> diff --git a/tinydns-config-html.lsp b/tinydns-config-html.lsp index 839570e..4c56ea3 100755 --- a/tinydns-config-html.lsp +++ b/tinydns-config-html.lsp @@ -1,4 +1,4 @@ -<? local form = ... +<? local form, viewlibrary = ... require("viewfunctions") ?> <? @@ -9,82 +9,16 @@ io.write("</span>") --]] ?> -<H1>SYSTEM INFO</H1> -<? -local myform = form.status -local tags = { "status", "version", "autostart", } -displayinfo(myform,tags,"viewonly") -?> - -<form name="cmd" action="<?= form.option.link ?>/<?= form.option.action ?>" method="POST"> -<H1>CONFIG</H1> -<H2>General settings</H2> -<? -local myform = form.config -local tags = { "listen","listen_cmd", } -displayinfo(myform,tags) -?> - -<H2>Locations</H2> -<? -local tags = { "locations","locations_cmd", "cmdnewlocations", } -displayinfo(myform,tags) -?> - - -<H2>Records</H2> -<H3><? io.write(tostring(form.config.nsourdomain.label) or "NS record") ?></H3> -<? -local tags = { "nsourdomain","nsourdomain_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.nsdomain.label) or "NS record") ?></H3> -<? -local tags = { "nsdomain","nsdomain_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.host.label) or "Hosts record") ?></H3> -<? -local tags = { "host","host_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.alias.label) or "Alias record") ?></H3> -<? -local tags = { "alias","alias_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.mx.label) or "MX record") ?></H3> -<? -local tags = { "mx","mx_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.ptr.label) or "PTR record") ?></H3> -<? -local tags = { "ptr","ptr_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.cname.label) or "CNAME record") ?></H3> -<? -local tags = { "cname","cname_cmd", } -displayinfo(myform,tags) -?> - -<H3><? io.write(tostring(form.config.soa.label) or "SOA record") ?></H3> -<? -local tags = { "soa","soa_cmd", } -displayinfo(myform,tags) -?> +<? if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("basicstatus") +end ?> -<H3><? io.write(tostring(form.config.generic.label) or "GENERIC record") ?></H3> +<h1>CONFIGURATION</h1> +<h2><?= form.label ?></h2> <? -local tags = { "generic","generic_cmd", } -displayinfo(myform,tags) + displayform(form) ?> -</form> +<? if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("startstop") +end ?> diff --git a/tinydns-confirmaction-html.lsp b/tinydns-confirmaction-html.lsp deleted file mode 100644 index 5303310..0000000 --- a/tinydns-confirmaction-html.lsp +++ /dev/null @@ -1,20 +0,0 @@ -<? local form = ... -require("viewfunctions") -?> -<? ---[[ 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>") ---]] -?> - - -<H1>Confirmation</H1> -<form name="myform" action="" method="POST"> -<DL> -<DT><? io.write(form.cmddelete.label or "") ?></DT> -<DD><? io.write(html.form[form.cmddelete.type](form.cmddelete)) ?> <? io.write(html.form[form.cancel.type](form.cancel)) ?> -<input type="hidden" value="<? io.write(form.name.value) ?>" name="name"> -</DD> -</form> diff --git a/tinydns-controller.lua b/tinydns-controller.lua index dc06911..b0f4272 100644 --- a/tinydns-controller.lua +++ b/tinydns-controller.lua @@ -1,405 +1,145 @@ module(..., package.seeall) --- Set variables -local newrecordtxt = "[New]" - -- ################################################################################ -- LOCAL FUNCTIONS -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 filtertable(t,limit,counter) - if not (counter) then counter = 0 end - counter = counter + 1 - - if (t) then - for k,v in pairs(t) do - if (counter > (limit + 2)) then - t[k] = nil - end - if (type(t[k]) == "table") then - filtertable(v,limit,counter) - end - end - end -end - -local function unpackoptions(t,array,descrfield) - for k,v in pairs(t) do - if not (v.option) then - if (type(v) == "table") then - unpackoptions(v,array,descrfield) - end - else - if (v.option[descrfield]) and (v.option[descrfield].value) then - table.insert(array, v.label .. " (" .. v.option[descrfield].value .. ")") - else - table.insert(array, v.label) - end - end - end -end - -local function unpackoptionstooriginal(t,array,filter) - for k,v in pairs(t) do - if not (v.option) then - if (type(v) == "table") then - unpackoptionstooriginal(v,array,filter) - end - else - if (v.orgrecordtable) and (v.orgrecordtable[2] == filter) then - table.insert(array, v.orgrecordtable) - end - end - end -end - -local function displaycmdmanagement(pidofstatus) - -- 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", - }) - -- next CFE can be used to present the result of the previous action - management.actionresult = cfe({ name="actionresult", - label="Previous action result", - }) - - -- Disable management buttons based on if the process is running or not - if (pidofstatus) then - management.start.disabled = "yes" - else - management.stop.disabled = "yes" - management.restart.disabled = "yes" - end - - return management -end - -- ################################################################################ -- PUBLIC FUNCTIONS default_action = "status" -function status(self) - local config = {} - config.settings = {} - local locations=self.model.getlocations(self) - local availablesigns = self.model.check_signs("prefix") - - config.locations = cfe ({ - name="locations", - label="Defining locations", - value=locations, - }) - - local prefix = "." - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.nsourdomain = cfe ({ - name="nsourdomain", - label=availablesigns[prefix], - value=domainoptions, - }) - end +function basicstatus(self) + return self.model.getstatus(self) +end - local prefix = "&" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.nsdomain = cfe ({ - name="nsdomain", - label=availablesigns[prefix], - value=domainoptions, - }) - end +function status(self) + return self.model.getconfigobjects(self) +end - local prefix = "=" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.host = cfe ({ - name="host", - label=availablesigns[prefix], - value=domainoptions, - }) +function startstop(self) + local result + if self.clientdata.action then + result = self.model:startstop_service(self.clientdata.action) + self.sessiondata.tinydnsstartstopresult = result + self.redirect_to_referrer(self) end - local prefix = "+" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.alias = cfe ({ - name="alias", - label=availablesigns[prefix], - value=domainoptions, - }) + local status = self.model.getstatus() + status = status.value.status + if self.sessiondata.tinydnsstartstopresult then + result = self.sessiondata.tinydnsstartstopresult + self.sessiondata.tinydnsstartstopresult = nil end - local prefix = "@" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.mx = cfe ({ - name="mx", - label=availablesigns[prefix], - value=domainoptions, - }) - end + return cfe({ type="group", value={status=status, result=result} }) +end - local prefix = "^" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.ptr = cfe ({ - name="ptr", - label=availablesigns[prefix], - value=domainoptions, - }) - end +function config(self) + local config = self.model.getconfig() - local prefix = "C" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.cname = cfe ({ - name="cname", - label=availablesigns[prefix], - value=domainoptions, - }) - end + if self.clientdata.Save then + for name,value in pairs(self.clientdata) do + if config.value[name] then + config.value[name].errtxt = nil + config.value[name].value = value + end + end - local prefix = "Z" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.soa = cfe ({ - name="soa", - label=availablesigns[prefix], - value=domainoptions, - }) + config = self.model.setconfig(config) + if not config.errtxt then + config.descr = "Configuration Set" + end end - local prefix = ":" - local domainoptions = self.model.getconfigobjects(self,prefix) - if (#domainoptions > 0) then - config.settings.generic = cfe ({ - name="generic", - label=availablesigns[prefix], - value=domainoptions, - }) - end ---[[ - -- This could be used for DEBUGGING - config.settings.all = cfe ({ - name="generic", - label="All available records", - value=self.model.getconfigobjects(self), - }) ---]] - local counter + config.type = "form" + config.option = "Save" + config.label = "Edit configuration" - return { - status=getstatus(self), - config=config, - } + return config end -function expert(self) - -- Start/Stop/Restart process - local cmdmanagement, actionresult - if ( self.clientdata.cmdmanagement) then - cmdmanagement = cfe({ - name="cmdmanagement", - label="Previous action result", - action=cfe({ - name="cmdmanagement", - value=string.lower(self.clientdata.cmdmanagement), -- This row contains start/stop/restart (one of these commands) - }), - }) - actionresult, cmdmanagement = self.model:startstop_service( cmdmanagement.action ) - end - - local configopts = self.model:getconfig() - -- Show buttons/fileds for creation of new confifiles - local create = {} - create.name = cfe ({ - name="name", - label="Name of the new configfile", - value=string.gsub(configopts.baseurl.value, "/$", "") .. "/", - }) - create.cmdnew = cfe ({ - name="cmdnew", - label="Create new file", - type="submit", - value="Create", - }) +function newfile(self) + local create = self.model.getnewconfigfile() + -- In case we are trying to create a new configfile - if (self.clientdata.cmdnew) then - if (self.clientdata.name) and - (#self.clientdata.name > 0) and not - (string.gsub(self.clientdata.name, "/$", "") == string.gsub(create.name.value, "/$", "")) then - local createcreated, createerrtxt = self.model:createconfigfile(self.clientdata.name) - if (createerrtxt) and (#createerrtxt > 0) then - create.name.errtxt = createerrtxt - create.name.value = self.clientdata.name + if (self.clientdata.Create) then + for name,value in pairs(self.clientdata) do + if create.value[name] then + create.value[name].errtxt = nil + create.value[name].value = value end - else - create.name.errtxt = "Incorrect filename" end - if not (create.name.errtxt) then - create.cmdnew.descr = "* File was created" - redirect(self, "edit?name=" .. (self.clientdata.name or "")) + + create = self.model.createconfigfile(create) + if not create.errtxt then + create.descr = "Created new config file" + redirect(self, "listfiles") end end - local status = getstatus(self) + create.type = "form" + create.option = "Create" + create.label = "Create new config file" - local configfiles = self.model:getfilelist() + return create +end + +function listfiles(self) + local configfiles = self.model.getfilelist() local config = {} - for k,v in pairs(configfiles) do - local filedetails = self.model:get_filedetails(v) + for k,v in pairs(configfiles.value) do + local filedetails = self.model.get_filedetails(v) table.insert(config,filedetails) end - -- Management buttons (Hide/show buttons - local pidofstatus - if (string.lower(status.status.value) == "enabled" ) then pidofstatus = true end - management = displaycmdmanagement(pidofstatus) - if (actionresult) then - management.actionresult.descr=cmdmanagement.descr - management.actionresult.errtxt=cmdmanagement.errtxt - end - if (status) and (status.version) and (#status.version.value == 0) then - management.start.disabled = "yes" - management.stop.disabled = "yes" - management.restart.disabled = "yes" - end - - return { - option={ script=self.conf.script, - prefix=self.conf.prefix, - controller = self.conf.controller, - action = "expert", - link = self.conf.script .. self.conf.prefix .. self.conf.controller, }, - management = management, - config = config, - status = status, - create = create, - startstop = startstop, - mhdebug = self.clientdata, - } - + return cfe({ type="list", value=config, label="Config files" }) end function edit(self) - - -- Save changes - if ( self.clientdata.cmdsave) then - local filetochange = cfe ({ name=self.clientdata.name, value=self.clientdata.filecontent, }) - modifications = self.model:updatefilecontent(filetochange) - end - - if not (self.model:valid_filename(self.clientdata.name)) then - redirect(self) - end - - local status = getstatus(self) - local file = self.model:get_filedetails(self.clientdata.name) - - - -- Add a cmd button to the view - file.cmdsave = cfe({ name="cmdsave", - label="Save/Apply above settings", - value="Save", - type="submit", - }) - file.cmddelete = cfe({ name="cmddelete", - label="Delete this configfile", - value="Delete", - type="submit", - }) - - if (self.clientdata.cmddelete) then - redirect(self, "confirmaction?action=delete&name=" .. (self.clientdata.name or "")) + local config = self.model.get_filedetails(self.clientdata.filename) + if self.clientdata.Save then + local result = self.model.updatefilecontent(self.clientdata.filename, self.clientdata.filecontent) + if not result.value then + config.value.filecontent.value = self.clientdata.filecontent + config.value.filecontent.errtxt = result.errtxt + config.errtxt = "Failed to save config!" + else + config = self.model.get_filedetails(self.clientdata.filename) + config.descr = "Saved file" + end end - if (modifications) then - file.cmdsave.descr="* Changes has been saved!" - end - - return { - option={ script=self.conf.script, - prefix=self.conf.prefix, - controller = self.conf.controller, - action = "edit", - extra = "", - link = self.conf.script .. self.conf.prefix .. self.conf.controller, }, - modifications = modifications, - file = file, - status = status, - startstop = startstop, - debugclientdata = self.clientdata, - } + config.type = "form" + config.option = "Save" + config.label = "Edit config file" + return config end -function confirmaction(self) - if (self.clientdata.cancel) then - redirect(self, "expert") - end - -- See to that only allowed files are modified - local fileexists, fileerrros = self.model:get_filedetails(self.clientdata.name) - if not (fileexists) then - redirect(self) +function expert(self) + local config = self.model.get_filedetails(self.clientdata.filename) + if self.clientdata.Save then + local result = self.model.updatefilecontent(self.clientdata.filename, self.clientdata.filecontent) + if not result.value then + config.value.filecontent.value = self.clientdata.filecontent + config.value.filecontent.errtxt = result.errtxt + config.errtxt = "Failed to save config!" + else + config = self.model.get_filedetails(self.clientdata.filename) + config.descr = "Saved file" + end end - local output = {} - output.cancel = cfe({ - name="cancel", - value="Cancel", - type="submit", - }) - output.cmddelete = cfe({ - name="cmddelete", - label="Are you sure you want to delete?", - value="Delete", - type="submit", - }) - output.name = cfe({ - name="name", - value=self.clientdata.name, - type="hidden", - }) + config.type = "form" + config.option = "Save" + config.label = "Edit config file" - output.mhdebug = cfe({ - name="mhdebug", - value=fileexists, - descr=self.clientdata, - errtxt=fileerrros, - }) - if (self.clientdata.cmddelete) then - local removesuccess, removeerrors = self.model:remove_file(self.clientdata.name) - if (removesuccess) then - redirect(self, "expert") - elseif (#removeerrors > 0) then - output.cmddelete.errtxt = removeerrors - end - end + return config +end - return output +function delete(self) + local cmdresult = self.model.remove_file(self.clientdata.filename) + --self.sessiondata.cmdresult = cmdresult + redirect_to_referrer(self) + return cmdresult end diff --git a/tinydns-edit-html.lsp b/tinydns-edit-html.lsp index ba9a696..93887dd 100644 --- a/tinydns-edit-html.lsp +++ b/tinydns-edit-html.lsp @@ -1,6 +1,5 @@ -<? local form = ... -require("viewfunctions") -?> +<? local form, viewlibrary = ... ?> +<? require("viewfunctions") ?> <? --[[ DEBUG INFORMATION io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>") @@ -9,50 +8,35 @@ io.write("</span>") --]] ?> -<H1>SYSTEM INFO</H1> -<DL> -<? -local myform = form.status -local tags = { "status", "version", "autostart", } -displayinfo(myform,tags,"viewonly") -?> -</DL> - -<form name="myform" action="" method="POST"> -<h1>CONFIGURATION</h1> -<H2>Expert config</H2> -<h3>File details</h3> +<H1>CONFIGURATION</H1> +<H2>EXPERT CONFIGURATION</H2> +<H3>FILE DETAILS</H3> <DL> <? -local myform = form.file -local tags = { "filename", "filesize", "mtime", "sumerrors", } -displayinfo(myform,tags,"viewonly") +displayitem(form.value.filename) +displayitem(form.value.filesize) +displayitem(form.value.mtime) ?> </DL> <H3>FILE CONTENT</H3> -<? -local myform = form.file -io.write('<input type="hidden" value="' .. myform.filename.value .. '" name="name">') -io.write(html.form[myform.filecontent.type](myform.filecontent)) -?> +<? if form.descr then ?><P CLASS='descr'><?= string.gsub(form.descr, "\n", "<BR>") ?></P><? end ?> +<? if form.errtxt then ?><P CLASS='error'><?= string.gsub(form.errtxt, "\n", "<BR>") ?></P><? end ?> +<form action="" method="POST"> +<input type="hidden" name="filename" value="<?= form.value.filename.value ?>"> +<textarea name="filecontent"> +<?= form.value.filecontent.value ?> +</textarea> +<? if form.value.filecontent.errtxt then ?><P CLASS='error'><?= string.gsub(form.value.filecontent.errtxt, "\n", "<BR>") ?></P><? end ?> <H2>SAVE AND APPLY ABOVE SETTINGS</H2> -<DL> -<? -local tags = { "cmddelete", "cmdsave", } -displayinfo(myform,tags) -?> -</DL> +<DL><DT>Save/Apply above settings</DT><DD><input class="submit" type="submit" name="<?= form.option ?>" value="Save"></DD></DL> +</form> <? --- Management buttons -local myform = form.management -local tags = { "start", "stop", "restart" } -if (myform) then - io.write("<H1>MANAGEMENT</H1>\n<DL>") - displaymanagement(myform,tags) - io.write("</DL>") -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>") +--]] ?> -</form> diff --git a/tinydns-expert-html.lsp b/tinydns-expert-html.lsp index 825267b..93887dd 100644 --- a/tinydns-expert-html.lsp +++ b/tinydns-expert-html.lsp @@ -1,6 +1,5 @@ -<? local form = ... -require("viewfunctions") -?> +<? local form, viewlibrary = ... ?> +<? require("viewfunctions") ?> <? --[[ DEBUG INFORMATION io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>") @@ -9,59 +8,35 @@ io.write("</span>") --]] ?> - -<H1>SYSTEM INFO</H1> +<H1>CONFIGURATION</H1> +<H2>EXPERT CONFIGURATION</H2> +<H3>FILE DETAILS</H3> <DL> <? -local myform = form.status -local tags = { "status", "version", "autostart", } -displayinfo(myform,tags,"viewonly") +displayitem(form.value.filename) +displayitem(form.value.filesize) +displayitem(form.value.mtime) ?> </DL> -<h1>CONFIGURATION</h1> -<h2>Expert config</h2> -<h3>Edit/View existing configfiles</h3> -<TABLE> - <TR style="background:#eee;font-weight:bold;"> - <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">File</TD> - <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Size</TD> - <TD style="white-space:nowrap;text-align:left;" class="header">Last Modified</TD> - </TR> -<? local myform = form.config ?> -<? for i = 1, table.maxn(myform) do ?> - <TR> - <TD style="padding-right:20px;white-space:nowrap;"><? io.write(html.link{value = "edit?name=" .. myform[i].filename.value , label=myform[i].filename.value }) ?></TD> - <TD style="padding-right:20px;white-space:nowrap;"><? io.write(myform[i].filesize.value or "--") ?></TD> - <TD style="white-space:nowrap;" width="90%"><? io.write(myform[i].mtime.value or "--") ?></TD> - </TR> -<? end ?> -</TABLE> +<H3>FILE CONTENT</H3> +<? if form.descr then ?><P CLASS='descr'><?= string.gsub(form.descr, "\n", "<BR>") ?></P><? end ?> +<? if form.errtxt then ?><P CLASS='error'><?= string.gsub(form.errtxt, "\n", "<BR>") ?></P><? end ?> +<form action="" method="POST"> +<input type="hidden" name="filename" value="<?= form.value.filename.value ?>"> +<textarea name="filecontent"> +<?= form.value.filecontent.value ?> +</textarea> +<? if form.value.filecontent.errtxt then ?><P CLASS='error'><?= string.gsub(form.value.filecontent.errtxt, "\n", "<BR>") ?></P><? end ?> -<h3>Create new configfile</h3> -<form action="<?= form.option.script .. "/" .. form.option.prefix .. - form.option.controller .. "/" .. form.option.action .. - (form.option.extra or "") ?>" method="POST"> -<DL> -<? -local myform = form.create -local tags = { "name", "cmdnew", } -displayinfo(myform,tags) -?> -</DL> +<H2>SAVE AND APPLY ABOVE SETTINGS</H2> +<DL><DT>Save/Apply above settings</DT><DD><input class="submit" type="submit" name="<?= form.option ?>" value="Save"></DD></DL> </form> -<form action="<?= form.option.script .. "/" .. form.option.prefix .. - form.option.controller .. "/" .. form.option.action .. - (form.option.extra or "") ?>" method="POST"> <? --- Management buttons -local myform = form.management -local tags = { "start", "stop", "restart" } -if (myform) then - io.write("<H1>MANAGEMENT</H1>\n<DL>") - displaymanagement(myform,tags) - io.write("</DL>") -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>") +--]] ?> -</form> diff --git a/tinydns-listfiles-html.lsp b/tinydns-listfiles-html.lsp new file mode 100644 index 0000000..f61ce25 --- /dev/null +++ b/tinydns-listfiles-html.lsp @@ -0,0 +1,49 @@ +<? local form, viewlibrary = ... +require("viewfunctions") +?> +<? +--[[ 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>") +--]] +?> + +<? if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("basicstatus") +end ?> + +<h1>CONFIGURATION</h1> +<h2>Edit/View existing config files</h2> +<TABLE> + <TR style="background:#eee;font-weight:bold;"> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD> + <TD style="padding-right:20px;white-space:nowrap;text-align:right;" class="header">Size</TD> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Last Modified</TD> + <TD style="white-space:nowrap;text-align:left;" class="header">File</TD> + </TR> +<? for i,file in ipairs(form.value) do ?> + <TR> + <TD style="padding-right:20px;white-space:nowrap;"> + <? io.write(html.link{value = "delete?filename=" .. file.value.filename.value, label="Delete " }) ?> + <? io.write(html.link{value = "edit?filename=" .. file.value.filename.value, label="Edit " }) ?> + <? io.write(html.link{value = "expert?filename=" .. file.value.filename.value, label="View " }) ?> + </TD> + <TD style="padding-right:20px;white-space:nowrap;text-align:right;"><?= file.value.filesize.value ?></TD> + <TD style="padding-right:20px;white-space:nowrap;"><?= file.value.mtime.value ?></TD> + <TD style="white-space:nowrap;" width="90%"><?= file.value.filename.value ?></TD> + </TR> +<? end ?> +</TABLE> + +<? if viewlibrary and viewlibrary.dispatch_component then + local newfileform = viewlibrary.dispatch_component("newfile", nil, true) ?> +<h2>Create new config file</h2> +<? + newfileform.action = "newfile" + displayform(newfileform) +end ?> + +<? if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("startstop") +end ?> diff --git a/tinydns-model.lua b/tinydns-model.lua index 1ace06f..fa0632f 100644 --- a/tinydns-model.lua +++ b/tinydns-model.lua @@ -10,23 +10,12 @@ require("daemoncontrol") require("validator") -- Set variables -local configdir -local datafile local configfiles = {} -local configitems = {} local packagename = "tinydns" local processname = "tinydns" local configfile = "/etc/conf.d/" .. processname -local baseurl = "/etc/tinydns" -local initdoptions = getopts.getoptsfromfile("/etc/init.d/" .. processname, "") -if (initdoptions) then - configdir = initdoptions.DATADIR - datafile = initdoptions.ROOT .. "/data" or "/var/cache/data" -else - configdir = "/etc/" .. processname - datafile = "/var/cache/data" -end -descr = { +local configdir = "/etc/"..processname +local descr = { prefix={ ['.']="Name server for your domain (NS + A + SOA)", ['&']="Deletegate subdomain (NS + A)", @@ -40,32 +29,20 @@ descr = { [':']="Generic record", ['%']="Client location", }, - reverse={ - ['nsourdomain']=".", - ['nsdomain']="&", - ['host']="=", - ['alias']="+", - ['mx']="@", - ['ptr']="^", - ['cname']="C", - ['soa']="Z", - [':']=":", - ['locations']="%", - }, fieldlabels={ - ['.']={"Prefix", "Domain", "IP address", "Name server", "Time to live", "Timestamp", "Location", }, - ['&']={"Prefix", "Domain", "IP address", "Name server", "Time to live", "Timestamp", "Location", }, - ['=']={"Prefix", "Host", "IP address", "Time to live", "Timestamp", "Location", }, - ['+']={"Prefix", "Alias", "IP address", "Time to live", "Timestamp", "Location", }, - ['@']={"Prefix", "Domain", "IP address", "Mail exchanger", "Distance", "Time to live", "Timestamp", "Location", }, - ['^']={"Prefix", "PTR", "Domain name", "Time to live", "Timestamp", "Location", }, - ['C']={"Prefix", "Domain name", "Canonical name", "Time to live", "Timestamp", "Location", }, - ['Z']={"Prefix", "Unknown", "Primary name server", "Contact address", "Serial number", "Refresh time", "Retry time", "Expire time", "Minimum time", "Time to live", "Timestamp", "Location",}, - [':']={"Prefix", }, - ['%']={"Prefix", }, + ['.']={"Domain", "IP address", "Name server", "Time to live", "Timestamp", "Location", }, + ['&']={"Domain", "IP address", "Name server", "Time to live", "Timestamp", "Location", }, + ['=']={"Host", "IP address", "Time to live", "Timestamp", "Location", }, + ['+']={"Alias", "IP address", "Time to live", "Timestamp", "Location", }, + ['@']={"Domain", "IP address", "Mail exchanger", "Distance", "Time to live", "Timestamp", "Location", }, + ['\'']={"Domain", "Text Record", "Time to live", "Timestamp", "Location", }, + ['^']={"PTR", "Domain name", "Time to live", "Timestamp", "Location", }, + ['C']={"Domain", "Canonical name", "Time to live", "Timestamp", "Location", }, + ['Z']={"Domain", "Primary name server", "Contact address", "Serial number", "Refresh time", "Retry time", "Expire time", "Minimum time", "Time to live", "Timestamp", "Location",}, + [':']={"Domain", "Record type", "Record data", "Time to live", "Timestamp", "Location", }, + ['%']={"Location", "IP prefix", }, }, } ---configdir = "hidden for the moment - This row is here only for debug purpose" -- ################################################################################ -- LOCAL FUNCTIONS @@ -110,9 +87,9 @@ end local function split_config_items(orgitem) local delimiter = ":" local output = {} - output = format.string_to_table(string.sub(orgitem,1,1) .. ":" .. string.sub(orgitem,2),delimiter) - output.type = descr['prefix'] - output.type = output.type[string.sub(orgitem,1,1)] or "unknown" + output = format.string_to_table(string.sub(orgitem,2),delimiter) + output.type = string.sub(orgitem,1,1) + output.label = descr['prefix'][output.type] or "unknown" return output end @@ -129,68 +106,8 @@ local function searchforconfigfiles() end searchforconfigfiles() --- Create table with doman levels -local function recursedomains(t,array,maxn,currnum) - if not (currnum) then currnum = maxn + 1 end - currnum = currnum - 1 - if not (currnum == 0) then - - if not (array[t[currnum]]) then - array[t[currnum]] = {} - end - recursedomains(t,array[t[currnum]],maxn,currnum) - end - - -- FIXME: This is a /really uggly/ hack to return the current table - -- If it's fixed nicely... it would be wonderful! - if (array[t[maxn]]) and - (array[t[maxn]][t[maxn-1]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]][t[maxn-5]]) then - return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]][t[maxn-5]] - end - - if (array[t[maxn]]) and - (array[t[maxn]][t[maxn-1]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]]) then - return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]][t[maxn-4]] - end - - if (array[t[maxn]]) and - (array[t[maxn]][t[maxn-1]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) then - return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]] - end - - if (array[t[maxn]]) and - (array[t[maxn]][t[maxn-1]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]]) then - return array[t[maxn]][t[maxn-1]][t[maxn-2]][t[maxn-3]] - end - - if (array[t[maxn]]) and - (array[t[maxn]][t[maxn-1]]) and - (array[t[maxn]][t[maxn-1]][t[maxn-2]]) then - return array[t[maxn]][t[maxn-1]][t[maxn-2]] - end - - if (array[t[maxn]]) and (array[t[maxn]][t[maxn-1]]) then - return array[t[maxn]][t[maxn-1]] - end - - if (array[t[maxn]]) then - return array[t[maxn]] - end -end - local function validfilename(path) - for k,v in pairs(getfilelist()) do + for k,v in pairs(getfilelist().value) do if (v == path) then return true end @@ -198,76 +115,13 @@ local function validfilename(path) return false, "Not a valid filename!" end --- Example taken from PIL --- Sort by Keys -local function pairsByKeys(t,f) - local a = {} - - for n in pairs(t) do - -- This is to fix some bug when next table is indexnumber instead of name - if (tonumber(n) == nil) then - a[#a + 1] = n - end - end - table.sort(a,f) - local i = 0 -- iterator variable - return function () --iterator function - i = i + 1 - return a[i], t[a[i]] - end -end - -local function rebuild_table(t,domains_rebuilt) - if not (type(t) == "string") then - for k,v in pairs(t) do - if (tonumber(k)) then - table.insert(domains_rebuilt, v) - else - table.insert(domains_rebuilt, {label=k}) - rebuild_table(v,domains_rebuilt[#domains_rebuilt]) - end - end - table.sort(domains_rebuilt, function(a,b) return (a.label < b.label) end) - end -end - --- This function removes all records that doesn't have the filter-value -local function filter_table(t1,domains_filtered,filter) - if not (type(t1) == "string") then - for k1,v1 in pairs(t1) do - for k2,v2 in pairs(v1) do - if (v2.label) then - if ( string.find(filter,v2.label) ) then - table.insert(domains_filtered, v2) - end - end - end - end - end -end - -- ################################################################################ -- 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 valid_filename(self,path) - return validfilename(path) -end - --- This function could be used to check that valid parameters are used in different places -function check_signs(sign) - local output - if (sign) and (descr[sign]) then - output = descr[sign] - end - return output + -- action is validated in daemoncontrol + local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, action) + return cfe({ type="boolean", value=cmdresult, descr=cmdmessage, errtxt=cmderror, label="Start/Stop result" }) end -- Present some general status @@ -275,460 +129,232 @@ function getstatus() local status = {} local value, errtxt = processinfo.package_version(packagename) - status.version = cfe({ name = "version", + status.version = cfe({ label="Program version", value=value, errtxt=errtxt, }) - status.status = cfe({ name="status", + status.status = cfe({ label="Program status", value=procps.pidof(processname), }) + if (#status.status.value > 0) then + status.status.value = "Enabled" + else + status.status.value = "Disabled" + end - status.configdir = cfe({ name="configdir", + status.configdir = cfe({ label="Config directory", value=configdir, }) - status.configfiles = cfe({ name="configfiles", + status.configfiles = cfe({ + type="list", label="Config files", value=configfiles, }) local autostart_sequense, autostart_errtxt = processinfo.process_botsequence(processname) - status.autostart = cfe({ name="autostart", + status.autostart = cfe({ label="Autostart sequence", value=autostart_sequense, errtxt=autostart_errtxt, }) - return status -end - + local config = getconfig() + status.listen = config.value.listen --- Return config-information -function getlocations(self,filter_type) - local config = {} - local configobjects = {} - local locations = {} - - -- Loop through all available configfiles - for k,v in pairs(configfiles) do - local filecontent, fileresult - fileresult, filecontent = get_value_from_file(v) - for kk,vv in pairs(filecontent) do - local domaindetails = {} - local filecontent_table = split_config_items(vv) - - -- This is mostly for debugging - -- This table contains all available configs - table.insert(configobjects, cfe({ - name=vv, - value=vv, - option=filecontent_table, - })) - - -- Create a table with location items - -- Containing all objects that start with % - if (filecontent_table[1] == "%") then - if not (locations[filecontent_table[2]]) then - locations[filecontent_table[2]] = {} - end - table.insert(locations[filecontent_table[2]], filecontent_table[3]) - end - end - end - - return locations + return cfe({ type="group", value=status, label="DNS Status" }) end -function getconfig(self,filter_type) +function getconfig() local config = {} - local listenaddr = getopts.getoptsfromfile(configfile,"","IP") or "" - - config.listen = cfe({ - name = "listen", + local listenaddr = getopts.getoptsfromfile(configfile,"","IP") or "" + config.listen = cfe({ label="IP address to listen on", value=listenaddr, }) + local test, errtxt = validator.is_ipv4(config.listen.value) + if not test then + config.listen.errtxt = errtxt + end - config.baseurl = cfe({ - name = "baseurl", - label="Baseurl for configfiles", - value=baseurl, - }) + return cfe({ type="group", value=config, label="TinyDNS Configuration" }) +end - return config +function setconfig(conf) + local test, errtxt = validator.is_ipv4(conf.value.listen.value) + if not test then + conf.value.listen.errtxt = errtxt + conf.errtxt = "Failed to set configuration" + else + getopts.setoptsinfile(configfile,"","IP",conf.value.listen.value) + end + + return conf end -- If you enter 'filter_type' (this should be one of the options found in local function check_signs() ) then -- the output will be filtered to only contain this type of data. -function getconfigobjects(self,filter_type, filter_levels) - local domains = {} - +function getconfigobjects(self, filter_type) + local configobjects = {} --Loop through all available configfiles - for k,v in pairs(configfiles) do + for i,filename in pairs(configfiles) do local filecontent, fileresult - fileresult, filecontent = get_value_from_file(v) - for kk,vv in pairs(filecontent) do + fileresult, filecontent = get_value_from_file(filename) + for j,configline in pairs(filecontent) do local domaindetails = {} - local filecontent_table = split_config_items(vv) - filecontent_table["orgrecord"] = vv - - -- Create domain information tables - local domain + local filecontent_table = split_config_items(configline) + filecontent_table.configline = configline - -- * START * COMMONT SETTINGS **************************************** - local descr=descr['prefix'] -- Use only configs that has a valid prefix - -- We filter away location-definitions -- If function is called with some filter options... then show only the filtered values - if ( not (filter_type) or - ( (filter_type) and (filter_type == filecontent_table[1]))) and - (descr[filecontent_table[1]]) and not - (filecontent_table[1] == "%") then - - domain = format.string_to_table(filecontent_table[2], "%.") - -- We rebuild the table and add previous level-information to the current level - for i = table.maxn(domain),2,-1 do - domain[i-1] = domain[i-1] .. "." .. domain[i] - end - - local domainoptions = {} - -- Add details to the previous object - table.insert(domainoptions, cfe ({ - name="type", - label="Type", - value=descr[filecontent_table[1]], - })) - - -- Set values and labels for field #3 - local name = "ip" - local label = "IP address" - -- Some configs uses third column in some other way - if (filecontent_table[1] == "^") or (filecontent_table[1] == "C") then - name = "pointdomain" - label = "Domain" - end - if (filecontent_table[1] == "Z") then - name = "mname" - label = "Primary nameserver" - end - if (filecontent_table[1] == ":") then - name = "rectype" - label = "Type of record" - end - if (filecontent_table[3]) and (#filecontent_table[3]> 0) and (name) then - table.insert(domainoptions, cfe ({ - name=name, - label=label, - value=filecontent_table[3], - })) - end - - -- Set values and labels for field #4 - name = "ttl" - label = "Time to live" - -- Some configs uses third column in some other way - if (filecontent_table[1] == ".") or (filecontent_table[1] == "&") then - name = "ns" - label = "Name server" - end - if (filecontent_table[1] == "@") then - name = "mx" - label = "Mail exchanger" - end - if (filecontent_table[1] == "Z") then - name = "rname" - label = "Contact address" - end - if (filecontent_table[4]) and (#filecontent_table[4]> 0) and (name) then - table.insert(domainoptions, cfe ({ - name=name, - label=label, - value=filecontent_table[4], - })) + if ( not (filter_type) or ((filter_type) and (filter_type == filecontent_table.type)) ) + and (filecontent_table.label) + then + local entry = {} + for i,value in ipairs(filecontent_table) do + entry[i] = value end - - -- Set values and labels for field #5 - name = "timestamp" - label = "Time stamp" - -- Some configs uses third column in some other way - if (filecontent_table[1] == ".") or (filecontent_table[1] == "&") then - name = "ttl" - label = "Time to live" - end - if (filecontent_table[1] == "@") then - name = "dist" - label = "Distance" - end - if (filecontent_table[1] == "Z") then - name = "ser" - label = "Serial number" - end - if (filecontent_table[5]) and (#filecontent_table[5]> 0) and (name) then - table.insert(domainoptions, cfe ({ - name=name, - label=label, - value=filecontent_table[5], - })) - end - - -- Set values and labels for field #6 - name = "lo" - label = "Location" - -- Some configs uses third column in some other way - if (filecontent_table[1] == ".") or (filecontent_table[1] == "&") then - name = "timestamp" - label = "Time stamp" - end - if (filecontent_table[1] == "@") then - name = "ttl" - label = "Time to live" - end - if (filecontent_table[1] == "Z") then - name = "ref" - label = "Refresh time" + -- we're gonna add a reverse domain name to make it easier to sort + local domain = {} + for mt in string.gmatch(entry[1], "([^.]+)") do + table.insert(domain, mt) end - - if (filecontent_table[6]) and (#filecontent_table[6]> 0) and (name) then - table.insert(domainoptions, cfe ({ - name=name, - label=label, - value=filecontent_table[6], - })) - end - - -- Set values and labels for field #7 - local name = nil - local label = nil - -- Some configs uses third column in some other way - if (filecontent_table[1] == ".") or (filecontent_table[1] == "&") then - name = "lo" - label = "Location" - end - if (filecontent_table[1] == "@") then - name = "timestamp" - label = "Timestamp" - end - if (filecontent_table[1] == "Z") then - name = "ret" - label = "Retry time" - end - if (filecontent_table[7]) and (#filecontent_table[7]> 0) and (name) then - table.insert(domainoptions, cfe ({ - name=name, - label=label, - value=filecontent_table[7], - })) + local reversedomain = {} + for i=#domain,1,-1 do + table.insert(reversedomain, domain[i]) end + entry.sort = table.concat(reversedomain, ".") - -- Set values and labels for field #8 - local name = nil - local label = nil - -- Some configs uses third column in some other way - if (filecontent_table[1] == "@") then - name = "lo" - label = "Location" - end - if (filecontent_table[1] == "Z") then - name = "exp" - label = "Expire time" - end - if (filecontent_table[8]) and (#filecontent_table[8]> 0) and (name) then - table.insert(domainoptions, cfe ({ - name=name, - label=label, - value=filecontent_table[8], - })) + -- add it to the table + if not configobjects[filecontent_table.type] then + configobjects[filecontent_table.type] = {label=filecontent_table.label, fieldlabels=descr.fieldlabels[filecontent_table.type]} end - - -- Set values and labels for field #9-12 - if (filecontent_table[1] == "Z") then - if (filecontent_table[9]) and (#filecontent_table[9]> 0) then - table.insert(domainoptions, cfe ({ - name="min", - label="Minimum time", - value=filecontent_table[9], - })) - end - if (filecontent_table[10]) and (#filecontent_table[10]> 0) then - table.insert(domainoptions, cfe ({ - name="ttl", - label="Time to live", - value=filecontent_table[10], - })) - end - if (filecontent_table[11]) and (#filecontent_table[11]> 0) then - table.insert(domainoptions, cfe ({ - name="timestamp", - label="Time stamp", - value=filecontent_table[11], - })) - end - if (filecontent_table[12]) and (#filecontent_table[12]> 0) then - table.insert(domainoptions, cfe ({ - name="location", - label="Location", - value=filecontent_table[12], - })) - end - end - - - -- This is the main information on each object - domaindetails = cfe ({ - name=filecontent_table[2], - label=filecontent_table[2], - option=domainoptions, - orgrecordtable=filecontent_table, - }) - - end - -- * END * COMMONT SETTINGS ******************************************** - -- Inject the previous data into the right table - local value = filecontent_table[2] - local currenttable - if (type(domain) == "table") then - currenttable = recursedomains(domain, domains, table.maxn(domain)) + table.insert(configobjects[filecontent_table.type], entry) end + end + end ----[[ - if (domaindetails.value) then - table.insert (currenttable , domaindetails) + -- Sort each of the tables by domain name (entry 1) + for type,entries in pairs(configobjects) do + table.sort(entries, function(a,b) + if a == b then + return false; + elseif a.sort ~= b.sort then + return a.sort < b.sort end ---]] - + for i in ipairs(a) do + if a[i] ~= b[i] then + return a[i] < b[i] + end + end + a.errtxt = "Duplicate entry" + b.errtxt = "Duplicate entry" + return false + end) + for i,entry in ipairs(entries) do + entry.sort = nil end end - -- TODO: Sort the domains table! - -- Sorting is not possible when things is done as they are (se above) - -- problem comese when we use keynames instead of [1], [2], ... - -- Next we rebuild the domains table and do it so it can be sorted - local domains_sorted = {} - - local domains_rebuilt = {} - rebuild_table(domains,domains_rebuilt) - - -- Filter away not wanted records - local domains_filtered = {} --- local filter_level2 = "" -- < This is DEBUG!!! REMOVE WHEN DONE! --- filter_table(domains_rebuilt,domains_filtered,filter_level2) - domains_filtered = domains_rebuilt - - return domains_filtered + return configobjects end function getfilelist () local listed_files = {} - for k,v in pairs{baseurl} do - recursedir(v, listed_files) - end --- table.sort(listed_files, function (a,b) return (a.name < b.name) end ) + recursedir(configdir, listed_files) - return listed_files + return cfe({ type="list", value=listed_files, label="List of config files" }) end -function get_filedetails(self,path) - if not (validfilename(path)) then - return false, "Not a valid filename!" - end +function get_filedetails(path) local file = {} local filedetails = {} - local config = {} local filenameerrtxt if (path) and (fs.is_file(path)) then filedetails = fs.stat(path) - config = getconfig(path) else - config = {} - config.filename = {} - config["filename"]["errtxt"]="Config file '".. tostring(path) .. "' is missing!" + filenameerrtxt="Config file '".. tostring(path) .. "' is missing!" end - file["filename" .. (num or "")] = cfe({ - name="filename" .. (num or ""), + file["filename"] = cfe({ label="File name", value=path, errtxt=filenameerrtxt }) - file["filesize" .. (num or "")] = cfe({ - name="filesize" .. (num or ""), + file["filesize"] = cfe({ label="File size", - value=filedetails.size or 0, + value=filedetails.size or "0", }) - file["mtime" .. (num or "")] = cfe({ - name="mtime" .. (num or ""), + file["mtime"] = cfe({ label="File date", value=filedetails.mtime or "---", }) - file["filecontent" .. (num or "")] = cfe({ + file["filecontent"] = cfe({ type="longtext", - name="filecontent" .. (num or ""), 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]) and (config[k]["errtxt"]) and (config[k]["errtxt"] ~= "") then - sumerrors = sumerrors .. config[k]["errtxt"] .. "\n" - end - end - if (sumerrors ~= "") then - file["sumerrors" .. (num or "")] = cfe ({ - name="sumerrors" .. (num or ""), - label = "Configuration errors", - errtxt = string.match(sumerrors, "(.-)\n$"), - }) - end - - return file + return cfe({ type="group", value=file, label="Config file details" }) end -function updatefilecontent (self, filetochange) - local path = filetochange.name - local modifications = filetochange.value +function updatefilecontent (path, modifications) + local success = false + local errtxt if not (fs.is_file(path)) then - return false, "Not a filename" - end - if (validfilename(path)) then + errtxt = "Not a filename" + elseif (validfilename(path)) then fs.write_file(path, format.dostounix(modifications)) - return true + success = true else - return false, "Not a valid filename!" + errtxt = "Not a valid filename!" end - return false, "Something went wrong!" + + return cfe({ type="boolean", value=success, label="Update file result", errtxt=errtxt }) end -function createconfigfile (self, path) - local validfilepath, filepatherror = validator.is_valid_filename(path,baseurl) - if (fs.is_file(path)) then - return false,"File already exists" - end +function getnewconfigfile() + local options = {} + options.filename = cfe({ value=configdir.."/", label="File Name" }) + return cfe({ type="group", value=options, label="New config file" }) +end + +function createconfigfile(configfile) + configfile.errtxt = "Failed to create file" + local path = configfile.value.filename.value + local validfilepath, filepatherror = validator.is_valid_filename(path,configdir) if (validfilepath) then - fs.write_file(path, "") - return true,nil + if (fs.is_file(path)) then + configfile.value.filename.errtxt = "File already exists" + else + local file = io.open(path, "w") + file:close() + configfile.errtxt = nil + end else - return false, filepatherror + configfile.value.filename.errtxt = filepatherror end - return false, "Something went wrong!" + + return configfile end -function remove_file(self, path) + +function remove_file(path) + local success = false + local errtxt if not (fs.is_file(path)) then - return false,"File doesn't exist!" - end - if (validfilename(path)) then + errtxt = "File doesn't exist!" + elseif (validfilename(path)) then local cmd, errors = io.popen( "/bin/rm " .. path, r ) local cmdoutput = cmd:read("*a") cmd:close() - return true, cmdoutput + success = true else - return false, "Not a valid filename!" + errtxt = "Not a valid filename!" end - return false, "Something went wrong!" + return cfe({ type="boolean", value=success, label="Delete config file result", errtxt=errtxt }) end diff --git a/tinydns-newfile-html.lsp b/tinydns-newfile-html.lsp new file mode 100644 index 0000000..f727833 --- /dev/null +++ b/tinydns-newfile-html.lsp @@ -0,0 +1,17 @@ +<? local form, viewlibrary = ... +require("viewfunctions") +?> +<? +--[[ 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>") +--]] +?> + +<h1>CONFIGURATION</h1> +<h2><?= form.label ?></h2> +<? + form.action = "newfile" + displayform(form) +?> diff --git a/tinydns-startstop-html.lsp b/tinydns-startstop-html.lsp new file mode 100644 index 0000000..f3f7013 --- /dev/null +++ b/tinydns-startstop-html.lsp @@ -0,0 +1,26 @@ +<? local data = ... ?> +<? --[[ +io.write(html.cfe_unpack(data)) +--]] ?> + +<H1>MANAGEMENT</H1> +<DL> +<form action="startstop" method="POST"> +<DT>Program control-panel</DT> +<DD> +<input class="submit" type="submit" name="action" value="Start" <? if data.value.status.value== "Enabled" then io.write("disabled") end ?>> +<input class="submit" type="submit" name="action" value="Stop" <? if data.value.status.value== "Disabled" then io.write("disabled") end ?>> +<input class="submit" type="submit" name="action" value="Restart" <? if data.value.status.value== "Disabled" then io.write("disabled") end ?>> +</DD> +</form> + +<? if data.value.result then ?> +<DT>Previous action result</DT> +<DD> +<? if data.value.result.descr then ?> +<P CLASS='descr'><?= string.gsub(data.value.result.descr, "\n", "<BR>") ?></P> +<? end if data.value.result.errtxt then ?> +<P CLASS='error'><?= string.gsub(data.value.result.errtxt, "\n", "<BR>") ?></P> +<? end end ?> +</DD> +</DL> diff --git a/tinydns-status-html.lsp b/tinydns-status-html.lsp index 28c7ee2..c006939 100644 --- a/tinydns-status-html.lsp +++ b/tinydns-status-html.lsp @@ -1,100 +1,123 @@ -<? local form = ... +<? local view, viewlibrary = ... require("viewfunctions") ?> + +<script type="text/javascript" src="/js/jquery-latest.js"></script> +<script type="text/javascript"> + last_phrase = "" + $(function(){ + $("#filter").keyup(function(){ + var phrase = this.value; + if (phrase == last_phrase) return false; + last_phrase = phrase; + var elems = $("#records").find("li"); + elems.each(function(){ + var elem = this + if (elem.innerText.indexOf(phrase)>=0) { + jQuery(elem).show(); + } else { + jQuery(elem).hide(); + }; + }) + }) + $("#filter-list").submit(function(){ + return false; + }).focus(); + }); +</script> + <? --[[ DEBUG INFORMATION io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>") -io.write(html.cfe_unpack(form)) +io.write(html.cfe_unpack(view)) io.write("</span>") --]] ?> -<H1>SYSTEM INFO</H1> +<? if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("basicstatus") +end ?> + +<H1>PROGRAM SPECIFIC OPTIONS/INFORMATION</H1> +<H2>Locations</H2> <DL> <? -local myform = form.status -local tags = { "status", "version", "autostart", } -displayinfo(myform,tags,"viewonly") -?> +if (view) and (view['%']) then + local val = view['%'] ?> + <DT<? if (val.errtxt) then io.write(" class='error'") end ?>><?= val.label ?></DT> + + <DD> + <? local currentloc = "" + for i,loc in ipairs(val) do + if currentloc ~= loc[1] then ?> + <IMG SRC='/skins/static/tango/16x16/places/start-here.png' width='16' height='16' alt> <B><?= loc[1] ?></B> + <? end + currentloc = loc[1] ?> + <BR><SPAN STYLE='margin-left:30px;'><?= loc[2] ?></SPAN><BR> + <? if (loc.errtxt) then ?><P CLASS='error'><?= string.gsub(loc.errtxt, "\n", "<BR>") ?></P><? end ?> + <? end ?> + </DD> +<? end ?> </DL> <? -local myform = form.config.locations -?> -<H2>PROGRAM SPECIFIC OPTIONS/INFORMATION</H2> -<H3>Locations</H3> -<? -io.write("<DL>") -if (myform) and (myform.value) then - local val = myform - io.write("\n\t<DT") - if (val.errtxt) then - io.write(" class='error'") +local function doListIndents(next, indent) + local newentry = {} + for mt in string.gmatch(next, "([^.]+)") do + table.insert(newentry, mt) end - io.write(">" .. val.label .. "</DT>") - - io.write("\n\t\t<DD>") - for k,v in pairs(myform.value) do - io.write("<IMG SRC='/skins/static/tango/16x16/places/start-here.png' width='16' height='16' alt> <B>" .. tostring(k) .. "</B>") - for kk,vv in pairs(v) do - io.write(tostring("<BR><SPAN STYLE='margin-left:30px;'>" .. vv .. "</SPAN>\n")) - end - io.write("<BR>") + local revnewentry = {} + for j=#newentry,1,-1 do + table.insert(revnewentry, newentry[j]) end - - if (val.descr) and (#val.descr > 0) then io.write("\n\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>") end - if (val.errtxt) then io.write("\n\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>") end - io.write("\n\t\t</DD>") -end -io.write("</DL>") -?> - -<? -local function recurseoutput(table,cnt) - if not (cnt) then cnt=0 end - cnt = cnt + 1 - for k,v in pairs(table or {}) do - if (table[k].label) then - if not (tonumber(k)) or (v.value) then --- if v.label then - io.write("\n\t\t\t<IMG SRC='/skins/static/tango/16x16/devices/computer.png' width='16' height='16' alt STYLE='margin-left:"..cnt.. - "0px'><SPAN STYLE=''> " .. tostring(v.label) .. "</SPAN><BR>") - io.write("\n\t\t\t<TABLE STYLE='margin-left:90px;'>") - for k1,v1 in pairs(v.option) do - if (v1.label) then - io.write("\n\t\t\t\t<TR>\n\t\t\t\t\t<TD WIDTH='160px' STYLE='border:none;'>".. tostring(v1.label) .. - ":</TD>\n\t\t\t\t\t<TD STYLE='border:none;'>".. tostring(v1.value) .."</TD>\n\t\t\t\t</TR>") - end - end - io.write("\n\t\t\t</TABLE>") --- end - else - io.write("\n\t\t\t<SPAN STYLE='margin-left:"..cnt.."0px;font-weight:bold;'> ".. - tostring(table[k].label) .. "</SPAN><BR>") - recurseoutput(v,cnt) - end - end + local i=1 + while indent[i] and revnewentry[i] == indent[i] do + i=i+1 end -end -?> - -<H3>Records</H3> -<? -local tags = {"nsourdomain", "nsdomain", "host", "alias", "mx", "ptr", "cname", "soa", "generic", "all" } -local myform = form.config.settings -io.write("<DL>") -for k,v in pairs(tags) do - local myform = myform[v] - if (myform) and (myform.value) then - io.write("\n\t<DT") - io.write(">" .. myform.label .. "</DT>") - io.write("\n\t\t<DD>") - - for k,v in pairs(myform.value) do - recurseoutput(v) - end - io.write("\n\t\t</DD>") + local ending = #indent-(i-1) + local starting = #newentry-(i-1) + for j=1,ending do + io.write("</li></ul>\n") + end + for j=1,starting do + io.write("<ul><li STYLE='margin-left:10px;'><strong>") + io.write(table.concat(newentry, ".", #newentry-(i+j-2), #newentry)) + io.write("</strong>\n") end + return revnewentry end -io.write("</DL>") ?> + +<H2>Records</H2> +<form id="filter-list">Filter: <input name="filter" id="filter" value="" maxlength="30" size="30" type="text"></form> +<DL id="records"> +<? +local tags = {".", "&", "=", "+", "@", "'", "^", "C", "Z", ":" } +for i,entrytype in ipairs(tags) do + local myview = view[entrytype] + if (myview) then ?> + <DT><?= myview.label ?></DT> + <DD><ul> + <? local indent = {} + for j,entry in ipairs(myview) do + indent = doListIndents(entry[1], indent) ?> + <ul><li STYLE='margin-left:10px;'><IMG SRC='/skins/static/tango/16x16/devices/computer.png' width='16' height='16'><?= tostring(entry[1]) ?><BR> + <TABLE STYLE='margin-left:<?= tostring(7-#indent) ?>0px;'> + <? for k=2,#entry do + local option = entry[k] + if (option) and option ~= "" then ?> + <TR><TD WIDTH='160px' STYLE='border:none;'><?= myview.fieldlabels[k] ?>:</TD> + <TD STYLE='border:none;'><?= option ?></TD></TR> + <? end + end ?> + </TABLE> + <? if entry.errtxt then ?> + <P CLASS='error'><?= string.gsub(entry.errtxt, "\n", "<BR>") ?></P> + <? end ?> + </li></ul> + <? end + doListIndents("", indent) ?> + </ul></DD> + <? end +end ?> +</DL> diff --git a/tinydns.menu b/tinydns.menu index 6d2ee02..70984b4 100644 --- a/tinydns.menu +++ b/tinydns.menu @@ -1,4 +1,4 @@ #CAT GROUP/DESC TAB ACTION Networking 10DNS Status status -#Networking 10DNS Config config -Networking 10DNS Expert expert +Networking 10DNS Config config +Networking 10DNS List_Files listfiles diff --git a/tinydns.roles b/tinydns.roles index 6e6fd1f..45a2655 100644 --- a/tinydns.roles +++ b/tinydns.roles @@ -1,2 +1,2 @@ -READ=tinydns:status -UPDATE=tinydns:expert,tinydns:edit,tinydns:confirmaction +READ=tinydns:status,tinydns:basicstatus +UPDATE=tinydns:config,tinydns:listfiles,tinydns:delete,tinydns:edit,tinydns:expert,tinydns:newfile,tinydns:startstop |