diff --git a/net/radicale2/Makefile b/net/radicale2/Makefile new file mode 100644 index 000000000..5bf5c1f44 --- /dev/null +++ b/net/radicale2/Makefile @@ -0,0 +1,106 @@ +# 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 + +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 +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)) diff --git a/net/radicale2/files/radicale2.config b/net/radicale2/files/radicale2.config new file mode 100644 index 000000000..5107219df --- /dev/null +++ b/net/radicale2/files/radicale2.config @@ -0,0 +1,7 @@ +#config section server + # list host 127.0.0.1:5232 + # list host ::1:5232 + +#config user + #option name user1 + #option password password1 diff --git a/net/radicale2/files/radicale2.init b/net/radicale2/files/radicale2.init new file mode 100755 index 000000000..ac7a81a75 --- /dev/null +++ b/net/radicale2/files/radicale2.init @@ -0,0 +1,278 @@ +#!/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" +} diff --git a/net/radicale2/patches/110-disable-setup_requirements.patch b/net/radicale2/patches/110-disable-setup_requirements.patch new file mode 100644 index 000000000..9957045ae --- /dev/null +++ b/net/radicale2/patches/110-disable-setup_requirements.patch @@ -0,0 +1,13 @@ +Index: radicale2-python3-2.1.11/setup.py +=================================================================== +--- radicale2-python3-2.1.11.orig/setup.py ++++ radicale2-python3-2.1.11/setup.py +@@ -67,7 +67,7 @@ setup( + package_data={"radicale": WEB_FILES}, + entry_points={"console_scripts": ["radicale = radicale.__main__:run"]}, + install_requires=["vobject>=0.9.6", "python-dateutil>=2.7.3"], +- setup_requires=pytest_runner, ++ setup_requires=[], + tests_require=tests_require, + extras_require={ + "test": tests_require,