[for-15.05] luci-app-radicale: copied from master

Initial release
with fixed function ipkg_ver_compare()

Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
This commit is contained in:
Christian Schoenebeck 2015-06-16 17:30:50 +02:00
parent f27ebb620c
commit aff488d5d1
8 changed files with 1896 additions and 0 deletions

View file

@ -0,0 +1,41 @@
#
# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-radicale
# Version == major.minor.patch
# increase "minor" on new functionality and "patch" on patches/optimization
PKG_VERSION:=1.0.1
# Release == build
# increase on changes of translation files
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Christian Schoenebeck <christian.schoenebeck@gmail.com>
# LuCI specific settings
LUCI_TITLE:=LuCI Support for Radicale CardDAV/CalDAV
LUCI_DEPENDS:=+luci-mod-admin-full
LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/config
# shown in make menuconfig <Help>
help
$(LUCI_TITLE)
.
!!! Package "radicale-py2" or "radicale-py3" needs to be !!!
!!! installed sepearatly. There is no buildin dependency set !!!
.
Version: $(PKG_VERSION)-$(PKG_RELEASE)
$(PKG_MAINTAINER)
endef
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View file

@ -0,0 +1,195 @@
-- Copyright 2014 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 I18N = require("luci.i18n") -- not globally avalible here
local UTIL = require("luci.util")
local SYS = require("luci.sys")
function index()
entry( {"admin", "services", "radicale"}, alias("admin", "services", "radicale", "edit"), _("CalDAV/CardDAV"), 58)
entry( {"admin", "services", "radicale", "edit"}, cbi("radicale") ).leaf = true
entry( {"admin", "services", "radicale", "logview"}, call("_logread") ).leaf = true
entry( {"admin", "services", "radicale", "startstop"}, call("_startstop") ).leaf = true
entry( {"admin", "services", "radicale", "status"}, call("_status") ).leaf = true
end
-- called by XHR.get from detail_logview.htm
function _logread()
-- read application settings
local uci = UCI.cursor()
local logfile = uci:get("radicale", "radicale", "logfile") or "/var/log/radicale"
uci:unload("radicale")
local ldata=NXFS.readfile(logfile)
if not ldata or #ldata == 0 then
ldata="_nodata_"
end
HTTP.write(ldata)
end
-- called by XHR.get from detail_startstop.htm
function _startstop()
local pid = get_pid()
if pid > 0 then
SYS.call("/etc/init.d/radicale stop")
NX.nanosleep(1) -- sleep a second
if NX.kill(pid, 0) then -- still running
NX.kill(pid, 9) -- send SIGKILL
end
pid = 0
else
SYS.call("/etc/init.d/radicale start")
NX.nanosleep(1) -- sleep a second
pid = get_pid()
if pid > 0 and not NX.kill(pid, 0) then
pid = 0 -- process did not start
end
end
HTTP.write(tostring(pid)) -- HTTP needs string not number
end
-- called by XHR.poll from detail_startstop.htm
function _status()
local pid = get_pid()
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><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")
end
function app_title_back()
return [[</a><a href="]]
.. DISP.build_url("admin", "services", "radicale")
.. [[">]]
.. I18N.translate("Radicale CalDAV/CardDAV Server")
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
end
-- all equal and not compare greater or lower then true
return not (comp == "<" or comp == ">")
end
-- 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()
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)
end
if (fvalue ~= cvalue) then self.section.changed = true end
else
self:remove(section)
self.section.changed = true
end
end

View file

@ -0,0 +1,748 @@
-- Copyright 2015 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
-- #################################################################################################
-- takeover arguments if any -- ################################################
-- then show/edit selected file
if arg[1] then
local argument = arg[1]
local filename = ""
-- SimpleForm ------------------------------------------------
local ft = SimpleForm("_text")
ft.title = TOOLS.app_title_back()
ft.description = TOOLS.app_description()
ft.redirect = DISP.build_url("admin", "services", "radicale") .. "#cbi-radicale-" .. argument
if argument == "logger" then
ft.reset = false
ft.submit = translate("Reload")
local uci = UCI.cursor()
filename = uci:get("radicale", "logger", "file_path") or "/var/log/radicale"
uci:unload("radicale")
filename = filename .. "/radicale"
elseif argument == "auth" then
ft.submit = translate("Save")
filename = "/etc/radicale/users"
elseif argument == "rights" then
ft.submit = translate("Save")
filename = "/etc/radicale/rights"
else
error("Invalid argument given as section")
end
if argument ~= "logger" and not NXFS.access(filename) then
NXFS.writefile(filename, "")
end
-- SimpleSection ---------------------------------------------
local fs = ft:section(SimpleSection)
if argument == "logger" then
fs.title = translate("Log-file Viewer")
fs.description = translate("Please press [Reload] button below to reread the file.")
elseif argument == "auth" then
fs.title = translate("Authentication")
fs.description = translate("Place here the 'user:password' pairs for your users which should have access to Radicale.")
.. [[<br /><strong>]]
.. translate("Keep in mind to use the correct hashing algorithm !")
.. [[</strong>]]
else -- rights
fs.title = translate("Rights")
fs.description = translate("Authentication login is matched against the 'user' key, "
.. "and collection's path is matched against the 'collection' key.") .. " "
.. translate("You can use Python's ConfigParser interpolation values %(login)s and %(path)s.") .. " "
.. translate("You can also get groups from the user regex in the collection with {0}, {1}, etc.")
.. [[<br />]]
.. translate("For example, for the 'user' key, '.+' means 'authenticated user'" .. " "
.. "and '.*' means 'anybody' (including anonymous users).")
.. [[<br />]]
.. translate("Section names are only used for naming the rule.")
.. [[<br />]]
.. translate("Leading or ending slashes are trimmed from collection's path.")
end
-- TextValue -------------------------------------------------
local tt = fs:option(TextValue, "_textvalue")
tt.rmempty = true
if argument == "logger" then
tt.readonly = true
tt.rows = 30
function tt.write()
HTTP.redirect(DISP.build_url("admin", "services", "radicale", "edit", argument))
end
else
tt.rows = 15
function tt.write(self, section, value)
if not value then value = "" end
NXFS.writefile(filename, value:gsub("\r\n", "\n"))
return true --HTTP.redirect(DISP.build_url("admin", "services", "radicale", "edit") .. "#cbi-radicale-" .. argument)
end
end
function tt.cfgvalue()
return NXFS.readfile(filename) or
string.format(translate("File '%s' not found !"), filename)
end
return ft
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()
function m.commit_handler(self)
if self.changed then -- changes ?
os.execute("/etc/init.d/radicale reload &") -- reload configuration
end
end
-- cbi-section "System" -- #####################################################
local sys = m:section( NamedSection, "_system" )
sys.title = translate("System")
sys.description = nil
function sys.cfgvalue(self, section)
return "_dummysection"
end
-- start/stop button -----------------------------------------------------------
local btn = sys:option(DummyValue, "_startstop")
btn.template = "radicale/btn_startstop"
btn.inputstyle = nil
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)
if pid > 0 then
btn.inputtitle = "PID: " .. pid
btn.inputstyle = "reset"
btn.disabled = false
else
btn.inputtitle = translate("Start")
btn.inputstyle = "apply"
btn.disabled = false
end
return true
end
-- enabled ---------------------------------------------------------------------
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
function ena.cfgvalue(self, section)
return (SYS.init.enabled("radicale")) and "1" or "0"
end
function ena.write(self, section, value)
if value == "1" then
return SYS.init.enable("radicale")
else
return SYS.init.disable("radicale")
end
end
-- cbi-section "Server" -- #####################################################
local srv = m:section( NamedSection, "server", "setting" )
srv.title = translate("Server")
srv.description = nil
function srv.cfgvalue(self, section)
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
-- hosts -----------------------------------------------------------------------
local sh = srv:option( DynamicList, "hosts" )
sh.title = translate("Address:Port")
sh.description = translate("'Hostname:Port' or 'IPv4:Port' or '[IPv6]:Port' Radicale should listen on")
.. [[<br /><strong>]]
.. translate("Port numbers below 1024 (Privileged ports) are not supported")
.. [[</strong>]]
sh.placeholder = "0.0.0.0:5232"
sh.rmempty = true
-- 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
end
function alm.validate(self, value)
if value then
return value
else
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
self.map:del(section, "certificate") -- certificate
self.map:del(section, "key") -- private key
self.map:del(section, "ciphers") -- ciphers
return self.map:del(section, self.option)
else
return self.map:set(section, self.option, value)
end
end
-- protocol --------------------------------------------------------------------
local prt = srv:option( ListValue, "protocol" )
prt.title = translate("SSL Protocol")
prt.description = translate("'AUTO' selects the highest protocol version that client and server support.")
prt.widget = "select"
prt.default = "PROTOCOL_SSLv23"
prt:depends ("ssl", "1")
prt:value ("PROTOCOL_SSLv23", translate("AUTO"))
prt:value ("PROTOCOL_SSLv2", "SSL v2")
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")
-- 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
end
function crt.validate(self, value)
local _ssl = ssl:formvalue(srv.section) or "0"
if _ssl == "0" then
return "" -- ignore if not https enabled
end
if value then -- otherwise errors in datatype check
if DTYP.file(value) then
return value
else
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)
end
end
-- key -------------------------------------------------------------------------
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
end
function key.validate(self, value)
local _ssl = ssl:formvalue(srv.section) or "0"
if _ssl == "0" then
return "" -- ignore if not https enabled
end
if value then -- otherwise errors in datatype check
if DTYP.file(value) then
return value
else
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)
end
end
-- ciphers ---------------------------------------------------------------------
--local cip = srv:option( Value, "ciphers" )
--cip.title = translate("Ciphers")
--cip.description = translate("OPTIONAL: See python's ssl module for available ciphers")
--cip.rmempty = true
--cip:depends ("ssl", "1")
-- cbi-section "Authentication" -- #############################################
local aut = m:section( NamedSection, "auth", "setting" )
aut.title = translate("Authentication")
aut.description = translate("Authentication method to allow access to Radicale server.")
function aut.cfgvalue(self, section)
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
-- type -----------------------------------------------------------------------
local aty = aut:option( ListValue, "type" )
aty.title = translate("Authentication method")
aty.description = nil
aty.widget = "select"
aty.default = "None"
aty:value ("None", translate("None"))
aty:value ("htpasswd", translate("htpasswd file"))
--aty:value ("IMAP", "IMAP") -- The IMAP authentication module relies on the imaplib module.
--aty:value ("LDAP", "LDAP") -- The LDAP authentication module relies on the python-ldap module.
--aty:value ("PAM", "PAM") -- The PAM authentication module relies on the python-pam module.
--aty:value ("courier", "courier")
--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.write(self, section, value)
if value ~= "htpasswd" then
self.map:del(section, "htpasswd_encryption")
elseif value ~= "IMAP" then
self.map:del(section, "imap_hostname")
self.map:del(section, "imap_port")
self.map:del(section, "imap_ssl")
end
if value ~= self.default then
return self.map:set(section, self.option, value)
else
return self.map:del(section, self.option)
end
end
-- htpasswd_encryption ---------------------------------------------------------
local hte = aut:option( ListValue, "htpasswd_encryption" )
hte.title = translate("Encryption method")
hte.description = nil
hte.widget = "select"
hte.default = "crypt"
hte:depends ("type", "htpasswd")
hte:value ("crypt", translate("crypt"))
hte:value ("plain", translate("plain"))
hte:value ("sha1", translate("SHA-1"))
hte:value ("ssha", translate("salted SHA-1"))
-- htpasswd_file (dummy) -------------------------------------------------------
local htf = aut:option( DummyValue, "_htf" )
htf.title = translate("htpasswd file")
htf.description = [[<strong>]]
.. translate("Read only!")
.. [[</strong> ]]
.. translate("Radicale uses '/etc/radicale/users' as htpasswd file.")
.. [[<br /><a href="]]
.. DISP.build_url("admin", "services", "radicale", "edit") .. [[/auth]]
.. [[">]]
.. 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()
return "/etc/radicale/users"
end
-- cbi-section "Rights" -- #####################################################
local rig = m:section( NamedSection, "rights", "setting" )
rig.title = translate("Rights")
rig.description = translate("Control the access to data collections.")
function rig.cfgvalue(self, section)
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
-- type -----------------------------------------------------------------------
local rty = rig:option( ListValue, "type" )
rty.title = translate("Rights backend")
rty.description = nil
rty.widget = "select"
rty.default = "None"
rty:value ("None", translate("Full access for everybody (including anonymous)"))
rty:value ("authenticated", translate("Full access for authenticated Users") )
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.write(self, section, value)
if value ~= "custom" then
self.map:del(section, "custom_handler")
end
if value ~= self.default then
return self.map:set(section, self.option, value)
else
return self.map:del(section, self.option)
end
end
-- from_file (dummy) -----------------------------------------------------------
local rtf = rig:option( DummyValue, "_rtf" )
rtf.title = translate("RegExp file")
rtf.description = [[<strong>]]
.. translate("Read only!")
.. [[</strong> ]]
.. translate("Radicale uses '/etc/radicale/rights' as regexp-based file.")
.. [[<br /><a href="]]
.. DISP.build_url("admin", "services", "radicale", "edit") .. [[/rights]]
.. [[">]]
.. 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()
return "/etc/radicale/rights"
end
-- cbi-section "Storage" -- ####################################################
local sto = m:section( NamedSection, "storage", "setting" )
sto.title = translate("Storage")
sto.description = nil
function sto.cfgvalue(self, section)
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
-- type -----------------------------------------------------------------------
local sty = sto:option( ListValue, "type" )
sty.title = translate("Storage backend")
sty.description = translate("WARNING: Only 'File-system' is documented and tested by Radicale development")
sty.widget = "select"
sty.default = "filesystem"
sty:value ("filesystem", translate("File-system"))
--sty:value ("multifilesystem", translate("") )
--sty:value ("database", translate("Database") )
--sty:value ("custom", translate("Custom") )
function sty.write(self, section, value)
if value ~= "filesystem" then
self.map:del(section, "filesystem_folder")
end
if value ~= self.default then
return self.map:set(section, self.option, value)
else
return self.map:del(section, self.option)
end
end
--filesystem_folder ------------------------------------------------------------
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: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
end
function sfi.validate(self, value)
local _typ = sty:formvalue(sto.section) or ""
if _typ ~= "filesystem" then
return "" -- ignore if not htpasswd
end
if value then -- otherwise errors in datatype check
if DTYP.directory(value) then
return value
else
return nil, self.title .. " - " .. translate("Directory not exists/found !")
end
else
return nil, self.title .. " - " .. translate("Directory required !")
end
end
-- cbi-section "Logging" -- ####################################################
local log = m:section( NamedSection, "logger", "logging" )
log.title = translate("Logging")
log.description = nil
function log.cfgvalue(self, section)
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
-- console_level ---------------------------------------------------------------
local lco = log:option( ListValue, "console_level" )
lco.title = translate("Console Log level")
lco.description = nil
lco.widget = "select"
lco.default = "ERROR"
lco:value ("DEBUG", translate("Debug"))
lco:value ("INFO", translate("Info") )
lco:value ("WARNING", translate("Warning") )
lco:value ("ERROR", translate("Error") )
lco:value ("CRITICAL", translate("Critical") )
function lco.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
-- syslog_level ----------------------------------------------------------------
local lsl = log:option( ListValue, "syslog_level" )
lsl.title = translate("Syslog Log level")
lsl.description = nil
lsl.widget = "select"
lsl.default = "WARNING"
lsl:value ("DEBUG", translate("Debug"))
lsl:value ("INFO", translate("Info") )
lsl:value ("WARNING", translate("Warning") )
lsl:value ("ERROR", translate("Error") )
lsl:value ("CRITICAL", translate("Critical") )
function lsl.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
-- file_level ------------------------------------------------------------------
local lfi = log:option( ListValue, "file_level" )
lfi.title = translate("File Log level")
lfi.description = nil
lfi.widget = "select"
lfi.default = "INFO"
lfi:value ("DEBUG", translate("Debug"))
lfi:value ("INFO", translate("Info") )
lfi:value ("WARNING", translate("Warning") )
lfi:value ("ERROR", translate("Error") )
lfi:value ("CRITICAL", translate("Critical") )
function lfi.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
-- file_path -------------------------------------------------------------------
local lfp = log:option( Value, "file_path" )
lfp.title = translate("Log-file directory")
lfp.description = translate("Directory where the rotating log-files are stored")
.. [[<br /><a href="]]
.. DISP.build_url("admin", "services", "radicale", "edit") .. [[/logger]]
.. [[">]]
.. 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)
end
end
-- file_maxbytes ---------------------------------------------------------------
local lmb = log:option( Value, "file_maxbytes" )
lmb.title = translate("Log-file size")
lmb.description = translate("Maximum size of each rotation log-file.")
.. [[<br /><strong>]]
.. translate("Setting this parameter to '0' will disable rotation of log-file.")
.. [[</strong>]]
lmb.default = "8196"
lmb.rmempty = false
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 !")
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)
end
end
-- file_backupcount ------------------------------------------------------------
local lbc = log:option( Value, "file_backupcount" )
lbc.title = translate("Log-backup Count")
lbc.description = translate("Number of backup files of log to create.")
.. [[<br /><strong>]]
.. translate("Setting this parameter to '0' will disable rotation of log-file.")
.. [[</strong>]]
lbc.default = "1"
lbc.rmempty = false
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 !")
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)
end
end
-- cbi-section "Encoding" -- ###################################################
local enc = m:section( NamedSection, "encoding", "setting" )
enc.title = translate("Encoding")
enc.description = translate("Change here the encoding Radicale will use instead of 'UTF-8' "
.. "for responses to the client and/or to store data inside collections.")
function enc.cfgvalue(self, section)
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
-- request ---------------------------------------------------------------------
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
-- 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
-- cbi-section "Headers" -- ####################################################
local hea = m:section( NamedSection, "headers", "setting" )
hea.title = translate("Additional HTTP headers")
hea.description = translate("Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts, JavaScript, etc.) "
.. "on a web page to be requested from another domain outside the domain from which the resource originated.")
function hea.cfgvalue(self, section)
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
-- Access_Control_Allow_Origin -------------------------------------------------
local heo = hea:option( DynamicList, "Access_Control_Allow_Origin" )
heo.title = translate("Access-Control-Allow-Origin")
heo.description = nil
heo.default = "*"
heo.optional = true
-- 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
-- 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
-- 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
return m

View file

@ -0,0 +1,49 @@
<!-- ++ BEGIN ++ Radicale ++ btn_startstop.htm ++ -->
<script type="text/javascript">//<![CDATA[
// show XHR.poll/XHR.get response on button
function _data2elements(x) {
var btn = document.getElementById("cbid.radicale._system._startstop");
if ( ! btn ) { return; } // security check
if (x.responseText == "0") {
btn.value = "<%:Start%>";
btn.className = "cbi-button cbi-button-apply";
btn.disabled = false;
} else {
btn.value = "PID: " + x.responseText;
btn.className = "cbi-button cbi-button-reset";
btn.disabled = false;
}
}
// event handler for start/stop button
function onclick_startstop(id) {
// do start/stop
var btnXHR = new XHR();
btnXHR.get('<%=luci.dispatcher.build_url("admin", "services", "radicale", "startstop")%>', null,
function(x) { _data2elements(x); }
);
}
XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "services", "radicale", "status")%>', null,
function(x, data) { _data2elements(x); }
);
//]]></script>
<%+cbi/valueheader%>
<% if self:cfgvalue(section) ~= false then
-- We need to garantie that function cfgvalue run first to set missing parameters
%>
<!-- style="font-size: 100%;" needed for openwrt theme to fix font size -->
<!-- type="button" onclick="..." enable standard onclick functionalty -->
<input class="cbi-button cbi-input-<%=self.inputstyle or "button" %>" style="font-size: 100%;" type="button" onclick="onclick_startstop(this.id)"
<%=
attr("name", section) .. attr("id", cbid) .. attr("value", self.inputtitle) .. ifattr(self.disabled, "disabled")
%> />
<% end %>
<%+cbi/valuefooter%>
<!-- ++ END ++ Radicale ++ btn_startstop.htm ++ -->

View file

@ -0,0 +1,35 @@
<%+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%>

View file

@ -0,0 +1,435 @@
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"
"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"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
msgid ""
"'AUTO' selects the highest protocol version that client and server support."
msgstr ""
"'AUTO' wählt die höchste Protokollversion, die Client und Server "
"unterstützen."
msgid ""
"'Hostname:Port' or 'IPv4:Port' or '[IPv6]:Port' Radicale should listen on"
msgstr ""
"'Hostname:Port' oder 'IPv4:Port' oder '[IPv6]:Port' die Radicale überwachen "
"soll."
msgid "-- Please choose --"
msgstr "-- Bitte auswählen --"
msgid "-- custom --"
msgstr "-- benutzerdefiniert --"
msgid "AUTO"
msgstr "AUTO"
msgid "Access-Control-Allow-Headers"
msgstr "Access-Control-Allow-Headers"
msgid "Access-Control-Allow-Methods"
msgstr "Access-Control-Allow-Methods"
msgid "Access-Control-Allow-Origin"
msgstr "Access-Control-Allow-Origin"
msgid "Access-Control-Expose-Headers"
msgstr "Access-Control-Expose-Headers"
msgid "Additional HTTP headers"
msgstr "Zusätzliche HTTP headers"
msgid "Address:Port"
msgstr "Adresse:Port"
msgid "Authentication"
msgstr "Authentifizierung"
msgid ""
"Authentication login is matched against the 'user' key, and collection's "
"path is matched against the 'collection' key."
msgstr ""
"Der Login wird gegen die 'user' Schlüssel und die Pfadsammlung gegen die "
"'collection' Schlüssel abgestimmt."
msgid "Authentication method"
msgstr "Authentifizierungsmethode"
msgid "Authentication method to allow access to Radicale server."
msgstr ""
"Authentifizierungsmethode um den Zugang zum Radicale Server zu kontrollieren."
msgid "Auto-start"
msgstr "Autostart"
msgid "CalDAV/CardDAV"
msgstr "CalDAV/CardDAV"
msgid ""
"Calendars and address books are available for both local and remote access, "
"possibly limited through authentication policies."
msgstr ""
"Auf Kalender und Adressbücher kann sowohl Lokal als auch Remote zugegriffen "
"werden, soweit nicht durch Authentifizierungsrichtlinien begrenzt."
msgid "Certificate file"
msgstr "Zertifikat Datei"
msgid ""
"Change here the encoding Radicale will use instead of 'UTF-8' for responses "
"to the client and/or to store data inside collections."
msgstr ""
"Ändern Sie hier die Zeichenkodierung die Radicale anstelle von \"UTF-8\" für "
"Antworten an den Client und/oder zum Speichern von Daten in einer Sammlung "
"verwendet."
msgid "Ciphers"
msgstr "Chiffren"
msgid "Console Log level"
msgstr "Konsole Protokoll Level"
msgid "Control the access to data collections."
msgstr "Kontrolliert den Zugriff auf die Daten Sammlungen."
msgid "Critical"
msgstr "Kritisch"
msgid ""
"Cross-origin resource sharing (CORS) is a mechanism that allows restricted "
"resources (e.g. fonts, JavaScript, etc.) on a web page to be requested from "
"another domain outside the domain from which the resource originated."
msgstr ""
"Cross-Origin Resource Sharing (CORS) ist ein Mechanismus, um Webbrowsern "
"oder auch anderen Webclients Cross-Origin-Requests zu ermöglichen."
msgid "Custom"
msgstr "Benutzerdefiniert"
msgid "Database"
msgstr "Datenbank"
msgid "Debug"
msgstr "Debug"
msgid "Directory"
msgstr "Verzeichnis"
msgid "Directory not exists/found !"
msgstr "Verzeichnis nicht gefunden / existiert nicht !"
msgid "Directory required !"
msgstr "Verzeichnis benötigt !"
msgid "Directory where the rotating log-files are stored"
msgstr ""
"Verzeichnis in dem die rollierenden Protokolldateien gespeichert werden"
msgid "Enable HTTPS"
msgstr "Verwende HTTPS"
msgid ""
"Enable/Disable auto-start of Radicale on system start-up and interface events"
msgstr ""
"Aktiviert/Deaktiviert den Autostart von Radicale beim Systemstart und bei "
"Schnittstellenereignissen."
msgid "Encoding"
msgstr "Zeichenkodierung"
msgid "Encoding for responding requests."
msgstr "Zeichenkodierung für die Beantwortung von Anfragen."
msgid "Encoding for storing local collections."
msgstr "Zeichenkodierung für die Speicherung von lokalen Sammlungen."
msgid "Encryption method"
msgstr "Verschlüsselungsmethode"
msgid "Error"
msgstr "Fehler"
msgid "File '%s' not found !"
msgstr "Datei '%s' wurde nicht gefunden!"
msgid "File Log level"
msgstr "Datei Protokoll Level"
msgid "File not found !"
msgstr "Datei nicht gefunden !"
msgid "File-system"
msgstr "Dateisystem"
msgid ""
"For example, for the 'user' key, '.+' means 'authenticated user' and '.*' "
"means 'anybody' (including anonymous users)."
msgstr ""
"Beispiel für den 'user' Schlüssel: '. +' bedeutet 'authentifizierten "
"Benutzer' und '. *' bedeutet 'jeder' (einschließlich anonyme Benutzer)."
msgid "Full access for Owner only"
msgstr "Voller Zugriff nur für den Besitzer"
msgid "Full access for authenticated Users"
msgstr "Voller Zugriff für authentifizierte Benutzer"
msgid "Full access for everybody (including anonymous)"
msgstr "Vollzugriff für jedermann (auch anonyme)"
msgid "Full path and file name of certificate"
msgstr "Vollständiger Pfad und Dateiname der Zertifikat Datei"
msgid "Full path and file name of private key"
msgstr "Vollständiger Pfad und Dateiname der Privaten Schlüsseldatei"
msgid "Info"
msgstr "Informationen"
msgid "Keep in mind to use the correct hashing algorithm !"
msgstr "Denken Sie daran, den korrekten Hash-Algorithmus zu verwenden!"
msgid "Leading or ending slashes are trimmed from collection's path."
msgstr ""
"Schrägstriche ('/') am Anfang und Ende der Pfadangabe der Sammlung werden "
"von der Pfadangabe abgeschnitten."
msgid "Log-backup Count"
msgstr "Protokoll Backup Zähler"
msgid "Log-file Viewer"
msgstr "Protokolldatei Betrachter"
msgid "Log-file directory"
msgstr "Protokoll-Datei Verzeichnis"
msgid "Log-file size"
msgstr "Protokoll Dateigröße"
msgid "Logging"
msgstr "Protokollierung"
msgid "Logon message"
msgstr "Anmelde-Hinweis"
msgid "Maximum size of each rotation log-file."
msgstr "Maximale Größe jeder rollierenden Protokoll-Datei."
msgid "Message displayed in the client when a password is needed."
msgstr "Meldung im Client, wenn ein Kennwort erforderlich ist."
msgid "NOT installed"
msgstr "nicht installiert"
msgid "None"
msgstr "Keine"
msgid "Number of backup files of log to create."
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 "Owner allow write, authenticated users allow read"
msgstr ""
"Besitzer haben Schreibrechte, Authentifizierten Benutzer dürfen nur lesen."
msgid "Path/File required !"
msgstr "Pfad/Datei erforderlich!"
msgid ""
"Place here the 'user:password' pairs for your users which should have access "
"to Radicale."
msgstr ""
"Speichern Sie hier die 'user: password' Paare für die Benutzer, die Zugriff "
"auf Radicale haben sollte."
msgid "Please install current version !"
msgstr "Installieren Sie bitte die aktuelle Version!"
msgid "Please press [Reload] button below to reread the file."
msgstr ""
"Bitte drücken Sie die [Neu laden]-Schaltfläche unten, um die Datei neu "
"einzulesen."
msgid "Please update to current version !"
msgstr "Aktualisieren Sie bitte auf die aktuelle Version!"
msgid "Port numbers below 1024 (Privileged ports) are not supported"
msgstr "Port Nummern unter 1024 (Privileged Ports) werden nicht unterstützt."
msgid "Private key file"
msgstr "Private Schlüssel Datei"
msgid "Radicale CalDAV/CardDAV Server"
msgstr "Radicale CalDAV/CardDAV Dienst"
msgid "Radicale uses '/etc/radicale/rights' as regexp-based file."
msgstr "Radicale verwendet '/etc/radicale/rights' als RegExp-basierte Datei."
msgid "Radicale uses '/etc/radicale/users' as htpasswd file."
msgstr "Radicale verwendet 'etc/radicale/users' als htpasswd Datei."
msgid "Read only!"
msgstr "Nur lesbar!"
msgid "RegExp file"
msgstr "RegExp Datei"
msgid "Reload"
msgstr "Neu laden"
msgid "Response Encoding"
msgstr "Antwort Zeichenkodierung"
msgid "Reveal/hide password"
msgstr "Passwort zeigen/verstecken"
msgid "Rights"
msgstr "Zugriffsrechte"
msgid "Rights are based on a regexp-based file"
msgstr "Zugriff basiert auf RegExp-basierter Datei."
msgid "Rights backend"
msgstr "Zugagsverwaltung"
msgid "SHA-1"
msgstr "SHA-1"
msgid "SSL Protocol"
msgstr "SSL Protokol"
msgid "Save"
msgstr "Speichern"
msgid "Section names are only used for naming the rule."
msgstr "Abschnittsnamen werden nur für die Benennung der Regel verwendet."
msgid "Server"
msgstr "Server"
msgid "Setting this parameter to '0' will disable rotation of log-file."
msgstr ""
"Wenn dieser Parameter auf '0' gesetzt wird, wird die Protokolldatei nicht "
"mehr rolliert!"
msgid "Software package '"
msgstr "Software Packet '"
msgid "Start"
msgstr "Start"
msgid "Start / Stop"
msgstr "Start / Stopp"
msgid "Start/Stop Radicale server"
msgstr "Start / Stopp Radicale Dienst"
msgid "Storage"
msgstr "Datenspeicher"
msgid "Storage Encoding"
msgstr "Datenspeicher Kodierung"
msgid "Storage backend"
msgstr "Datenspeicher Verwaltung"
msgid "Syslog Log level"
msgstr "Systemlog Level"
msgid "System"
msgstr "System"
msgid ""
"The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) "
"server solution."
msgstr ""
"Das Raidcale Projekt bietet eine vollständige CalDAV (Kalender) und CardDAV "
"(Adressbuch) Server Lösung."
msgid ""
"They can be viewed and edited by calendar and contact clients on mobile "
"phones or computers."
msgstr ""
"Diese können von Kalender- und Adressbuch-Anwendungen auf mobilen Endgeräten "
"und Computern angezeigt und bearbeitet werden."
msgid "To edit the file follow this link!"
msgstr "Um die Datei zu bearbeiten, folgend Sie dieser Verknüpfung!"
msgid "To view latest log file follow this link!"
msgstr ""
"Zur Anzeige der letzten Protokolldatei, folgen Sie dieser Verknüpfung !"
msgid "Value is not an Integer >= 0 !"
msgstr "Eingabe ist keine Ganzzahl >= 0 !"
msgid "Value required ! Integer >= 0 !"
msgstr "Eingabe erforderlich ! Ganzzahl >= 0 !"
msgid "Version"
msgstr "Version"
msgid "Version Information"
msgstr "Versionsinformationen"
msgid ""
"WARNING: Only 'File-system' is documented and tested by Radicale development"
msgstr ""
"WARNUNG: Nur 'File-system' ist vom Radicale Entwicklerteam derzeit "
"dokumentiert und getestet."
msgid "Warning"
msgstr "Warnung"
msgid ""
"You can also get groups from the user regex in the collection with {0}, {1}, "
"etc."
msgstr ""
msgid ""
"You can use Python's ConfigParser interpolation values %(login)s and "
"%(path)s."
msgstr ""
"Sie können Python ConfigParser Werte '%(login)s' und '%(path)s' verwenden."
msgid "crypt"
msgstr "crypt"
msgid "custom"
msgstr "benutzerdefiniert"
msgid "htpasswd file"
msgstr "htpasswd Datei"
msgid "installed"
msgstr "installiert"
msgid "or higher"
msgstr "oder höher"
msgid "plain"
msgstr "unverschlüsselt"
msgid "required"
msgstr "erforderlich"
msgid "salted SHA-1"
msgstr "Salted SHA-1"
#~ msgid "File"
#~ msgstr "Datei"
#~ msgid "not found !"
#~ msgstr "nicht gefunden !"

View file

@ -0,0 +1,381 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid ""
"'AUTO' selects the highest protocol version that client and server support."
msgstr ""
msgid ""
"'Hostname:Port' or 'IPv4:Port' or '[IPv6]:Port' Radicale should listen on"
msgstr ""
msgid "-- Please choose --"
msgstr ""
msgid "-- custom --"
msgstr ""
msgid "AUTO"
msgstr ""
msgid "Access-Control-Allow-Headers"
msgstr ""
msgid "Access-Control-Allow-Methods"
msgstr ""
msgid "Access-Control-Allow-Origin"
msgstr ""
msgid "Access-Control-Expose-Headers"
msgstr ""
msgid "Additional HTTP headers"
msgstr ""
msgid "Address:Port"
msgstr ""
msgid "Authentication"
msgstr ""
msgid ""
"Authentication login is matched against the 'user' key, and collection's "
"path is matched against the 'collection' key."
msgstr ""
msgid "Authentication method"
msgstr ""
msgid "Authentication method to allow access to Radicale server."
msgstr ""
msgid "Auto-start"
msgstr ""
msgid "CalDAV/CardDAV"
msgstr ""
msgid ""
"Calendars and address books are available for both local and remote access, "
"possibly limited through authentication policies."
msgstr ""
msgid "Certificate file"
msgstr ""
msgid ""
"Change here the encoding Radicale will use instead of 'UTF-8' for responses "
"to the client and/or to store data inside collections."
msgstr ""
msgid "Ciphers"
msgstr ""
msgid "Console Log level"
msgstr ""
msgid "Control the access to data collections."
msgstr ""
msgid "Critical"
msgstr ""
msgid ""
"Cross-origin resource sharing (CORS) is a mechanism that allows restricted "
"resources (e.g. fonts, JavaScript, etc.) on a web page to be requested from "
"another domain outside the domain from which the resource originated."
msgstr ""
msgid "Custom"
msgstr ""
msgid "Database"
msgstr ""
msgid "Debug"
msgstr ""
msgid "Directory"
msgstr ""
msgid "Directory not exists/found !"
msgstr ""
msgid "Directory required !"
msgstr ""
msgid "Directory where the rotating log-files are stored"
msgstr ""
msgid "Enable HTTPS"
msgstr ""
msgid ""
"Enable/Disable auto-start of Radicale on system start-up and interface events"
msgstr ""
msgid "Encoding"
msgstr ""
msgid "Encoding for responding requests."
msgstr ""
msgid "Encoding for storing local collections."
msgstr ""
msgid "Encryption method"
msgstr ""
msgid "Error"
msgstr ""
msgid "File '%s' not found !"
msgstr ""
msgid "File Log level"
msgstr ""
msgid "File not found !"
msgstr ""
msgid "File-system"
msgstr ""
msgid ""
"For example, for the 'user' key, '.+' means 'authenticated user' and '.*' "
"means 'anybody' (including anonymous users)."
msgstr ""
msgid "Full access for Owner only"
msgstr ""
msgid "Full access for authenticated Users"
msgstr ""
msgid "Full access for everybody (including anonymous)"
msgstr ""
msgid "Full path and file name of certificate"
msgstr ""
msgid "Full path and file name of private key"
msgstr ""
msgid "Info"
msgstr ""
msgid "Keep in mind to use the correct hashing algorithm !"
msgstr ""
msgid "Leading or ending slashes are trimmed from collection's path."
msgstr ""
msgid "Log-backup Count"
msgstr ""
msgid "Log-file Viewer"
msgstr ""
msgid "Log-file directory"
msgstr ""
msgid "Log-file size"
msgstr ""
msgid "Logging"
msgstr ""
msgid "Logon message"
msgstr ""
msgid "Maximum size of each rotation log-file."
msgstr ""
msgid "Message displayed in the client when a password is needed."
msgstr ""
msgid "NOT installed"
msgstr ""
msgid "None"
msgstr ""
msgid "Number of backup files of log to create."
msgstr ""
msgid "OPTIONAL: See python's ssl module for available ciphers"
msgstr ""
msgid "Owner allow write, authenticated users allow read"
msgstr ""
msgid "Path/File required !"
msgstr ""
msgid ""
"Place here the 'user:password' pairs for your users which should have access "
"to Radicale."
msgstr ""
msgid "Please install current version !"
msgstr ""
msgid "Please press [Reload] button below to reread the file."
msgstr ""
msgid "Please update to current version !"
msgstr ""
msgid "Port numbers below 1024 (Privileged ports) are not supported"
msgstr ""
msgid "Private key file"
msgstr ""
msgid "Radicale CalDAV/CardDAV Server"
msgstr ""
msgid "Radicale uses '/etc/radicale/rights' as regexp-based file."
msgstr ""
msgid "Radicale uses '/etc/radicale/users' as htpasswd file."
msgstr ""
msgid "Read only!"
msgstr ""
msgid "RegExp file"
msgstr ""
msgid "Reload"
msgstr ""
msgid "Response Encoding"
msgstr ""
msgid "Reveal/hide password"
msgstr ""
msgid "Rights"
msgstr ""
msgid "Rights are based on a regexp-based file"
msgstr ""
msgid "Rights backend"
msgstr ""
msgid "SHA-1"
msgstr ""
msgid "SSL Protocol"
msgstr ""
msgid "Save"
msgstr ""
msgid "Section names are only used for naming the rule."
msgstr ""
msgid "Server"
msgstr ""
msgid "Setting this parameter to '0' will disable rotation of log-file."
msgstr ""
msgid "Software package '"
msgstr ""
msgid "Start"
msgstr ""
msgid "Start / Stop"
msgstr ""
msgid "Start/Stop Radicale server"
msgstr ""
msgid "Storage"
msgstr ""
msgid "Storage Encoding"
msgstr ""
msgid "Storage backend"
msgstr ""
msgid "Syslog Log level"
msgstr ""
msgid "System"
msgstr ""
msgid ""
"The Radicale Project is a complete CalDAV (calendar) and CardDAV (contact) "
"server solution."
msgstr ""
msgid ""
"They can be viewed and edited by calendar and contact clients on mobile "
"phones or computers."
msgstr ""
msgid "To edit the file follow this link!"
msgstr ""
msgid "To view latest log file follow this link!"
msgstr ""
msgid "Value is not an Integer >= 0 !"
msgstr ""
msgid "Value required ! Integer >= 0 !"
msgstr ""
msgid "Version"
msgstr ""
msgid "Version Information"
msgstr ""
msgid ""
"WARNING: Only 'File-system' is documented and tested by Radicale development"
msgstr ""
msgid "Warning"
msgstr ""
msgid ""
"You can also get groups from the user regex in the collection with {0}, {1}, "
"etc."
msgstr ""
msgid ""
"You can use Python's ConfigParser interpolation values %(login)s and "
"%(path)s."
msgstr ""
msgid "crypt"
msgstr ""
msgid "custom"
msgstr ""
msgid "htpasswd file"
msgstr ""
msgid "installed"
msgstr ""
msgid "or higher"
msgstr ""
msgid "plain"
msgstr ""
msgid "required"
msgstr ""
msgid "salted SHA-1"
msgstr ""

View file

@ -0,0 +1,12 @@
#!/bin/sh
# no longer needed for "Save and Apply" to restart radicale
# luci-app-radicale calls /etc/init.d/radicale reload
uci -q batch <<-EOF >/dev/null
delete ucitrack.@radicale[-1]
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0