radicale: [NEW] Python-based CalDAV/CardDAV Server 1156/head
authorChristian Schoenebeck <christian.schoenebeck@gmail.com>
Mon, 20 Apr 2015 19:14:03 +0000 (21:14 +0200)
committerChristian Schoenebeck <christian.schoenebeck@gmail.com>
Mon, 20 Apr 2015 19:14:03 +0000 (21:14 +0200)
Inspired by OpenWrt Ticket System Ticket 9119
Python3 package currently marked as @BROKEN because no time for testing.

Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
net/radicale/Makefile [new file with mode: 0644]
net/radicale/files/config.template [new file with mode: 0644]
net/radicale/files/logging.template [new file with mode: 0644]
net/radicale/files/radicale.config [new file with mode: 0644]
net/radicale/files/radicale.hotplug [new file with mode: 0644]
net/radicale/files/radicale.init [new file with mode: 0755]
net/radicale/files/radicale.rights [new file with mode: 0644]
net/radicale/files/radicale.users [new file with mode: 0644]
net/radicale/patches/010-Run-as-user-group-radicale-radicale.patch [new file with mode: 0644]

diff --git a/net/radicale/Makefile b/net/radicale/Makefile
new file mode 100644 (file)
index 0000000..329ab68
--- /dev/null
@@ -0,0 +1,138 @@
+#
+# Copyright (C) 2008-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=radicale
+PKG_VERSION:=0.10
+PKG_RELEASE:=1
+PKG_MAINTAINER:=Christian Schoenebeck <chris5560@web.de>
+
+PKG_LICENSE:=GPL-3.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_SOURCE:=Radicale-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://pypi.python.org/packages/source/R/Radicale/
+PKG_MD5SUM:=32655d8893962956ead0ad690cca6044
+
+# needed for "r"adicale <-> "R"adicale
+PKG_BUILD_DIR:=$(BUILD_DIR)/Radicale-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+# no default dependencies
+PKG_DEFAULT_DEPENDS=
+
+define Package/$(PKG_NAME)/Default
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=Web Servers/Proxies
+  URL:=http://radicale.org/
+  PKGARCH:=all
+  USERID:=radicale=5232:radicale=5232
+endef
+define Package/$(PKG_NAME)-py2
+  $(call Package/$(PKG_NAME)/Default)
+  PYTHON_VERSION:=2.7
+  TITLE:=Radicale CalDAV/CardDAV server (Python 2)
+  VARIANT:=python2
+  DEPENDS:=+python-logging +python-openssl +python-xml +python-codecs
+endef
+define Package/$(PKG_NAME)-py3
+  $(call Package/$(PKG_NAME)/Default)
+  PYTHON_VERSION:=3.4
+  TITLE:=Radicale CalDAV/CardDAV server (Python 3)
+  VARIANT:=python3
+  DEPENDS:=+python3-logging +python3-openssl +python3-xml +python3-codecs +python3-email @BROKEN
+endef
+
+# shown in LuCI package description
+define Package/$(PKG_NAME)-py2/description
+Radicale CalDAV/CardDAV server (Python 2) - Homepage: http://radicale.org/
+endef
+define Package/$(PKG_NAME)-py3/description
+Radicale CalDAV/CardDAV server (Python 3) - Homepage: http://radicale.org/
+endef
+
+# shown in make menuconfig <Help>
+define Package/$(PKG_NAME)-py2/config
+    help
+       The Radicale Project is a CalDAV (calendar) and CardDAV (contact) server.
+       It aims to be a light solution, easy to use, easy to install, easy to configure.
+       As a consequence, it requires few software dependances and is pre-configured to work out-of-the-box.
+       !!! Will install and use Python $(PYTHON_VERSION) !!!
+       .
+       Version : $(PKG_VERSION)
+       Homepage: http://radicale.org/
+       .
+       $(PKG_MAINTAINER)
+endef
+Package/$(PKG_NAME)-py3/config = $(Package/$(PKG_NAME)-py2/config)
+
+define Package/$(PKG_NAME)-py2/conffiles
+/etc/config/radicale
+/etc/radicale/users
+/etc/radicale/rights
+endef
+Package/$(PKG_NAME)-py3/conffiles = $(Package/$(PKG_NAME)-py2/conffiles)
+
+define Build/Configure
+endef
+define Build/Compile
+endef
+
+define Package/$(PKG_NAME)-py2/preinst
+       #!/bin/sh
+       [ -n "$${IPKG_INSTROOT}" ] && exit 0    # if run within buildroot exit
+
+       # stop service if PKG_UPGRADE
+       [ "$${PKG_UPGRADE}" = "1" ] && /etc/init.d/$(PKG_NAME) stop >/dev/null 2>&1
+
+       exit 0  # supress errors from stop command
+endef
+define Package/$(PKG_NAME)-py3/preinst
+$(call Package/$(PKG_NAME)-py2/preinst)
+endef
+
+define Package/$(PKG_NAME)-py2/install
+       $(INSTALL_DIR)  $(1)/etc/init.d
+       $(INSTALL_BIN)  ./files/radicale.init $(1)/etc/init.d/radicale
+       $(INSTALL_DIR)  $(1)/etc/hotplug.d/iface
+       $(INSTALL_BIN)  ./files/radicale.hotplug $(1)/etc/hotplug.d/iface/80-radicale
+       $(INSTALL_DIR)  $(1)/etc/config
+       $(INSTALL_CONF) ./files/radicale.config $(1)/etc/config/radicale
+
+       $(INSTALL_DIR)  $(1)/etc/radicale/ssl
+       $(INSTALL_DATA) ./files/config.template  $(1)/etc/radicale/
+       $(INSTALL_DATA) ./files/logging.template $(1)/etc/radicale/
+       $(INSTALL_DATA) ./files/radicale.users   $(1)/etc/radicale/users
+       $(INSTALL_DATA) ./files/radicale.rights  $(1)/etc/radicale/rights
+
+       $(INSTALL_DIR) $(1)/usr/lib/python$(PYTHON_VERSION)/site-packages/radicale
+       $(CP) \
+               $(PKG_BUILD_DIR)/radicale/* \
+               $(1)/usr/lib/python$(PYTHON_VERSION)/site-packages/radicale
+
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/radicale $(1)/usr/bin/
+endef
+define Package/$(PKG_NAME)-py3/install
+       $(call Package/$(PKG_NAME)-py2/install, $(1))
+endef
+
+define Package/$(PKG_NAME)-py2/postinst
+       #!/bin/sh
+       # patch /usr/bin/radicale force run using python2
+       /bin/sed -i 's/python/python2/' $${IPKG_INSTROOT}/usr/bin/radicale
+endef
+define Package/$(PKG_NAME)-py3/postinst
+       #!/bin/sh
+       # patch /usr/bin/radicale force run using python3
+       /bin/sed -i 's/python/python3/' $${IPKG_INSTROOT}/usr/bin/radicale
+endef
+
+$(eval $(call BuildPackage,$(PKG_NAME)-py2))
+$(eval $(call BuildPackage,$(PKG_NAME)-py3))
diff --git a/net/radicale/files/config.template b/net/radicale/files/config.template
new file mode 100644 (file)
index 0000000..1b8fcf2
--- /dev/null
@@ -0,0 +1,30 @@
+# -*- mode: conf -*-
+# vim:ft=cfg
+
+### AUTO-GENERATED CONFIGURATION
+###      USED BY RADICALE
+###         DO NOT EDIT
+### SEE /etc/config/radicale INSTEAD
+
+[server]
+# daemon               # handled by /etc/init.d/radicale
+# pid                  # handled by /etc/init.d/radicale
+
+[encoding]
+
+[well-known]
+
+[auth]
+# htpasswd_filename    # hard-coded /etc/radicale/users
+
+[git]
+
+[rights]
+# file                 # hard-coded /etc/radicale/rights
+
+[storage]
+
+[logging]
+# config               # hard-coded /var/etc/radicale/logging
+
+[headers]
diff --git a/net/radicale/files/logging.template b/net/radicale/files/logging.template
new file mode 100644 (file)
index 0000000..a730ca0
--- /dev/null
@@ -0,0 +1,47 @@
+# -*- mode: conf -*-
+# vim:ft=cfg
+
+### AUTO-GENERATED CONFIGURATION
+###      USED BY RADICALE
+###         DO NOT EDIT
+### SEE /etc/config/radicale INSTEAD
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console,file,syslog
+
+[formatters]
+keys = simple,full,syslog
+
+[logger_root]
+level = DEBUG
+handlers = console,file,syslog
+
+[handler_console]
+class = StreamHandler
+args = (sys.stdout,)
+formatter = simple
+# level = WARNING                                      # set via /etc/config/radicale
+
+[handler_file]
+class = handlers.RotatingFileHandler
+formatter = full
+# level = INFO                                         # set via /etc/config/radicale
+# args = ('[filename]','a',[maxbytes],[backupcount])   # set via /etc/config/radicale
+
+[handler_syslog]
+class = handlers.SysLogHandler
+args  = ('/dev/log', handlers.SysLogHandler.LOG_DAEMON)
+formatter = syslog
+# level = WARNING                                      # set via /etc/config/radicale
+
+[formatter_simple]
+format = %(message)s
+
+[formatter_full]
+format = %(asctime)s - %(levelname)s: %(message)s
+
+[formatter_syslog]
+format = radicale [%(process)d]: %(message)s
diff --git a/net/radicale/files/radicale.config b/net/radicale/files/radicale.config
new file mode 100644 (file)
index 0000000..ea10bc9
--- /dev/null
@@ -0,0 +1,192 @@
+#
+# You find additional information on Radicale Homepage
+# http://radicale.org
+#
+# OpenWrt's wiki needs to be setup/updated ;-)
+#
+# if setting additional options please remember that UCI does not support
+# section names and option names with "-" (Dash) inside their name
+# to use them anyway replace "-" with "_" (Underscore)
+# Each Radicale's config [section] is setup as UCI config setting 'section'
+#
+
+####################################################
+# Server options
+#
+config setting 'server'
+
+       # hostname:port
+       # IPv4 syntax: address:port
+       # IPv6 syntax: [address]:port
+       # ATTENTION:
+       # only use ports > 1024 (non-privileged Ports)
+       # because this implementation is running as non-root user
+       # Default: 0.0.0.0:5232
+#      list hosts '0.0.0.0:5232'
+#      list hosts 'localhost:5232'
+
+       # SSL flag, enable HTTPS protocol
+       # Default: 0 (disabled)
+#      option ssl '1'
+
+       # SSL Protocol used. See python's ssl module for available values
+       # Default: PROTOCOL_SSLv23
+#      option protocol 'PROTOCOL_SSLv23'
+
+       # Ciphers available. See python's ssl module for available ciphers
+#      option ciphers ''
+
+       # SSL certificate path and file
+#      option certificate '/etc/radicale/ssl/server.crt'
+
+       # SSL private key path and file
+#      option key '/etc/radicale/ssl/server.key'
+
+       # Reverse DNS to resolve client address in logs
+       # Default: 0 (disabled)
+#      option dns_lookup '1'
+
+       # Message displayed in the client when a password is needed
+#      option realm 'Radicale - Password Required'
+
+
+####################################################
+# Encoding options
+#
+config setting 'encoding'
+
+       # Encoding for responding requests
+#      option  request 'utf-8'
+
+       # Encoding for storing local collections
+#      option  stock   'utf-8'
+
+
+####################################################
+# Authentication options
+#
+config setting 'auth'
+
+       # Authentication method
+       # Value: None | htpasswd | IMAP | LDAP | PAM | courier | http | remote_user | custom
+       # Default: None
+       # if setting 'htpasswd' the file /etc/radicale/users is used (hardcoded)
+#      option type 'htpasswd'
+
+       # Htpasswd encryption method
+       # Value: plain | sha1 | ssha | crypt
+#      option htpasswd_encryption 'crypt'
+
+       # for other authenication methods consult Radicale documentation
+       # and set options here
+
+
+####################################################
+# Git default options
+#
+config setting 'git'
+
+       # Git default options
+#      option committer 'Radicale <radicale@example.com>'
+
+
+####################################################
+# Rights backend
+#
+config setting 'rights'
+
+       # Value: None | authenticated | owner_only | owner_write | from_file | custom
+       # Default: None
+       # if setting 'from_file' the file /etc/radicale/rights is used (hardcoded)
+#      option  type    'from_file'
+
+       # Custom rights handler
+#      option custom_handler ''
+
+
+####################################################
+# Storage backend
+# -------
+# WARNING: ONLY "filesystem" IS DOCUMENTED AND TESTED,
+#          OTHER BACKENDS ARE NOT READY FOR PRODUCTION.
+# -------
+#
+config setting 'storage'
+       # Value: filesystem | multifilesystem | database | custom
+       option  type                    'filesystem'
+       option  filesystem_folder       '/srv/radicale'
+
+
+####################################################
+# Additional HTTP headers
+#
+config setting 'headers'
+       # enable all if using CardDavMATE-, CalDavZAP- or InfCloud- WEBclient
+#      list    Access_Control_Allow_Origin     '*'
+#      list    Access_Control_Allow_Methods    'GET'
+#      list    Access_Control_Allow_Methods    'POST'
+#      list    Access_Control_Allow_Methods    'OPTIONS'
+#      list    Access_Control_Allow_Methods    'PROPFIND'
+#      list    Access_Control_Allow_Methods    'PROPPATCH'
+#      list    Access_Control_Allow_Methods    'REPORT'
+#      list    Access_Control_Allow_Methods    'PUT'
+#      list    Access_Control_Allow_Methods    'MOVE'
+#      list    Access_Control_Allow_Methods    'DELETE'
+#      list    Access_Control_Allow_Methods    'LOCK'
+#      list    Access_Control_Allow_Methods    'UNLOCK'
+#      list    Access_Control_Allow_Headers    'User-Agent'
+#      list    Access_Control_Allow_Headers    'Authorization'
+#      list    Access_Control_Allow_Headers    'Content-type'
+#      list    Access_Control_Allow_Headers    'Depth'
+#      list    Access_Control_Allow_Headers    'If-match'
+#      list    Access_Control_Allow_Headers    'If-None-Match'
+#      list    Access_Control_Allow_Headers    'Lock-Token'
+#      list    Access_Control_Allow_Headers    'Timeout'
+#      list    Access_Control_Allow_Headers    'Destination'
+#      list    Access_Control_Allow_Headers    'Overwrite'
+#      list    Access_Control_Allow_Headers    'X-client'
+#      list    Access_Control_Allow_Headers    'X-Requested-With'
+#      list    Access_Control_Expose_Headers   'Etag'
+
+
+####################################################
+# Global logging options
+#
+config setting 'logging'
+
+       # Set the default logging level to debug for all outputs (ignore output level settings)
+       # Default: 0 (disabled)
+#      option  debug   '1'
+       # Log all environment variables (including those set in the shell) when starting
+       # Default: 0 (disabled)
+#      option  full_environment '1'
+
+
+####################################################
+# Spezial logging options
+# !!! not documented in Radicale documentation
+# !!! special settings for this implementation
+#
+config logging 'logger'
+
+       # Level: DEBUG | INFO | WARNING | ERROR | CRITICAL
+       # To nearly disable logging set level to critical
+
+       # log level on console
+#      option  console_level   'ERROR'
+
+       # Here we use Rotating Logfiles in this implementation
+       # !!! if maxbytes and/or backupcount is set to 0  !!!
+       # !!! file rotation is disabled and logfile grows endless !!!
+       # log level
+#      option  file_level      'INFO'
+       # directory where log files are written
+#      option  file_path       '/var/log/radicale'
+       # max size of each logfile (see warning above)
+#      option  file_maxbytes   '8196'
+       # number of backup files to create (see warning above)
+#      option  file_backupcount        '1'
+
+       # log level for syslog logging
+#      option  syslog_level    'WARNING'
+
diff --git a/net/radicale/files/radicale.hotplug b/net/radicale/files/radicale.hotplug
new file mode 100644 (file)
index 0000000..634ad2e
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# only (re-)start on ifup
+[ "$ACTION" = "ifup" ] || exit 0
+
+_PID=$(ps | grep '[p]ython.*[r]adicale' 2>/dev/null | awk '{print \$1}')
+kill -1 $_PID 2>/dev/null
+if [ $? -eq 0 ]; then
+       # only restart if already running
+       logger -p user.info -t "radicale[$_PID]" \
+               "Restart request due to '$ACTION' of interface '$INTERFACE'"
+       /etc/init.d/radicale restart
+else
+       # only start if enabled
+       /etc/init.d/radicale enabled && /etc/init.d/radicale start
+fi
diff --git a/net/radicale/files/radicale.init b/net/radicale/files/radicale.init
new file mode 100755 (executable)
index 0000000..bb35a18
--- /dev/null
@@ -0,0 +1,220 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2006-2015 OpenWrt.org
+
+START=80
+STOP=10
+
+CFGDIR=/var/etc/radicale
+SYSCFG=$CFGDIR/config
+LOGCFG=$CFGDIR/logging
+
+DATADIR="/srv/radicale"
+LOGDIR=""
+
+PGREP="ps | grep '[p]ython.*[r]adicale' 2>/dev/null | awk '{print \$1}' "
+
+# we could start with empty configuration file using defaults
+[ -f /etc/config/radicale ] || touch /etc/config/radicale
+
+_uci2radicale() {
+       local _SYSTMP="$SYSCFG.tmp"
+       local _LOGTMP="$LOGCFG.tmp"
+       local _LOPT                             # list option name
+       local _LVAL                             # list option value
+       local _STYPE                            # section type
+       local _SNAME                            # section name
+       local _console_level="ERROR"            # logging console level
+       local _file_level="INFO"                # logging file level
+       local _file_path="/var/log/radicale"    # logging file path
+       local _file_maxbytes="8196"             # logging file maxBytes
+       local _file_backupcount="1"             # logging file backupCount
+       local _syslog_level="WARNING"           # logging syslog level
+
+       # write list values to config
+       _write_list() {
+               _write_value "$_LOPT" "$_LVAL"  # there might be spaces in _LVAL
+               _LOPT=""
+               _LVAL=""
+       }
+
+       _write_value() {
+               # $1    option
+               # $2    value
+               local __OPT=$1
+               local __VAL=$2
+               # section "server" ignore option "daemon" and "pid"
+               [ "$_SNAME" = "server" -a "$__OPT" = "daemon" ] && return 0
+               [ "$_SNAME" = "server" -a "$__OPT" = "pid" ] && return 0
+               # section "logging" ignore option "config" (logging config file)
+               [ "$_SNAME" = "logging" -a "$__OPT" = "config" ] && return 0
+               # section "auth" ignore option "htpasswd_filename" (htpasswd file)
+               [ "$_SNAME" = "auth" -a "$__OPT" = "htpasswd_filename" ] && return 0
+               # section "rights" ignore option "file" (reg-based rights file)
+               [ "$_SNAME" = "rights" -a "$__OPT" = "file" ] && return 0
+               # section "headers" replace "_" with "-" in option (UCI problem)
+               [ "$_SNAME" = "headers" ] && __OPT=$(echo "$__OPT" | sed -e "s#_#-#g")
+               # save data driectory
+               [ "$_SNAME" = "storage" -a "$__OPT" = "filesystem_folder" ] && DATADIR="$__VAL"
+               # special handling for well-known, value needs single quotes
+               [ "$_SNAME" = "well-known" -a "${__VAL#*\%\(}" != "$__VAL" ] && __VAL="'$__VAL'"
+               # handling of log settings
+               if [ "$_STYPE" = "logging" -a "$_SNAME" = "logger" ]; then
+                       eval "_$__OPT='$__VAL'" # set to environment for later use
+               else
+                       # handle bool
+                       [ "$__VAL" = "0" ] && __VAL="False"
+                       [ "$__VAL" = "1" ] && __VAL="True"
+                       # append data to the corresponding section
+                       sed -i "/\[$_SNAME\]/a $__OPT = $__VAL" $_SYSTMP
+               fi
+       }
+
+       # redefined callback for sections when calling config_load
+       config_cb() {
+               # $1    "Type"
+               # $2    "Name"
+               # write out last list option
+               [ -n "$_LOPT" ] && _write_list
+               # mark invalid
+               _STYPE=""
+               _SNAME=""
+               # check section type
+               [ "$1" = "setting" -o "$1" = "logging" ] && {
+                       _STYPE="$1"
+                       _SNAME="$2"
+               }
+               # translate section name
+               [ "$2" = "well_known" ] && _SNAME="well-known"
+               return 0
+       }
+
+       # redefined callback for lists when calling config_load
+       list_cb() {
+               # $1    name of variable
+               # $2    value
+               # invalid section type then ignore
+               [ -z "$_STYPE" -o -z "$_SNAME" ] && return 0
+               # write out last list option if new list starts
+               [ -n "$_LOPT" -a "$_LOPT" != "$1" ] && _write_list
+               # new list option
+               if [ -z "$_LOPT" ]; then
+                       _LOPT="$1"
+                       _LVAL="$2"
+               else
+                       _LVAL="$_LVAL, $2"
+               fi
+               return 0
+       }
+
+       # redefined callback for options when calling config_load
+       option_cb() {
+               # $1    name of variable
+               # $2    value
+               local __OPT="$1"
+               local __VAL="$2"
+               # invalid section type then ignore
+               [ -z "$_STYPE" -o -z "$_SNAME" ] && return 0
+               # ignore list entrys will be handled by list_cb()
+               [ "${__OPT#*_ITEM}" != "$__OPT" ]   && return 0 # ignore lists *_ITEM*
+               [ "${__OPT#*_LENGTH}" != "$__OPT" ] && return 0 # ignore lists *_LENGTH
+               # write out last list option and clear
+               [ -n "$_LOPT" ] && _write_list
+               # write to file
+               _write_value "$__OPT" "$__VAL"  # there might be spaces in __VAL
+               return 0
+       }
+
+       # temporary config file
+       # radicale need read access
+       mkdir -m0755 -p $CFGDIR
+
+       cp /etc/radicale/config.template  $_SYSTMP
+       config_load radicale    # calling above config_cb()/option_cb()/list_cb() and write into $_SYSTMP
+       sed -i "/\[logging\]/a config = /var/etc/radicale/logging" $_SYSTMP     # hard-code logging config
+       sed -i "/\[auth\]/a htpasswd_filename = /etc/radicale/users" $_SYSTMP   # hard-code htpasswd
+       sed -i "/\[rights\]/a file = /etc/radicale/rights" $_SYSTMP             # hard-code regexp-based rights
+
+       # temporary logging config file
+       cp /etc/radicale/logging.template $_LOGTMP
+       LOGDIR="$_file_path"
+       sed -i "/\[handler_console\]/a level = $_console_level" $_LOGTMP
+       sed -i "/\[handler_file\]/a level = $_file_level" $_LOGTMP
+       sed -i "/\[handler_file\]/a args = ('$_file_path/radicale','a',$_file_maxbytes,$_file_backupcount)" $_LOGTMP
+       sed -i "/\[handler_syslog\]/a level = $_syslog_level" $_LOGTMP
+
+       # move tmp to final
+       mv -f $_SYSTMP $SYSCFG
+       mv -f $_LOGTMP $LOGCFG
+}
+
+_set_permission() {
+       # config file permissions (read access for group)
+       chmod 644 $SYSCFG $LOGCFG
+       chgrp -R radicale $CFGDIR
+       # log directory (full access and owner)
+       [ -d $LOGDIR ] || mkdir -m0755 -p $LOGDIR
+       chown -R radicale:radicale $LOGDIR
+       # data directory does not exist
+       [ -d $DATADIR ] || {
+               logger -p user.error -t "radicale[----]" "Data directory '$DATADIR' does not exists. Startup failed !!!"
+               exit 1
+       }
+       chgrp -R radicale $DATADIR
+}
+
+boot() {
+       return 0        # will be started by "iface" hotplug events
+}
+
+start() {
+       _running() {
+               sleep 2         # give radicale time to completely come up
+               local _PID=$(eval "$PGREP")
+               kill -1 $_PID 2>/dev/null
+               [ $? -eq 0 ] \
+                       && logger -p user.notice -t "radicale[$_PID]" "Service started successfully"\
+                       || logger -p user.warn -t "radicale[----]" "Service failed to start"
+       }
+
+       # if already running do nothing
+       local _PID=$(eval "$PGREP")
+       kill -1 $_PID 2>/dev/null && return 0
+
+       _uci2radicale
+       _set_permission
+
+       radicale --daemon --config=$SYSCFG
+
+       _running &      # check if running and syslog
+
+       return 0
+}
+
+reload() {
+       # reload is also used by luci
+       local _PID=$(eval "$PGREP")
+       kill -1 $_PID 2>/dev/null
+       if [ $? -eq 0 ]; then
+               # only restart if already running
+               restart
+       else
+               # only start if enabled
+               enabled && start
+       fi
+       return 0
+}
+
+stop() {
+       local _PID=$(eval "$PGREP")
+       [ -z "$_PID" ] && return 0      # not running
+       kill -15 $_PID 2>/dev/null
+       sleep 1                 # give time to shutdown
+       local _tmp=$(eval "$PGREP")
+       if [ -z "$_tmp" ]; then
+               logger -p user.notice -t "radicale[$_PID]" "Service shutdown successfully"
+       else
+               kill -9 $_tmp   # Normally never come here
+               logger -p user.warn -t "radicale[----]" "Service shutdown FORCED"
+       fi
+       return 0
+}
diff --git a/net/radicale/files/radicale.rights b/net/radicale/files/radicale.rights
new file mode 100644 (file)
index 0000000..3de3955
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# Authentication login is matched against the "user" key, and collection's path is matched against the "collection" key.
+# You can use Python's ConfigParser interpolation values %(login)s and %(path)s.
+# You can also get groups from the user regex in the collection with {0}, {1}, etc.
+#
+# For example, for the "user" key, ".+" means "authenticated user" and ".*" means "anybody" (including anonymous users).
+#
+# Section names are only used for naming the rule.
+# Leading or ending slashes are trimmed from collection's path.
+#
+
+# This means all users starting with "admin" may read any collection
+[admin]
+user: ^admin.*$
+collection: .*
+permission: r
+
+# This means all users may read and write any collection starting with public.
+# We do so by just not testing against the user string.
+[public]
+user: .*
+collection: ^public(/.+)?$
+permission: rw
+
+# A little more complex: give read access to users from a domain for all
+# collections of all the users (ie. user@domain.tld can read domain/\*).
+[domain-wide-access]
+user: ^.+@(.+)\..+$
+collection: ^{0}/.+$
+permission: r
+
+# Allow authenticated user to read all collections
+[allow-everyone-read]
+user: .+
+collection: .*
+permission: r
+
+# Give write access to owners
+[owner-write]
+user: .+
+collection: ^%(login)s(/.+)?$
+permission: rw
+
+# Allow CardDavMATE-, CalDavZAP- or InfCloud- WEBclient to work
+# anonymous users have read access to "/" but no files or subdir
+[infcloud]
+user: .*
+collection: /
+permission: r
diff --git a/net/radicale/files/radicale.users b/net/radicale/files/radicale.users
new file mode 100644 (file)
index 0000000..7722176
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Sample File
+#
+
+user1:password1
+user2:password2
\ No newline at end of file
diff --git a/net/radicale/patches/010-Run-as-user-group-radicale-radicale.patch b/net/radicale/patches/010-Run-as-user-group-radicale-radicale.patch
new file mode 100644 (file)
index 0000000..e1f1c21
--- /dev/null
@@ -0,0 +1,30 @@
+Subject: [PATCH] Run as user radicale and group radicale
+
+Patch to run Radicale service as radicale:radicale non root user
+
+Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
+---
+ bin/radicale | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/bin/radicale b/bin/radicale
+index 619aca5..7466020 100755
+--- a/bin/radicale
++++ b/bin/radicale
+@@ -26,6 +26,13 @@ Launch the server according to configuration and command-line options.
+ """
++# inserted to run as user radicale
++import pwd, grp, os
++uid = pwd.getpwnam('radicale').pw_uid
++gid = grp.getgrnam('radicale').gr_gid
++os.setegid(gid)
++os.seteuid(uid)
++
+ import radicale.__main__
+-- 
+2.1.0
+