--- /dev/null
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=radicale2
+PKG_VERSION:=2.1.11
+PKG_RELEASE:=1
+PKG_MAINTAINER:=Daniel Dickinson <cshored@thecshore.com>
+
+PKG_LICENSE:=GPL-3.0
+PKG_LICENSE_FILES:=COPYING
+
+PKG_SOURCE:=Radicale-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://files.pythonhosted.org/packages/source/R/Radicale/
+PKG_HASH:=02273fcc6ae10e0f74aa12652e24d0001eec8dbf467d54ddb4dfcc2af7d7a5db
+PKG_BUILD_DIR:=$(BUILD_DIR)/radicale2-$(BUILD_VARIANT)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+include ../../lang/python/python3-package.mk
+
+PKG_UNPACK:=$(HOST_TAR) -C $(PKG_BUILD_DIR) --strip-components=1 -xzf $(DL_DIR)/$(PKG_SOURCE)
+
+define Package/radicale2/Default
+ SECTION:=net
+ CATEGORY:=Network
+ SUBMENU:=Web Servers/Proxies
+ URL:=http://radicale.org/
+ TITLE:=Radicale 2.x CalDAV/CardDAV server
+ MAINTAINER:=Daniel Dickinson <cshored@thecshore.com>
+endef
+
+define Package/radicale2
+$(call Package/radicale2/Default)
+ USERID:=radicale2=225:radicale2=225
+ DEPENDS:=+python3 +python3-dateutil +python3-vobject +python3-setuptools
+ CONFLICTS:=radicale
+ VARIANT:=python3
+endef
+
+define Package/radicale2-examples
+$(call Package/radicale2/Default)
+ TITLE:=Radicale v2 example configs
+endef
+
+define Package/radicale2-meta/description
+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.
+
+The Radicale Project runs on most of the UNIX-like platforms (Linux, BSD, MacOS X) and Windows. It is known to work with Evolution, Lightning, iPhone and Android clients. It is free and open-source software, released under GPL version 3.
+endef
+
+define Package/radicale2/description
+$(call Package/radicale2-meta/description)
+.
+This package contains the python files.
+endef
+
+define Package/radicale2-examples/description
+$(call Package/radicale2-meta/description)
+.
+This package contains upstream configs for example purposes.
+endef
+
+define Package/radicale2/conffiles
+/etc/config/radicale2
+/etc/radicale2/config
+/etc/radicale2/users
+/etc/radicale2/rights
+/etc/radicale2/logging
+endef
+
+define Package/radicale2/preinst
+ #!/bin/sh
+ [ -n "$${IPKG_INSTROOT}" ] && exit 0 # if run within buildroot exit
+
+ # stop service if PKG_UPGRADE
+ [ "$${PKG_UPGRADE}" = "1" ] && /etc/init.d/radicale2 stop >/dev/null 2>&1
+
+ exit 0 # suppress errors from stop command
+endef
+
+define Py3Package/radicale2/filespec
+ +|$(PYTHON3_PKG_DIR)
+ +|/usr/bin/radicale2|0755
+endef
+
+define Py3Package/radicale2/install
+ $(INSTALL_DIR) $(1)/usr/bin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/radicale $(PKG_INSTALL_DIR)/usr/bin/radicale2
+ $(SED) 's,^#!.*python.*,#!/usr/bin/python$(PYTHON3_VERSION),' $(PKG_INSTALL_DIR)/usr/bin/radicale2
+ $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d
+ $(INSTALL_CONF) ./files/radicale2.config $(1)/etc/config/radicale2
+ $(INSTALL_BIN) ./files/radicale2.init $(1)/etc/init.d/radicale2
+endef
+
+define Package/radicale2-examples/install
+ $(INSTALL_DIR) $(1)/usr/share/radicale2
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/config $(1)/usr/share/radicale2/config.example
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/rights $(1)/usr/share/radicale2/rights.example
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/logging $(1)/usr/share/radicale2/logging.example
+endef
+
+$(eval $(call Py3Package,radicale2))
+$(eval $(call BuildPackage,radicale2))
+$(eval $(call BuildPackage,radicale2-src))
+$(eval $(call BuildPackage,radicale2-examples))
--- /dev/null
+#!/bin/sh /etc/rc.common
+
+START=80
+STOP=10
+
+CFGDIR=/var/etc/radicale2
+SYSCFG=$CFGDIR/config
+USRCFG=$CFGDIR/users
+
+DATADIR="/srv/radicale2/data"
+LOGDIR=""
+USE_PROCD=1
+
+# we could start with empty configuration file using defaults
+[ -f ${IPKG_INSTROOT}/etc/config/radicale2 ] || touch ${IPKG_INSTROOT}/etc/config/radicale2
+
+conf_line() {
+ local cfgfile="$1"
+ local option="$2"
+ local value="$3"
+
+ if [ -n "$value" ]; then
+ eval "echo '$2' = '$value' >>'$cfgfile'"
+ fi
+}
+
+conf_getline() {
+ local cfg="$1"
+ local cfgfile="$2"
+ local option="$3"
+ local defval="$4"
+ local flag="$5"
+ unset value
+
+ if [ "$flag" != "1" ]; then
+ config_get value "$cfg" "$option" "$defval"
+ conf_line "$cfgfile" "$option" "$value"
+ else
+ config_get_bool value "$cfg" "$option" "$defval"
+ [ -z "$defval" ] && defval=1
+ if [ "$value" -ne "$defval" ]; then
+ if [ "$value" -ne 0 ]; then
+ conf_line "$cfgfile" "$option" "True"
+ else
+ conf_line "$cfgfile" "$option" "False"
+ fi
+ fi
+ fi
+}
+
+build_hosts_line() {
+ local val="$1"
+
+ append hostlist "$val" ", "
+}
+
+conf_section() {
+ local cfg="$1"
+ local cfgfile="$2"
+ local hostlist=""
+ local value
+
+ echo "[$cfg]
+" >>$cfgfile
+
+ case $cfg in
+ server)
+ config_list_foreach "$cfg" host build_hosts_line
+ conf_line "$tmpfile" hosts "$hostlist"
+ conf_getline "$cfg" $tmpfile max_connections
+ conf_getline "$cfg" $tmpfile max_conntent_length
+ conf_getline "$cfg" $tmpfile timeout
+
+ conf_getline "$cfg" $tmpfile ssl 0 1
+ if [ "$value" -eq 1 ]; then
+ conf_getline "$cfg" $tmpfile certificate
+ conf_getline "$cfg" $tmpfile key
+ conf_getline "$cfg" $tmpfile certificate_authority
+ conf_getline "$cfg" $tmpfile protocol
+ conf_getline "$cfg" $tmpfile ciphers
+ fi
+
+ conf_getline "$cfg" $tmpfile dns_lookup 1 1
+ conf_getline "$cfg" $tmpfile realm
+ ;;
+ encoding)
+ conf_getline "$cfg" $tmpfile request
+ conf_getline "$cfg" $tmpfile stock
+ ;;
+ auth)
+ conf_getline "$cfg" $tmpfile "type" htpasswd
+ if [ "$value" = "htpasswd" ]; then
+ conf_getline "$cfg" $tmpfile htpasswd_filename $CFGDIR/users
+ conf_getline "$cfg" "$tmpfile" htpasswd_encryption plain
+ fi
+
+ conf_getline "$cfg" "$tmpfile" delay
+ ;;
+ rights)
+ conf_getline "$cfg" "$tmpfile" "type"
+ if [ "$value" = "from_file" ]; then
+ conf_getline "$cfg" "$tmpfile" "file"
+ fi
+ ;;
+ storage)
+ conf_getline "$cfg" $tmpfile filesystem_folder "$DATADIR"
+ DATADIR="$value"
+ conf_getline "$cfg" $tmpfile filesystem_locking 1 1
+ conf_getline "$cfg" $tmpfile max_sync_token_age
+ conf_getline "$cfg" $tmpfile filesystem_close_lock_file 0 1
+ conf_getline "$cfg" $tmpfile hook
+ ;;
+ web)
+ conf_getline "$cfg" $tmpfile "type"
+ ;;
+ logging)
+ conf_getline "$cfg" "$tmpfile" config
+ conf_getline "$cfg" "$tmpfile" debug 0 1
+ conf_getline "$cfg" "$tmpfile" full_environment 0 1
+ conf_getline "$cfg" "$tmpfile" mask_passwords 1 1
+ ;;
+ headers)
+ config_get "$cfg" "$tmpfile" cors
+ if [ -n "$cors" ]; then
+ echo "Access-Control-Allow-Origin = $cors" >>$tmpfile
+ fi
+ ;;
+ esac
+
+ echo "
+" >>$cfgfile
+}
+
+add_missing_sections() {
+ local cfgfile="$1"
+
+ for section in server encoding auth rights storage web logging headers; do
+ if [ "$section" = "server" ]; then
+ grep -q "\[$section\]" $cfgfile || echo "
+[$section]
+hosts = 0.0.0.0:5232, [::]:5232
+
+" >>$cfgfile
+ elif [ "$section" = "auth" ]; then
+ grep -q "\[$section\]" $cfgfile || echo "
+[$section]
+type = htpasswd
+htpasswd_filename = $CFGDIR/users
+htpasswd_encryption = plain
+
+" >>$cfgfile
+ elif [ "$section" = "storage" ]; then
+ grep -q "\[$section\]" $cfgfile || echo "
+[$section]
+filesystem_folder = $DATADIR
+
+" >>$cfgfile
+ else
+ grep -q "\[$section\]" $cfgfile || echo "
+[$section]
+
+" >>$cfgfile
+ fi
+ done
+}
+
+add_user() {
+ local cfg="$1"
+ local tmpfile="$2"
+ local name password
+
+ config_get name "$cfg" name
+ config_get password "$cfg" password
+
+ [ -n "$name" ] && echo "$name:$password" >>$tmpfile
+}
+
+build_users() {
+ local tmpfile="$1"
+
+ # temporary config file
+ # radicale2 needs read access
+ chmod 0640 $tmpfile
+
+ config_foreach add_user user "$tmpfile"
+}
+
+build_config() {
+ local tmpfile=$(mktemp)
+ local tmpfile2=$(mktemp)
+
+ # temporary config file
+ # radicale2 need read access
+ chmod 0640 $tmpfile
+
+ config_load radicale2
+ config_foreach conf_section section $tmpfile
+ add_missing_sections $tmpfile
+
+ build_users $tmpfile2
+
+ # move tmp to final
+ mkdir -m0750 -p $CFGDIR
+ cat $tmpfile >$SYSCFG
+ rm -f $tmpfile
+ cat $tmpfile2 >$USRCFG
+ rm -f $tmpfile2
+}
+
+set_permission() {
+ # config file permissions (read access for group)
+ chmod 0750 $CFGDIR
+ chmod 0640 $SYSCFG
+ chmod 0640 $USRCFG
+ chgrp -R radicale2 $CFGDIR
+ # data directory does not exist
+ [ -d $DATADIR ] || {
+ logger -p user.error -t "radicale2[----]" "Data directory '$DATADIR' does not exist. Startup failed !!!"
+ }
+}
+
+
+interface_triggers() {
+ local action="$1"
+ local triggerlist trigger
+
+ config_load radicale2
+ config_get triggerlist server triggerlist
+
+ . /lib/functions/network.sh
+
+ if [ -n "$triggerlist" ]; then
+ for trigger in $triggerlist; do
+ if [ "$action" = "add_trigger" ]; then
+ procd_add_interface_trigger "interface.*" "$trigger" /etc/init.d/radicale2 reload
+ else
+ network_is_up "$trigger" && return 0
+ fi
+ done
+ else
+ if [ "$action" = "add_trigger" ]; then
+ procd_add_raw_trigger "interface.*.up" 2000 /etc/init.d/radicale2 reload
+ else
+ ubus call network.device status | grep -q '"up": true' && return 0
+ fi
+ fi
+ [ "$action" = "add_trigger" ] || return 1
+}
+
+start_service() {
+ local haveinterface
+
+ if [ ! -r /etc/radicale2/config ]; then
+ build_config
+ set_permission
+ fi
+
+ interface_triggers "check_interface_up" || return
+
+ procd_open_instance "radicale2"
+ procd_set_param respawn
+ procd_set_param stderr 1
+ procd_set_param stdout 1
+ if [ ! -r /etc/radicale2/config ]; then
+ procd_set_param command /usr/bin/radicale2 --config="$SYSCFG"
+ else
+ procd_set_param command /usr/bin/radicale2 --config="/etc/radicale2/config"
+ fi
+ procd_set_param user radicale2
+ procd_close_instance
+
+ return 0
+}
+
+service_triggers() {
+ interface_triggers "add_trigger"
+ procd_add_reload_trigger "radicale2"
+}