luci-app-radicale: bump to version 1.1.0 643/head
authorChristian Schoenebeck <christian.schoenebeck@gmail.com>
Sun, 7 Feb 2016 08:30:29 +0000 (09:30 +0100)
committerChristian Schoenebeck <christian.schoenebeck@gmail.com>
Sun, 7 Feb 2016 08:30:29 +0000 (09:30 +0100)
- support Radicale > v1.1
- modified version detection
- adaption to new function version_compare() in ipkg.lua
- adaption to fixed Flag.parse() in cbi.lua
- adaption to new property map.tabbed in cbi.lua using map template with extensions
- change optional values to non optional
- add support new option "system.boot_delay"

Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
applications/luci-app-radicale/Makefile
applications/luci-app-radicale/luasrc/controller/radicale.lua
applications/luci-app-radicale/luasrc/model/cbi/radicale.lua
applications/luci-app-radicale/luasrc/view/radicale/btn_startstop.htm
applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm [deleted file]
applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm [new file with mode: 0644]
applications/luci-app-radicale/po/de/radicale.po
applications/luci-app-radicale/po/sv/radicale.po
applications/luci-app-radicale/po/templates/radicale.pot

index c403ba5..2b969ac 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org>
+# Copyright (C) 2008-2016 The LuCI Team <luci@lists.subsignal.org>
 #
 # This is free software, licensed under the Apache License, Version 2.0 .
 #
@@ -10,7 +10,7 @@ PKG_NAME:=luci-app-radicale
 
 # Version == major.minor.patch
 # increase "minor" on new functionality and "patch" on patches/optimization
-PKG_VERSION:=1.0.2
+PKG_VERSION:=1.1.0
 
 # Release == build
 # increase on changes of translation files
index 10ec1fe..0be433a 100644 (file)
@@ -1,15 +1,23 @@
--- Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Copyright 2014-2016 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
 -- Licensed under the Apache License, Version 2.0
 
 module("luci.controller.radicale", package.seeall)
 
-local NX    = require("nixio")
-local NXFS  = require("nixio.fs")
-local DISP  = require "luci.dispatcher"
-local HTTP  = require("luci.http")
+local NX   = require("nixio")
+local NXFS = require("nixio.fs")
+local DISP = require("luci.dispatcher")
+local HTTP = require("luci.http")
 local I18N = require("luci.i18n")      -- not globally avalible here
-local UTIL  = require("luci.util")
-local SYS   = require("luci.sys")
+local IPKG = require("luci.model.ipkg")
+local UTIL = require("luci.util")
+local SYS  = require("luci.sys")
+
+local srv_name    = "radicale"
+local srv_ver_min = "1.1"              -- minimum version of service required
+local srv_ver_cmd = [[/usr/bin/radicale --version]]
+local app_name    = "luci-app-radicale"
+local app_title   = I18N.translate("Radicale CalDAV/CardDAV Server")
+local app_version = "1.1.0-1"
 
 function index()
        entry( {"admin", "services", "radicale"}, alias("admin", "services", "radicale", "edit"), _("CalDAV/CardDAV"), 58)
@@ -19,6 +27,75 @@ function index()
        entry( {"admin", "services", "radicale", "status"}, call("_status") ).leaf = true
 end
 
+-- Application / Service specific information functions
+function app_description()
+       return  I18N.translate("The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) server solution.") .. [[<br />]]
+            .. I18N.translate("Calendars and address books are available for both local and remote access, possibly limited through authentication policies.") .. [[<br />]]
+            .. I18N.translate("They can be viewed and edited by calendar and contact clients on mobile phones or computers.")
+end
+function app_title_main()
+       return  [[<a href="javascript:alert(']]
+                       .. I18N.translate("Version Information")
+                       .. [[\n\n]] .. app_name
+                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]] .. app_version
+                       .. [[\n\n]] .. srv_name .. [[ ]] .. I18N.translate("required") .. [[:]]
+                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
+                               .. srv_ver_min .. [[ ]] .. I18N.translate("or higher")
+                       .. [[\n\n]] .. srv_name .. [[ ]] .. I18N.translate("installed") .. [[:]]
+                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
+                               .. (service_version() or I18N.translate("NOT installed"))
+                       .. [[\n\n]]
+               .. [[')">]]
+               .. I18N.translate(app_title)
+               .. [[</a>]]
+end
+function app_title_back()
+       return  [[<a href="]]
+                       .. DISP.build_url("admin", "services", "radicale")
+               .. [[">]]
+               .. I18N.translate(app_title)
+               .. [[</a>]]
+end
+function app_err_value()
+       if not service_version() then
+               return [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. I18N.translate("Software package '%s' is not installed." % srv_name)
+                       .. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. I18N.translate("required") .. [[: ]] .. srv_name .. [[ ]] .. srv_ver_min
+                       .. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
+                       .. I18N.translate("Please install current version !")
+                       .. [[</a><br />&nbsp;</strong></h3>]]
+       else
+               return [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. I18N.translate("Software package '%s' is outdated." % srv_name)
+                       .. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. I18N.translate("installed") .. [[: ]] .. srv_name .. [[ ]] .. service_version()
+                       .. [[<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. I18N.translate("required") .. [[: ]] .. srv_name .. [[ ]] .. srv_ver_min
+                       .. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
+                       .. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
+                       .. I18N.translate("Please update to current version !")
+                       .. [[</a><br />&nbsp;</strong></h3>]]
+       end
+end
+
+function service_version()
+       local ver = nil
+       IPKG.list_installed(srv_name, function(n, v, d)
+                       if v and (#v > 0) then ver = v end
+               end
+       )
+       if not ver or (#ver == 0) then
+               ver = UTIL.exec(srv_ver_cmd)
+               if #ver == 0 then ver = nil end
+       end
+       return  ver
+end
+function service_ok()
+       return  IPKG.compare_versions((service_version() or "0"), ">=", srv_ver_min)
+end
+
 -- called by XHR.get from detail_logview.htm
 function _logread()
        -- read application settings
@@ -60,138 +137,103 @@ function _status()
        HTTP.write(tostring(pid))       -- HTTP needs string not number
 end
 
--- Application / Service specific information functions ########################
-function luci_app_name()
-       return  "luci-app-radicale"
-end
-
-function service_name()
-       return  "radicale"
-end
-function service_required()
-       return  "0.10-1"
-end
-function service_installed()
-       local v = ipkg_ver_installed("radicale-py2")
-       if not v or #v == 0 then v = ipkg_ver_installed("radicale-py3") end
-       if not v or #v == 0 then v = "0" end
-       return v
-end
-function service_ok()
-       return  ipkg_ver_compare(service_installed(),">=",service_required())
-end
-
-function app_title_main()
-       return  [[<a href="javascript:alert(']]
-                       .. I18N.translate("Version Information")
-                       .. [[\n\n]] .. luci_app_name()
-                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
-                               .. (ipkg_ver_installed(luci_app_name()) == ""
-                                       and I18N.translate("NOT installed")
-                                       or ipkg_ver_installed(luci_app_name()) )
-                       .. [[\n\n]] .. service_name() .. [[ ]] .. I18N.translate("required") .. [[:]]
-                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
-                               .. service_required() .. [[ ]] .. I18N.translate("or higher")
-                       .. [[\n\n]] .. service_name() .. [[ ]] .. I18N.translate("installed") .. [[:]]
-                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
-                               .. (service_installed() == "0"
-                                       and I18N.translate("NOT installed")
-                                       or service_installed())
-                       .. [[\n\n]]
-               .. [[')">]]
-               .. I18N.translate("Radicale CalDAV/CardDAV Server")
-               .. [[</a>]]
-end
-function app_title_back()
-       return  [[<a href="]]
-                       .. DISP.build_url("admin", "services", "radicale")
-               .. [[">]]
-               .. I18N.translate("Radicale CalDAV/CardDAV Server")
-               .. [[</a>]]
-end
-function app_description()
-       return  I18N.translate("The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) server solution.") .. [[<br />]]
-            .. I18N.translate("Calendars and address books are available for both local and remote access, possibly limited through authentication policies.") .. [[<br />]]
-            .. I18N.translate("They can be viewed and edited by calendar and contact clients on mobile phones or computers.")
-end
-
--- other multiused functions ###################################################
-
 --return pid of running process
 function get_pid()
        return tonumber(SYS.exec([[ps | grep "[p]ython.*[r]adicale" 2>/dev/null | awk '{print $1}']])) or 0
 end
 
--- compare versions using "<=" "<" ">" ">=" "=" "<<" ">>"
-function ipkg_ver_compare(ver1, comp, ver2)
-       if not ver1 or not ver2
-       or not comp or not (#comp > 0) then return nil end
-       -- correct compare string
-       if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
-       elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
-       elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
-       elseif comp == "="  or comp == "==" then comp = "=="
-       elseif comp == "<<" then comp = "<"
-       elseif comp == ">>" then comp = ">"
-       else return nil end
-
-       local av1 = UTIL.split(ver1, "[%.%-]", nil, true)
-       local av2 = UTIL.split(ver2, "[%.%-]", nil, true)
-
-       for i = 1, math.max(table.getn(av1),table.getn(av2)), 1  do
-               local s1 = av1[i] or ""
-               local s2 = av2[i] or ""
-
-               -- first "not equal" found return true
-               if comp == "~=" and (s1 ~= s2) then return true end
-               -- first "lower" found return true
-               if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
-               -- first "greater" found return true
-               if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
-               -- not equal then return false
-               if (s1 ~= s2) then return false end
+-- replacement of build-in parse of "Value"
+-- modified AbstractValue.parse(self, section, novld) from cbi.lua
+-- validate is called if rmempty/optional true or false
+-- before write check if forcewrite, value eq default, and more
+function value_parse(self, section, novld)
+       local fvalue = self:formvalue(section)
+       local fexist = ( fvalue and (#fvalue > 0) )     -- not "nil" and "not empty"
+       local cvalue = self:cfgvalue(section)
+       local rm_opt = ( self.rmempty or self.optional )
+       local eq_cfg                                    -- flag: equal cfgvalue
+
+       -- If favlue and cvalue are both tables and have the same content
+       -- make them identical
+       if type(fvalue) == "table" and type(cvalue) == "table" then
+               eq_cfg = (#fvalue == #cvalue)
+               if eq_cfg then
+                       for i=1, #fvalue do
+                               if cvalue[i] ~= fvalue[i] then
+                                       eq_cfg = false
+                               end
+                       end
+               end
+               if eq_cfg then
+                       fvalue = cvalue
+               end
        end
 
-       -- all equal and not compare greater or lower then true
-       return not (comp == "<" or comp == ">")
-end
+       -- removed parameter "section" from function call because used/accepted nowhere
+       -- also removed call to function "transfer"
+       local vvalue, errtxt = self:validate(fvalue)
 
--- read version information for given package if installed
-function ipkg_ver_installed(pkg)
-       local version = ""
-       local control = io.open("/usr/lib/opkg/info/%s.control" % pkg, "r")
-       if control then
-               local ln
-               repeat
-                       ln = control:read("*l")
-                       if ln and ln:match("^Version: ") then
-                               version = ln:gsub("^Version: ", "")
-                               break
-                       end
-               until not ln
-               control:close()
+       -- error handling; validate return "nil"
+       if not vvalue then
+               if novld then           -- and "novld" set
+                       return          -- then exit without raising an error
+               end
+
+               if fexist then          -- and there is a formvalue
+                       self:add_error(section, "invalid", errtxt)
+                       return          -- so data are invalid
+               elseif not rm_opt then  -- and empty formvalue but NOT (rmempty or optional) set
+                       self:add_error(section, "missing", errtxt)
+                       return          -- so data is missing
+               elseif errtxt then
+                       self:add_error(section, "invalid", errtxt)
+                       return
+               end
+--             error  ("\n option: " .. self.option ..
+--                     "\n fvalue: " .. tostring(fvalue) ..
+--                     "\n fexist: " .. tostring(fexist) ..
+--                     "\n cvalue: " .. tostring(cvalue) ..
+--                     "\n vvalue: " .. tostring(vvalue) ..
+--                     "\n vexist: " .. tostring(vexist) ..
+--                     "\n rm_opt: " .. tostring(rm_opt) ..
+--                     "\n eq_cfg: " .. tostring(eq_cfg) ..
+--                     "\n eq_def: " .. tostring(eq_def) ..
+--                     "\n novld : " .. tostring(novld) ..
+--                     "\n errtxt: " .. tostring(errtxt) )
        end
-       return version
-end
 
--- replacement of build-in Flag.parse of cbi.lua
--- modified to mark section as changed if value changes
--- current parse did not do this, but it is done AbstaractValue.parse()
-function flag_parse(self, section)
-       local fexists = self.map:formvalue(
-               luci.cbi.FEXIST_PREFIX .. self.config .. "." .. section .. "." .. self.option)
-
-       if fexists then
-               local fvalue = self:formvalue(section) and self.enabled or self.disabled
-               local cvalue = self:cfgvalue(section)
-               if fvalue ~= self.default or (not self.optional and not self.rmempty) then
-                       self:write(section, fvalue)
-               else
-                       self:remove(section)
+       -- lets continue with value returned from validate
+       eq_cfg  = ( vvalue == cvalue )                                  -- update equal_config flag
+       local vexist = ( vvalue and (#vvalue > 0) ) and true or false   -- not "nil" and "not empty"
+       local eq_def = ( vvalue == self.default )                       -- equal_default flag
+
+       -- (rmempty or optional) and (no data or equal_default)
+       if rm_opt and (not vexist or eq_def) then
+               if self:remove(section) then            -- remove data from UCI
+                       self.section.changed = true     -- and push events
                end
-               if (fvalue ~= cvalue) then self.section.changed = true end
-       else
-               self:remove(section)
+               return
+       end
+
+       -- not forcewrite and no changes, so nothing to write
+       if not self.forcewrite and eq_cfg then
+               return
+       end
+
+       -- we should have a valid value here
+       assert (vvalue, "\n option: " .. self.option ..
+                       "\n fvalue: " .. tostring(fvalue) ..
+                       "\n fexist: " .. tostring(fexist) ..
+                       "\n cvalue: " .. tostring(cvalue) ..
+                       "\n vvalue: " .. tostring(vvalue) ..
+                       "\n vexist: " .. tostring(vexist) ..
+                       "\n rm_opt: " .. tostring(rm_opt) ..
+                       "\n eq_cfg: " .. tostring(eq_cfg) ..
+                       "\n eq_def: " .. tostring(eq_def) ..
+                       "\n errtxt: " .. tostring(errtxt) )
+
+       -- write data to UCI; raise event only on changes
+       if self:write(section, vvalue) and not eq_cfg then
                self.section.changed = true
        end
 end
index 8abb688..c610478 100644 (file)
@@ -1,14 +1,43 @@
--- Copyright 2015 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Copyright 2015-2016 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
 -- Licensed under the Apache License, Version 2.0
 
-local NXFS  = require("nixio.fs")
-local DISP  = require("luci.dispatcher")
-local DTYP  = require("luci.cbi.datatypes")
-local HTTP  = require("luci.http")
-local UTIL  = require("luci.util")
-local UCI   = require("luci.model.uci")
-local SYS   = require("luci.sys")
-local TOOLS = require("luci.controller.radicale")      -- this application's controller and multiused functions
+local NXFS = require("nixio.fs")
+local DISP = require("luci.dispatcher")
+local DTYP = require("luci.cbi.datatypes")
+local HTTP = require("luci.http")
+local UTIL = require("luci.util")
+local UCI  = require("luci.model.uci")
+local SYS  = require("luci.sys")
+local WADM = require("luci.tools.webadmin")
+local CTRL = require("luci.controller.radicale")       -- this application's controller and multiused functions
+
+-- #################################################################################################
+-- Error handling if not installed or wrong version -- #########################
+if not CTRL.service_ok() then
+       local f         = SimpleForm("__sf")
+       f.title         = CTRL.app_title_main()
+       f.description   = CTRL.app_description()
+       f.embedded      = true
+       f.submit        = false
+       f.reset         = false
+
+       local s = f:section(SimpleSection)
+       s.title = [[<font color="red">]] .. [[<strong>]]
+               .. translate("Software update required")
+               .. [[</strong>]] .. [[</font>]]
+
+       local v   = s:option(DummyValue, "_dv")
+       v.rawhtml = true
+       v.value   = CTRL.app_err_value
+
+       return f
+end
+
+-- #################################################################################################
+-- Error handling if no config, create an empty one -- #########################
+if not NXFS.access("/etc/config/radicale") then
+       NXFS.writefile("/etc/config/radicale", "")
+end
 
 -- #################################################################################################
 -- takeover arguments if any -- ################################################
@@ -19,8 +48,8 @@ if arg[1] then
 
        -- SimpleForm ------------------------------------------------
        local ft        = SimpleForm("_text")
-       ft.title        = TOOLS.app_title_back()
-       ft.description  = TOOLS.app_description()
+       ft.title        = CTRL.app_title_back()
+       ft.description  = CTRL.app_description()
        ft.redirect     = DISP.build_url("admin", "services", "radicale") .. "#cbi-radicale-" .. argument
        if argument == "logger" then
                ft.reset        = false
@@ -95,54 +124,12 @@ if arg[1] then
 
 end
 
--- #################################################################################################
--- Error handling if not installed or wrong version -- #########################
-if not TOOLS.service_ok() then
-       local f         = SimpleForm("_no_config")
-       f.title         = TOOLS.app_title_main()
-       f.description   = TOOLS.app_description()
-       f.submit        = false
-       f.reset         = false
-
-       local s = f:section(SimpleSection)
-
-       local v    = s:option(DummyValue, "_update_needed")
-       v.rawhtml  = true
-       if TOOLS.service_installed() == "0" then
-               v.value    = [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. translate("Software package '" .. TOOLS.service_name() .. "' is not installed.")
-                          .. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. translate("required") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_required()
-                          .. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
-                          .. translate("Please install current version !")
-                          .. [[</a><br />&nbsp;</strong></h3>]]
-       else
-               v.value    = [[<h3><strong><br /><font color="red">&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. translate("Software package '" .. TOOLS.service_name() .. "' is outdated.")
-                          .. [[</font><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. translate("installed") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_installed()
-                          .. [[<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. translate("required") .. [[: ]] .. TOOLS.service_name() .. [[ ]] .. TOOLS.service_required()
-                          .. [[<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;]]
-                          .. [[<a href="]] .. DISP.build_url("admin", "system", "packages") ..[[">]]
-                          .. translate("Please update to current version !")
-                          .. [[</a><br />&nbsp;</strong></h3>]]
-       end
-
-       return f
-end
-
--- #################################################################################################
--- Error handling if no config, create an empty one -- #########################
-if not NXFS.access("/etc/config/radicale") then
-       NXFS.writefile("/etc/config/radicale", "")
-end
-
 -- cbi-map -- ##################################################################
 local m                = Map("radicale")
-m.title                = TOOLS.app_title_main()
-m.description  = TOOLS.app_description()
+m.title                = CTRL.app_title_main()
+m.description  = CTRL.app_description()
+m.template     = "radicale/tabmap_nsections"
+m.tabbed       = true
 function m.commit_handler(self)
        if self.changed then    -- changes ?
                os.execute("/etc/init.d/radicale reload &")     -- reload configuration
@@ -150,11 +137,14 @@ function m.commit_handler(self)
 end
 
 -- cbi-section "System" -- #####################################################
-local sys      = m:section( NamedSection, "_system" )
+local sys      = m:section( NamedSection, "system", "system" )
 sys.title      = translate("System")
 sys.description        = nil
 function sys.cfgvalue(self, section)
-       return "_dummysection"
+       if not self.map:get(section) then       -- section might not exist
+               self.map:set(section, nil, self.sectiontype)
+       end
+       return self.map:get(section)
 end
 
 -- start/stop button -----------------------------------------------------------
@@ -165,7 +155,7 @@ btn.rmempty = true
 btn.title      = translate("Start / Stop")
 btn.description        = translate("Start/Stop Radicale server")
 function btn.cfgvalue(self, section)
-       local pid = TOOLS.get_pid(true)
+       local pid = CTRL.get_pid(true)
        if pid > 0 then
                btn.inputtitle  = "PID: " .. pid
                btn.inputstyle  = "reset"
@@ -183,18 +173,39 @@ local ena = sys:option(Flag, "_enabled")
 ena.title       = translate("Auto-start")
 ena.description = translate("Enable/Disable auto-start of Radicale on system start-up and interface events")
 ena.orientation = "horizontal" -- put description under the checkbox
-ena.rmempty    = false         -- we need write
+ena.rmempty    = false         -- force write() function
 function ena.cfgvalue(self, section)
-       return (SYS.init.enabled("radicale")) and "1" or "0"
+       return (SYS.init.enabled("radicale")) and self.enabled or self.disabled
 end
 function ena.write(self, section, value)
-       if value == "1" then
+       if value == self.enabled then
                return SYS.init.enable("radicale")
        else
                return SYS.init.disable("radicale")
        end
 end
 
+-- boot_delay ------------------------------------------------------------------
+local bd       = sys:option(Value, "boot_delay")
+bd.title       = translate("Boot delay")
+bd.description = translate("Delay (in seconds) during system boot before Radicale start")
+               .. [[<br />]]
+               .. translate("During delay ifup-events are not monitored !")
+bd.default     = "10"
+function bd.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
+function bd.validate(self, value)
+       local val = tonumber(value)
+       if not val then
+               return nil, self.title .. ": " .. translate("Value is not a number")
+       elseif val < 0 or val > 300 then
+               return nil, self.title .. ": " .. translate("Value not between 0 and 300")
+       end
+       return value
+end
+
+
 -- cbi-section "Server" -- #####################################################
 local srv      = m:section( NamedSection, "server", "setting" )
 srv.title      = translate("Server")
@@ -215,15 +226,17 @@ sh.description    = translate("'Hostname:Port' or 'IPv4:Port' or '[IPv6]:Port' Radi
                .. [[</strong>]]
 sh.placeholder = "0.0.0.0:5232"
 sh.rmempty     = true
+function sh.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- realm -----------------------------------------------------------------------
 local alm      = srv:option( Value, "realm" )
 alm.title      = translate("Logon message")
 alm.description        = translate("Message displayed in the client when a password is needed.")
 alm.default    = "Radicale - Password Required"
-alm.rmempty    = false
-function alm.parse(self, section)
-       AbstractValue.parse(self, section, "true")      -- otherwise unspecific validate error
+function alm.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
 end
 function alm.validate(self, value)
        if value then
@@ -232,22 +245,11 @@ function alm.validate(self, value)
                return self.default
        end
 end
-function alm.write(self, section, value)
-       if value ~= self.default then
-               return self.map:set(section, self.option, value)
-       else
-               return self.map:del(section, self.option)
-       end
-end
 
 -- ssl -------------------------------------------------------------------------
 local ssl      = srv:option( Flag, "ssl" )
 ssl.title      = translate("Enable HTTPS")
 ssl.description        = nil
-ssl.rmempty    = false
-function ssl.parse(self, section)
-       TOOLS.flag_parse(self, section)
-end
 function ssl.write(self, section, value)
        if value == "0" then                                    -- delete all if not https enabled
                self.map:del(section, "protocol")               -- protocol
@@ -273,18 +275,18 @@ prt:value ("PROTOCOL_SSLv3", "SSL v3")
 prt:value      ("PROTOCOL_TLSv1", "TLS v1")
 prt:value      ("PROTOCOL_TLSv1_1", "TLS v1.1")
 prt:value      ("PROTOCOL_TLSv1_2", "TLS v1.2")
+function prt.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- certificate -----------------------------------------------------------------
 local crt      = srv:option( Value, "certificate" )
 crt.title      = translate("Certificate file")
 crt.description        = translate("Full path and file name of certificate")
 crt.placeholder        = "/etc/radicale/ssl/server.crt"
-crt.rmempty    = false         -- force validate/write
 crt:depends    ("ssl", "1")
-function crt.parse(self, section)
-       local  _ssl = ssl:formvalue(section) or "0"
-       local novld = (_ssl == "0")
-       AbstractValue.parse(self, section, novld)       -- otherwise unspecific validate error
+function crt.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
 end
 function crt.validate(self, value)
        local _ssl = ssl:formvalue(srv.section) or "0"
@@ -295,17 +297,10 @@ function crt.validate(self, value)
                if DTYP.file(value) then
                        return value
                else
-                       return nil, self.title .. " - " .. translate("File not found !")
+                       return nil, self.title .. ": " .. translate("File not found !")
                end
        else
-               return nil, self.title .. " - " .. translate("Path/File required !")
-       end
-end
-function crt.write(self, section, value)
-       if not value or #value == 0 then
-               return self.map:del(section, self.option)
-       else
-               return self.map:set(section, self.option, value)
+               return nil, self.title .. ": " .. translate("Path/File required !")
        end
 end
 
@@ -314,12 +309,9 @@ local key  = srv:option( Value, "key" )
 key.title      = translate("Private key file")
 key.description        = translate("Full path and file name of private key")
 key.placeholder        = "/etc/radicale/ssl/server.key"
-key.rmempty    = false         -- force validate/write
 key:depends    ("ssl", "1")
-function key.parse(self, section)
-       local  _ssl = ssl:formvalue(section) or "0"
-       local novld = (_ssl == "0")
-       AbstractValue.parse(self, section, novld)       -- otherwise unspecific validate error
+function key.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
 end
 function key.validate(self, value)
        local _ssl = ssl:formvalue(srv.section) or "0"
@@ -330,17 +322,10 @@ function key.validate(self, value)
                if DTYP.file(value) then
                        return value
                else
-                       return nil, self.title .. " - " .. translate("File not found !")
+                       return nil, self.title .. ": " .. translate("File not found !")
                end
        else
-               return nil, self.title .. " - " .. translate("Path/File required !")
-       end
-end
-function key.write(self, section, value)
-       if not value or #value == 0 then
-               return self.map:del(section, self.option)
-       else
-               return self.map:set(section, self.option, value)
+               return nil, self.title .. ": " .. translate("Path/File required !")
        end
 end
 
@@ -377,6 +362,9 @@ aty:value   ("htpasswd", translate("htpasswd file"))
 --aty:value    ("HTTP", "HTTP")                        -- The HTTP authentication module relies on the requests module
 --aty:value    ("remote_user", "remote_user")
 --aty:value    ("custom", translate("custom"))
+function aty.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function aty.write(self, section, value)
        if value ~= "htpasswd" then
                self.map:del(section, "htpasswd_encryption")
@@ -403,9 +391,12 @@ hte:value  ("crypt", translate("crypt"))
 hte:value      ("plain", translate("plain"))
 hte:value      ("sha1",  translate("SHA-1"))
 hte:value      ("ssha",  translate("salted SHA-1"))
+function hte.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- htpasswd_file (dummy) -------------------------------------------------------
-local htf      = aut:option( DummyValue, "_htf" )
+local htf      = aut:option( Value, "_htf" )
 htf.title      = translate("htpasswd file")
 htf.description        = [[<strong>]]
                .. translate("Read only!")
@@ -416,9 +407,6 @@ htf.description     = [[<strong>]]
                .. [[">]]
                .. translate("To edit the file follow this link!")
                .. [[</a>]]
-htf.keylist    = {}    -- required by template
-htf.vallist    = {}    -- required by template
-htf.template   = "radicale/ro_value"
 htf.readonly   = true
 htf:depends    ("type", "htpasswd")
 function htf.cfgvalue()
@@ -448,6 +436,9 @@ rty:value   ("owner_only", translate("Full access for Owner only") )
 rty:value      ("owner_write", translate("Owner allow write, authenticated users allow read") )
 rty:value      ("from_file", translate("Rights are based on a regexp-based file") )
 --rty:value    ("custom", "Custom handler")
+function rty.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function rty.write(self, section, value)
        if value ~= "custom" then
                self.map:del(section, "custom_handler")
@@ -460,7 +451,7 @@ function rty.write(self, section, value)
 end
 
 -- from_file (dummy) -----------------------------------------------------------
-local rtf      = rig:option( DummyValue, "_rtf" )
+local rtf      = rig:option( Value, "_rtf" )
 rtf.title      = translate("RegExp file")
 rtf.description        = [[<strong>]]
                .. translate("Read only!")
@@ -471,9 +462,6 @@ rtf.description     = [[<strong>]]
                .. [[">]]
                .. translate("To edit the file follow this link!")
                .. [[</a>]]
-rtf.keylist    = {}    -- required by template
-rtf.vallist    = {}    -- required by template
-rtf.template   = "radicale/ro_value"
 rtf.readonly   = true
 rtf:depends    ("type", "from_file")
 function rtf.cfgvalue()
@@ -501,6 +489,9 @@ sty:value   ("filesystem", translate("File-system"))
 --sty:value    ("multifilesystem", translate("") )
 --sty:value    ("database", translate("Database") )
 --sty:value    ("custom", translate("Custom") )
+function sty.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function sty.write(self, section, value)
        if value ~= "filesystem" then
                self.map:del(section, "filesystem_folder")
@@ -516,13 +507,10 @@ end
 local sfi      = sto:option( Value, "filesystem_folder" )
 sfi.title      = translate("Directory")
 sfi.description        = nil
-sfi.default    = "/srv/radicale"
-sfi.rmempty    = false         -- force validate/write
+sfi.placeholder        = "/srv/radicale"
 sfi:depends    ("type", "filesystem")
-function sfi.parse(self, section)
-       local  _typ = sty:formvalue(sto.section) or ""
-       local novld = (_typ ~= "filesystem")
-       AbstractValue.parse(self, section, novld)       -- otherwise unspecific validate error
+function sfi.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
 end
 function sfi.validate(self, value)
        local _typ = sty:formvalue(sto.section) or ""
@@ -533,10 +521,10 @@ function sfi.validate(self, value)
                if DTYP.directory(value) then
                        return value
                else
-                       return nil, self.title .. " - " .. translate("Directory not exists/found !")
+                       return nil, self.title .. ": " .. translate("Directory not exists/found !")
                end
        else
-               return nil, self.title .. " - " .. translate("Directory required !")
+               return nil, self.title .. ": " .. translate("Directory required !")
        end
 end
 
@@ -562,6 +550,9 @@ lco:value   ("INFO", translate("Info") )
 lco:value      ("WARNING", translate("Warning") )
 lco:value      ("ERROR", translate("Error") )
 lco:value      ("CRITICAL", translate("Critical") )
+function lco.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function lco.write(self, section, value)
        if value ~= self.default then
                return self.map:set(section, self.option, value)
@@ -581,6 +572,9 @@ lsl:value   ("INFO", translate("Info") )
 lsl:value      ("WARNING", translate("Warning") )
 lsl:value      ("ERROR", translate("Error") )
 lsl:value      ("CRITICAL", translate("Critical") )
+function lsl.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function lsl.write(self, section, value)
        if value ~= self.default then
                return self.map:set(section, self.option, value)
@@ -600,6 +594,9 @@ lfi:value   ("INFO", translate("Info") )
 lfi:value      ("WARNING", translate("Warning") )
 lfi:value      ("ERROR", translate("Error") )
 lfi:value      ("CRITICAL", translate("Critical") )
+function lfi.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function lfi.write(self, section, value)
        if value ~= self.default then
                return self.map:set(section, self.option, value)
@@ -618,12 +615,14 @@ lfp.description   = translate("Directory where the rotating log-files are stored")
                .. translate("To view latest log file follow this link!")
                .. [[</a>]]
 lfp.default    = "/var/log/radicale"
-function lfp.write(self, section, value)
-       if value ~= self.default then
-               return self.map:set(section, self.option, value)
-       else
-               return self.map:del(section, self.option)
+function lfp.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
+function lfp.validate(self, value)
+       if not value or (#value < 1) or (value:find("/") ~= 1) then
+               return nil, self.title .. ": " .. translate("no valid path given!")
        end
+       return value
 end
 
 -- file_maxbytes ---------------------------------------------------------------
@@ -634,23 +633,18 @@ lmb.description   = translate("Maximum size of each rotation log-file.")
                .. translate("Setting this parameter to '0' will disable rotation of log-file.")
                .. [[</strong>]]
 lmb.default    = "8196"
-lmb.rmempty    = false
+function lmb.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function lmb.validate(self, value)
        if value then           -- otherwise errors in datatype check
                if DTYP.uinteger(value) then
                        return value
                else
-                       return nil, self.title .. " - " .. translate("Value is not an Integer >= 0 !")
+                       return nil, self.title .. ": " .. translate("Value is not an Integer >= 0 !")
                end
        else
-               return nil, self.title .. " - " .. translate("Value required ! Integer >= 0 !")
-       end
-end
-function lmb.write(self, section, value)
-       if value ~= self.default then
-               return self.map:set(section, self.option, value)
-       else
-               return self.map:del(section, self.option)
+               return nil, self.title .. ": " .. translate("Value required ! Integer >= 0 !")
        end
 end
 
@@ -662,23 +656,18 @@ lbc.description   = translate("Number of backup files of log to create.")
                .. translate("Setting this parameter to '0' will disable rotation of log-file.")
                .. [[</strong>]]
 lbc.default    = "1"
-lbc.rmempty    = false
+function lbc.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 function lbc.validate(self, value)
        if value then           -- otherwise errors in datatype check
                if DTYP.uinteger(value) then
                        return value
                else
-                       return nil, self.title .. " - " .. translate("Value is not an Integer >= 0 !")
+                       return nil, self.title .. ": " .. translate("Value is not an Integer >= 0 !")
                end
        else
-               return nil, self.title .. " - " .. translate("Value required ! Integer >= 0 !")
-       end
-end
-function lbc.write(self, section, value)
-       if value ~= self.default then
-               return self.map:set(section, self.option, value)
-       else
-               return self.map:del(section, self.option)
+               return nil, self.title .. ": " .. translate("Value required ! Integer >= 0 !")
        end
 end
 
@@ -699,14 +688,18 @@ local enr = enc:option( Value, "request" )
 enr.title      = translate("Response Encoding")
 enr.description        = translate("Encoding for responding requests.")
 enr.default    = "utf-8"
-enr.optional   = true
+function enr.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- stock -----------------------------------------------------------------------
 local ens      = enc:option( Value, "stock" )
 ens.title      = translate("Storage Encoding")
 ens.description        = translate("Encoding for storing local collections.")
 ens.default    = "utf-8"
-ens.optional   = true
+function ens.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- cbi-section "Headers" -- ####################################################
 local hea      = m:section( NamedSection, "headers", "setting" )
@@ -724,25 +717,32 @@ end
 local heo      = hea:option( DynamicList, "Access_Control_Allow_Origin" )
 heo.title      = translate("Access-Control-Allow-Origin")
 heo.description        = nil
-heo.default    = "*"
-heo.optional   = true
+function heo.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- Access_Control_Allow_Methods ------------------------------------------------
 local hem      = hea:option( DynamicList, "Access_Control_Allow_Methods" )
 hem.title      = translate("Access-Control-Allow-Methods")
 hem.description        = nil
-hem.optional   = true
+function hem.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- Access_Control_Allow_Headers ------------------------------------------------
 local heh      = hea:option( DynamicList, "Access_Control_Allow_Headers" )
 heh.title      = translate("Access-Control-Allow-Headers")
 heh.description        = nil
-heh.optional   = true
+function heh.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 -- Access_Control_Expose_Headers -----------------------------------------------
 local hee      = hea:option( DynamicList, "Access_Control_Expose_Headers" )
 hee.title      = translate("Access-Control-Expose-Headers")
 hee.description        = nil
-hee.optional   = true
+function hee.parse(self, section, novld)
+       CTRL.value_parse(self, section, novld)
+end
 
 return m
index dbf4ddd..d9ef822 100644 (file)
@@ -4,7 +4,7 @@
 
        // show XHR.poll/XHR.get response on button
        function _data2elements(x) {
-               var btn = document.getElementById("cbid.radicale._system._startstop");
+               var btn = document.getElementById("cbid.radicale.<%=section%>._startstop");
                if ( ! btn ) { return; }        // security check
                if (x.responseText == "0") {
                        btn.value = "<%:Start%>";
        function onclick_startstop(id) {
                // do start/stop
                var btnXHR = new XHR();
-               btnXHR.post('<%=url('admin/services/radicale/startstop')%>', { token: '<%=token%>' },
+               btnXHR.post('<%=url([[admin/services/radicale/startstop]])%>', { token: '<%=token%>' },
                        function(x) { _data2elements(x); }
                );
        }
 
-       XHR.poll(5, '<%=url('admin/services/radicale/status')%>', null,
+       XHR.poll(5, '<%=url([[admin/services/radicale/status]])%>', null,
                function(x, data) { _data2elements(x); }
        );
 
diff --git a/applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm b/applications/luci-app-radicale/luasrc/view/radicale/ro_value.htm
deleted file mode 100644 (file)
index 6e05206..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<%+cbi/valueheader%>
-       <input type="<%=self.password and 'password" class="cbi-input-password' or 'text" class="cbi-input-text' %>" onchange="cbi_d_update(this.id)"<%=
-               attr("name", cbid) .. attr("id", cbid) .. attr("value", self:cfgvalue(section) or self.default) ..
-               ifattr(self.size, "size") .. ifattr(self.placeholder, "placeholder") .. ifattr(self.readonly, "readonly")
-       %> />
-       <% if self.password then %><img src="<%=resource%>/cbi/reload.gif" style="vertical-align:middle" title="<%:Reveal/hide password%>" onclick="var e = document.getElementById('<%=cbid%>'); e.type = (e.type=='password') ? 'text' : 'password';" /><% end %>
-       <% if #self.keylist > 0 or self.datatype then -%>
-       <script type="text/javascript">//<![CDATA[
-               <% if #self.keylist > 0 then -%>
-               cbi_combobox_init('<%=cbid%>', {
-               <%-
-                       for i, k in ipairs(self.keylist) do
-               -%>
-                       <%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%>
-                       <%-if i<#self.keylist then-%>,<%-end-%>
-               <%-
-                       end
-               -%>
-               }, '<%- if not self.rmempty and not self.optional then -%>
-                       <%-: -- Please choose -- -%>
-                       <%- elseif self.placeholder then -%>
-                       <%-= pcdata(self.placeholder) -%>
-               <%- end -%>', '
-               <%- if self.combobox_manual then -%>
-                       <%-=self.combobox_manual-%>
-               <%- else -%>
-                       <%-: -- custom -- -%>
-               <%- end -%>');
-               <%- end %>
-               <% if self.datatype then -%>
-               cbi_validate_field('<%=cbid%>', <%=tostring((self.optional or self.rmempty) == true)%>, '<%=self.datatype:gsub("'", "\\'")%>');
-               <%- end %>
-       //]]></script>
-       <% end -%>
-<%+cbi/valuefooter%>
diff --git a/applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm b/applications/luci-app-radicale/luasrc/view/radicale/tabmap_nsections.htm
new file mode 100644 (file)
index 0000000..45fe60c
--- /dev/null
@@ -0,0 +1,49 @@
+<%- if firstmap and messages then local msg; for _, msg in ipairs(messages) do -%>
+       <div class="errorbox"><%=pcdata(msg)%></div>
+<%- end end -%>
+
+<%-+cbi/apply_xhr-%>
+
+<div class="cbi-map" id="cbi-<%=self.config%>">
+       <% if self.title and #self.title > 0 then %><h2 name="content"><%=self.title%></h2><% end %>
+       <% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
+       <%- if firstmap and applymap then cbi_apply_xhr(self.config, parsechain, redirect) end -%>
+
+       <% if self.tabbed then %>
+               <ul class="cbi-tabmenu map">
+                       <%- self.selected_tab = luci.http.formvalue("tab.m-" .. self.config) %>
+                       <% for i, section in ipairs(self.children) do %>
+                               <%- if not self.selected_tab then self.selected_tab = section.sectiontype end %>
+                               <li id="tab.m-<%=self.config%>.<%=section.section or section.sectiontype%>" class="cbi-tab<%=(section.sectiontype == self.selected_tab) and '' or '-disabled'%>">
+                                       <a onclick="this.blur(); return cbi_t_switch('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')" href="<%=REQUEST_URI%>?tab.m-<%=self.config%>=<%=section.section or section.sectiontype%>"><%=section.title or section.section or section.sectiontype %></a>
+                                       <% if section.sectiontype == self.selected_tab then %><input type="hidden" id="tab.m-<%=self.config%>" name="tab.m-<%=self.config%>" value="<%=section.section or section.sectiontype%>" /><% end %>
+                               </li>
+                       <% end %>
+               </ul>
+               <br />
+               <% for i, section in ipairs(self.children) do %>
+                       <div class="cbi-tabcontainer" id="container.m-<%=self.config%>.<%=section.section or section.sectiontype%>"<% if section.sectiontype ~= self.selected_tab then %> style="display:none"<% end %>>
+                               <% section:render() %>
+                       </div>
+                       <script type="text/javascript">cbi_t_add('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')</script>
+               <% end %>
+
+       <% else %>
+               <%- self:render_children() %>
+       <% end %>
+
+       <% if not self.save then -%>
+               <div class="cbi-section-error">
+                       <% for _, section in ipairs(self.children) do %>
+                               <% if section.error and section.error[section.section] then -%>
+                                       <ul><li>
+                                               <%:One or more missing/invalid fields on tab%>:&nbsp;<%=section.title or section.section or section.sectiontype%>
+                                       </li></ul>
+                               <%- end %>
+                       <% end %>
+               </div>
+       <%- end %>
+
+       <br />
+
+</div>
index 57850dc..ef47988 100644 (file)
@@ -1,15 +1,15 @@
 msgid ""
 msgstr ""
-"Project-Id-Version: luci-app-radicale\n"
-"POT-Creation-Date: 2015-05-02 19:32+0100\n"
-"PO-Revision-Date: 2015-05-02 22:43+0100\n"
-"Last-Translator: Christian Schoenebeck <christian.schoenebeck@gmail.com>\n"
+"Project-Id-Version: luci-app-radicale 1.1.0-1\n"
+"POT-Creation-Date: 2016-01-30 20:34+0100\n"
+"PO-Revision-Date: 2016-01-31 20:49+0100\n"
+"Last-Translator: Christian Schönebeck <christian.schoenebeck@gmail.com>\n"
 "Language-Team: \n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.7.5\n"
+"X-Generator: Poedit 1.8.4\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Poedit-SourceCharset: UTF-8\n"
 
@@ -72,6 +72,9 @@ msgstr ""
 msgid "Auto-start"
 msgstr "Autostart"
 
+msgid "Boot delay"
+msgstr "Systemstart-Verzögerung"
+
 msgid "CalDAV/CardDAV"
 msgstr "CalDAV/CardDAV"
 
@@ -122,6 +125,10 @@ msgstr "Datenbank"
 msgid "Debug"
 msgstr "Debug"
 
+msgid "Delay (in seconds) during system boot before Radicale start"
+msgstr ""
+"Verzögerung (in Sekunden) während des Systemstarts, bevor Radicale startet"
+
 msgid "Directory"
 msgstr "Verzeichnis"
 
@@ -135,6 +142,9 @@ msgid "Directory where the rotating log-files are stored"
 msgstr ""
 "Verzeichnis in dem die rollierenden Protokolldateien gespeichert werden"
 
+msgid "During delay ifup-events are not monitored !"
+msgstr "Während der Verzögerung werden 'ifup'-Ereignisse nicht überwacht!"
+
 msgid "Enable HTTPS"
 msgstr "Verwende HTTPS"
 
@@ -240,6 +250,9 @@ msgstr "Anzahl der Protokoll Backup Dateien, die angelegt werden."
 msgid "OPTIONAL: See python's ssl module for available ciphers"
 msgstr "OPTIONAL: Siehe Python SSL-Modul Dokumentation"
 
+msgid "One or more missing/invalid fields on tab"
+msgstr "Ein oder mehrere fehlende/ungültige Felder auf der Registerkarte"
+
 msgid "Owner allow write, authenticated users allow read"
 msgstr ""
 "Besitzer haben Schreibrechte, Authentifizierten Benutzer dürfen nur lesen."
@@ -324,8 +337,14 @@ msgstr ""
 "Wenn dieser Parameter auf '0' gesetzt wird, wird die Protokolldatei nicht "
 "mehr rolliert!"
 
-msgid "Software package '"
-msgstr "Software Packet '"
+msgid "Software package '%s' is not installed."
+msgstr "Software Paket '%s' ist nicht installiert."
+
+msgid "Software package '%s' is outdated."
+msgstr "Software Paket '%s' ist nicht aktuell."
+
+msgid "Software update required"
+msgstr "Software-Update erforderlich"
 
 msgid "Start"
 msgstr "Start"
@@ -372,9 +391,15 @@ msgid "To view latest log file follow this link!"
 msgstr ""
 "Zur Anzeige der letzten Protokolldatei, folgen Sie dieser Verknüpfung !"
 
+msgid "Value is not a number"
+msgstr "Wert ist keine Zahl"
+
 msgid "Value is not an Integer >= 0 !"
 msgstr "Eingabe ist keine Ganzzahl >= 0 !"
 
+msgid "Value not between 0 and 300"
+msgstr "Wert nicht zwischen 0 und 300"
+
 msgid "Value required ! Integer >= 0 !"
 msgstr "Eingabe erforderlich ! Ganzzahl >= 0 !"
 
@@ -397,6 +422,8 @@ msgid ""
 "You can also get groups from the user regex in the collection with {0}, {1}, "
 "etc."
 msgstr ""
+"Sie können auch Gruppen aus der Benutzer regex in der Sammlung mit {0}, {1} "
+"usw. bekommen."
 
 msgid ""
 "You can use Python's ConfigParser interpolation values %(login)s and "
@@ -416,6 +443,9 @@ msgstr "htpasswd Datei"
 msgid "installed"
 msgstr "installiert"
 
+msgid "no valid path given!"
+msgstr "Keine gültige Pfadangabe!"
+
 msgid "or higher"
 msgstr "oder höher"
 
@@ -427,9 +457,3 @@ msgstr "erforderlich"
 
 msgid "salted SHA-1"
 msgstr "Salted SHA-1"
-
-#~ msgid "File"
-#~ msgstr "Datei"
-
-#~ msgid "not found !"
-#~ msgstr "nicht gefunden !"
index 3b141a2..cf899d8 100644 (file)
@@ -1,5 +1,15 @@
 msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8\n"
+msgstr ""
+"Project-Id-Version: luci-app-radicale 1.1.0-1\n"
+"POT-Creation-Date: 2016-01-30 20:34+0100\n"
+"PO-Revision-Date: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.4\n"
 
 msgid ""
 "'AUTO' selects the highest protocol version that client and server support."
@@ -53,6 +63,9 @@ msgstr "Autentiseringsmetod för att tillåta åtkomst till Radicale-servern."
 msgid "Auto-start"
 msgstr "Starta automatiskt"
 
+msgid "Boot delay"
+msgstr ""
+
 msgid "CalDAV/CardDAV"
 msgstr "CalDAV/CardDAV"
 
@@ -98,6 +111,9 @@ msgstr "Databas"
 msgid "Debug"
 msgstr "Felsök"
 
+msgid "Delay (in seconds) during system boot before Radicale start"
+msgstr ""
+
 msgid "Directory"
 msgstr "Mapp"
 
@@ -110,6 +126,9 @@ msgstr "Mapp krävs !"
 msgid "Directory where the rotating log-files are stored"
 msgstr "Mappen där de roterade logg-filerna lagras"
 
+msgid "During delay ifup-events are not monitored !"
+msgstr ""
+
 msgid "Enable HTTPS"
 msgstr "Aktivera HTTPS"
 
@@ -209,6 +228,9 @@ msgstr ""
 msgid "OPTIONAL: See python's ssl module for available ciphers"
 msgstr "VALFRITT: Kolla in python's ssl-modul för tillgängliga chiffer"
 
+msgid "One or more missing/invalid fields on tab"
+msgstr ""
+
 msgid "Owner allow write, authenticated users allow read"
 msgstr ""
 
@@ -289,8 +311,14 @@ msgstr ""
 "Genom att ställa in den här parametern till '0' så kommer du att stänga av "
 "rotering av logg-fil."
 
-msgid "Software package '"
-msgstr "Mjukvaru-paket '"
+msgid "Software package '%s' is not installed."
+msgstr ""
+
+msgid "Software package '%s' is outdated."
+msgstr ""
+
+msgid "Software update required"
+msgstr ""
 
 msgid "Start"
 msgstr "Starta"
@@ -332,9 +360,15 @@ msgstr "Följ den här länken för att redigera den här filen!"
 msgid "To view latest log file follow this link!"
 msgstr "Följ den här länken för att visa den senaste logg-filen"
 
+msgid "Value is not a number"
+msgstr ""
+
 msgid "Value is not an Integer >= 0 !"
 msgstr "Värdet är inte ett heltal >= 0 !"
 
+msgid "Value not between 0 and 300"
+msgstr ""
+
 msgid "Value required ! Integer >= 0 !"
 msgstr "Värde krävs ! Heltal >= 0 !"
 
@@ -375,6 +409,9 @@ msgstr "htpasswd-fil"
 msgid "installed"
 msgstr "installerad"
 
+msgid "no valid path given!"
+msgstr ""
+
 msgid "or higher"
 msgstr "eller högre"
 
index c5e0797..1c01c4a 100644 (file)
@@ -53,6 +53,9 @@ msgstr ""
 msgid "Auto-start"
 msgstr ""
 
+msgid "Boot delay"
+msgstr ""
+
 msgid "CalDAV/CardDAV"
 msgstr ""
 
@@ -96,6 +99,9 @@ msgstr ""
 msgid "Debug"
 msgstr ""
 
+msgid "Delay (in seconds) during system boot before Radicale start"
+msgstr ""
+
 msgid "Directory"
 msgstr ""
 
@@ -108,6 +114,9 @@ msgstr ""
 msgid "Directory where the rotating log-files are stored"
 msgstr ""
 
+msgid "During delay ifup-events are not monitored !"
+msgstr ""
+
 msgid "Enable HTTPS"
 msgstr ""
 
@@ -207,6 +216,9 @@ msgstr ""
 msgid "OPTIONAL: See python's ssl module for available ciphers"
 msgstr ""
 
+msgid "One or more missing/invalid fields on tab"
+msgstr ""
+
 msgid "Owner allow write, authenticated users allow read"
 msgstr ""
 
@@ -284,7 +296,13 @@ msgstr ""
 msgid "Setting this parameter to '0' will disable rotation of log-file."
 msgstr ""
 
-msgid "Software package '"
+msgid "Software package '%s' is not installed."
+msgstr ""
+
+msgid "Software package '%s' is outdated."
+msgstr ""
+
+msgid "Software update required"
 msgstr ""
 
 msgid "Start"
@@ -327,9 +345,15 @@ msgstr ""
 msgid "To view latest log file follow this link!"
 msgstr ""
 
+msgid "Value is not a number"
+msgstr ""
+
 msgid "Value is not an Integer >= 0 !"
 msgstr ""
 
+msgid "Value not between 0 and 300"
+msgstr ""
+
 msgid "Value required ! Integer >= 0 !"
 msgstr ""
 
@@ -368,6 +392,9 @@ msgstr ""
 msgid "installed"
 msgstr ""
 
+msgid "no valid path given!"
+msgstr ""
+
 msgid "or higher"
 msgstr ""