diff options
author | Ted Trask <ttrask01@yahoo.com> | 2008-06-24 15:25:39 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2008-06-24 15:25:39 +0000 |
commit | e5b81fd75226b70136264addc95e30cecffce444 (patch) | |
tree | cc724394d5202125af7340a256fd5f201af6f6e3 | |
parent | bc4c53f27f100f3f0280d4d8d5c2d02e4bc3cfd0 (diff) | |
download | acf-tinydns-e5b81fd75226b70136264addc95e30cecffce444.tar.bz2 acf-tinydns-e5b81fd75226b70136264addc95e30cecffce444.tar.xz |
Updated tinydns as follows: Renames status to view and basicstatus to status. Added ability to view individual config file / domain. Added link from view to edit actual line. Modified view.
Updated jQuery to latest 1.2.6
git-svn-id: svn://svn.alpinelinux.org/acf/tinydns/trunk@1253 ab2d0c66-481e-0410-8bed-d214d4d58bed
-rw-r--r-- | tinydns-basicstatus-html.lsp | 16 | ||||
-rwxr-xr-x | tinydns-config-html.lsp | 2 | ||||
-rw-r--r-- | tinydns-controller.lua | 9 | ||||
-rw-r--r-- | tinydns-edit-html.lsp | 45 | ||||
-rw-r--r-- | tinydns-listfiles-html.lsp | 15 | ||||
-rw-r--r-- | tinydns-model.lua | 73 | ||||
-rw-r--r-- | tinydns-status-html.lsp | 134 | ||||
-rw-r--r-- | tinydns-view-html.lsp | 144 | ||||
-rw-r--r-- | tinydns.menu | 3 | ||||
-rw-r--r-- | tinydns.roles | 2 |
10 files changed, 234 insertions, 209 deletions
diff --git a/tinydns-basicstatus-html.lsp b/tinydns-basicstatus-html.lsp deleted file mode 100644 index d0eae68..0000000 --- a/tinydns-basicstatus-html.lsp +++ /dev/null @@ -1,16 +0,0 @@ -<? 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 4c56ea3..1119a50 100755 --- a/tinydns-config-html.lsp +++ b/tinydns-config-html.lsp @@ -10,7 +10,7 @@ io.write("</span>") ?> <? if viewlibrary and viewlibrary.dispatch_component then - viewlibrary.dispatch_component("basicstatus") + viewlibrary.dispatch_component("status") end ?> <h1>CONFIGURATION</h1> diff --git a/tinydns-controller.lua b/tinydns-controller.lua index b0f4272..c97bca2 100644 --- a/tinydns-controller.lua +++ b/tinydns-controller.lua @@ -1,4 +1,5 @@ module(..., package.seeall) +require("validator") -- ################################################################################ -- LOCAL FUNCTIONS @@ -8,12 +9,12 @@ module(..., package.seeall) default_action = "status" -function basicstatus(self) +function status(self) return self.model.getstatus(self) end -function status(self) - return self.model.getconfigobjects(self) +function view(self) + return self.model.getconfigobjects(self.clientdata.filename) end function startstop(self) @@ -107,6 +108,8 @@ function edit(self) config = self.model.get_filedetails(self.clientdata.filename) config.descr = "Saved file" end + elseif validator.is_integer(self.clientdata.linenumber) then + config.value.filecontent.linenumber = self.clientdata.linenumber end config.type = "form" diff --git a/tinydns-edit-html.lsp b/tinydns-edit-html.lsp index 6a19c65..95b2fa0 100644 --- a/tinydns-edit-html.lsp +++ b/tinydns-edit-html.lsp @@ -16,21 +16,19 @@ this.descriptions[0]=descr0;this.descriptions[1]=descr1;this.descriptions[2]=descr2;this.descriptions[3]=descr3;this.descriptions[4]=descr4;this.descriptions[5]=descr5;this.descriptions[6]=descr6;this.descriptions[7]=descr7;this.descriptions[8]=descr8;this.descriptions[9]=descr9;this.descriptions[10]=descr10; } - var entryTypes = new Array(14); - entryTypes[0]=new Entry("","Empty line",0); - entryTypes[1]=new Entry(";","Comment line",1,"Comment"); - entryTypes[2]=new Entry("#","Comment line",1,"Comment"); - entryTypes[3]=new Entry(".","Name server",6,"Domain","IP address","Name server","Time to live","Timestamp","Location"); - entryTypes[4]=new Entry("&","Delegate subdomain",6,"Domain","IP address","Name server","Time to live","Timestamp","Location"); - entryTypes[5]=new Entry("=","Host",5,"Host","IP address","Time to live","Timestamp","Location"); - entryTypes[6]=new Entry("+","Alias",5,"Alias","IP address","Time to live","Timestamp","Location"); - entryTypes[7]=new Entry("@","Mail exchanger",7,"Domain","IP address","Mail exchanger","Distance","Time to live","Timestamp","Location"); - entryTypes[8]=new Entry("'","Text record",5,"Domain","Text Record","Time to live","Timestamp","Location"); - entryTypes[9]=new Entry("^","Reverse record",5,"PTR","Domain name","Time to live","Timestamp","Location"); - entryTypes[10]=new Entry("C","Canonical name",5,"Domain","Canonical name","Time to live","Timestamp","Location"); - entryTypes[11]=new Entry("Z","SOA record",11,"Domain","Primary name server","Contact address","Serial number","Refresh time","Retry time","Expire time","Minimum time","Time to live","Timestamp","Location"); - entryTypes[12]=new Entry(":","Generic record",6,"Domain","Record type","Record data","Time to live","Timestamp","Location"); - entryTypes[13]=new Entry("%","Client location",2,"Location","IP prefix"); + var entryTypes = new Array(12); + entryTypes[0]=new Entry("","Comment line",1,"Comment"); + entryTypes[1]=new Entry(".","Name server",6,"Domain","IP address","Name server","Time to live","Timestamp","Location"); + entryTypes[2]=new Entry("&","Delegate subdomain",6,"Domain","IP address","Name server","Time to live","Timestamp","Location"); + entryTypes[3]=new Entry("=","Host",5,"Host","IP address","Time to live","Timestamp","Location"); + entryTypes[4]=new Entry("+","Alias",5,"Alias","IP address","Time to live","Timestamp","Location"); + entryTypes[5]=new Entry("@","Mail exchanger",7,"Domain","IP address","Mail exchanger","Distance","Time to live","Timestamp","Location"); + entryTypes[6]=new Entry("'","Text record",5,"Domain","Text Record","Time to live","Timestamp","Location"); + entryTypes[7]=new Entry("^","Reverse record",5,"PTR","Domain name","Time to live","Timestamp","Location"); + entryTypes[8]=new Entry("C","Canonical name",5,"Domain","Canonical name","Time to live","Timestamp","Location"); + entryTypes[9]=new Entry("Z","SOA record",11,"Domain","Primary name server","Contact address","Serial number","Refresh time","Retry time","Expire time","Minimum time","Time to live","Timestamp","Location"); + entryTypes[10]=new Entry(":","Generic record",6,"Domain","Record type","Record data","Time to live","Timestamp","Location"); + entryTypes[11]=new Entry("%","Client location",2,"Location","IP prefix"); function finishForm(entry){ var entrytext = entry.find("select").val() + entry.find("input").map(function(){ @@ -44,17 +42,23 @@ var form = '<select>'; var typechar = entrytext.charAt(0); if (typechar === null) { typechar = ""; } - for (i=0; i<14; i++) { + for (i=0; i<12; i++) { form = form + '<option '; if (typechar == entryTypes[i].entryType){ entryType=entryTypes[i]; form = form + 'selected '; } - form = form + 'value="' + entryTypes[i].entryType + '">' + entryTypes[i].entryType + ' (' + entryTypes[i].descr + ')</option>'; + form = form + 'value="' + entryTypes[i].entryType + '">' + entryTypes[i].descr + '</option>'; } form = form + "</select><br><dl>"; - entrytext = entrytext.substring(1,entrytext.length) + "::::::::::"; - var entries = entrytext.split(":"); + var entries; + if (entryType.entryType == ""){ + entries = new Array(1); + entries[0] = entrytext; + } else { + entrytext = entrytext.substring(1,entrytext.length) + "::::::::::"; + entries = entrytext.split(":"); + } for (i=0; i<entryType.num; i++){ if (entries[i] === null) { entries[i] = ""; } form = form + '<dt>' + entryType.descriptions[i] + '</dt><dd><input type="text" value="' + entries[i] + '"></dd>'; @@ -110,6 +114,9 @@ $(function(){ addLinks($("#entries").find("tr")); $("input.submit").click(submitFile); + <? if form.value.filecontent.linenumber then ?> + $("#entries tr:eq(<?= form.value.filecontent.linenumber - 1 ?>)").find("a:eq(2)").click().parent().next().focus(); + <? end ?> }); </script> diff --git a/tinydns-listfiles-html.lsp b/tinydns-listfiles-html.lsp index f61ce25..c2407e2 100644 --- a/tinydns-listfiles-html.lsp +++ b/tinydns-listfiles-html.lsp @@ -9,12 +9,8 @@ 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> +<h2>Edit/View existing Domains</h2> <TABLE> <TR style="background:#eee;font-weight:bold;"> <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD> @@ -26,8 +22,9 @@ end ?> <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 = "view?filename=" .. file.value.filename.value, label="View " }) ?> <? 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 " }) ?> + <? io.write(html.link{value = "expert?filename=" .. file.value.filename.value, label="Expert " }) ?> </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> @@ -38,12 +35,8 @@ end ?> <? if viewlibrary and viewlibrary.dispatch_component then local newfileform = viewlibrary.dispatch_component("newfile", nil, true) ?> -<h2>Create new config file</h2> +<h2>Create new Domain</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 e75f937..43bf8ea 100644 --- a/tinydns-model.lua +++ b/tinydns-model.lua @@ -89,7 +89,7 @@ local function split_config_items(orgitem) local output = {} 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" + output.label = descr['prefix'][output.type] return output end @@ -199,42 +199,47 @@ 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) +function getconfigobjects(file_name, filter_type) local configobjects = {} --Loop through all available configfiles for i,filename in pairs(configfiles) do - local filecontent, fileresult - fileresult, filecontent = get_value_from_file(filename) - for j,configline in pairs(filecontent) do - local domaindetails = {} - local filecontent_table = split_config_items(configline) - filecontent_table.configline = configline - - -- Use only configs that has a valid prefix - -- 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.type)) ) - and (filecontent_table.label) - then - local entry = {} - for i,value in ipairs(filecontent_table) do - entry[i] = value + if not file_name or file_name == filename then + local filecontent = fs.read_file_as_array(filename) + for linenumber,configline in ipairs(filecontent) do + local domaindetails = {} + local filecontent_table = split_config_items(configline) + filecontent_table.configline = configline + + -- Use only configs that has a valid prefix + -- 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.type)) ) + and (filecontent_table.label) + then + local entry = {} + for i,value in ipairs(filecontent_table) do + entry[i] = value + end + -- add in the filename and line number + entry.filename = filename + entry.linenumber = linenumber + + -- 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 + local reversedomain = {} + for i=#domain,1,-1 do + table.insert(reversedomain, domain[i]) + end + entry.sort = table.concat(reversedomain, ".") + + -- 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 + table.insert(configobjects[filecontent_table.type], entry) end - -- 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 - local reversedomain = {} - for i=#domain,1,-1 do - table.insert(reversedomain, domain[i]) - end - entry.sort = table.concat(reversedomain, ".") - - -- 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 - table.insert(configobjects[filecontent_table.type], entry) end end end @@ -261,7 +266,7 @@ function getconfigobjects(self, filter_type) end end - return configobjects + return cfe({ type="structure", value=configobjects, label="DNS Entries", filename=file_name }) end function getfilelist () diff --git a/tinydns-status-html.lsp b/tinydns-status-html.lsp index ca0ddf4..d0eae68 100644 --- a/tinydns-status-html.lsp +++ b/tinydns-status-html.lsp @@ -1,128 +1,16 @@ -<? local view, viewlibrary = ... -require("viewfunctions") -?> - -<script type="text/javascript" src="/js/jquery-latest.js"></script> -<script type="text/javascript"> - var last_phrase = ""; - function filterPage(){ - var phrase = $("#filter").val(); - if (phrase != last_phrase){ - last_phrase = phrase; - $("#records li").each(function(){ - var elem = jQuery(this); - if (elem.text().indexOf(phrase)>=0) { - elem.show(); - } else { - elem.hide(); - } - }); - } - } - var filterTimer; - $(function(){ - $("#filter").keyup(function(){ - window.clearTimeout(filterTimer); - filterTimer = window.setTimeout("filterPage();",250); - }); - $("#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(view)) -io.write("</span>") ---]] -?> - -<? if viewlibrary and viewlibrary.dispatch_component then - viewlibrary.dispatch_component("basicstatus") -end ?> +<? local data = ... ?> +<? require("viewfunctions") ?> +<? --[[ +io.write(html.cfe_unpack(data)) +--]] ?> -<H1>PROGRAM SPECIFIC OPTIONS/INFORMATION</H1> -<H2>Locations</H2> +<H1>SYSTEM INFO</H1> <DL> <? -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 function doListIndents(next, indent) - local newentry = {} - for mt in string.gmatch(next, "([^.]+)") do - table.insert(newentry, mt) - end - local revnewentry = {} - for j=#newentry,1,-1 do - table.insert(revnewentry, newentry[j]) - end - local i=1 - while indent[i] and revnewentry[i] == indent[i] do - i=i+1 - end - 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 +displayitem(data.value.status) +displayitem(data.value.version) +displayitem(data.value.autostart) +displayitem(data.value.configdir) +displayitem(data.value.listen) ?> - -<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-view-html.lsp b/tinydns-view-html.lsp new file mode 100644 index 0000000..8ec8b9e --- /dev/null +++ b/tinydns-view-html.lsp @@ -0,0 +1,144 @@ +<? local view, viewlibrary = ... +require("viewfunctions") +?> + +<script type="text/javascript" src="/js/jquery-latest.js"></script> +<script type="text/javascript"> + var last_phrase = ""; + function filterPage(){ + var phrase = $("#filter").val(); + if (phrase != last_phrase){ + last_phrase = phrase; + $("#records li").each(function(){ + var elem = jQuery(this); + if (elem.text().indexOf(phrase)>=0) { + elem.show(); + } else { + elem.hide(); + } + }); + } + } + function editEntry(){ + window.location.href = "edit?" + this.id; + } + var filterTimer; + $(function(){ + $("#filter").keyup(function(){ + window.clearTimeout(filterTimer); + filterTimer = window.setTimeout("filterPage();",250); + }); + $("#filter-list").submit(function(){ + return false; + }).focus(); + $("#records li").not(":has(ul)").dblclick(editEntry); + $("#locations li").not(":has(ul)").dblclick(editEntry); + }); +</script> + +<? +--[[ DEBUG INFORMATION +io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>") +io.write(html.cfe_unpack(view)) +io.write("</span>") +--]] +?> + +<H1>DNS Entries +<? if view.filename then io.write(" for "..view.filename) end ?> +</H1> +<H2>Locations</H2> +<DL id="locations"> +<? +if (view.value) and (view.value['%']) then + local val = view.value['%'] ?> + <DT<? if (val.errtxt) then io.write(" class='error'") end ?>><?= val.label ?></DT> + + <DD><ul> + <? local currentloc = "" + for i,loc in ipairs(val) do + if currentloc ~= loc[1] then + if currentloc ~= "" then ?> + </ul> + <? end ?> + <li><IMG SRC='/skins/static/tango/16x16/places/start-here.png' width='16' height='16' alt> <B><?= loc[1] ?></B></li> + <ul STYLE='margin-left:30px';> + <? end + currentloc = loc[1] ?> + <li id='filename=<?= loc.filename ?>;linenumber=<?= loc.linenumber ?>'> + <?= loc[2] ?><? if loc[2] == "" then io.write('*') end ?> + <? if (loc.errtxt) then ?><P CLASS='error'><?= string.gsub(loc.errtxt, "\n", "<BR>") ?></P><? end ?> + </li> + <? end + if currentloc ~= "" then ?> + </ul> + <? end ?> + </ul> + </DD> +<? else ?> + No locations defined +<? end ?> +</DL> + +<? +local function doListIndents(next, indent) + local newentry = {} + for mt in string.gmatch(next, "([^.]+)") do + table.insert(newentry, mt) + end + local revnewentry = {} + for j=#newentry,1,-1 do + table.insert(revnewentry, newentry[j]) + end + local i=1 + while indent[i] and revnewentry[i] == indent[i] do + i=i+1 + end + 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 +?> + +<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.value[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;' id='filename=<?= entry.filename ?>;linenumber=<?= entry.linenumber ?>'> + <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 70984b4..5243d05 100644 --- a/tinydns.menu +++ b/tinydns.menu @@ -1,4 +1,5 @@ #CAT GROUP/DESC TAB ACTION Networking 10DNS Status status +Networking 10DNS View view +Networking 10DNS List_Domains listfiles Networking 10DNS Config config -Networking 10DNS List_Files listfiles diff --git a/tinydns.roles b/tinydns.roles index 45a2655..d473bb7 100644 --- a/tinydns.roles +++ b/tinydns.roles @@ -1,2 +1,2 @@ -READ=tinydns:status,tinydns:basicstatus +READ=tinydns:status,tinydns:view UPDATE=tinydns:config,tinydns:listfiles,tinydns:delete,tinydns:edit,tinydns:expert,tinydns:newfile,tinydns:startstop |