Browse Source

radicale: [NEW] Python-based CalDAV/CardDAV Server

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>
Christian Schoenebeck 9 years ago
parent
commit
f98dbf5aab

+ 138
- 0
net/radicale/Makefile View File

@@ -0,0 +1,138 @@
1
+#
2
+# Copyright (C) 2008-2015 OpenWrt.org
3
+#
4
+# This is free software, licensed under the GNU General Public License v2.
5
+#
6
+
7
+include $(TOPDIR)/rules.mk
8
+
9
+PKG_NAME:=radicale
10
+PKG_VERSION:=0.10
11
+PKG_RELEASE:=1
12
+PKG_MAINTAINER:=Christian Schoenebeck <chris5560@web.de>
13
+
14
+PKG_LICENSE:=GPL-3.0
15
+PKG_LICENSE_FILES:=COPYING
16
+
17
+PKG_SOURCE:=Radicale-$(PKG_VERSION).tar.gz
18
+PKG_SOURCE_URL:=http://pypi.python.org/packages/source/R/Radicale/
19
+PKG_MD5SUM:=32655d8893962956ead0ad690cca6044
20
+
21
+# needed for "r"adicale <-> "R"adicale
22
+PKG_BUILD_DIR:=$(BUILD_DIR)/Radicale-$(PKG_VERSION)
23
+
24
+include $(INCLUDE_DIR)/package.mk
25
+
26
+# no default dependencies
27
+PKG_DEFAULT_DEPENDS=
28
+
29
+define Package/$(PKG_NAME)/Default
30
+  SECTION:=net
31
+  CATEGORY:=Network
32
+  SUBMENU:=Web Servers/Proxies
33
+  URL:=http://radicale.org/
34
+  PKGARCH:=all
35
+  USERID:=radicale=5232:radicale=5232
36
+endef
37
+define Package/$(PKG_NAME)-py2
38
+  $(call Package/$(PKG_NAME)/Default)
39
+  PYTHON_VERSION:=2.7
40
+  TITLE:=Radicale CalDAV/CardDAV server (Python 2)
41
+  VARIANT:=python2
42
+  DEPENDS:=+python-logging +python-openssl +python-xml +python-codecs
43
+endef
44
+define Package/$(PKG_NAME)-py3
45
+  $(call Package/$(PKG_NAME)/Default)
46
+  PYTHON_VERSION:=3.4
47
+  TITLE:=Radicale CalDAV/CardDAV server (Python 3)
48
+  VARIANT:=python3
49
+  DEPENDS:=+python3-logging +python3-openssl +python3-xml +python3-codecs +python3-email @BROKEN
50
+endef
51
+
52
+# shown in LuCI package description
53
+define Package/$(PKG_NAME)-py2/description
54
+Radicale CalDAV/CardDAV server (Python 2) - Homepage: http://radicale.org/
55
+endef
56
+define Package/$(PKG_NAME)-py3/description
57
+Radicale CalDAV/CardDAV server (Python 3) - Homepage: http://radicale.org/
58
+endef
59
+
60
+# shown in make menuconfig <Help>
61
+define Package/$(PKG_NAME)-py2/config
62
+    help
63
+	The Radicale Project is a CalDAV (calendar) and CardDAV (contact) server.
64
+	It aims to be a light solution, easy to use, easy to install, easy to configure.
65
+	As a consequence, it requires few software dependances and is pre-configured to work out-of-the-box.
66
+	!!! Will install and use Python $(PYTHON_VERSION) !!!
67
+	.
68
+	Version : $(PKG_VERSION)
69
+	Homepage: http://radicale.org/
70
+	.
71
+	$(PKG_MAINTAINER)
72
+endef
73
+Package/$(PKG_NAME)-py3/config = $(Package/$(PKG_NAME)-py2/config)
74
+
75
+define Package/$(PKG_NAME)-py2/conffiles
76
+/etc/config/radicale
77
+/etc/radicale/users
78
+/etc/radicale/rights
79
+endef
80
+Package/$(PKG_NAME)-py3/conffiles = $(Package/$(PKG_NAME)-py2/conffiles)
81
+
82
+define Build/Configure
83
+endef
84
+define Build/Compile
85
+endef
86
+
87
+define Package/$(PKG_NAME)-py2/preinst
88
+	#!/bin/sh
89
+	[ -n "$${IPKG_INSTROOT}" ] && exit 0	# if run within buildroot exit
90
+
91
+	# stop service if PKG_UPGRADE
92
+	[ "$${PKG_UPGRADE}" = "1" ] && /etc/init.d/$(PKG_NAME) stop >/dev/null 2>&1
93
+
94
+	exit 0	# supress errors from stop command
95
+endef
96
+define Package/$(PKG_NAME)-py3/preinst
97
+$(call Package/$(PKG_NAME)-py2/preinst)
98
+endef
99
+
100
+define Package/$(PKG_NAME)-py2/install
101
+	$(INSTALL_DIR)  $(1)/etc/init.d
102
+	$(INSTALL_BIN)  ./files/radicale.init $(1)/etc/init.d/radicale
103
+	$(INSTALL_DIR)  $(1)/etc/hotplug.d/iface
104
+	$(INSTALL_BIN)  ./files/radicale.hotplug $(1)/etc/hotplug.d/iface/80-radicale
105
+	$(INSTALL_DIR)  $(1)/etc/config
106
+	$(INSTALL_CONF) ./files/radicale.config $(1)/etc/config/radicale
107
+
108
+	$(INSTALL_DIR)  $(1)/etc/radicale/ssl
109
+	$(INSTALL_DATA) ./files/config.template  $(1)/etc/radicale/
110
+	$(INSTALL_DATA) ./files/logging.template $(1)/etc/radicale/
111
+	$(INSTALL_DATA) ./files/radicale.users   $(1)/etc/radicale/users
112
+	$(INSTALL_DATA) ./files/radicale.rights  $(1)/etc/radicale/rights
113
+
114
+	$(INSTALL_DIR) $(1)/usr/lib/python$(PYTHON_VERSION)/site-packages/radicale
115
+	$(CP) \
116
+		$(PKG_BUILD_DIR)/radicale/* \
117
+		$(1)/usr/lib/python$(PYTHON_VERSION)/site-packages/radicale
118
+
119
+	$(INSTALL_DIR) $(1)/usr/bin
120
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/radicale $(1)/usr/bin/
121
+endef
122
+define Package/$(PKG_NAME)-py3/install
123
+	$(call Package/$(PKG_NAME)-py2/install, $(1))
124
+endef
125
+
126
+define Package/$(PKG_NAME)-py2/postinst
127
+	#!/bin/sh
128
+	# patch /usr/bin/radicale force run using python2
129
+	/bin/sed -i 's/python/python2/' $${IPKG_INSTROOT}/usr/bin/radicale
130
+endef
131
+define Package/$(PKG_NAME)-py3/postinst
132
+	#!/bin/sh
133
+	# patch /usr/bin/radicale force run using python3
134
+	/bin/sed -i 's/python/python3/' $${IPKG_INSTROOT}/usr/bin/radicale
135
+endef
136
+
137
+$(eval $(call BuildPackage,$(PKG_NAME)-py2))
138
+$(eval $(call BuildPackage,$(PKG_NAME)-py3))

+ 30
- 0
net/radicale/files/config.template View File

@@ -0,0 +1,30 @@
1
+# -*- mode: conf -*-
2
+# vim:ft=cfg
3
+
4
+### AUTO-GENERATED CONFIGURATION
5
+###      USED BY RADICALE
6
+###         DO NOT EDIT
7
+### SEE /etc/config/radicale INSTEAD
8
+
9
+[server]
10
+# daemon		# handled by /etc/init.d/radicale
11
+# pid			# handled by /etc/init.d/radicale
12
+
13
+[encoding]
14
+
15
+[well-known]
16
+
17
+[auth]
18
+# htpasswd_filename	# hard-coded /etc/radicale/users
19
+
20
+[git]
21
+
22
+[rights]
23
+# file			# hard-coded /etc/radicale/rights
24
+
25
+[storage]
26
+
27
+[logging]
28
+# config		# hard-coded /var/etc/radicale/logging
29
+
30
+[headers]

+ 47
- 0
net/radicale/files/logging.template View File

@@ -0,0 +1,47 @@
1
+# -*- mode: conf -*-
2
+# vim:ft=cfg
3
+
4
+### AUTO-GENERATED CONFIGURATION
5
+###      USED BY RADICALE
6
+###         DO NOT EDIT
7
+### SEE /etc/config/radicale INSTEAD
8
+
9
+[loggers]
10
+keys = root
11
+
12
+[handlers]
13
+keys = console,file,syslog
14
+
15
+[formatters]
16
+keys = simple,full,syslog
17
+
18
+[logger_root]
19
+level = DEBUG
20
+handlers = console,file,syslog
21
+
22
+[handler_console]
23
+class = StreamHandler
24
+args = (sys.stdout,)
25
+formatter = simple
26
+# level = WARNING					# set via /etc/config/radicale
27
+
28
+[handler_file]
29
+class = handlers.RotatingFileHandler
30
+formatter = full
31
+# level = INFO						# set via /etc/config/radicale
32
+# args = ('[filename]','a',[maxbytes],[backupcount])	# set via /etc/config/radicale
33
+
34
+[handler_syslog]
35
+class = handlers.SysLogHandler
36
+args  = ('/dev/log', handlers.SysLogHandler.LOG_DAEMON)
37
+formatter = syslog
38
+# level = WARNING					# set via /etc/config/radicale
39
+
40
+[formatter_simple]
41
+format = %(message)s
42
+
43
+[formatter_full]
44
+format = %(asctime)s - %(levelname)s: %(message)s
45
+
46
+[formatter_syslog]
47
+format = radicale [%(process)d]: %(message)s

+ 192
- 0
net/radicale/files/radicale.config View File

@@ -0,0 +1,192 @@
1
+#
2
+# You find additional information on Radicale Homepage
3
+# http://radicale.org
4
+#
5
+# OpenWrt's wiki needs to be setup/updated ;-)
6
+#
7
+# if setting additional options please remember that UCI does not support
8
+# section names and option names with "-" (Dash) inside their name
9
+# to use them anyway replace "-" with "_" (Underscore)
10
+# Each Radicale's config [section] is setup as UCI config setting 'section'
11
+#
12
+
13
+####################################################
14
+# Server options
15
+#
16
+config setting 'server'
17
+
18
+	# hostname:port
19
+	# IPv4 syntax: address:port
20
+	# IPv6 syntax: [address]:port
21
+	# ATTENTION:
22
+	# only use ports > 1024 (non-privileged Ports)
23
+	# because this implementation is running as non-root user
24
+	# Default: 0.0.0.0:5232
25
+#	list hosts '0.0.0.0:5232'
26
+#	list hosts 'localhost:5232'
27
+
28
+	# SSL flag, enable HTTPS protocol
29
+	# Default: 0 (disabled)
30
+#	option ssl '1'
31
+
32
+	# SSL Protocol used. See python's ssl module for available values
33
+	# Default: PROTOCOL_SSLv23
34
+#	option protocol 'PROTOCOL_SSLv23'
35
+
36
+	# Ciphers available. See python's ssl module for available ciphers
37
+#	option ciphers ''
38
+
39
+	# SSL certificate path and file
40
+#	option certificate '/etc/radicale/ssl/server.crt'
41
+
42
+	# SSL private key path and file
43
+#	option key '/etc/radicale/ssl/server.key'
44
+
45
+	# Reverse DNS to resolve client address in logs
46
+	# Default: 0 (disabled)
47
+#	option dns_lookup '1'
48
+
49
+	# Message displayed in the client when a password is needed
50
+#	option realm 'Radicale - Password Required'
51
+
52
+
53
+####################################################
54
+# Encoding options
55
+#
56
+config	setting	'encoding'
57
+
58
+	# Encoding for responding requests
59
+#	option	request	'utf-8'
60
+
61
+	# Encoding for storing local collections
62
+#	option	stock	'utf-8'
63
+
64
+
65
+####################################################
66
+# Authentication options
67
+#
68
+config setting 'auth'
69
+
70
+	# Authentication method
71
+	# Value: None | htpasswd | IMAP | LDAP | PAM | courier | http | remote_user | custom
72
+	# Default: None
73
+	# if setting 'htpasswd' the file /etc/radicale/users is used (hardcoded)
74
+#	option type 'htpasswd'
75
+
76
+	# Htpasswd encryption method
77
+	# Value: plain | sha1 | ssha | crypt
78
+#	option htpasswd_encryption 'crypt'
79
+
80
+	# for other authenication methods consult Radicale documentation
81
+	# and set options here
82
+
83
+
84
+####################################################
85
+# Git default options
86
+#
87
+config	setting	'git'
88
+
89
+	# Git default options
90
+#	option committer 'Radicale <radicale@example.com>'
91
+
92
+
93
+####################################################
94
+# Rights backend
95
+#
96
+config setting 'rights'
97
+
98
+	# Value: None | authenticated | owner_only | owner_write | from_file | custom
99
+	# Default: None
100
+	# if setting 'from_file' the file /etc/radicale/rights is used (hardcoded)
101
+#	option	type	'from_file'
102
+
103
+	# Custom rights handler
104
+#	option custom_handler ''
105
+
106
+
107
+####################################################
108
+# Storage backend
109
+# -------
110
+# WARNING: ONLY "filesystem" IS DOCUMENTED AND TESTED,
111
+#          OTHER BACKENDS ARE NOT READY FOR PRODUCTION.
112
+# -------
113
+#
114
+config setting 'storage'
115
+	# Value: filesystem | multifilesystem | database | custom
116
+	option	type			'filesystem'
117
+	option	filesystem_folder	'/srv/radicale'
118
+
119
+
120
+####################################################
121
+# Additional HTTP headers
122
+#
123
+config	setting	'headers'
124
+	# enable all if using CardDavMATE-, CalDavZAP- or InfCloud- WEBclient
125
+#	list	Access_Control_Allow_Origin	'*'
126
+#	list	Access_Control_Allow_Methods	'GET'
127
+#	list	Access_Control_Allow_Methods	'POST'
128
+#	list	Access_Control_Allow_Methods	'OPTIONS'
129
+#	list	Access_Control_Allow_Methods	'PROPFIND'
130
+#	list	Access_Control_Allow_Methods	'PROPPATCH'
131
+#	list	Access_Control_Allow_Methods	'REPORT'
132
+#	list	Access_Control_Allow_Methods	'PUT'
133
+#	list	Access_Control_Allow_Methods	'MOVE'
134
+#	list	Access_Control_Allow_Methods	'DELETE'
135
+#	list	Access_Control_Allow_Methods	'LOCK'
136
+#	list	Access_Control_Allow_Methods	'UNLOCK'
137
+#	list	Access_Control_Allow_Headers	'User-Agent'
138
+#	list	Access_Control_Allow_Headers	'Authorization'
139
+#	list	Access_Control_Allow_Headers	'Content-type'
140
+#	list	Access_Control_Allow_Headers	'Depth'
141
+#	list	Access_Control_Allow_Headers	'If-match'
142
+#	list	Access_Control_Allow_Headers	'If-None-Match'
143
+#	list	Access_Control_Allow_Headers	'Lock-Token'
144
+#	list	Access_Control_Allow_Headers	'Timeout'
145
+#	list	Access_Control_Allow_Headers	'Destination'
146
+#	list	Access_Control_Allow_Headers	'Overwrite'
147
+#	list	Access_Control_Allow_Headers	'X-client'
148
+#	list	Access_Control_Allow_Headers	'X-Requested-With'
149
+#	list	Access_Control_Expose_Headers	'Etag'
150
+
151
+
152
+####################################################
153
+# Global logging options
154
+#
155
+config setting 'logging'
156
+
157
+	# Set the default logging level to debug for all outputs (ignore output level settings)
158
+	# Default: 0 (disabled)
159
+#	option	debug	'1'
160
+	# Log all environment variables (including those set in the shell) when starting
161
+	# Default: 0 (disabled)
162
+#	option	full_environment '1'
163
+
164
+
165
+####################################################
166
+# Spezial logging options
167
+# !!! not documented in Radicale documentation
168
+# !!! special settings for this implementation
169
+#
170
+config logging 'logger'
171
+
172
+	# Level: DEBUG | INFO | WARNING | ERROR | CRITICAL
173
+	# To nearly disable logging set level to critical
174
+
175
+	# log level on console
176
+#	option	console_level	'ERROR'
177
+
178
+	# Here we use Rotating Logfiles in this implementation
179
+	# !!! if maxbytes and/or backupcount is set to 0  !!!
180
+	# !!! file rotation is disabled and logfile grows endless !!!
181
+	# log level
182
+#	option	file_level	'INFO'
183
+	# directory where log files are written
184
+#	option	file_path	'/var/log/radicale'
185
+	# max size of each logfile (see warning above)
186
+#	option	file_maxbytes	'8196'
187
+	# number of backup files to create (see warning above)
188
+#	option	file_backupcount	'1'
189
+
190
+	# log level for syslog logging
191
+#	option	syslog_level	'WARNING'
192
+

+ 16
- 0
net/radicale/files/radicale.hotplug View File

@@ -0,0 +1,16 @@
1
+#!/bin/sh
2
+
3
+# only (re-)start on ifup
4
+[ "$ACTION" = "ifup" ] || exit 0
5
+
6
+_PID=$(ps | grep '[p]ython.*[r]adicale' 2>/dev/null | awk '{print \$1}')
7
+kill -1 $_PID 2>/dev/null
8
+if [ $? -eq 0 ]; then
9
+	# only restart if already running
10
+	logger -p user.info -t "radicale[$_PID]" \
11
+		"Restart request due to '$ACTION' of interface '$INTERFACE'"
12
+	/etc/init.d/radicale restart
13
+else
14
+	# only start if enabled
15
+	/etc/init.d/radicale enabled && /etc/init.d/radicale start
16
+fi

+ 220
- 0
net/radicale/files/radicale.init View File

@@ -0,0 +1,220 @@
1
+#!/bin/sh /etc/rc.common
2
+# Copyright (C) 2006-2015 OpenWrt.org
3
+
4
+START=80
5
+STOP=10
6
+
7
+CFGDIR=/var/etc/radicale
8
+SYSCFG=$CFGDIR/config
9
+LOGCFG=$CFGDIR/logging
10
+
11
+DATADIR="/srv/radicale"
12
+LOGDIR=""
13
+
14
+PGREP="ps | grep '[p]ython.*[r]adicale' 2>/dev/null | awk '{print \$1}' "
15
+
16
+# we could start with empty configuration file using defaults
17
+[ -f /etc/config/radicale ] || touch /etc/config/radicale
18
+
19
+_uci2radicale() {
20
+	local _SYSTMP="$SYSCFG.tmp"
21
+	local _LOGTMP="$LOGCFG.tmp"
22
+	local _LOPT				# list option name
23
+	local _LVAL				# list option value
24
+	local _STYPE				# section type
25
+	local _SNAME				# section name
26
+	local _console_level="ERROR"		# logging console level
27
+	local _file_level="INFO"		# logging file level
28
+	local _file_path="/var/log/radicale"	# logging file path
29
+	local _file_maxbytes="8196"		# logging file maxBytes
30
+	local _file_backupcount="1"		# logging file backupCount
31
+	local _syslog_level="WARNING"		# logging syslog level
32
+
33
+	# write list values to config
34
+	_write_list() {
35
+		_write_value "$_LOPT" "$_LVAL"	# there might be spaces in _LVAL
36
+		_LOPT=""
37
+		_LVAL=""
38
+	}
39
+
40
+	_write_value() {
41
+		# $1	option
42
+		# $2	value
43
+		local __OPT=$1
44
+		local __VAL=$2
45
+		# section "server" ignore option "daemon" and "pid"
46
+		[ "$_SNAME" = "server" -a "$__OPT" = "daemon" ] && return 0
47
+		[ "$_SNAME" = "server" -a "$__OPT" = "pid" ] && return 0
48
+		# section "logging" ignore option "config" (logging config file)
49
+		[ "$_SNAME" = "logging" -a "$__OPT" = "config" ] && return 0
50
+		# section "auth" ignore option "htpasswd_filename" (htpasswd file)
51
+		[ "$_SNAME" = "auth" -a "$__OPT" = "htpasswd_filename" ] && return 0
52
+		# section "rights" ignore option "file" (reg-based rights file)
53
+		[ "$_SNAME" = "rights" -a "$__OPT" = "file" ] && return 0
54
+		# section "headers" replace "_" with "-" in option (UCI problem)
55
+		[ "$_SNAME" = "headers" ] && __OPT=$(echo "$__OPT" | sed -e "s#_#-#g")
56
+		# save data driectory
57
+		[ "$_SNAME" = "storage" -a "$__OPT" = "filesystem_folder" ] && DATADIR="$__VAL"
58
+		# special handling for well-known, value needs single quotes
59
+		[ "$_SNAME" = "well-known" -a "${__VAL#*\%\(}" != "$__VAL" ] && __VAL="'$__VAL'"
60
+		# handling of log settings
61
+		if [ "$_STYPE" = "logging" -a "$_SNAME" = "logger" ]; then
62
+			eval "_$__OPT='$__VAL'"	# set to environment for later use
63
+		else
64
+			# handle bool
65
+			[ "$__VAL" = "0" ] && __VAL="False"
66
+			[ "$__VAL" = "1" ] && __VAL="True"
67
+			# append data to the corresponding section
68
+			sed -i "/\[$_SNAME\]/a $__OPT = $__VAL" $_SYSTMP
69
+		fi
70
+	}
71
+
72
+	# redefined callback for sections when calling config_load
73
+	config_cb() {
74
+		# $1	"Type"
75
+		# $2	"Name"
76
+		# write out last list option
77
+		[ -n "$_LOPT" ] && _write_list
78
+		# mark invalid
79
+		_STYPE=""
80
+		_SNAME=""
81
+		# check section type
82
+		[ "$1" = "setting" -o "$1" = "logging" ] && {
83
+			_STYPE="$1"
84
+			_SNAME="$2"
85
+		}
86
+		# translate section name
87
+		[ "$2" = "well_known" ] && _SNAME="well-known"
88
+		return 0
89
+	}
90
+
91
+	# redefined callback for lists when calling config_load
92
+	list_cb() {
93
+		# $1	name of variable
94
+		# $2	value
95
+		# invalid section type then ignore
96
+		[ -z "$_STYPE" -o -z "$_SNAME" ] && return 0
97
+		# write out last list option if new list starts
98
+		[ -n "$_LOPT" -a "$_LOPT" != "$1" ] && _write_list
99
+		# new list option
100
+		if [ -z "$_LOPT" ]; then
101
+			_LOPT="$1"
102
+			_LVAL="$2"
103
+		else
104
+			_LVAL="$_LVAL, $2"
105
+		fi
106
+		return 0
107
+	}
108
+
109
+	# redefined callback for options when calling config_load
110
+	option_cb() {
111
+		# $1	name of variable
112
+		# $2	value
113
+		local __OPT="$1"
114
+		local __VAL="$2"
115
+		# invalid section type then ignore
116
+		[ -z "$_STYPE" -o -z "$_SNAME" ] && return 0
117
+		# ignore list entrys will be handled by list_cb()
118
+    		[ "${__OPT#*_ITEM}" != "$__OPT" ]   && return 0	# ignore lists *_ITEM*
119
+    		[ "${__OPT#*_LENGTH}" != "$__OPT" ] && return 0	# ignore lists *_LENGTH
120
+		# write out last list option and clear
121
+		[ -n "$_LOPT" ] && _write_list
122
+		# write to file
123
+		_write_value "$__OPT" "$__VAL"	# there might be spaces in __VAL
124
+		return 0
125
+	}
126
+
127
+	# temporary config file
128
+	# radicale need read access
129
+	mkdir -m0755 -p $CFGDIR
130
+
131
+	cp /etc/radicale/config.template  $_SYSTMP
132
+	config_load radicale	# calling above config_cb()/option_cb()/list_cb() and write into $_SYSTMP
133
+	sed -i "/\[logging\]/a config = /var/etc/radicale/logging" $_SYSTMP	# hard-code logging config
134
+	sed -i "/\[auth\]/a htpasswd_filename = /etc/radicale/users" $_SYSTMP	# hard-code htpasswd
135
+	sed -i "/\[rights\]/a file = /etc/radicale/rights" $_SYSTMP		# hard-code regexp-based rights
136
+
137
+	# temporary logging config file
138
+	cp /etc/radicale/logging.template $_LOGTMP
139
+	LOGDIR="$_file_path"
140
+	sed -i "/\[handler_console\]/a level = $_console_level" $_LOGTMP
141
+	sed -i "/\[handler_file\]/a level = $_file_level" $_LOGTMP
142
+	sed -i "/\[handler_file\]/a args = ('$_file_path/radicale','a',$_file_maxbytes,$_file_backupcount)" $_LOGTMP
143
+	sed -i "/\[handler_syslog\]/a level = $_syslog_level" $_LOGTMP
144
+
145
+	# move tmp to final
146
+	mv -f $_SYSTMP $SYSCFG
147
+	mv -f $_LOGTMP $LOGCFG
148
+}
149
+
150
+_set_permission() {
151
+	# config file permissions (read access for group)
152
+	chmod 644 $SYSCFG $LOGCFG
153
+	chgrp -R radicale $CFGDIR
154
+	# log directory (full access and owner)
155
+	[ -d $LOGDIR ] || mkdir -m0755 -p $LOGDIR
156
+	chown -R radicale:radicale $LOGDIR
157
+	# data directory does not exist
158
+	[ -d $DATADIR ] || {
159
+		logger -p user.error -t "radicale[----]" "Data directory '$DATADIR' does not exists. Startup failed !!!"
160
+		exit 1
161
+	}
162
+	chgrp -R radicale $DATADIR
163
+}
164
+
165
+boot() {
166
+	return 0	# will be started by "iface" hotplug events
167
+}
168
+
169
+start() {
170
+	_running() {
171
+		sleep 2		# give radicale time to completely come up
172
+		local _PID=$(eval "$PGREP")
173
+		kill -1 $_PID 2>/dev/null
174
+		[ $? -eq 0 ] \
175
+			&& logger -p user.notice -t "radicale[$_PID]" "Service started successfully"\
176
+			|| logger -p user.warn -t "radicale[----]" "Service failed to start"
177
+	}
178
+
179
+	# if already running do nothing
180
+	local _PID=$(eval "$PGREP")
181
+	kill -1 $_PID 2>/dev/null && return 0
182
+
183
+	_uci2radicale
184
+	_set_permission
185
+
186
+	radicale --daemon --config=$SYSCFG
187
+
188
+	_running &	# check if running and syslog
189
+
190
+	return 0
191
+}
192
+
193
+reload() {
194
+	# reload is also used by luci
195
+	local _PID=$(eval "$PGREP")
196
+	kill -1 $_PID 2>/dev/null
197
+	if [ $? -eq 0 ]; then
198
+		# only restart if already running
199
+		restart
200
+	else
201
+		# only start if enabled
202
+		enabled && start
203
+	fi
204
+	return 0
205
+}
206
+
207
+stop() {
208
+	local _PID=$(eval "$PGREP")
209
+	[ -z "$_PID" ] && return 0	# not running
210
+	kill -15 $_PID 2>/dev/null
211
+	sleep 1			# give time to shutdown
212
+	local _tmp=$(eval "$PGREP")
213
+	if [ -z "$_tmp" ]; then
214
+		logger -p user.notice -t "radicale[$_PID]" "Service shutdown successfully"
215
+	else
216
+		kill -9 $_tmp	# Normally never come here
217
+		logger -p user.warn -t "radicale[----]" "Service shutdown FORCED"
218
+	fi
219
+	return 0
220
+}

+ 49
- 0
net/radicale/files/radicale.rights View File

@@ -0,0 +1,49 @@
1
+#
2
+# Authentication login is matched against the "user" key, and collection's path is matched against the "collection" key.
3
+# You can use Python's ConfigParser interpolation values %(login)s and %(path)s.
4
+# You can also get groups from the user regex in the collection with {0}, {1}, etc.
5
+#
6
+# For example, for the "user" key, ".+" means "authenticated user" and ".*" means "anybody" (including anonymous users).
7
+#
8
+# Section names are only used for naming the rule.
9
+# Leading or ending slashes are trimmed from collection's path.
10
+#
11
+
12
+# This means all users starting with "admin" may read any collection
13
+[admin]
14
+user: ^admin.*$
15
+collection: .*
16
+permission: r
17
+
18
+# This means all users may read and write any collection starting with public.
19
+# We do so by just not testing against the user string.
20
+[public]
21
+user: .*
22
+collection: ^public(/.+)?$
23
+permission: rw
24
+
25
+# A little more complex: give read access to users from a domain for all
26
+# collections of all the users (ie. user@domain.tld can read domain/\*).
27
+[domain-wide-access]
28
+user: ^.+@(.+)\..+$
29
+collection: ^{0}/.+$
30
+permission: r
31
+
32
+# Allow authenticated user to read all collections
33
+[allow-everyone-read]
34
+user: .+
35
+collection: .*
36
+permission: r
37
+
38
+# Give write access to owners
39
+[owner-write]
40
+user: .+
41
+collection: ^%(login)s(/.+)?$
42
+permission: rw
43
+
44
+# Allow CardDavMATE-, CalDavZAP- or InfCloud- WEBclient to work
45
+# anonymous users have read access to "/" but no files or subdir
46
+[infcloud]
47
+user: .*
48
+collection: /
49
+permission: r

+ 6
- 0
net/radicale/files/radicale.users View File

@@ -0,0 +1,6 @@
1
+#
2
+# Sample File
3
+#
4
+
5
+user1:password1
6
+user2:password2

+ 30
- 0
net/radicale/patches/010-Run-as-user-group-radicale-radicale.patch View File

@@ -0,0 +1,30 @@
1
+Subject: [PATCH] Run as user radicale and group radicale
2
+
3
+Patch to run Radicale service as radicale:radicale non root user
4
+
5
+Signed-off-by: Christian Schoenebeck <christian.schoenebeck@gmail.com>
6
+---
7
+ bin/radicale | 7 +++++++
8
+ 1 file changed, 7 insertions(+)
9
+
10
+diff --git a/bin/radicale b/bin/radicale
11
+index 619aca5..7466020 100755
12
+--- a/bin/radicale
13
++++ b/bin/radicale
14
+@@ -26,6 +26,13 @@ Launch the server according to configuration and command-line options.
15
+ 
16
+ """
17
+ 
18
++# inserted to run as user radicale
19
++import pwd, grp, os
20
++uid = pwd.getpwnam('radicale').pw_uid
21
++gid = grp.getgrnam('radicale').gr_gid
22
++os.setegid(gid)
23
++os.seteuid(uid)
24
++
25
+ import radicale.__main__
26
+ 
27
+ 
28
+-- 
29
+2.1.0
30
+