Merge pull request #22645 from yggdrasil-openwrt/yggdrasil-2023-11-11
authorJo-Philipp Wich <jo@mein.io>
Thu, 30 Nov 2023 15:25:36 +0000 (16:25 +0100)
committerGitHub <noreply@github.com>
Thu, 30 Nov 2023 15:25:36 +0000 (16:25 +0100)
yggdrasil: overhaul package with netifd support

196 files changed:
.github/workflows/multi-arch-test-build.yml
lang/golang/golang/Makefile
lang/lua-eco/Makefile
lang/luajit2/Makefile
lang/node/Makefile
lang/node/patches/003-path.patch
lang/perl/Makefile
lang/perl/files/base.config
lang/perl/files/libc.config
lang/perl/files/version.config
lang/perl/patches/001-macos_11_support.patch [deleted file]
lang/perl/patches/002-add-Internals-getcwd.patch [deleted file]
lang/perl/patches/003-fallback-to-the-built-in-getcwd-if-we-ca.patch [deleted file]
lang/perl/patches/010-musl-compat.patch
lang/perl/patches/020-storables-stacksize.patch [deleted file]
lang/perl/patches/110-always_use_miniperl.patch
lang/perl/patches/120-remove-build-timestamp.patch
lang/perl/patches/301-fix_macos_static_linking.patch [deleted file]
lang/perl/patches/320-copy-pod-hack.patch
lang/perl/patches/900-use-rm-force.patch
lang/perl/patches/910-miniperl-needs-inc-dot.patch
lang/perl/patches/920-fix-no-locale.patch [deleted file]
lang/perl/patches/998-Errno_errno.h_path.patch
lang/perl/patches/999-fix-build-failure-against-gcc-10.patch [deleted file]
lang/perl/patches/999-fixup-regex-engine-build-under-Uusedl.patch [new file with mode: 0644]
lang/perl/perlbase.mk
lang/perl/perlver.mk
lang/python/pipx/Makefile [new file with mode: 0644]
lang/python/pipx/test.sh [new file with mode: 0644]
lang/python/python-argcomplete/Makefile [new file with mode: 0644]
lang/python/python-argcomplete/patches/001-unpin-setuptools.patch [new file with mode: 0644]
lang/python/python-argcomplete/test.sh [new file with mode: 0644]
lang/python/python-fnv-hash-fast/Makefile [new file with mode: 0644]
lang/python/python-fnvhash/Makefile [new file with mode: 0644]
lang/python/python-hatch-vcs/Makefile
lang/python/python-idna/Makefile
lang/python/python-idna/test.sh [new file with mode: 0644]
lang/python/python-jsonschema-specifications/Makefile [new file with mode: 0644]
lang/python/python-jsonschema-specifications/test.sh [new file with mode: 0644]
lang/python/python-jsonschema/Makefile
lang/python/python-jsonschema/test.sh [new file with mode: 0644]
lang/python/python-lru-dict/Makefile [new file with mode: 0644]
lang/python/python-mako/Makefile
lang/python/python-orjson/Makefile [new file with mode: 0644]
lang/python/python-poetry-core/Makefile
lang/python/python-pyasn1/Makefile
lang/python/python-pyasn1/test.sh [new file with mode: 0644]
lang/python/python-referencing/Makefile [new file with mode: 0644]
lang/python/python-referencing/test.sh [new file with mode: 0644]
lang/python/python-rpds-py/Makefile [new file with mode: 0644]
lang/python/python-rpds-py/test.sh [new file with mode: 0644]
lang/python/python-setuptools/Makefile
lang/python/python-trove-classifiers/Makefile
lang/python/python-twisted/Makefile
lang/python/python-twisted/patches/001-omit-tkconch.patch
lang/python/python-twisted/patches/002-omit-tests.patch
lang/python/python-userpath/Makefile [new file with mode: 0644]
lang/python/python-userpath/patches/0001-Handle-OSErrors-when-running-show-path-commands.patch [new file with mode: 0644]
lang/python/python-userpath/patches/0001-Use-Sh-as-base-class-for-Bash-and-Zsh.patch [new file with mode: 0644]
lang/python/python-userpath/patches/0002-Add-support-for-ash-Almquist-shell.patch [new file with mode: 0644]
lang/python/python-userpath/test.sh [new file with mode: 0644]
lang/python/python-wheel/Makefile
lang/rust/Makefile
lang/rust/patches/0001-Update-xz2-and-use-it-static.patch
lang/rust/patches/0002-rustc-bootstrap-cache.patch
lang/rust/patches/0003-bump-libc-deps-to-0.2.146.patch
libs/avahi/Makefile
libs/elektra/Makefile
libs/elektra/patches/010-gcc13.patch [new file with mode: 0644]
libs/icu/Makefile
libs/libdaq3/Makefile
libs/libnpupnp/Makefile
libs/libupnpp/Makefile
libs/liburing/Makefile
libs/libzip/Makefile
libs/libzip/patches/010-nossl.patch [deleted file]
libs/quasselc/Makefile [deleted file]
libs/quasselc/patches/001-respect-cflags-ldflags.patch [deleted file]
multimedia/yt-dlp/Makefile
net/acme-acmesh/Makefile
net/adblock-fast/Makefile
net/adblock-fast/files/etc/config/adblock-fast
net/adblock-fast/files/etc/init.d/adblock-fast
net/adblock-fast/files/etc/uci-defaults/90-adblock-fast
net/aria2/Makefile
net/banip/Makefile
net/banip/files/banip-functions.sh
net/banip/files/banip.feeds
net/banip/files/banip.init
net/cni-protocol/Makefile [deleted file]
net/cni-protocol/files/cni.sh [deleted file]
net/croc/Makefile
net/crowdsec/Makefile
net/ddns-scripts/Makefile
net/ddns-scripts/files/usr/lib/ddns/update_route53_v1.sh
net/dhtd/Makefile [new file with mode: 0644]
net/dhtd/files/dhtd.config [new file with mode: 0644]
net/dhtd/files/dhtd.init [new file with mode: 0755]
net/dnsproxy/Makefile
net/external-protocol/Makefile [new file with mode: 0644]
net/external-protocol/files/external.sh [new file with mode: 0755]
net/fail2ban/Makefile
net/fail2ban/patches/101-move-global-groups-to-start-of-expression-python-3.11-compat.patch [new file with mode: 0644]
net/fail2ban/patches/102-wrap-global-flags-to-local-flags-if-supported-by-RE-engine-in-the-python-version.patch [new file with mode: 0644]
net/freeradius3/Makefile
net/gensio/Makefile
net/gensio/patches/0001-Ensure-that-ax_python_devel_found-is-defined.patch [new file with mode: 0644]
net/gensio/patches/0002_ax_python_devel-fix-serial.patch [new file with mode: 0644]
net/gensio/patches/0003-Revert-ax_pkg_swig.m4-to-latest-vanilla-version.patch [new file with mode: 0644]
net/haproxy/Makefile
net/haproxy/get-latest-patches.sh
net/hcxdumptool/Makefile
net/hcxdumptool/patches/010-openssl.patch [deleted file]
net/hcxtools/Makefile
net/hcxtools/patches/010-openssl.patch [deleted file]
net/https-dns-proxy/Makefile
net/https-dns-proxy/files/etc/init.d/https-dns-proxy
net/https-dns-proxy/patches/020-src-options.c-add-version.patch
net/iperf3/Makefile
net/netbird/Makefile
net/netbird/files/netbird.init
net/openvpn/Makefile
net/openvpn/patches/100-mbedtls-disable-runtime-version-check.patch
net/openvpn/patches/101-Fix-EVP_PKEY_CTX_-compilation-with-wolfSSL.patch
net/openvpn/patches/102-Disable-external-ec-key-support-when-building-with-wolfSSL.patch
net/openvpn/patches/103-define-LN_serialNumber-for-wolfSSL.patch
net/pdns-recursor/Makefile
net/pptpd/Makefile
net/pptpd/files/pptpd.init
net/quassel-irssi/Makefile [deleted file]
net/quassel-irssi/patches/001-respect-cflags.patch [deleted file]
net/quassel-irssi/patches/002-use-cc-var.patch [deleted file]
net/quassel-irssi/patches/003-use-pkgconfig-ldflags-quasselc.patch [deleted file]
net/quassel-irssi/patches/010-Get-compatible-with-potential-irssi-abi-8-and-drop-p.patch [deleted file]
net/sing-box/Makefile
net/snort3/Makefile
net/snort3/patches/010-gcc13.patch [new file with mode: 0644]
net/sstp-client/Makefile
net/sstp-client/patches/200-openssl-deprecated.patch
net/strongswan/Makefile
net/strongswan/files/swanctl.init
net/strongswan/patches/0900-src-Patch-for-building-with-musl-on-openwrt-taken-ve.patch
net/strongswan/patches/0904-gmpdh-Plugin-that-implements-gmp-DH-functions-in-an-.patch
net/tailscale/Makefile
net/travelmate/Makefile
net/travelmate/files/hreward.login [new file with mode: 0755]
net/udp-broadcast-relay-redux-openwrt/Makefile
net/udp-broadcast-relay-redux-openwrt/files/udp-broadcast-relay-redux.init
net/udp-broadcast-relay-redux-openwrt/files/udp_broadcast_relay_redux.config
net/unbound/Makefile
net/unbound/files/dnsmasq.sh
net/unbound/patches/010-configure-uname.patch
net/v2ray-core/Makefile
net/v2ray-geodata/Makefile
net/v2raya/Makefile
net/xray-core/Makefile
sound/pulseaudio/Makefile
sound/shairplay/Makefile [deleted file]
sound/shairplay/files/shairplay.config [deleted file]
sound/shairplay/files/shairplay.init [deleted file]
sound/shairplay/patches/001-key_file_dir.patch [deleted file]
sound/shairplay/patches/003-fix_big-endian.patch [deleted file]
sound/shairplay/patches/010-configure-only-check-for-dns_sd.h-in-case-libdl-was-.patch [deleted file]
sound/upmpdcli/Makefile
utils/docker-compose/Makefile
utils/domoticz/Makefile
utils/domoticz/patches/010-gcc12.patch [deleted file]
utils/domoticz/patches/012-minizip-overflow.patch [deleted file]
utils/domoticz/patches/990-python3.10_fix.patch [deleted file]
utils/domoticz/patches/991-linux_crash_when_formating_py.patch [deleted file]
utils/domoticz/patches/992-prevent_crash_processing_py.patch [deleted file]
utils/domoticz/patches/994-compile_err_whitout_py.patch [deleted file]
utils/domoticz/patches/995-make_sure_compile_works_without_py.patch [deleted file]
utils/dysk/Makefile [new file with mode: 0644]
utils/fuse3/Makefile
utils/fx/Makefile [new file with mode: 0644]
utils/gl-puli-mcu/Config.in [new file with mode: 0644]
utils/gl-puli-mcu/Makefile
utils/gl-puli-mcu/src/gl-puli-mcu.c
utils/gummiboot/Makefile
utils/gummiboot/patches/030-fix-efi-conflicts.patch [new file with mode: 0644]
utils/irqbalance/Makefile
utils/irqbalance/patches/001-upstream-fix-aarch64-irq-parsing.patch [deleted file]
utils/mc/Makefile
utils/mc/patches/010-subshell.patch
utils/mc/patches/020-fix-mouse-handling-newer-terminfo.patch
utils/mc/patches/030-mc-mksh-subshell-v2.patch
utils/nano/Makefile
utils/nano/files/ucode.nanorc [new file with mode: 0644]
utils/pps-tools/Makefile
utils/pps-tools/patches/001-time_t_64bit.patch [new file with mode: 0644]
utils/sockread/Makefile
utils/sockread/src/main.c
utils/tang/Makefile
utils/tang/files/tang.init
utils/yq/Makefile

index 57182b96b65fe8e748263c91590d2b0103080a26..396bd190d9b035504c4485bd7cb1839a02b7eac5 100644 (file)
@@ -101,17 +101,20 @@ jobs:
           echo "$EOF" >> $GITHUB_ENV
 
       - name: Build
-        uses: openwrt/gh-action-sdk@v5
+        uses: openwrt/gh-action-sdk@v7
         env:
           ARCH: ${{ matrix.arch }}-${{ env.BRANCH }}
           FEEDNAME: packages_ci
           INDEX: 1
           KEY_BUILD: ${{ env.KEY_BUILD }}
+          V: s
 
       - name: Move created packages to project dir
+        if: always()
         run: cp bin/packages/${{ matrix.arch }}/packages_ci/* . || true
 
       - name: Collect metadata
+        if: always()
         run: |
           MERGE_ID=$(git rev-parse --short HEAD)
           echo "MERGE_ID=$MERGE_ID" >> $GITHUB_ENV
@@ -122,6 +125,7 @@ jobs:
           echo "ARCHIVE_NAME=${{matrix.arch}}-PR$PRNUMBER-$MERGE_ID" >> $GITHUB_ENV
 
       - name: Generate metadata
+        if: always()
         run: |
           cat << _EOF_ > PKG-INFO
           Metadata-Version: 2.1
@@ -148,6 +152,7 @@ jobs:
           cat PKG-INFO
 
       - name: Store packages
+        if: always()
         uses: actions/upload-artifact@v3
         with:
           name: ${{env.ARCHIVE_NAME}}-packages
@@ -158,6 +163,7 @@ jobs:
             PKG-INFO
 
       - name: Store logs
+        if: always()
         uses: actions/upload-artifact@v3
         with:
           name: ${{env.ARCHIVE_NAME}}-logs
@@ -166,6 +172,7 @@ jobs:
             PKG-INFO
 
       - name: Remove logs
+        if: always()
         run: sudo rm -rf logs/ || true
 
       - name: Check if any packages were built
index 094dea2b11e48b61a115686267b8b74b871b683e..55da6587bd4589a247e0e0925751666fd21c5459 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 GO_VERSION_MAJOR_MINOR:=1.21
-GO_VERSION_PATCH:=3
+GO_VERSION_PATCH:=4
 
 PKG_NAME:=golang
 PKG_VERSION:=$(GO_VERSION_MAJOR_MINOR)$(if $(GO_VERSION_PATCH),.$(GO_VERSION_PATCH))
@@ -20,7 +20,7 @@ GO_SOURCE_URLS:=https://dl.google.com/go/ \
 
 PKG_SOURCE:=go$(PKG_VERSION).src.tar.gz
 PKG_SOURCE_URL:=$(GO_SOURCE_URLS)
-PKG_HASH:=186f2b6f8c8b704e696821b09ab2041a5c1ee13dcbc3156a13adcf75931ee488
+PKG_HASH:=47b26a83d2b65a3c1c1bcace273b69bee49a7a7b5168a7604ded3d26a37bd787
 
 PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
 PKG_LICENSE:=BSD-3-Clause
index 95b9fd38f8737913a0a54b0c2b3f73830eae676e..1d472f22627c61b8c5c94c5d53bdcf0540023141 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=lua-eco
-PKG_VERSION:=3.0.1
+PKG_VERSION:=3.1.0
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL=https://github.com/zhaojh329/lua-eco/releases/download/v$(PKG_VERSION)
-PKG_HASH:=96f008932e319739df2fe99dc1cba7e9a1a389015a4b96ad0f63d95bb6422b09
+PKG_HASH:=bb48af3f65a2c5d69b06b32ec2734bcb77cc6315b208be4fe3b0ae5fc0a82a33
 
 PKG_MAINTAINER:=Jianhui Zhao <zhaojh329@gmail.com>
 PKG_LICENSE:=MIT
@@ -61,6 +61,7 @@ Package/lua-eco-termios=$(call Package/lua-eco/Module,termios)
 Package/lua-eco-netlink=$(call Package/lua-eco/Module,netlink,+lua-eco-socket)
 Package/lua-eco-ip=$(call Package/lua-eco/Module,ip utils,+lua-eco-netlink)
 Package/lua-eco-nl80211=$(call Package/lua-eco/Module,nl80211,+lua-eco-netlink)
+Package/lua-eco-ssh=$(call Package/lua-eco/Module,ssh,+lua-eco-socket +libssh2)
 
 define Package/lua-eco-ssl/config
        choice
@@ -182,6 +183,12 @@ define Package/lua-eco-nl80211/install
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/nl80211.so $(1)/usr/local/lib/lua/5.3/eco/core
 endef
 
+define Package/lua-eco-ssh/install
+       $(INSTALL_DIR) $(1)/usr/local/lib/lua/5.3/eco/core
+       $(INSTALL_DATA) $(PKG_BUILD_DIR)/ssh.lua $(1)/usr/local/lib/lua/5.3/eco
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/ssh.so $(1)/usr/local/lib/lua/5.3/eco/core
+endef
+
 $(eval $(call BuildPackage,lua-eco))
 $(eval $(call BuildPackage,lua-eco-log))
 $(eval $(call BuildPackage,lua-eco-base64))
@@ -198,3 +205,4 @@ $(eval $(call BuildPackage,lua-eco-termios))
 $(eval $(call BuildPackage,lua-eco-netlink))
 $(eval $(call BuildPackage,lua-eco-ip))
 $(eval $(call BuildPackage,lua-eco-nl80211))
+$(eval $(call BuildPackage,lua-eco-ssh))
index 756381374eb3109b01aa55f79de1f74eb9b1cdeb..219736d964e5ee19c2ddc83443e4cc305559a416 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=luajit2
-PKG_VERSION:=2.1-20231006
+PKG_VERSION:=2.1-20231117
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://github.com/openresty/luajit2/archive/refs/tags/v$(PKG_VERSION).tar.gz?
-PKG_HASH:=41530b3f00d3f284e771cfd09add2a0c672f1214f8780644ca9261da9e4d9310
+PKG_HASH:=cc92968c57c00303eb9eaebf65cc8b29a0f851670f16bb514896ab5057ae381f
 
 PKG_MAINTAINER:=Javier Marcet <javier@marcet.info>
 PKG_LICENSE:=MIT
index 692bedf3876a2c3671358e98bc484e9c0b054799..b37c433b336dee9f4ecb947ba674e4d408db9d8d 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=node
-PKG_VERSION:=v20.9.0
+PKG_VERSION:=v20.10.0
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://nodejs.org/dist/$(PKG_VERSION)
-PKG_HASH:=a23d96810abf0455426b349d47ce5310f33095b7bc0571b9cc510f481c3a4519
+PKG_HASH:=32eb256eebd8cacd5574e6631e54b42be7ec8ebe25ad47a8ca685403bad15535
 
 PKG_MAINTAINER:=Hirokazu MORIKAWA <morikw2@gmail.com>, Adrian Panella <ianchi74@outlook.com>
 PKG_LICENSE:=MIT
index 011b02489760f585f1842bf9641544071e2ce7a2..06201179bc291e9af37a5f02380435a563c9eef7 100644 (file)
@@ -1,6 +1,6 @@
 --- a/lib/internal/modules/cjs/loader.js
 +++ b/lib/internal/modules/cjs/loader.js
-@@ -1378,7 +1378,8 @@ Module._initPaths = function() {
+@@ -1537,7 +1537,8 @@ Module._initPaths = function() {
      path.resolve(process.execPath, '..') :
      path.resolve(process.execPath, '..', '..');
  
index 7b603b5af28842f35a8873f07b6259a667037c1c..5249a0505e2ec2032d1bf5cd70e455e440d2ec9c 100644 (file)
@@ -11,22 +11,15 @@ include perlver.mk
 
 PKG_NAME:=perl
 PKG_VERSION:=$(PERL_VERSION)
-PKG_RELEASE:=10
-
-PKG_SOURCE_URL:=\
-               https://cpan.metacpan.org/src/5.0 \
-               https://cpan.uib.no/src/5.0 \
-               https://mirrors.rit.edu/CPAN/src/5.0 \
-               https://mirror.transip.net/CPAN/src/5.0 \
-               https://mirrors.sonic.net/cpan/src/5.0 \
-               https://www.cpan.org/src/5.0
+PKG_RELEASE:=1
+
+PKG_SOURCE_URL:=https://www.cpan.org/src/5.0
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
-PKG_HASH:=fea7162d4cca940a387f0587b93f6737d884bf74d8a9d7cfd978bc12cd0b202d
+PKG_HASH:=eca551caec3bc549a4e590c0015003790bdd1a604ffe19cc78ee631d51f7072e
 
 PKG_LICENSE:=GPL-1.0-or-later Artistic-1.0-Perl
 PKG_LICENSE_FILES:=Copying Artistic README
-PKG_MAINTAINER:=Marcel Denia <naoir@gmx.net>, \
-               Philip Prindeville <philipp@redfish-solutions.com>
+PKG_MAINTAINER:=Marcel Denia <naoir@gmx.net>, Philip Prindeville <philipp@redfish-solutions.com>
 PKG_CPE_ID:=cpe:/a:perl:perl
 
 # Build settings
index f2d18f547061f25ee93d0bda0937d9190042e441..67232b6d83e70505e7e85ad6893a2661f4571f7f 100644 (file)
@@ -81,6 +81,7 @@ d_asinh='define'
 d_atanh='define'
 d_atolf='undef'
 d_atoll='define'
+d_attribute_always_inline='define'
 d_attribute_deprecated='define'
 d_attribute_format='define'
 d_attribute_malloc='define'
@@ -88,6 +89,7 @@ d_attribute_nonnull='define'
 d_attribute_noreturn='define'
 d_attribute_pure='define'
 d_attribute_unused='define'
+d_attribute_visibility='define'
 d_attribute_warn_unused_result='define'
 d_backtrace='define'
 d_bcmp='define'
@@ -179,6 +181,8 @@ d_fd_macros='define'
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_ffs='define'
+d_ffsl='define'
 d_fgetpos='define'
 d_finite='define'
 d_finitel='undef'
@@ -214,6 +218,7 @@ d_gdbm_ndbm_h_uses_prototypes='undef'
 d_gdbmndbm_h_uses_prototypes='undef'
 d_getaddrinfo='define'
 d_getcwd='define'
+d_getenv_preserves_other_thread='define'
 d_getespwnam='undef'
 d_getfsstat='undef'
 d_getgrent='define'
@@ -363,6 +368,8 @@ d_newlocale='define'
 d_nextafter='define'
 d_nice='define'
 d_nl_langinfo='define'
+d_nl_langinfo_l='define'
+d_non_int_bitfields='define'
 d_nv_zero_is_allbits_zero='define'
 d_old_pthread_create_joinable='undef'
 d_oldpthreads='undef'
@@ -427,6 +434,7 @@ d_semget='define'
 d_semop='define'
 d_sendmsg='define'
 d_setegid='define'
+d_setenv='define'
 d_seteuid='define'
 d_setgrent='define'
 d_setgrent_r='undef'
@@ -436,6 +444,7 @@ d_sethostent_r='undef'
 d_setitimer='define'
 d_setlinebuf='define'
 d_setlocale='define'
+d_setlocale_accepts_any_locale_name='undef'
 d_setlocale_r='undef'
 d_setnent='define'
 d_setnetent_r='undef'
@@ -482,6 +491,7 @@ d_sitearch='define'
 d_snprintf='define'
 d_sockaddr_in6="$owrt:ipv6"
 d_sockaddr_sa_len='undef'
+d_sockaddr_storage='define'
 d_sockatmark='undef'
 d_sockatmarkproto='undef'
 d_socket='define'
@@ -524,6 +534,7 @@ d_strtoul='define'
 d_strtoull='define'
 d_strtouq='define'
 d_strxfrm='define'
+d_strxfrm_l='define'
 d_suidsafe='undef'
 d_symlink='define'
 d_syscall='define'
@@ -537,12 +548,15 @@ d_tcsetpgrp='define'
 d_telldir='define'
 d_telldirproto='define'
 d_tgamma='define'
+d_thread_local='define'
 d_thread_safe_nl_langinfo_l='define'
 d_time='define'
 d_timegm='define'
 d_times='define'
 d_tm_tm_gmtoff='define'
 d_tm_tm_zone='define'
+d_towlower='define'
+d_towupper='define'
 d_trunc='define'
 d_truncate='define'
 d_truncl='define'
@@ -571,6 +585,7 @@ d_vprintf='define'
 d_vsnprintf='define'
 d_wait4='define'
 d_waitpid='define'
+d_wcrtomb='define'
 d_wcscmp='define'
 d_wcstombs='define'
 d_wcsxfrm='define'
@@ -717,6 +732,7 @@ i_syssockio='undef'
 i_sysstat='define'
 i_sysstatfs='define'
 i_sysstatvfs='define'
+i_syssyscall='define'
 i_systime='define'
 i_systimek='undef'
 i_systimes='define'
@@ -737,6 +753,7 @@ i_varargs='undef'
 i_varhdr='stdarg.h'
 i_vfork='undef'
 i_wchar='define'
+i_wctype='define'
 i_xlocale='undef'
 ignore_versioned_solibs='y'
 inc_version_list=' '
@@ -924,6 +941,8 @@ spackage='Perl5'
 spitshell='cat'
 src='.'
 ssizetype='ssize_t'
+st_dev_sign='1'
+st_dev_size='8'
 st_ino_sign='1'
 st_ino_size='8'
 startperl='#!/usr/bin/perl'
@@ -969,6 +988,7 @@ uniq='uniq'
 use5005threads='undef'
 usecbacktrace='undef'
 usecrosscompile='define'
+usedefaultstrict='undef'
 usedevel='undef'
 usedl='define'
 usedtrace='undef'
@@ -1025,6 +1045,7 @@ versiononly='undef'
 vi=''
 voidflags='15'
 xlibpth='/usr/lib/386 /lib/386'
+xlocale_needed='undef'
 yacc='yacc'
 yaccflags=''
 zcat=''
index 93d190c5a8bfa68f756184f124352a185291e479..1b198981a96f1590a398c6332b61eab071600fa0 100644 (file)
 }
 
 ($owrt:libc eq 'musl') {
-       # musl does not provide a working setlocale(). It accepts arbitrary locales
-       # and makes them act as if they were C.UTF-8.
-       d_setlocale='undef'
-       
        d_stdio_ptr_lval='undef'
        d_stdio_ptr_lval_sets_cnt='undef'
        d_stdiobase='undef'
index b318648e0109855bb130933986c529a2222c3fe5..fbd0361309f463ddefcb55c76f6ba710e5094cec 100644 (file)
@@ -1,17 +1,17 @@
 # Set the version here
 PERL_REVISION=5
-PERL_VERSION=28
-PERL_SUBVERSION=1
+PERL_VERSION=38
+PERL_SUBVERSION=0
 
 # (api_revison, api_version, api_subversion) = (revision, version, 0) usually
 PERL_API_REVISION=5
-PERL_API_VERSION=28
+PERL_API_VERSION=38
 PERL_API_SUBVERSION=0
 
-known_extensions='B Compress/Raw/Zlib Cwd DB_File Data/Dumper Devel/DProf Devel/PPPort Devel/Peek Digest/MD5 Digest/SHA Encode Fcntl File/Glob Filter/Util/Call GDBM_File Hash/Util I18N/Langinfo IO IPC/SysV List/Util MIME/Base64 Math/BigInt/FastCalc NDBM_File ODBM_File Opcode POSIX PerlIO/encoding PerlIO/scalar PerlIO/via SDBM_File Socket Storable Sys/Hostname Sys/Syslog Text/Soundex Time/HiRes Time/Piece Unicode/Normalize Win32 Win32API/File Win32CORE XS/APItest XS/Typemap attrs re threads threads/shared Hash/Util/FieldHash'
-extensions='B Compress/Raw/Bzip2 Compress/Raw/Zlib Cwd DB_File Data/Dumper Devel/PPPort Devel/Peek Digest/MD5 Digest/SHA Encode Fcntl File/DosGlob File/Glob Filter/Util/Call GDBM_File Hash/Util Hash/Util/FieldHash I18N/Langinfo IO IPC/SysV List/Util MIME/Base64 Math/BigInt/FastCalc Opcode POSIX PerlIO/encoding PerlIO/mmap PerlIO/scalar PerlIO/via SDBM_File Socket Storable Sys/Hostname Sys/Syslog Tie/Hash/NamedCapture Time/HiRes Time/Piece Unicode/Collate XS/APItest XS/Typemap arybase attributes mro re threads threads/shared Archive/Tar Attribute/Handlers AutoLoader B/Debug CPAN CPAN/Meta CPAN/Meta/Requirements CPAN/Meta/YAML Carp Config/Perl/V Devel/SelfStubber Digest Dumpvalue Env Errno Exporter ExtUtils/CBuilder ExtUtils/Command ExtUtils/Constant ExtUtils/Install ExtUtils/MakeMaker ExtUtils/Manifest ExtUtils/Miniperl ExtUtils/ParseXS File/Fetch File/Find File/Path File/Temp FileCache Filter/Simple Getopt/Long HTTP/Tiny I18N/Collate I18N/LangTags IO/Compress IO/Socket/IP IO/Zlib IPC/Cmd IPC/Open3 JSON/PP Locale/Codes Locale/Maketext Locale/Maketext/Simple Math/BigInt Math/BigRat Math/Complex Memoize Module/CoreList Module/Load Module/Load/Conditional Module/Loaded Module/Metadata NEXT Net/Ping Params/Check Parse/CPAN/Meta Perl/OSType PerlIO/via/QuotedPrint Pod/Checker Pod/Escapes Pod/Functions Pod/Html Pod/Parser Pod/Perldoc Pod/Simple Pod/Usage Safe Search/Dict SelfLoader Term/ANSIColor Term/Cap Term/Complete Term/ReadLine Test Test/Harness Test/Simple Text/Abbrev Text/Balanced Text/ParseWords Text/Tabs Thread/Queue Thread/Semaphore Tie/File Tie/Memoize Tie/RefHash Time/Local XSLoader autodie autouse base bignum constant encoding/warnings experimental if lib libnet parent perlfaq podlators Unicode/Normalize version'
-nonxs_ext='Archive/Tar Attribute/Handlers AutoLoader B/Debug CPAN CPAN/Meta CPAN/Meta/Requirements CPAN/Meta/YAML Carp Config/Perl/V Devel/SelfStubber Digest Dumpvalue Env Errno Exporter ExtUtils/CBuilder ExtUtils/Command ExtUtils/Constant ExtUtils/Install ExtUtils/MakeMaker ExtUtils/Manifest ExtUtils/Miniperl ExtUtils/ParseXS File/Fetch File/Find File/Path File/Temp FileCache Filter/Simple Getopt/Long HTTP/Tiny I18N/Collate I18N/LangTags IO/Compress IO/Socket/IP IO/Zlib IPC/Cmd IPC/Open3 JSON/PP Locale/Codes Locale/Maketext Locale/Maketext/Simple Math/BigInt Math/BigRat Math/Complex Memoize Module/CoreList Module/Load Module/Load/Conditional Module/Loaded Module/Metadata NEXT Net/Ping Params/Check Parse/CPAN/Meta Perl/OSType PerlIO/via/QuotedPrint Pod/Checker Pod/Escapes Pod/Functions Pod/Html Pod/Parser Pod/Perldoc Pod/Simple Pod/Usage Safe Search/Dict SelfLoader Term/ANSIColor Term/Cap Term/Complete Term/ReadLine Test Test/Harness Test/Simple Text/Abbrev Text/Balanced Text/ParseWords Text/Tabs Thread/Queue Thread/Semaphore Tie/File Tie/Memoize Tie/RefHash Time/Local XSLoader autodie autouse base bignum constant encoding/warnings experimental if lib libnet parent perlfaq podlators Unicode/Normalize version'
-dynamic_ext='B Compress/Raw/Bzip2 Compress/Raw/Zlib Cwd DB_File Data/Dumper Devel/PPPort Devel/Peek Digest/MD5 Digest/SHA Encode Fcntl File/DosGlob File/Glob Filter/Util/Call GDBM_File Hash/Util Hash/Util/FieldHash I18N/Langinfo IO IPC/SysV List/Util MIME/Base64 Math/BigInt/FastCalc Opcode POSIX PerlIO/encoding PerlIO/mmap PerlIO/scalar PerlIO/via SDBM_File Socket Storable Sys/Hostname Sys/Syslog Tie/Hash/NamedCapture Time/HiRes Time/Piece Unicode/Collate XS/APItest XS/Typemap arybase attributes mro re threads threads/shared'
+dynamic_ext='attributes B Compress/Raw/Bzip2 Compress/Raw/Zlib Cwd Data/Dumper DB_File Devel/Peek Devel/PPPort Digest/MD5 Digest/SHA Encode Fcntl File/DosGlob File/Glob Filter/Util/Call GDBM_File Hash/Util Hash/Util/FieldHash I18N/Langinfo IO IPC/SysV List/Util Math/BigInt/FastCalc MIME/Base64 mro Opcode PerlIO/encoding PerlIO/mmap PerlIO/scalar PerlIO/via POSIX re SDBM_File Socket Storable Sys/Hostname Sys/Syslog threads threads/shared Time/HiRes Time/Piece Unicode/Collate Unicode/Normalize XS/APItest XS/Typemap'
+extensions='attributes B Compress/Raw/Bzip2 Compress/Raw/Zlib Cwd Data/Dumper DB_File Devel/Peek Devel/PPPort Digest/MD5 Digest/SHA Encode Fcntl File/DosGlob File/Glob Filter/Util/Call Hash/Util Hash/Util/FieldHash I18N/Langinfo IO IPC/SysV List/Util Math/BigInt/FastCalc MIME/Base64 mro Opcode PerlIO/encoding PerlIO/mmap PerlIO/scalar PerlIO/via POSIX re SDBM_File Socket Storable Sys/Hostname Sys/Syslog threads threads/shared Time/HiRes Time/Piece Unicode/Collate Unicode/Normalize XS/APItest XS/Typemap Archive/Tar Attribute/Handlers autodie AutoLoader autouse base bignum Carp Config/Perl/V constant CPAN CPAN/Meta CPAN/Meta/Requirements CPAN/Meta/YAML Devel/SelfStubber Digest Dumpvalue encoding/warnings Env Errno experimental Exporter ExtUtils/CBuilder ExtUtils/Constant ExtUtils/Install ExtUtils/MakeMaker ExtUtils/Manifest ExtUtils/Miniperl ExtUtils/ParseXS ExtUtils/PL2Bat FileCache File/Fetch File/Find File/Path File/Temp Filter/Simple FindBin GDBM_File Getopt/Long HTTP/Tiny I18N/Collate I18N/LangTags if IO/Compress IO/Socket/IP IO/Zlib IPC/Cmd IPC/Open3 JSON/PP lib libnet Locale/Maketext Locale/Maketext/Simple Math/BigInt Math/BigRat Math/Complex Memoize Module/CoreList Module/Load Module/Load/Conditional Module/Loaded Module/Metadata Net/Ping NEXT Params/Check parent perlfaq PerlIO/via/QuotedPrint Perl/OSType Pod/Checker Pod/Escapes Pod/Functions Pod/Html podlators Pod/Perldoc Pod/Simple Pod/Usage Safe Search/Dict SelfLoader Term/ANSIColor Term/Cap Term/Complete Term/ReadLine Test Test/Harness Test/Simple Text/Abbrev Text/Balanced Text/ParseWords Text/Tabs Thread/Queue Thread/Semaphore Tie/File Tie/Hash/NamedCapture Tie/Memoize Tie/RefHash Time/Local version XSLoader'
+known_extensions='Amiga/ARexx Amiga/Exec Archive/Tar Attribute/Handlers attributes autodie AutoLoader autouse B base bignum Carp Compress/Raw/Bzip2 Compress/Raw/Zlib Config/Perl/V constant CPAN CPAN/Meta CPAN/Meta/Requirements CPAN/Meta/YAML Cwd Data/Dumper DB_File Devel/Peek Devel/PPPort Devel/SelfStubber Digest Digest/MD5 Digest/SHA Dumpvalue Encode encoding/warnings Env Errno experimental Exporter ExtUtils/CBuilder ExtUtils/Constant ExtUtils/Install ExtUtils/MakeMaker ExtUtils/Manifest ExtUtils/Miniperl ExtUtils/ParseXS ExtUtils/PL2Bat Fcntl FileCache File/DosGlob File/Fetch File/Find File/Glob File/Path File/Temp Filter/Simple Filter/Util/Call FindBin GDBM_File Getopt/Long Hash/Util Hash/Util/FieldHash HTTP/Tiny I18N/Collate I18N/Langinfo I18N/LangTags if IO IO/Compress IO/Socket/IP IO/Zlib IPC/Cmd IPC/Open3 IPC/SysV JSON/PP lib libnet List/Util Locale/Maketext Locale/Maketext/Simple Math/BigInt Math/BigInt/FastCalc Math/BigRat Math/Complex Memoize MIME/Base64 Module/CoreList Module/Load Module/Load/Conditional Module/Loaded Module/Metadata mro NDBM_File Net/Ping NEXT ODBM_File Opcode Params/Check parent perlfaq PerlIO/encoding PerlIO/mmap PerlIO/scalar PerlIO/via PerlIO/via/QuotedPrint Perl/OSType Pod/Checker Pod/Escapes Pod/Functions Pod/Html podlators Pod/Perldoc Pod/Simple Pod/Usage POSIX re Safe SDBM_File Search/Dict SelfLoader Socket Storable Sys/Hostname Sys/Syslog Term/ANSIColor Term/Cap Term/Complete Term/ReadLine Test Test/Harness Test/Simple Text/Abbrev Text/Balanced Text/ParseWords Text/Tabs Thread/Queue threads Thread/Semaphore threads/shared Tie/File Tie/Hash/NamedCapture Tie/Memoize Tie/RefHash Time/HiRes Time/Local Time/Piece Unicode/Collate Unicode/Normalize version VMS/DCLsym VMS/Filespec VMS/Stdio Win32 Win32API/File Win32CORE XS/APItest XSLoader XS/Typemap'
+nonxs_ext='Archive/Tar Attribute/Handlers autodie AutoLoader autouse base bignum Carp Config/Perl/V constant CPAN CPAN/Meta CPAN/Meta/Requirements CPAN/Meta/YAML Devel/SelfStubber Digest Dumpvalue encoding/warnings Env Errno experimental Exporter ExtUtils/CBuilder ExtUtils/Constant ExtUtils/Install ExtUtils/MakeMaker ExtUtils/Manifest ExtUtils/Miniperl ExtUtils/ParseXS ExtUtils/PL2Bat FileCache File/Fetch File/Find File/Path File/Temp Filter/Simple FindBin Getopt/Long HTTP/Tiny I18N/Collate I18N/LangTags if IO/Compress IO/Socket/IP IO/Zlib IPC/Cmd IPC/Open3 JSON/PP lib libnet Locale/Maketext Locale/Maketext/Simple Math/BigInt Math/BigRat Math/Complex Memoize Module/CoreList Module/Load Module/Load/Conditional Module/Loaded Module/Metadata Net/Ping NEXT Params/Check parent perlfaq PerlIO/via/QuotedPrint Perl/OSType Pod/Checker Pod/Escapes Pod/Functions Pod/Html podlators Pod/Perldoc Pod/Simple Pod/Usage Safe Search/Dict SelfLoader Term/ANSIColor Term/Cap Term/Complete Term/ReadLine Test Test/Harness Test/Simple Text/Abbrev Text/Balanced Text/ParseWords Text/Tabs Thread/Queue Thread/Semaphore Tie/File Tie/Hash/NamedCapture Tie/Memoize Tie/RefHash Time/Local version XSLoader'
 
 # No need to change anything from here on
 owrt:perllibpath="/usr/lib/perl5/$PERL_REVISION.$PERL_VERSION"
diff --git a/lang/perl/patches/001-macos_11_support.patch b/lang/perl/patches/001-macos_11_support.patch
deleted file mode 100644 (file)
index f61c519..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/hints/darwin.sh
-+++ b/hints/darwin.sh
-@@ -301,7 +301,7 @@ case "$osvers" in  # Note: osvers is the
-    # We now use MACOSX_DEPLOYMENT_TARGET, if set, as an override by
-    # capturing its value and adding it to the flags.
-     case "$MACOSX_DEPLOYMENT_TARGET" in
--    10.*)
-+    [1-9][0-9].*)
-       add_macosx_version_min ccflags $MACOSX_DEPLOYMENT_TARGET
-       add_macosx_version_min ldflags $MACOSX_DEPLOYMENT_TARGET
-       ;;
-@@ -313,7 +313,7 @@ case "$osvers" in  # Note: osvers is the
- *** Unexpected MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET
- ***
--*** Please either set it to 10.something, or to empty.
-+*** Please either set it to a valid macOS version number (e.g., 10.15) or to empty.
- EOM
-       exit 1
-@@ -327,7 +327,7 @@ EOM
-     # "ProductVersion:    10.11"     "10.11"
-         prodvers=`sw_vers|awk '/^ProductVersion:/{print $2}'|awk -F. '{print $1"."$2}'`
-     case "$prodvers" in
--    10.*)
-+    [1-9][0-9].*)
-       add_macosx_version_min ccflags $prodvers
-       add_macosx_version_min ldflags $prodvers
-       ;;
diff --git a/lang/perl/patches/002-add-Internals-getcwd.patch b/lang/perl/patches/002-add-Internals-getcwd.patch
deleted file mode 100644 (file)
index d2a8497..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-From 15f67d146cf1f32504e8a11de3faa2abc0f467cd Mon Sep 17 00:00:00 2001
-From: Tony Cook <tony@develop-help.com>
-Date: Mon, 25 Mar 2019 16:48:40 +1100
-Subject: [PATCH] (perl #133951) add Internals::getcwd
-
----
- MANIFEST      |  1 +
- t/io/getcwd.t | 22 ++++++++++++++++++++++
- universal.c   | 22 ++++++++++++++++++++++
- 3 files changed, 45 insertions(+)
- create mode 100644 t/io/getcwd.t
-
---- a/MANIFEST
-+++ b/MANIFEST
-@@ -5456,6 +5456,7 @@ t/io/errno.t                     See if $! is correctly se
- t/io/errnosig.t                       Test case for restoration $! when leaving signal handlers
- t/io/fflush.t                 See if auto-flush on fork/exec/system/qx works
- t/io/fs.t                     See if directory manipulations work
-+t/io/getcwd.t                 See if Internals::getcwd is sane
- t/io/inplace.t                        See if inplace editing works
- t/io/iofile.t                 See if we can load IO::File on demand
- t/io/iprefix.t                        See if inplace editing works with prefixes
---- /dev/null
-+++ b/t/io/getcwd.t
-@@ -0,0 +1,22 @@
-+#!./perl -w
-+
-+BEGIN {
-+    chdir 't' if -d 't';
-+    require "./test.pl";
-+    set_up_inc('../lib');
-+}
-+
-+use Config;
-+
-+$Config{d_getcwd}
-+  or plan skip_all => "no getcwd";
-+
-+my $cwd = Internals::getcwd();
-+ok(!defined $cwd || $cwd ne "",
-+   "Internals::getcwd() returned a reasonable result");
-+
-+if (defined $cwd) {
-+    ok(-d $cwd, "check a success result is a directory");
-+}
-+
-+done_testing();
---- a/universal.c
-+++ b/universal.c
-@@ -986,6 +986,25 @@ XS(XS_re_regexp_pattern)
-     NOT_REACHED; /* NOTREACHED */
- }
-+#ifdef HAS_GETCWD
-+
-+XS(XS_Internals_getcwd)
-+{
-+    dXSARGS;
-+    SV *sv = sv_newmortal();
-+
-+    if (items != 0)
-+        croak_xs_usage(cv, "");
-+
-+    (void)getcwd_sv(sv);
-+
-+    SvTAINTED_on(sv);
-+    PUSHs(sv);
-+    XSRETURN(1);
-+}
-+
-+#endif
-+
- #include "vutil.h"
- #include "vxs.inc"
-@@ -1020,6 +1039,9 @@ static const struct xsub_details details
-     {"re::regnames", XS_re_regnames, ";$"},
-     {"re::regnames_count", XS_re_regnames_count, ""},
-     {"re::regexp_pattern", XS_re_regexp_pattern, "$"},
-+#ifdef HAS_GETCWD
-+    {"Internals::getcwd", XS_Internals_getcwd, ""},
-+#endif
- };
- STATIC OP*
diff --git a/lang/perl/patches/003-fallback-to-the-built-in-getcwd-if-we-ca.patch b/lang/perl/patches/003-fallback-to-the-built-in-getcwd-if-we-ca.patch
deleted file mode 100644 (file)
index dcadb31..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
---- a/dist/PathTools/Cwd.pm
-+++ b/dist/PathTools/Cwd.pm
-@@ -659,6 +659,10 @@ if (exists $METHOD_MAP{$^O}) {
-   }
- }
-+# built-in from 5.30
-+*getcwd = \&Internals::getcwd
-+  if !defined &getcwd && defined &Internals::getcwd;
-+
- # In case the XS version doesn't load.
- *abs_path = \&_perl_abs_path unless defined &abs_path;
- *getcwd = \&_perl_getcwd unless defined &getcwd;
---- a/dist/PathTools/t/cwd.t
-+++ b/dist/PathTools/t/cwd.t
-@@ -10,6 +10,7 @@ chdir 't';
- use Config;
- use File::Spec;
- use File::Path;
-+use Errno qw(EACCES);
- use lib File::Spec->catdir('t', 'lib');
- use Test::More;
-@@ -208,7 +209,15 @@ SKIP: {
-     like($abs_path,      qr|$want$|i, "Cwd::abs_path produced $abs_path");
-     like($fast_abs_path, qr|$want$|i, "Cwd::fast_abs_path produced $fast_abs_path");
--    like($pas,           qr|$want$|i, "Cwd::_perl_abs_path produced $pas") if $EXTRA_ABSPATH_TESTS;
-+    if ($EXTRA_ABSPATH_TESTS) {
-+        # _perl_abs_path() can fail if some ancestor directory isn't readable
-+        if (defined $pas) {
-+            like($pas,           qr|$want$|i, "Cwd::_perl_abs_path produced $pas");
-+        }
-+        else {
-+            is($!+0, EACCES, "check we got the expected error on failure");
-+        }
-+    }
-     rmtree($test_dirs[0], 0, 0);
-     1 while unlink $file;
index 77ea26f46b25213b33097fe3a6c31bc4dd184020..e38a05be8d553641ef984d0e5ef7e21b42b1b631 100644 (file)
@@ -1,6 +1,6 @@
 --- a/perl.c
 +++ b/perl.c
-@@ -303,7 +303,7 @@ perl_construct(pTHXx)
+@@ -317,7 +317,7 @@ perl_construct(pTHXx)
      PL_localpatches = local_patches;  /* For possible -v */
  #endif
  
diff --git a/lang/perl/patches/020-storables-stacksize.patch b/lang/perl/patches/020-storables-stacksize.patch
deleted file mode 100644 (file)
index 903d90b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-From 682a4acb98783a7f9b5c286b308f12863599fec3 Mon Sep 17 00:00:00 2001
-From: Tony Cook <tony@develop-help.com>
-Date: Mon, 30 Jul 2018 21:00:52 +1000
-Subject: (perl #133411) don't try to load Storable with -Dusecrosscompile
-
----
- dist/Storable/Makefile.PL |  9 ++++++++-
- dist/Storable/stacksize   | 10 +++++++---
- 2 files changed, 15 insertions(+), 4 deletions(-)
-
---- a/dist/Storable/Makefile.PL
-+++ b/dist/Storable/Makefile.PL
-@@ -90,12 +90,19 @@ sub depend {
-         # blib.pm needs arch/lib
-         $extra_deps = ' Storable.pm';
-     }
-+    my $whichperl;
-+    if ($Config::Config{usecrosscompile}) {
-+        $whichperl = '$(PERLRUN)';
-+    }
-+    else {
-+        $whichperl = '$(FULLPERLRUNINST)';
-+    }
-     my $linktype = uc($_[0]->{LINKTYPE});
-     my $limit_pm = File::Spec->catfile('lib', 'Storable', 'Limit.pm');
-     "
- $limit_pm : stacksize \$(INST_$linktype)$extra_deps
-       \$(MKPATH) \$(INST_LIB)
--      \$(FULLPERLRUNINST) stacksize $options
-+      $whichperl stacksize $options
- release : dist
-       git tag \$(VERSION)
---- a/dist/Storable/stacksize
-+++ b/dist/Storable/stacksize
-@@ -7,6 +7,9 @@ use Cwd;
- use File::Spec;
- use strict;
-+-d "lib" or mkdir "lib";
-+-d "lib/Storable" or mkdir "lib/Storable";
-+
- my $fn = "lib/Storable/Limit.pm";
- my $ptrsize = $Config{ptrsize};
- my ($bad1, $bad2) = (65001, 25000);
-@@ -29,6 +32,10 @@ sub is_miniperl {
- }
- if (is_miniperl()) {
-+    if ($Config{usecrosscompile}) {
-+        write_limits(500, 265);
-+        exit;
-+    }
-     die "Should not run during miniperl\n";
- }
- my $prefix = "";
-@@ -68,9 +75,6 @@ if ($ENV{PERL_CORE}) {
-     }
- }
---d "lib" or mkdir "lib";
---d "lib/Storable" or mkdir "lib/Storable";
--
- if ($^O eq "MSWin32") {
-     require Win32;
-     my ($str, $major, $minor) = Win32::GetOSVersion();
index 2f7ebcbc49667e2a397561b0b73b60a1500548b7..806a31256b2007ee5f2c36d75261fac0d176cc21 100644 (file)
@@ -1,8 +1,8 @@
 --- a/Makefile.SH
 +++ b/Makefile.SH
-@@ -339,22 +339,11 @@ MANIFEST_SRT = MANIFEST.srt
- !GROK!THIS!
+@@ -360,22 +360,11 @@ PERL_EXE_LDFLAGS=$exeldflags
+       ;;
+ esac
  
 -case "$usecrosscompile$perl" in
 -define?*)
index b0e783462b79ddee3efe6bd5ecb37f6aa2d6f327..ae044c8f165937c8bdaba558ad9d53e5d9ff5241 100644 (file)
@@ -1,8 +1,8 @@
 --- a/perl.c
 +++ b/perl.c
-@@ -1987,16 +1987,6 @@ S_Internals_V(pTHX_ CV *cv)
+@@ -2098,16 +2098,6 @@ S_Internals_V(pTHX_ CV *cv)
      PUSHs(Perl_newSVpvn_flags(aTHX_ non_bincompat_options,
-                             sizeof(non_bincompat_options) - 1, SVs_TEMP));
+                               sizeof(non_bincompat_options) - 1, SVs_TEMP));
  
 -#ifndef PERL_BUILD_DATE
 -#  ifdef __DATE__
@@ -16,4 +16,4 @@
 -
  #ifdef PERL_BUILD_DATE
      PUSHs(Perl_newSVpvn_flags(aTHX_
-                             STR_WITH_LEN("Compiled at " PERL_BUILD_DATE),
+                               STR_WITH_LEN("Compiled at " PERL_BUILD_DATE),
diff --git a/lang/perl/patches/301-fix_macos_static_linking.patch b/lang/perl/patches/301-fix_macos_static_linking.patch
deleted file mode 100644 (file)
index 4b4ef92..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
---- a/cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Unix.pm
-+++ b/cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Unix.pm
-@@ -2738,14 +2738,14 @@ sub _find_static_libs {
- Called by a utility method of makeaperl. Checks whether a given file
- is an XS library by seeing whether it defines any symbols starting
--with C<boot_>.
-+with C<boot_> (with an optional leading underscore – needed on MacOS).
- =cut
- sub xs_static_lib_is_xs {
-     my ($self, $libfile) = @_;
-     my $devnull = File::Spec->devnull;
--    return `nm $libfile 2>$devnull` =~ /\bboot_/;
-+    return `nm $libfile 2>$devnull` =~ /\b_?boot_/;
- }
- =item makefile (o)
index 9afb8a8ce79a09283050be9aff56d2e0b7fc793b..efe8e0c2993f161c16538a6fbc26c205f0667544 100644 (file)
@@ -1,8 +1,8 @@
 --- a/cpan/podlators/Makefile.PL
 +++ b/cpan/podlators/Makefile.PL
-@@ -18,6 +18,19 @@ use Config;
use ExtUtils::MakeMaker;
- use File::Spec;
+@@ -39,6 +39,19 @@ sub dist_version {
    die "$0: cannot find version in lib/Pod/Man.pm\n";
+ }
  
 +foreach (glob('scripts/pod*.PL')) {
 +    # The various pod*.PL extractors change directory. Doing that with relative
@@ -20,7 +20,7 @@
  # Generate full paths for scripts distributed in the bin directory.  Appends
  # the .com extension to scripts on VMS, unless they already have the .PL
  # extension.
-@@ -28,7 +41,7 @@ use File::Spec;
+@@ -49,7 +62,7 @@ sub dist_version {
  #          (Scalar) Space-separated relative paths from top of distribution
  sub scripts {
      my (@scripts) = @_;
@@ -29,7 +29,7 @@
      if ($^O eq 'VMS') {
          @paths = map { m{ [.] PL \z }xms ? $_ : $_ . '.com' } @paths;
      }
-@@ -77,8 +90,8 @@ my %metadata = (
+@@ -101,8 +114,8 @@ my %metadata = (
  
      # Override the files that generate section 1 man pages.
      MAN1PODS => {
index d2197571a9299d6ad32990374487b5f3666fac57..857cd1e9e2dd0b9a70b84e4be391fa928dc76c65 100644 (file)
@@ -1,14 +1,14 @@
 --- a/Makefile.SH
 +++ b/Makefile.SH
-@@ -275,6 +275,7 @@ LNS = $lns
+@@ -289,6 +289,7 @@ LNS = $lns
  # NOTE: some systems don't grok "cp -f". XXX Configure test needed?
  CPS = $cp
  RMS = rm -f
 +RMS_R = rm -rf
  ranlib = $ranlib
+ ECHO = $echo
  
- # The following are mentioned only to make metaconfig include the
-@@ -736,7 +737,7 @@ bitcount.h: generate_uudmap$(HOST_EXE_EX
+@@ -786,7 +787,7 @@ bitcount.h: generate_uudmap$(HOST_EXE_EX
        ./generate_uudmap$(HOST_EXE_EXT) $(generated_headers)
  
  generate_uudmap$(HOST_EXE_EXT): generate_uudmap$(OBJ_EXT)
@@ -17,7 +17,7 @@
        $(LNS) $(HOST_GENERATE) generate_uudmap$(HOST_EXE_EXT)
  
  !NO!SUBS!
-@@ -876,26 +877,26 @@ mydtrace.h: $(DTRACE_H)
+@@ -891,26 +892,26 @@ mydtrace.h: $(DTRACE_H)
        define)
                $spitshell >>$Makefile <<'!NO!SUBS!'
  $(DTRACE_MINI_O): perldtrace.d $(miniperl_objs_nodt)
@@ -48,7 +48,7 @@
  
  !NO!SUBS!
                ;;
-@@ -906,13 +907,13 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
+@@ -921,13 +922,13 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
        case "$useshrplib" in
        true)
                $spitshell >>$Makefile <<'!NO!SUBS!'
@@ -64,7 +64,7 @@
        mv $@ libperl$(OBJ_EXT)
        $(AR) qv $(LIBPERL) libperl$(OBJ_EXT)
  !NO!SUBS!
-@@ -921,7 +922,7 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
+@@ -936,7 +937,7 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
                ;;
        *)
                $spitshell >>$Makefile <<'!NO!SUBS!'
@@ -73,7 +73,7 @@
        $(AR) rc $(LIBPERL) $(perllib_objs) $(DYNALOADER)
        @$(ranlib) $(LIBPERL)
  !NO!SUBS!
-@@ -954,7 +955,7 @@ $(MINIPERL_EXE): lib/buildcustomize.pl
+@@ -970,7 +971,7 @@ $(MINIPERL_EXE): lib/buildcustomize.pl
        amigaos*)
                $spitshell >>$Makefile <<'!NO!SUBS!'
  lib/buildcustomize.pl: $& $(miniperl_objs) write_buildcustomize.pl
 +      @$(RMS) miniperl.xok
  !NO!SUBS!
  
-         case $osname in
-@@ -1119,8 +1120,8 @@ pod/perl5281delta.pod: pod/perldelta.pod
-       $(LNS) perldelta.pod pod/perl5281delta.pod
+         case "$osname" in
+@@ -1133,8 +1134,8 @@ pod/perl5380delta.pod: pod/perldelta.pod
+       $(LNS) perldelta.pod pod/perl5380delta.pod
  
  extra.pods: $(MINIPERL_EXE)
 -      -@test ! -f extra.pods || rm -f `cat extra.pods`
        -@for x in `grep -l '^=[a-z]' README.* | grep -v README.vms` ; do \
            nx=`echo $$x | sed -e "s/README\.//"`; \
            $(LNS) ../$$x "pod/perl"$$nx".pod" ; \
-@@ -1340,11 +1341,11 @@ realclean:     _realcleaner _mopup
+@@ -1334,11 +1335,11 @@ realclean:     _realcleaner _mopup
        @echo "Note that '$(MAKE) realclean' does not delete config.sh or Policy.sh"
  
  _clobber:
  
  clobber:      _realcleaner _mopup _clobber
  
-@@ -1352,23 +1353,23 @@ distclean:     clobber
+@@ -1346,24 +1347,24 @@ distclean:     clobber
  
  # Like distclean but also removes emacs backups and *.orig.
  veryclean:    _verycleaner _mopup _clobber
  
  # Do not 'make _mopup' directly.
  _mopup:
--      rm -f *$(OBJ_EXT) *$(LIB_EXT) all perlmain.c opmini.c perlmini.c generate_uudmap$(EXE_EXT) $(generated_headers)
-+      $(RMS) *$(OBJ_EXT) *$(LIB_EXT) all perlmain.c opmini.c perlmini.c generate_uudmap$(EXE_EXT) $(generated_headers)
+-      rm -f *$(OBJ_EXT) *$(LIB_EXT) all perlmain.c $(mini_only_src) generate_uudmap$(EXE_EXT) $(generated_headers)
++      $(RMS) *$(OBJ_EXT) *$(LIB_EXT) all perlmain.c $(mini_only_src) generate_uudmap$(EXE_EXT) $(generated_headers)
        -rmdir .depending
+-      -rm *.depends makedepend_file
 -      -@test -f extra.pods && rm -f `cat extra.pods`
 -      -@test -f vms/README_vms.pod && rm -f vms/README_vms.pod
--      -rm -f perl.exp ext.libs $(generated_pods) uni.data opmini.o perlmini.o pod/roffitall
+-      -rm -f perl.exp ext.libs $(generated_pods) uni.data $(mini_only_objs) pod/roffitall
 -      -rm -f perl.export perl.dll perl.libexp perl.map perl.def
 -      -rm -f *perl.xok
 -      -rm -f cygwin.c libperl*.def libperl*.dll cygperl*.dll *.exe.stackdump
 -      -rm -f $(PERL_EXE) $(MINIPERL_EXE) $(LIBPERL) libperl.* microperl
 -      -rm -f config.arch config.over $(DTRACE_H)
++      $(RMS) *.depends makedepend_file
 +      -@test -f extra.pods && $(RMS) `cat extra.pods`
 +      -@test -f vms/README_vms.pod && $(RMS) vms/README_vms.pod
-+      $(RMS) perl.exp ext.libs $(generated_pods) uni.data opmini.o perlmini.o pod/roffitall
++      $(RMS) perl.exp ext.libs $(generated_pods) uni.data $(mini_only_objs) pod/roffitall
 +      $(RMS) perl.export perl.dll perl.libexp perl.map perl.def
 +      $(RMS) *perl.xok
 +      $(RMS) cygwin.c libperl*.def libperl*.dll cygperl*.dll *.exe.stackdump
        -cd pod; $(LDLIBPTH) $(MAKE) $(CLEAN)
        -cd utils; $(LDLIBPTH) $(MAKE) $(CLEAN)
        -@if test -f $(MINIPERL_EXE) ; then \
-@@ -1378,31 +1379,31 @@ _cleaner1:
+@@ -1373,8 +1374,8 @@ _cleaner1:
        else \
        sh $(CLEAN).sh ; \
        fi
 +      $(RMS) `grep -v ^# mkppport.lst | grep . | sed -e 's/$$/\/ppport.h/'`
  
  # Dear POSIX, thanks for making the default to xargs to be
- # run once if nothhing is passed in. It is such a great help.
- # Some systems do not support "?", so keep these files separate.
+ # run once if nothing is passed in. It is such a great help.
+@@ -1389,24 +1390,24 @@ _cleaner1:
+ # Add new rules before that line - the next line (rm -f so_locations ...) is
+ # used as a placeholder by a regen script.
  _cleaner2:
 -      -rm -f core.*perl.*.? t/core.perl.*.? .?*.c
 -      rm -f core *perl.core t/core t/*perl.core core.* t/core.*
 +      $(RMS) pod2htmd.tmp
 +      $(RMS_R) pod/perlfunc pod/perlipc
        -rmdir ext/B/lib
--      rm -f so_locations $(LIBPERL_NONSHR) $(MINIPERL_NONSHR)
-+      $(RMS) so_locations $(LIBPERL_NONSHR) $(MINIPERL_NONSHR)
+-      -rm -f dist/Time-HiRes/xdefine
+-      rm -f so_locations $(LIBPERL_NONSHR)
++      $(RMS) dist/Time-HiRes/xdefine
++      $(RMS) so_locations $(LIBPERL_NONSHR)
        -rmdir lib/version lib/threads lib/inc/ExtUtils lib/inc lib/encoding
        -rmdir lib/autodie/exception lib/autodie/Scope lib/autodie lib/XS
        -rmdir lib/Win32API lib/VMS lib/Unicode/Collate/Locale
-@@ -1452,11 +1453,11 @@ _realcleaner:
+@@ -1457,11 +1458,11 @@ _realcleaner:
  _verycleaner:
        @$(LDLIBPTH) $(MAKE) _cleaner1 CLEAN=veryclean
        @$(LDLIBPTH) $(MAKE) _cleaner2
        lint $(lintflags) -DPERL_CORE -D_REENTRANT -DDEBUGGING -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(c)
  
  cscopeflags = -Rb  # Recursive, build-only.
-@@ -1514,7 +1515,7 @@ case "$targethost" in
+@@ -1522,7 +1523,7 @@ case "$targethost" in
  '') $spitshell >>$Makefile <<'!NO!SUBS!'
  test_prep test-prep: test_prep_pre $(MINIPERL_EXE) $(unidatafiles) $(PERL_EXE) \
        $(dynamic_ext) $(TEST_PERL_DLL) runtests $(generated_pods) common_build
  
  !NO!SUBS!
  ;;
-@@ -1564,7 +1565,7 @@ test_prep test-prep: test_prep_pre \$(MI
+@@ -1572,7 +1573,7 @@ test_prep test-prep: test_prep_pre \$(MI
        $to config.sh
  # --- For lib/diagnostics.t with -Duseshrplib
        $to \$(PERL_EXE)
        $to t/\$(PERL_EXE)
  
  !GROK!THIS!
-@@ -1574,7 +1575,7 @@ esac
+@@ -1582,7 +1583,7 @@ esac
  $spitshell >>$Makefile <<'!NO!SUBS!'
  test_prep_reonly: $(MINIPERL_EXE) $(PERL_EXE) $(dynamic_ext_re) $(TEST_PERL_DLL)
        $(MINIPERL) make_ext.pl $(dynamic_ext_re) MAKE="$(MAKE)" LIBPERL_A=$(LIBPERL) LINKTYPE=dynamic
  !NO!SUBS!
  
  case "$targethost" in
-@@ -1629,7 +1630,7 @@ minitest_prep:
+@@ -1637,7 +1638,7 @@ minitest_prep: $(MINIPERL_EXE)
        @echo "You may see some irrelevant test failures if you have been unable"
        @echo "to build lib/Config.pm, or the Unicode data files."
        @echo " "
--      cd t && (rm -f $(PERL_EXE); $(LNS) ../$(MINIPERL_EXE) $(PERL_EXE))
-+      cd t && ($(RMS) $(PERL_EXE); $(LNS) ../$(MINIPERL_EXE) $(PERL_EXE))
+-      cd t && (rm -f $(PERL_EXE); $(LNS) ../$(MINIPERL_EXE) $(PERL_EXE))
++      cd t && ($(RMS) $(PERL_EXE); $(LNS) ../$(MINIPERL_EXE) $(PERL_EXE))
  
  MINITEST_TESTS = base/*.t comp/*.t cmd/*.t run/*.t io/*.t re/*.t opbasic/*.t op/*.t uni/*.t perf/*.t
  
index 347f6f2a3f33d4e639c423509d5d53b2d73891ba..6589926bc511746e59a3f1f51bada4cfd29a1f63 100644 (file)
@@ -1,6 +1,6 @@
 --- a/Makefile.SH
 +++ b/Makefile.SH
-@@ -333,7 +333,7 @@ PATH_SEP = $p_
+@@ -346,7 +346,7 @@ OBJ_EXT = $_o
  # Macros to invoke a copy of miniperl during the build.  Targets which
  # are built using these macros should depend on \$(MINIPERL_EXE)
  MINIPERL_EXE = miniperl\$(EXE_EXT)
diff --git a/lang/perl/patches/920-fix-no-locale.patch b/lang/perl/patches/920-fix-no-locale.patch
deleted file mode 100644 (file)
index 25ff285..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-commit d36adde059ed1c4f7af210b4f9fc3a7bd2d7d343
-Author: Karl Williamson <khw@cpan.org>
-Date:   Wed May 23 15:32:47 2018 -0600
-
-    Fix to compile under -DNO_LOCALE
-    
-    Several problems with this compile option were not caught before 5.28
-    was frozen.
-
---- a/embed.fnc
-+++ b/embed.fnc
-@@ -2793,9 +2793,11 @@ s       |bool   |isa_lookup     |NN HV *stash|NN con
- #endif
- #if defined(PERL_IN_LOCALE_C)
-+#  ifdef USE_LOCALE
- sn    |const char*|category_name |const int category
- s     |const char*|switch_category_locale_to_template|const int switch_category|const int template_category|NULLOK const char * template_locale
- s     |void   |restore_switched_locale|const int category|NULLOK const char * const original_locale
-+#  endif
- #  ifdef HAS_NL_LANGINFO
- sn    |const char*|my_nl_langinfo|const nl_item item|bool toggle
- #  else
---- a/embed.h
-+++ b/embed.h
-@@ -1796,16 +1796,16 @@
- #define unshare_hek_or_pvn(a,b,c,d)   S_unshare_hek_or_pvn(aTHX_ a,b,c,d)
- #  endif
- #  if defined(PERL_IN_LOCALE_C)
--#define category_name         S_category_name
--#define restore_switched_locale(a,b)  S_restore_switched_locale(aTHX_ a,b)
- #define save_to_buffer                S_save_to_buffer
--#define switch_category_locale_to_template(a,b,c)     S_switch_category_locale_to_template(aTHX_ a,b,c)
- #    if defined(USE_LOCALE)
-+#define category_name         S_category_name
- #define new_collate(a)                S_new_collate(aTHX_ a)
- #define new_ctype(a)          S_new_ctype(aTHX_ a)
- #define new_numeric(a)                S_new_numeric(aTHX_ a)
-+#define restore_switched_locale(a,b)  S_restore_switched_locale(aTHX_ a,b)
- #define set_numeric_radix(a)  S_set_numeric_radix(aTHX_ a)
- #define stdize_locale(a)      S_stdize_locale(aTHX_ a)
-+#define switch_category_locale_to_template(a,b,c)     S_switch_category_locale_to_template(aTHX_ a,b,c)
- #      if defined(USE_POSIX_2008_LOCALE)
- #define emulate_setlocale     S_emulate_setlocale
- #      endif
---- a/locale.c
-+++ b/locale.c
-@@ -1264,6 +1264,7 @@ S_locking_setlocale(pTHX_
- }
- #endif
-+#ifdef USE_LOCALE
- STATIC void
- S_set_numeric_radix(pTHX_ const bool use_locale)
-@@ -1299,6 +1300,10 @@ S_set_numeric_radix(pTHX_ const bool use
-     }
- #  endif
-+#else
-+
-+    PERL_UNUSED_ARG(use_locale);
-+
- #endif /* USE_LOCALE_NUMERIC and can find the radix char */
- }
-@@ -1481,7 +1486,6 @@ S_new_ctype(pTHX_ const char *newctype)
- #ifndef USE_LOCALE_CTYPE
--    PERL_ARGS_ASSERT_NEW_CTYPE;
-     PERL_UNUSED_ARG(newctype);
-     PERL_UNUSED_CONTEXT;
-@@ -1994,6 +1998,8 @@ S_new_collate(pTHX_ const char *newcoll)
- }
-+#endif
-+
- #ifdef WIN32
- STATIC char *
-@@ -2139,11 +2145,20 @@ Perl_setlocale(const int category, const
- {
-     /* This wraps POSIX::setlocale() */
-+#ifdef NO_LOCALE
-+
-+    PERL_UNUSED_ARG(category);
-+    PERL_UNUSED_ARG(locale);
-+
-+    return "C";
-+
-+#else
-+
-     const char * retval;
-     const char * newlocale;
-     dSAVEDERRNO;
--    DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
-     dTHX;
-+    DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
- #ifdef USE_LOCALE_NUMERIC
-@@ -2262,6 +2277,8 @@ Perl_setlocale(const int category, const
-     return retval;
-+#endif
-+
- }
- PERL_STATIC_INLINE const char *
-@@ -2414,13 +2431,16 @@ S_my_nl_langinfo(const int item, bool to
-     dTHX;
-     const char * retval;
-+#ifdef USE_LOCALE_NUMERIC
-+
-     /* We only need to toggle into the underlying LC_NUMERIC locale for these
-      * two items, and only if not already there */
-     if (toggle && ((   item != RADIXCHAR && item != THOUSEP)
-                     || PL_numeric_underlying))
--    {
-+
-+#endif  /* No toggling needed if not using LC_NUMERIC */
-+
-         toggle = FALSE;
--    }
- #if defined(HAS_NL_LANGINFO) /* nl_langinfo() is available.  */
- #  if   ! defined(HAS_THREAD_SAFE_NL_LANGINFO_L)      \
-@@ -2468,6 +2488,8 @@ S_my_nl_langinfo(const int item, bool to
-             do_free = TRUE;
-         }
-+#    ifdef USE_LOCALE_NUMERIC
-+
-         if (toggle) {
-             if (PL_underlying_numeric_obj) {
-                 cur = PL_underlying_numeric_obj;
-@@ -2478,6 +2500,8 @@ S_my_nl_langinfo(const int item, bool to
-             }
-         }
-+#    endif
-+
-         /* We have to save it to a buffer, because the freelocale() just below
-          * can invalidate the internal one */
-         retval = save_to_buffer(nl_langinfo_l(item, cur),
-@@ -5169,9 +5193,7 @@ Perl_my_strerror(pTHX_ const int errnum)
-     LOCALE_UNLOCK;
- #  endif /* End of doesn't have strerror_l */
--#endif   /* End of does have locale messages */
--
--#ifdef DEBUGGING
-+#  ifdef DEBUGGING
-     if (DEBUG_Lv_TEST) {
-         PerlIO_printf(Perl_debug_log, "Strerror returned; saving a copy: '");
-@@ -5179,7 +5201,8 @@ Perl_my_strerror(pTHX_ const int errnum)
-         PerlIO_printf(Perl_debug_log, "'\n");
-     }
--#endif
-+#  endif
-+#endif   /* End of does have locale messages */
-     SAVEFREEPV(errstr);
-     return errstr;
-@@ -5301,10 +5324,17 @@ L<C<Perl_switch_to_global_locale>|perlap
- bool
- Perl_sync_locale()
- {
-+
-+#ifndef USE_LOCALE
-+
-+    return TRUE;
-+
-+#else
-+
-     const char * newlocale;
-     dTHX;
--#ifdef USE_POSIX_2008_LOCALE
-+#  ifdef USE_POSIX_2008_LOCALE
-     bool was_in_global_locale = FALSE;
-     locale_t cur_obj = uselocale((locale_t) 0);
-@@ -5316,11 +5346,11 @@ Perl_sync_locale()
-      * will affect the */
-     if (cur_obj == LC_GLOBAL_LOCALE) {
--#  ifdef HAS_QUERY_LOCALE
-+#    ifdef HAS_QUERY_LOCALE
-         do_setlocale_c(LC_ALL, setlocale(LC_ALL, NULL));
--#  else
-+#    else
-         unsigned int i;
-@@ -5330,17 +5360,17 @@ Perl_sync_locale()
-             do_setlocale_r(categories[i], setlocale(categories[i], NULL));
-         }
--#  endif
-+#    endif
-         was_in_global_locale = TRUE;
-     }
--#else
-+#  else
-     bool was_in_global_locale = TRUE;
--#endif
--#ifdef USE_LOCALE_CTYPE
-+#  endif
-+#  ifdef USE_LOCALE_CTYPE
-     newlocale = savepv(do_setlocale_c(LC_CTYPE, NULL));
-     DEBUG_Lv(PerlIO_printf(Perl_debug_log,
-@@ -5349,8 +5379,8 @@ Perl_sync_locale()
-     new_ctype(newlocale);
-     Safefree(newlocale);
--#endif /* USE_LOCALE_CTYPE */
--#ifdef USE_LOCALE_COLLATE
-+#  endif /* USE_LOCALE_CTYPE */
-+#  ifdef USE_LOCALE_COLLATE
-     newlocale = savepv(do_setlocale_c(LC_COLLATE, NULL));
-     DEBUG_Lv(PerlIO_printf(Perl_debug_log,
-@@ -5359,8 +5389,8 @@ Perl_sync_locale()
-     new_collate(newlocale);
-     Safefree(newlocale);
--#endif
--#ifdef USE_LOCALE_NUMERIC
-+#  endif
-+#  ifdef USE_LOCALE_NUMERIC
-     newlocale = savepv(do_setlocale_c(LC_NUMERIC, NULL));
-     DEBUG_Lv(PerlIO_printf(Perl_debug_log,
-@@ -5369,9 +5399,12 @@ Perl_sync_locale()
-     new_numeric(newlocale);
-     Safefree(newlocale);
--#endif /* USE_LOCALE_NUMERIC */
-+#  endif /* USE_LOCALE_NUMERIC */
-     return was_in_global_locale;
-+
-+#endif
-+
- }
- #if defined(DEBUGGING) && defined(USE_LOCALE)
---- a/makedef.pl
-+++ b/makedef.pl
-@@ -574,6 +574,9 @@ unless ($define{USE_LOCALE_COLLATE}) {
-                   PL_collxfrm_mult
-                   Perl_sv_collxfrm
-                   Perl_sv_collxfrm_flags
-+                    PL_strxfrm_NUL_replacement
-+                    PL_strxfrm_is_behaved
-+                    PL_strxfrm_max_cp
-                        );
- }
-@@ -583,6 +586,9 @@ unless ($define{USE_LOCALE_NUMERIC}) {
-                   PL_numeric_name
-                   PL_numeric_radix_sv
-                   PL_numeric_standard
-+                    PL_numeric_underlying
-+                    PL_numeric_underlying_is_standard
-+                    PL_underlying_numeric_obj
-                        );
- }
---- a/perl.h
-+++ b/perl.h
-@@ -5656,6 +5656,9 @@ typedef struct am_table_short AMTS;
- #  define IN_LC_COMPILETIME(category)      0
- #  define IN_LC_RUNTIME(category)          0
- #  define IN_LC(category)                  0
-+#  define _CHECK_AND_WARN_PROBLEMATIC_LOCALE
-+#  define _CHECK_AND_OUTPUT_WIDE_LOCALE_UTF8_MSG(s, send)
-+#  define _CHECK_AND_OUTPUT_WIDE_LOCALE_CP_MSG(c)
- #endif
---- a/proto.h
-+++ b/proto.h
-@@ -4886,8 +4886,6 @@ PERL_CALLCONV SV*        Perl_hfree_next_entry(
-       assert(hv); assert(indexp)
- #endif
- #if defined(PERL_IN_LOCALE_C)
--STATIC const char*    S_category_name(const int category);
--STATIC void   S_restore_switched_locale(pTHX_ const int category, const char * const original_locale);
- #ifndef PERL_NO_INLINE_FUNCTIONS
- PERL_STATIC_INLINE const char *       S_save_to_buffer(const char * string, char **buf, Size_t *buf_size, const Size_t offset)
-                       __attribute__warn_unused_result__;
-@@ -4895,17 +4893,19 @@ PERL_STATIC_INLINE const char *        S_save_t
-       assert(buf_size)
- #endif
--STATIC const char*    S_switch_category_locale_to_template(pTHX_ const int switch_category, const int template_category, const char * template_locale);
- #  if defined(USE_LOCALE)
-+STATIC const char*    S_category_name(const int category);
- STATIC void   S_new_collate(pTHX_ const char* newcoll);
- STATIC void   S_new_ctype(pTHX_ const char* newctype);
- #define PERL_ARGS_ASSERT_NEW_CTYPE    \
-       assert(newctype)
- STATIC void   S_new_numeric(pTHX_ const char* newnum);
-+STATIC void   S_restore_switched_locale(pTHX_ const int category, const char * const original_locale);
- STATIC void   S_set_numeric_radix(pTHX_ const bool use_locale);
- STATIC char*  S_stdize_locale(pTHX_ char* locs);
- #define PERL_ARGS_ASSERT_STDIZE_LOCALE        \
-       assert(locs)
-+STATIC const char*    S_switch_category_locale_to_template(pTHX_ const int switch_category, const int template_category, const char * template_locale);
- #    if defined(USE_POSIX_2008_LOCALE)
- STATIC const char*    S_emulate_setlocale(const int category, const char* locale, unsigned int index, const bool is_index_valid);
- #    endif
---- a/sv.c
-+++ b/sv.c
-@@ -13330,10 +13330,15 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const s
-     SvTAINT(sv);
-+#ifdef USE_LOCALE_NUMERIC
-+
-     if (lc_numeric_set) {
-         RESTORE_LC_NUMERIC();   /* Done outside loop, so don't have to
-                                    save/restore each iteration. */
-     }
-+
-+#endif
-+
- }
- /* =========================================================================
---- a/t/lib/warnings/regexec
-+++ b/t/lib/warnings/regexec
-@@ -215,6 +215,10 @@ Use of \b{} or \B{} for non-UTF-8 locale
- Use of \b{} or \B{} for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 17.
- ########
- # NAME (?[ ]) in non-UTF-8 locale
-+require '../loc_tools.pl';
-+unless (locales_enabled()) {
-+    print("SKIPPED\n# locales not available\n"),exit;
-+}
- eval { require POSIX; POSIX->import("locale_h") };
- if ($@) {
-     print("SKIPPED\n# no POSIX\n"),exit;
-@@ -229,14 +233,14 @@ setlocale(&POSIX::LC_CTYPE, "C");
- ":" =~ /(?[ \: ])/;
- no warnings 'locale';
- EXPECT
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 9.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 9.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 10.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 10.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 11.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 11.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 12.
--Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 12.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 13.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 13.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 14.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 14.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 15.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 15.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 16.
-+Use of (?[ ]) for non-UTF-8 locale is wrong.  Assuming a UTF-8 locale at - line 16.
- ########
- # NAME (?[ ]) in UTF-8 locale
- require '../loc_tools.pl';
index a098210dd3a5ed0885f0a31cd699f9b1c703b5df..d0ccec913fc6c1496fd1c5e8cbc9617545b549b3 100644 (file)
@@ -1,11 +1,11 @@
 --- a/ext/Errno/Errno_pm.PL
 +++ b/ext/Errno/Errno_pm.PL
-@@ -133,7 +133,7 @@ sub get_files {
+@@ -115,7 +115,7 @@ sub get_files {
        # Some Linuxes have weird errno.hs which generate
        # no #file or #line directives
-       my ($linux_errno_h) = grep { -e $_ } map { "$_/errno.h" }
+       ($linux_errno_h) = grep { -e $_ } map { "$_/errno.h" }
 -          "$sysroot/usr/include", "$sysroot/usr/local/include",
 +          "$sysroot/usr/include", "$sysroot/usr/local/include", "$sysroot/include",
-           split / / => $Config{locincpth} or
-               die "Cannot find errno.h";
-       $file{$linux_errno_h} = 1;
+           split / / => $Config{locincpth};
+     }
diff --git a/lang/perl/patches/999-fix-build-failure-against-gcc-10.patch b/lang/perl/patches/999-fix-build-failure-against-gcc-10.patch
deleted file mode 100644 (file)
index aa43f05..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-From 6bd6308fcea3541e505651bf8e8127a4a03d22cd Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
-Date: Tue, 12 Nov 2019 09:19:18 +0100
-Subject: [PATCH] Adapt Configure to GCC version 10
-
-I got a notice from Jeff Law <law@redhat.com>:
-
-    Your particular package fails its testsuite. This was ultimately
-    tracked down to a Configure problem. The perl configure script treated
-    gcc-10 as gcc-1 and turned on -fpcc-struct-return. This is an ABI
-    changing flag and caused Perl to not be able to interact properly with
-    the dbm libraries on the system leading to a segfault.
-
-His proposed patch corrected only this one instance of the version
-mismatch. Reading the Configure script revealed more issues. This
-patch fixes all of them I found.
-
----
- Configure | 14 +++++++-------
- cflags.SH |  2 +-
- 2 files changed, 8 insertions(+), 8 deletions(-)
-
---- a/Configure
-+++ b/Configure
-@@ -4689,7 +4689,7 @@ else
- fi
- $rm -f try try.*
- case "$gccversion" in
--1*) cpp=`./loc gcc-cpp $cpp $pth` ;;
-+1.*) cpp=`./loc gcc-cpp $cpp $pth` ;;
- esac
- case "$gccversion" in
- '') gccosandvers='' ;;
-@@ -4729,7 +4729,7 @@ esac
- # gcc 3.* complain about adding -Idirectories that they already know about,
- # so we will take those off from locincpth.
- case "$gccversion" in
--3*)
-+3.*)
-     echo "main(){}">try.c
-     for incdir in $locincpth; do
-        warn=`$cc $ccflags -I$incdir -c try.c 2>&1 | \
-@@ -5455,13 +5455,13 @@ fi
- case "$hint" in
- default|recommended)
-       case "$gccversion" in
--      1*) dflt="$dflt -fpcc-struct-return" ;;
-+      1.*) dflt="$dflt -fpcc-struct-return" ;;
-       esac
-       case "$optimize:$DEBUGGING" in
-       *-g*:old) dflt="$dflt -DDEBUGGING";;
-       esac
-       case "$gccversion" in
--      2*) if $test -d /etc/conf/kconfig.d &&
-+      2.*) if $test -d /etc/conf/kconfig.d &&
-                       $contains _POSIX_VERSION $usrinc/sys/unistd.h >/dev/null 2>&1
-               then
-                       # Interactive Systems (ISC) POSIX mode.
-@@ -5470,7 +5470,7 @@ default|recommended)
-               ;;
-       esac
-       case "$gccversion" in
--      1*) ;;
-+      1.*) ;;
-       2.[0-8]*) ;;
-       ?*)     set strict-aliasing -fno-strict-aliasing
-               eval $checkccflag
-@@ -5588,7 +5588,7 @@ case "$cppflags" in
-     ;;
- esac
- case "$gccversion" in
--1*) cppflags="$cppflags -D__GNUC__"
-+1.*) cppflags="$cppflags -D__GNUC__"
- esac
- case "$mips_type" in
- '');;
-@@ -22957,7 +22957,7 @@ fi
- : add -D_FORTIFY_SOURCE if feasible and not already there
- case "$gccversion" in
--[4567].*)     case "$optimize$ccflags" in
-+[456789].*|[1-9][0-9]*)       case "$optimize$ccflags" in
-       *-O*)   case "$ccflags$cppsymbols" in
-               *_FORTIFY_SOURCE=*) # Don't add it again.
-                       echo "You seem to have -D_FORTIFY_SOURCE already, not adding it." >&4
---- a/cflags.SH
-+++ b/cflags.SH
-@@ -156,7 +156,7 @@ esac
- case "$gccversion" in
- '') ;;
--[12]*) ;; # gcc versions 1 (gasp!) and 2 are not good for this.
-+[12].*) ;; # gcc versions 1 (gasp!) and 2 are not good for this.
- Intel*) ;; # # Is that you, Intel C++?
- #
- # NOTE 1: the -std=c89 without -pedantic is a bit pointless.
diff --git a/lang/perl/patches/999-fixup-regex-engine-build-under-Uusedl.patch b/lang/perl/patches/999-fixup-regex-engine-build-under-Uusedl.patch
new file mode 100644 (file)
index 0000000..99cc13b
--- /dev/null
@@ -0,0 +1,541 @@
+From ba6e2c38aafc23cf114f3ba0d0ff3baead34328b Mon Sep 17 00:00:00 2001
+From: Yves Orton <demerphq@gmail.com>
+Date: Tue, 1 Aug 2023 23:12:46 +0200
+Subject: [PATCH] regcomp*.c, regexec.c - fixup regex engine build under
+ -Uusedl
+
+The regex engine is built a bit different from most of the perl
+codebase. It is compiled as part of the main libperl.so and it is
+also compiled (with DEBUGGING enabled) as part of the re extension.
+When perl itself is compiled with DEBUGGING enabled then the code
+in the re.so extension and the code in libperl.so is the same.
+
+This all works fine and dandy until you have a static build where the
+re.so is linked into libperl.so, which results in duplicate symbols
+being defined. These symbols come in two flaviours: "auxiliary" and
+"debugging" related symbols.
+
+We have basically three cases:
+
+1. USE_DYNAMIC_LOADING is defined. In this case we are doing a dynamic
+   build and re.so will be separate from libperl.so, so it even if this
+   is a DEBUGGING enabled build debug and auxiliary functions can be
+   compiled into *both* re.so and libperl.so. This is basically the
+   "standard build".
+
+2. USE_DYNAMIC_LOADING is not defined, and DEBUGGING is not defined
+   either. In this case auxiliary functions should only be compiled in
+   libperl.so, and the debug functions should only be compiled into
+   re.so
+
+3. USE_DYNAMIC_LOADING is not defined, and DEBUGGING *is* defined. In
+   this case auxiliary functions AND debug functions should only be
+   compiled into libperl.so
+
+It is possible to detect the different build options by looking at the
+defines 'USE_DYNAMIC_LOADING', 'PERL_EXT_RE_DEBUG' and
+'DEBUGGING_RE_ONLY'. 'USE_DYNAMIC_LOADING' is NOT defined when we are
+building a static perl. 'PERL_EXT_RE_DEBUG' is defined only when we are
+building re.so, and 'DEBUGGING_RE_ONLY' is defined only when we are
+building re.so in a perl that is not itself already a DEBUGGING enabled
+perl. The file ext/re/re_top.h responsible for setting up
+DEBUGGING_RE_ONLY.
+
+This patch uses 'PERL_EXT_RE_DEBUG', 'DEBUGGING_RE_ONLY' and
+'USE_DYNAMIC_LOADING' to define in regcomp.h two further define flags
+'PERL_RE_BUILD_DEBUG' and 'PERL_RE_BUILD_AUX'.
+
+The 'PERL_RE_BUILD_DEBUG' flag determines if the debugging functions
+should be compiled into libperl.so or re.so or both. The
+'PERL_RE_BUILD_AUX' flag determines if the auxiliary functions should be
+compiled into just libperl.so or into it and re.so. We then use these
+flags to guard the different types of functions so that we can build in
+all three modes without duplicate symbols.
+---
+ regcomp.c         |  13 +-
+ regcomp.h         |  14 ++-
+ regcomp_debug.c   | 308 +++++++++++++++++++++++-----------------------
+ regcomp_invlist.c |   3 +-
+ regexec.c         |   3 +-
+ 5 files changed, 181 insertions(+), 160 deletions(-)
+
+--- a/regcomp.c
++++ b/regcomp.c
+@@ -290,6 +290,7 @@ S_edit_distance(const UV* src,
+ /* END of edit_distance() stuff
+  * ========================================================= */
++#ifdef PERL_RE_BUILD_AUX
+ /* add a data member to the struct reg_data attached to this regex, it should
+  * always return a non-zero return. the 's' argument is the type of the items
+  * being added and the n is the number of items. The length of 's' should match
+@@ -340,6 +341,7 @@ Perl_reg_add_data(RExC_state_t* const pR
+     assert(count>0);
+     return count;
+ }
++#endif /* PERL_RE_BUILD_AUX */
+ /*XXX: todo make this not included in a non debugging perl, but appears to be
+  * used anyway there, in 'use re' */
+@@ -7443,6 +7445,7 @@ S_regatom(pTHX_ RExC_state_t *pRExC_stat
+ }
++#ifdef PERL_RE_BUILD_AUX
+ void
+ Perl_populate_anyof_bitmap_from_invlist(pTHX_ regnode *node, SV** invlist_ptr)
+ {
+@@ -7502,6 +7505,7 @@ Perl_populate_anyof_bitmap_from_invlist(
+         }
+     }
+ }
++#endif /* PERL_RE_BUILD_AUX */
+ /* Parse POSIX character classes: [[:foo:]], [[=foo=]], [[.foo.]].
+    Character classes ([:foo:]) can also be negated ([:^foo:]).
+@@ -9095,6 +9099,7 @@ S_dump_regex_sets_structures(pTHX_ RExC_
+ #undef IS_OPERATOR
+ #undef IS_OPERAND
++#ifdef PERL_RE_BUILD_AUX
+ void
+ Perl_add_above_Latin1_folds(pTHX_ RExC_state_t *pRExC_state, const U8 cp, SV** invlist)
+ {
+@@ -9182,6 +9187,8 @@ Perl_add_above_Latin1_folds(pTHX_ RExC_s
+          }
+     }
+ }
++#endif /* PERL_RE_BUILD_AUX */
++
+ STATIC void
+ S_output_posix_warnings(pTHX_ RExC_state_t *pRExC_state, AV* posix_warnings)
+@@ -12105,6 +12112,7 @@ S_optimize_regclass(pTHX_
+ #undef HAS_NONLOCALE_RUNTIME_PROPERTY_DEFINITION
++#ifdef PERL_RE_BUILD_AUX
+ void
+ Perl_set_ANYOF_arg(pTHX_ RExC_state_t* const pRExC_state,
+                 regnode* const node,
+@@ -12261,6 +12269,7 @@ Perl_set_ANYOF_arg(pTHX_ RExC_state_t* c
+     RExC_rxi->data->data[n] = (void*)rv;
+     ARG1u_SET(node, n);
+ }
++#endif /* PERL_RE_BUILD_AUX */
+ SV *
+@@ -12999,6 +13008,8 @@ S_regtail_study(pTHX_ RExC_state_t *pREx
+ }
+ #endif
++
++#ifdef PERL_RE_BUILD_AUX
+ SV*
+ Perl_get_ANYOFM_contents(pTHX_ const regnode * n) {
+@@ -13047,7 +13058,7 @@ Perl_get_ANYOFHbbm_contents(pTHX_ const
+                                       UTF_CONTINUATION_MARK | 0));
+     return cp_list;
+ }
+-
++#endif /* PERL_RE_BUILD_AUX */
+ SV *
+--- a/regcomp.h
++++ b/regcomp.h
+@@ -1554,7 +1554,19 @@ typedef enum {
+ #define EVAL_OPTIMISTIC_FLAG    128
+ #define EVAL_FLAGS_MASK         (EVAL_OPTIMISTIC_FLAG-1)
+-
++/* We define PERL_RE_BUILD_DEBUG if we are NOT compiling the re extension and
++ * we are under DEBUGGING, or if we are ARE compiling the re extension
++ * and this is not a DEBUGGING enabled build (identified by
++ * DEBUGGING_RE_ONLY being defined)
++ */
++#if ( defined(USE_DYNAMIC_LOADING) && defined(DEBUGGING)) || \
++    ( defined(PERL_EXT_RE_BUILD) && defined(DEBUGGING_RE_ONLY)) || \
++    (!defined(PERL_EXT_RE_BUILD) && defined(DEBUGGING))
++#define PERL_RE_BUILD_DEBUG
++#endif
++#if ( defined(USE_DYNAMIC_LOADING) || !defined(PERL_EXT_RE_BUILD) )
++#define PERL_RE_BUILD_AUX
++#endif
+ #endif /* PERL_REGCOMP_H_ */
+--- a/regcomp_debug.c
++++ b/regcomp_debug.c
+@@ -18,8 +18,7 @@
+ #include "unicode_constants.h"
+ #include "regcomp_internal.h"
+-#ifdef DEBUGGING
+-
++#ifdef PERL_RE_BUILD_DEBUG
+ int
+ Perl_re_printf(pTHX_ const char *fmt, ...)
+ {
+@@ -159,13 +158,160 @@ Perl_debug_peep(pTHX_ const char *str, c
+    });
+ }
+-#endif /* DEBUGGING */
++const regnode *
++Perl_dumpuntil(pTHX_ const regexp *r, const regnode *start, const regnode *node,
++            const regnode *last, const regnode *plast,
++            SV* sv, I32 indent, U32 depth)
++{
++    const regnode *next;
++    const regnode *optstart= NULL;
++
++    RXi_GET_DECL(r, ri);
++    DECLARE_AND_GET_RE_DEBUG_FLAGS;
++
++    PERL_ARGS_ASSERT_DUMPUNTIL;
++
++#ifdef DEBUG_DUMPUNTIL
++    Perl_re_printf( aTHX_  "--- %d : %d - %d - %d\n", indent, node-start,
++        last ? last-start : 0, plast ? plast-start : 0);
++#endif
++
++    if (plast && plast < last)
++        last= plast;
++
++    while (node && (!last || node < last)) {
++        const U8 op = OP(node);
++
++        if (op == CLOSE || op == SRCLOSE || op == WHILEM)
++            indent--;
++        next = regnext((regnode *)node);
++        const regnode *after = regnode_after((regnode *)node,0);
++
++        /* Where, what. */
++        if (op == OPTIMIZED) {
++            if (!optstart && RE_DEBUG_FLAG(RE_DEBUG_COMPILE_OPTIMISE))
++                optstart = node;
++            else
++                goto after_print;
++        } else
++            CLEAR_OPTSTART;
++
++        regprop(r, sv, node, NULL, NULL);
++        Perl_re_printf( aTHX_  "%4" IVdf ":%*s%s", (IV)(node - start),
++                      (int)(2*indent + 1), "", SvPVX_const(sv));
++
++        if (op != OPTIMIZED) {
++            if (next == NULL)           /* Next ptr. */
++                Perl_re_printf( aTHX_  " (0)");
++            else if (REGNODE_TYPE(op) == BRANCH
++                     && REGNODE_TYPE(OP(next)) != BRANCH )
++                Perl_re_printf( aTHX_  " (FAIL)");
++            else
++                Perl_re_printf( aTHX_  " (%" IVdf ")", (IV)(next - start));
++            Perl_re_printf( aTHX_ "\n");
++        }
++
++      after_print:
++        if (REGNODE_TYPE(op) == BRANCHJ) {
++            assert(next);
++            const regnode *nnode = (OP(next) == LONGJMP
++                                   ? regnext((regnode *)next)
++                                   : next);
++            if (last && nnode > last)
++                nnode = last;
++            DUMPUNTIL(after, nnode);
++        }
++        else if (REGNODE_TYPE(op) == BRANCH) {
++            assert(next);
++            DUMPUNTIL(after, next);
++        }
++        else if ( REGNODE_TYPE(op)  == TRIE ) {
++            const regnode *this_trie = node;
++            const U32 n = ARG1u(node);
++            const reg_ac_data * const ac = op>=AHOCORASICK ?
++               (reg_ac_data *)ri->data->data[n] :
++               NULL;
++            const reg_trie_data * const trie =
++                (reg_trie_data*)ri->data->data[op<AHOCORASICK ? n : ac->trie];
++#ifdef DEBUGGING
++            AV *const trie_words
++                           = MUTABLE_AV(ri->data->data[n + TRIE_WORDS_OFFSET]);
++#endif
++            const regnode *nextbranch= NULL;
++            I32 word_idx;
++            SvPVCLEAR(sv);
++            for (word_idx= 0; word_idx < (I32)trie->wordcount; word_idx++) {
++                SV ** const elem_ptr = av_fetch_simple(trie_words, word_idx, 0);
++
++                Perl_re_indentf( aTHX_  "%s ",
++                    indent+3,
++                    elem_ptr
++                    ? pv_pretty(sv, SvPV_nolen_const(*elem_ptr),
++                                SvCUR(*elem_ptr), PL_dump_re_max_len,
++                                PL_colors[0], PL_colors[1],
++                                (SvUTF8(*elem_ptr)
++                                 ? PERL_PV_ESCAPE_UNI
++                                 : 0)
++                                | PERL_PV_PRETTY_ELLIPSES
++                                | PERL_PV_PRETTY_LTGT
++                            )
++                    : "???"
++                );
++                if (trie->jump) {
++                    U16 dist= trie->jump[word_idx+1];
++                    Perl_re_printf( aTHX_  "(%" UVuf ")\n",
++                               (UV)((dist ? this_trie + dist : next) - start));
++                    if (dist) {
++                        if (!nextbranch)
++                            nextbranch= this_trie + trie->jump[0];
++                        DUMPUNTIL(this_trie + dist, nextbranch);
++                    }
++                    if (nextbranch && REGNODE_TYPE(OP(nextbranch))==BRANCH)
++                        nextbranch= regnext((regnode *)nextbranch);
++                } else {
++                    Perl_re_printf( aTHX_  "\n");
++                }
++            }
++            if (last && next > last)
++                node= last;
++            else
++                node= next;
++        }
++        else if ( op == CURLY ) {   /* "next" might be very big: optimizer */
++            DUMPUNTIL(after, after + 1); /* +1 is NOT a REGNODE_AFTER */
++        }
++        else if (REGNODE_TYPE(op) == CURLY && op != CURLYX) {
++            assert(next);
++            DUMPUNTIL(after, next);
++        }
++        else if ( op == PLUS || op == STAR) {
++            DUMPUNTIL(after, after + 1); /* +1 NOT a REGNODE_AFTER */
++        }
++        else if (REGNODE_TYPE(op) == EXACT || op == ANYOFHs) {
++            /* Literal string, where present. */
++            node = (const regnode *)REGNODE_AFTER_varies(node);
++        }
++        else {
++            node = REGNODE_AFTER_opcode(node,op);
++        }
++        if (op == CURLYX || op == OPEN || op == SROPEN)
++            indent++;
++        if (REGNODE_TYPE(op) == END)
++            break;
++    }
++    CLEAR_OPTSTART;
++#ifdef DEBUG_DUMPUNTIL
++    Perl_re_printf( aTHX_  "--- %d\n", (int)indent);
++#endif
++    return node;
++}
++
++#endif  /* PERL_RE_BUILD_DEBUG */
+ /*
+  - regdump - dump a regexp onto Perl_debug_log in vaguely comprehensible form
+  */
+ #ifdef DEBUGGING
+-
+ static void
+ S_regdump_intflags(pTHX_ const char *lead, const U32 flags)
+ {
+@@ -907,8 +1053,8 @@ Perl_regprop(pTHX_ const regexp *prog, S
+ #endif  /* DEBUGGING */
+ }
+-#ifdef DEBUGGING
++#ifdef DEBUGGING
+ STATIC void
+ S_put_code_point(pTHX_ SV *sv, UV c)
+ {
+@@ -1517,154 +1663,4 @@ S_put_charclass_bitmap_innards(pTHX_ SV
+     return did_output_something;
+ }
+-
+-
+-const regnode *
+-Perl_dumpuntil(pTHX_ const regexp *r, const regnode *start, const regnode *node,
+-            const regnode *last, const regnode *plast,
+-            SV* sv, I32 indent, U32 depth)
+-{
+-    const regnode *next;
+-    const regnode *optstart= NULL;
+-
+-    RXi_GET_DECL(r, ri);
+-    DECLARE_AND_GET_RE_DEBUG_FLAGS;
+-
+-    PERL_ARGS_ASSERT_DUMPUNTIL;
+-
+-#ifdef DEBUG_DUMPUNTIL
+-    Perl_re_printf( aTHX_  "--- %d : %d - %d - %d\n", indent, node-start,
+-        last ? last-start : 0, plast ? plast-start : 0);
+-#endif
+-
+-    if (plast && plast < last)
+-        last= plast;
+-
+-    while (node && (!last || node < last)) {
+-        const U8 op = OP(node);
+-
+-        if (op == CLOSE || op == SRCLOSE || op == WHILEM)
+-            indent--;
+-        next = regnext((regnode *)node);
+-        const regnode *after = regnode_after((regnode *)node,0);
+-
+-        /* Where, what. */
+-        if (op == OPTIMIZED) {
+-            if (!optstart && RE_DEBUG_FLAG(RE_DEBUG_COMPILE_OPTIMISE))
+-                optstart = node;
+-            else
+-                goto after_print;
+-        } else
+-            CLEAR_OPTSTART;
+-
+-        regprop(r, sv, node, NULL, NULL);
+-        Perl_re_printf( aTHX_  "%4" IVdf ":%*s%s", (IV)(node - start),
+-                      (int)(2*indent + 1), "", SvPVX_const(sv));
+-
+-        if (op != OPTIMIZED) {
+-            if (next == NULL)           /* Next ptr. */
+-                Perl_re_printf( aTHX_  " (0)");
+-            else if (REGNODE_TYPE(op) == BRANCH
+-                     && REGNODE_TYPE(OP(next)) != BRANCH )
+-                Perl_re_printf( aTHX_  " (FAIL)");
+-            else
+-                Perl_re_printf( aTHX_  " (%" IVdf ")", (IV)(next - start));
+-            Perl_re_printf( aTHX_ "\n");
+-        }
+-
+-      after_print:
+-        if (REGNODE_TYPE(op) == BRANCHJ) {
+-            assert(next);
+-            const regnode *nnode = (OP(next) == LONGJMP
+-                                   ? regnext((regnode *)next)
+-                                   : next);
+-            if (last && nnode > last)
+-                nnode = last;
+-            DUMPUNTIL(after, nnode);
+-        }
+-        else if (REGNODE_TYPE(op) == BRANCH) {
+-            assert(next);
+-            DUMPUNTIL(after, next);
+-        }
+-        else if ( REGNODE_TYPE(op)  == TRIE ) {
+-            const regnode *this_trie = node;
+-            const U32 n = ARG1u(node);
+-            const reg_ac_data * const ac = op>=AHOCORASICK ?
+-               (reg_ac_data *)ri->data->data[n] :
+-               NULL;
+-            const reg_trie_data * const trie =
+-                (reg_trie_data*)ri->data->data[op<AHOCORASICK ? n : ac->trie];
+-#ifdef DEBUGGING
+-            AV *const trie_words
+-                           = MUTABLE_AV(ri->data->data[n + TRIE_WORDS_OFFSET]);
+-#endif
+-            const regnode *nextbranch= NULL;
+-            I32 word_idx;
+-            SvPVCLEAR(sv);
+-            for (word_idx= 0; word_idx < (I32)trie->wordcount; word_idx++) {
+-                SV ** const elem_ptr = av_fetch_simple(trie_words, word_idx, 0);
+-
+-                Perl_re_indentf( aTHX_  "%s ",
+-                    indent+3,
+-                    elem_ptr
+-                    ? pv_pretty(sv, SvPV_nolen_const(*elem_ptr),
+-                                SvCUR(*elem_ptr), PL_dump_re_max_len,
+-                                PL_colors[0], PL_colors[1],
+-                                (SvUTF8(*elem_ptr)
+-                                 ? PERL_PV_ESCAPE_UNI
+-                                 : 0)
+-                                | PERL_PV_PRETTY_ELLIPSES
+-                                | PERL_PV_PRETTY_LTGT
+-                            )
+-                    : "???"
+-                );
+-                if (trie->jump) {
+-                    U16 dist= trie->jump[word_idx+1];
+-                    Perl_re_printf( aTHX_  "(%" UVuf ")\n",
+-                               (UV)((dist ? this_trie + dist : next) - start));
+-                    if (dist) {
+-                        if (!nextbranch)
+-                            nextbranch= this_trie + trie->jump[0];
+-                        DUMPUNTIL(this_trie + dist, nextbranch);
+-                    }
+-                    if (nextbranch && REGNODE_TYPE(OP(nextbranch))==BRANCH)
+-                        nextbranch= regnext((regnode *)nextbranch);
+-                } else {
+-                    Perl_re_printf( aTHX_  "\n");
+-                }
+-            }
+-            if (last && next > last)
+-                node= last;
+-            else
+-                node= next;
+-        }
+-        else if ( op == CURLY ) {   /* "next" might be very big: optimizer */
+-            DUMPUNTIL(after, after + 1); /* +1 is NOT a REGNODE_AFTER */
+-        }
+-        else if (REGNODE_TYPE(op) == CURLY && op != CURLYX) {
+-            assert(next);
+-            DUMPUNTIL(after, next);
+-        }
+-        else if ( op == PLUS || op == STAR) {
+-            DUMPUNTIL(after, after + 1); /* +1 NOT a REGNODE_AFTER */
+-        }
+-        else if (REGNODE_TYPE(op) == EXACT || op == ANYOFHs) {
+-            /* Literal string, where present. */
+-            node = (const regnode *)REGNODE_AFTER_varies(node);
+-        }
+-        else {
+-            node = REGNODE_AFTER_opcode(node,op);
+-        }
+-        if (op == CURLYX || op == OPEN || op == SROPEN)
+-            indent++;
+-        if (REGNODE_TYPE(op) == END)
+-            break;
+-    }
+-    CLEAR_OPTSTART;
+-#ifdef DEBUG_DUMPUNTIL
+-    Perl_re_printf( aTHX_  "--- %d\n", (int)indent);
+-#endif
+-    return node;
+-}
+-
+-#endif  /* DEBUGGING */
++#endif /* DEBUGGING */
+--- a/regcomp_invlist.c
++++ b/regcomp_invlist.c
+@@ -18,7 +18,7 @@
+ #include "unicode_constants.h"
+ #include "regcomp_internal.h"
+-
++#ifdef PERL_RE_BUILD_AUX
+ void
+ Perl_populate_bitmap_from_invlist(pTHX_ SV * invlist, const UV offset, const U8 * bitmap, const Size_t len)
+ {
+@@ -70,6 +70,7 @@ Perl_populate_invlist_from_bitmap(pTHX_
+         }
+     }
+ }
++#endif /* PERL_RE_BUILD_AUX */
+ /* This section of code defines the inversion list object and its methods.  The
+  * interfaces are highly subject to change, so as much as possible is static to
+--- a/regexec.c
++++ b/regexec.c
+@@ -4421,7 +4421,8 @@ S_regtry(pTHX_ regmatch_info *reginfo, c
+ */
+ #define REPORT_CODE_OFF 29
+ #define INDENT_CHARS(depth) ((int)(depth) % 20)
+-#ifdef DEBUGGING
++
++#ifdef PERL_RE_BUILD_DEBUG
+ int
+ Perl_re_exec_indentf(pTHX_ const char *fmt, U32 depth, ...)
+ {
index e23bf8ef58ed0e44102a4d9185e07aad600ae435..f3d65a51772d939b71bc231456ed29e6cd9feb76 100644 (file)
@@ -51,20 +51,6 @@ endef
 $(eval $(call BuildPackage,perlbase-archive))
 
 
-define Package/perlbase-arybase
-$(call Package/perlbase-template)
-TITLE:=arybase perl module
-DEPENDS+=+perlbase-xsloader
-endef
-
-define Package/perlbase-arybase/install
-$(call perlmod/Install,$(1),arybase.pm auto/arybase,)
-$(call perlmod/InstallBaseTests,$(1),ext/arybase/t)
-endef
-
-$(eval $(call BuildPackage,perlbase-arybase))
-
-
 define Package/perlbase-attribute
 $(call Package/perlbase-template)
 TITLE:=Attribute perl module
@@ -725,7 +711,7 @@ endef
 
 define Package/perlbase-findbin/install
 $(call perlmod/Install,$(1),FindBin.pm,)
-$(call perlmod/InstallBaseTests,$(1),lib/FindBin.t)
+$(call perlmod/InstallBaseTests,$(1),dist/FindBin/t)
 endef
 
 $(eval $(call BuildPackage,perlbase-findbin))
@@ -1441,7 +1427,7 @@ DEPENDS+=+perlbase-essential +perlbase-fcntl +perlbase-xsloader
 endef
 
 define Package/perlbase-tie/install
-$(call perlmod/Install,$(1),Tie auto/Tie,)
+$(call perlmod/Install,$(1),Tie,)
 $(call perlmod/InstallBaseTests,$(1),cpan/Tie-RefHash/t dist/Tie-File/t ext/Tie-Hash-NamedCapture/t ext/Tie-Memoize/lib/Tie/Memoize.pm ext/Tie-Memoize/t lib/Tie/Array/push.t lib/Tie/Array/splice.t lib/Tie/Array/std.t lib/Tie/Array/stdpush.t lib/Tie/ExtraHash.t lib/Tie/Handle/stdhandle.t lib/Tie/Handle/stdhandle_from_handle.t lib/Tie/Hash.t lib/Tie/Scalar.t lib/Tie/SubstrHash.t)
 endef
 
@@ -1522,7 +1508,7 @@ DEPENDS+=+perlbase-essential +perlbase-re +perlbase-unicore
 endef
 
 define Package/perlbase-utf8/install
-$(call perlmod/Install,$(1),utf8.pm utf8_heavy.pl,)
+$(call perlmod/Install,$(1),utf8.pm,)
 $(call perlmod/InstallBaseTests,$(1),lib/utf8.t)
 endef
 
index dbec8151ebe6aa1b7fc0c3b7a100d85697770321..465140bf1b0c5a5b4b9621f731461f4647cc1e74 100644 (file)
@@ -1,4 +1,4 @@
-PERL_VERSION:=5.28.1
+PERL_VERSION:=5.38.0
 
 PERL_EXPLODE:=$(subst ., ,$(PERL_VERSION))
 
diff --git a/lang/python/pipx/Makefile b/lang/python/pipx/Makefile
new file mode 100644 (file)
index 0000000..92835b7
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2023 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=pipx
+PKG_VERSION:=1.2.1
+PKG_RELEASE:=1
+
+PYPI_NAME:=pipx
+PKG_HASH:=698777c05a97cca81df4dc6a71d9ca4ece2184c6f91dc7a0e4802ac51d86d32a
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+
+PKG_BUILD_DEPENDS:=python-hatchling/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/pipx
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Install/Run Python Applications in Isolated Environments
+  URL:=https://github.com/pypa/pipx
+  DEPENDS:= \
+    +python3-light \
+    +python3-logging \
+    +python3-urllib \
+    +python3-venv \
+    +python3-argcomplete \
+    +python3-packaging \
+    +python3-userpath
+endef
+
+define Package/pipx/description
+pipx is a tool to help you install and run end-user applications written
+in Python. It's roughly similar to macOS's brew, JavaScript's npx, and
+Linux's apt.
+
+It's closely related to pip. In fact, it uses pip, but is focused on
+installing and managing Python packages that can be run from the command
+line directly as applications.
+endef
+
+$(eval $(call Py3Package,pipx))
+$(eval $(call BuildPackage,pipx))
+$(eval $(call BuildPackage,pipx-src))
diff --git a/lang/python/pipx/test.sh b/lang/python/pipx/test.sh
new file mode 100644 (file)
index 0000000..a4f2348
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "$1" = pipx ] || exit 0
+
+pipx --version | grep -Fx "$PKG_VERSION"
diff --git a/lang/python/python-argcomplete/Makefile b/lang/python/python-argcomplete/Makefile
new file mode 100644 (file)
index 0000000..534131e
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2023 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-argcomplete
+PKG_VERSION:=3.1.6
+PKG_RELEASE:=1
+
+PYPI_NAME:=argcomplete
+PKG_HASH:=3b1f07d133332547a53c79437527c00be48cca3807b1d4ca5cab1b26313386a6
+
+PKG_LICENSE:=Apache-2.0
+PKG_LICENSE_FILES:=LICENSE.rst
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+
+PKG_BUILD_DEPENDS:=python-setuptools-scm/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-argcomplete
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Bash tab completion for argparse
+  URL:=https://github.com/kislyuk/argcomplete
+  DEPENDS:=+python3-light
+endef
+
+define Package/python3-argcomplete/description
+Argcomplete provides easy, extensible command line tab completion of
+arguments for your Python application.
+endef
+
+$(eval $(call Py3Package,python3-argcomplete))
+$(eval $(call BuildPackage,python3-argcomplete))
+$(eval $(call BuildPackage,python3-argcomplete-src))
diff --git a/lang/python/python-argcomplete/patches/001-unpin-setuptools.patch b/lang/python/python-argcomplete/patches/001-unpin-setuptools.patch
new file mode 100644 (file)
index 0000000..a85ce85
--- /dev/null
@@ -0,0 +1,9 @@
+--- a/pyproject.toml
++++ b/pyproject.toml
+@@ -1,5 +1,5 @@
+ [build-system]
+-requires = ["setuptools>=67.7.2", "setuptools_scm[toml]>=6.2"]
++requires = ["setuptools", "setuptools_scm[toml]>=6.2"]
+ build-backend = "setuptools.build_meta"
+ [project]
diff --git a/lang/python/python-argcomplete/test.sh b/lang/python/python-argcomplete/test.sh
new file mode 100644 (file)
index 0000000..0ecba3e
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "$1" = python3-argcomplete ] || exit 0
+
+python3 -c 'import argcomplete'
diff --git a/lang/python/python-fnv-hash-fast/Makefile b/lang/python/python-fnv-hash-fast/Makefile
new file mode 100644 (file)
index 0000000..b475859
--- /dev/null
@@ -0,0 +1,38 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-fnv-hash-fast
+PKG_VERSION:=0.5.0
+PKG_RELEASE:=1
+
+PYPI_NAME:=fnv-hash-fast
+PYPI_SOURCE_NAME:=fnv_hash_fast
+PKG_HASH:=a84d658952776a186418f4158fc8e55ff3c576ac32cc9ef7f8077efdf2d0b89f
+
+PKG_MAINTAINER:=Timothy Ace <openwrt@timothyace.com>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_BUILD_DEPENDS:=python-cython/host python-poetry-core/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-fnv-hash-fast
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=A fast version of fnv1a
+  URL:=https://github.com/bdraco/fnv-hash-fast
+  DEPENDS:=+libstdcpp +python3-light +python3-fnvhash
+endef
+
+define Package/python3-fnv-hash-fast/description
+A fast version of fnv1a. This library will use a CPP implementation of fnv1a
+(32) if cython is available, and will fallback to pure python from the fnvhash
+package if it is not.
+endef
+
+$(eval $(call Py3Package,python3-fnv-hash-fast))
+$(eval $(call BuildPackage,python3-fnv-hash-fast))
+$(eval $(call BuildPackage,python3-fnv-hash-fast-src))
diff --git a/lang/python/python-fnvhash/Makefile b/lang/python/python-fnvhash/Makefile
new file mode 100644 (file)
index 0000000..b0c2316
--- /dev/null
@@ -0,0 +1,33 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-fnvhash
+PKG_VERSION:=0.1.0
+PKG_RELEASE:=1
+
+PYPI_NAME:=fnvhash
+PKG_HASH:=3e82d505054f9f3987b2b5b649f7e7b6f48349f6af8a1b8e4d66779699c85a8e
+
+PKG_MAINTAINER:=Timothy Ace <openwrt@timothyace.com>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-fnvhash
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Pure Python FNV hash implementation
+  URL:=https://github.com/znerol/py-fnvhash
+  DEPENDS:=+python3-light
+endef
+
+define Package/python3-fnvhash/description
+Pure Python implementation of the FNV hash family with 100% test coverage.
+endef
+
+$(eval $(call Py3Package,python3-fnvhash))
+$(eval $(call BuildPackage,python3-fnvhash))
+$(eval $(call BuildPackage,python3-fnvhash-src))
index 39f890985afbb3612381f6cecf18a80562c0607b..6726a77768d63b4ff2f9b9f77d8744b76ced0dd4 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-hatch-vcs
-PKG_VERSION:=0.3.0
+PKG_VERSION:=0.4.0
 PKG_RELEASE:=1
 
 PYPI_NAME:=hatch-vcs
 PYPI_SOURCE_NAME:=hatch_vcs
-PKG_HASH:=cec5107cfce482c67f8bc96f18bbc320c9aa0d068180e14ad317bbee5a153fee
+PKG_HASH:=093810748fe01db0d451fabcf2c1ac2688caefd232d4ede967090b1c1b07d9f7
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE.txt
index ee8738a61a3526e3b0b84fe07df0208074e80bad..33129b03a8f1991bfbc24a80e983729c8ca5884a 100644 (file)
@@ -8,14 +8,14 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-idna
-PKG_VERSION:=3.4
+PKG_VERSION:=3.6
 PKG_RELEASE:=1
 
 PYPI_NAME:=idna
-PKG_HASH:=814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4
+PKG_HASH:=9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca
 
 PKG_LICENSE:=BSD-3-Clause
-PKG_LICENSE_FILES:=LICENSE.rst
+PKG_LICENSE_FILES:=LICENSE.md
 PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
 
 PKG_BUILD_DEPENDS:=python-flit-core/host
@@ -30,9 +30,7 @@ define Package/python3-idna
   SUBMENU:=Python
   TITLE:=IDNA library
   URL:=https://github.com/kjd/idna
-  DEPENDS:= \
-      +python3-light \
-      +python3-codecs
+  DEPENDS:=+python3-light +python3-codecs
 endef
 
 define Package/python3-idna/description
diff --git a/lang/python/python-idna/test.sh b/lang/python/python-idna/test.sh
new file mode 100644 (file)
index 0000000..85f779c
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+[ "$1" = python3-idna ] || exit 0
+
+python3 - << 'EOF'
+
+import idna
+import idna.codec
+
+assert idna.encode('ドメイン.テスト') == b'xn--eckwd4c7c.xn--zckzah'
+assert idna.decode('xn--eckwd4c7c.xn--zckzah') == 'ドメイン.テスト'
+
+assert 'домен.испытание'.encode('idna2008') == b'xn--d1acufc.xn--80akhbyknj4f'
+assert b'xn--d1acufc.xn--80akhbyknj4f'.decode('idna2008') == 'домен.испытание'
+
+assert idna.alabel('测试') == b'xn--0zwm56d'
+
+assert idna.encode('Königsgäßchen', uts46=True) == b'xn--knigsgchen-b4a3dun'
+assert idna.decode('xn--knigsgchen-b4a3dun') == 'königsgäßchen'
+
+assert idna.encode('Königsgäßchen', uts46=True, transitional=True) == b'xn--knigsgsschen-lcb0w'
+
+EOF
diff --git a/lang/python/python-jsonschema-specifications/Makefile b/lang/python/python-jsonschema-specifications/Makefile
new file mode 100644 (file)
index 0000000..88cc0ba
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2023 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-jsonschema-specifications
+PKG_VERSION:=2023.7.1
+PKG_RELEASE:=1
+
+PYPI_NAME:=jsonschema-specifications
+PYPI_SOURCE_NAME:=jsonschema_specifications
+PKG_HASH:=c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=COPYING
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+
+PKG_BUILD_DEPENDS:=python-hatchling/host python-hatch-vcs/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-jsonschema-specifications
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=JSON Schema meta-schemas and vocabularies
+  URL:=https://github.com/python-jsonschema/jsonschema-specifications
+  DEPENDS:=+python3-light +python3-referencing
+endef
+
+define Package/python3-jsonschema-specifications/description
+JSON support files from the JSON Schema Specifications (metaschemas,
+vocabularies, etc.), packaged for runtime access from Python as a
+referencing-based Schema Registry.
+endef
+
+$(eval $(call Py3Package,python3-jsonschema-specifications))
+$(eval $(call BuildPackage,python3-jsonschema-specifications))
+$(eval $(call BuildPackage,python3-jsonschema-specifications-src))
diff --git a/lang/python/python-jsonschema-specifications/test.sh b/lang/python/python-jsonschema-specifications/test.sh
new file mode 100644 (file)
index 0000000..cdf2f57
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+[ "$1" = python3-jsonschema-specifications ] || exit 0
+
+python3 - << 'EOF'
+
+from jsonschema_specifications import REGISTRY as SPECIFICATIONS
+
+DRAFT202012_DIALECT_URI = "https://json-schema.org/draft/2020-12/schema"
+assert SPECIFICATIONS.contents(DRAFT202012_DIALECT_URI) != ""
+
+EOF
index 4c6e44d4680c7a1c585bd2a4e6b68082f3de0b79..4e3b9c7e41818ae65f3d5c86350179e658a34fd0 100644 (file)
@@ -1,11 +1,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-jsonschema
-PKG_VERSION:=4.17.3
-PKG_RELEASE:=3
+PKG_VERSION:=4.19.1
+PKG_RELEASE:=1
 
 PYPI_NAME:=jsonschema
-PKG_HASH:=0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d
+PKG_HASH:=ec84cc37cfa703ef7cd4928db24f9cb31428a5d0fa77747b8b51a847458e0bbf
 
 PKG_MAINTAINER:=Javier Marcet <javier@marcet.info>
 PKG_LICENSE:=MIT
@@ -22,9 +22,16 @@ define Package/python3-jsonschema
   CATEGORY:=Languages
   SUBMENU:=Python
   TITLE:=An implementation of JSON Schema validation
-  URL:=https://github.com/Julian/jsonschema
-  DEPENDS:=+python3-light +python3-attrs +python3-urllib \
-         +python3-six +python3-pyrsistent +python3-setuptools
+  URL:=https://github.com/python-jsonschema/jsonschema
+  DEPENDS:= \
+         +python3-light \
+         +python3-decimal \
+         +python3-urllib \
+         +python3-uuid \
+         +python3-attrs \
+         +python3-jsonschema-specifications \
+         +python3-referencing \
+         +python3-rpds-py
 endef
 
 define Package/python3-jsonschema/description
diff --git a/lang/python/python-jsonschema/test.sh b/lang/python/python-jsonschema/test.sh
new file mode 100644 (file)
index 0000000..37fe492
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+[ "$1" = python3-jsonschema ] || exit 0
+
+python3 - << 'EOF'
+
+from jsonschema import validate
+
+# A sample schema, like what we'd get from json.load()
+schema = {
+    "type" : "object",
+    "properties" : {
+        "price" : {"type" : "number"},
+        "name" : {"type" : "string"},
+    },
+}
+
+# If no exception is raised by validate(), the instance is valid.
+validate(instance={"name" : "Eggs", "price" : 34.99}, schema=schema)
+
+EOF
diff --git a/lang/python/python-lru-dict/Makefile b/lang/python/python-lru-dict/Makefile
new file mode 100644 (file)
index 0000000..a5171d6
--- /dev/null
@@ -0,0 +1,37 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-lru-dict
+PKG_VERSION:=1.3.0
+PKG_RELEASE:=1
+
+PYPI_NAME:=lru-dict
+PKG_HASH:=54fd1966d6bd1fcde781596cb86068214edeebff1db13a2cea11079e3fd07b6b
+
+PKG_MAINTAINER:=Timothy Ace <openwrt@timothyace.com>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-lru-dict
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=An Dict like LRU container
+  URL:=https://github.com/amitdev/lru-dict
+  DEPENDS:=+python3-light
+endef
+
+define Package/python3-lru-dict/description
+A fixed size dict like container which evicts Least Recently Used (LRU) items
+once size limit is exceeded. There are many python implementations available
+which does similar things. This is a fast and efficient C implementation. LRU
+maximum capacity can be modified at run-time. If you are looking for pure
+python version, look elsewhere.
+endef
+
+$(eval $(call Py3Package,python3-lru-dict))
+$(eval $(call BuildPackage,python3-lru-dict))
+$(eval $(call BuildPackage,python3-lru-dict-src))
index 50f828151457f067cde934e0bb11e95b0e441d41..51465159328a4de6854d576aa1da65113a9dbef3 100644 (file)
@@ -6,11 +6,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-mako
-PKG_VERSION:=1.2.4
+PKG_VERSION:=1.3.0
 PKG_RELEASE:=1
 
 PYPI_NAME:=Mako
-PKG_HASH:=d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34
+PKG_HASH:=e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b
 
 PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
 PKG_LICENSE:=MIT
diff --git a/lang/python/python-orjson/Makefile b/lang/python/python-orjson/Makefile
new file mode 100644 (file)
index 0000000..39ef2cf
--- /dev/null
@@ -0,0 +1,37 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-orjson
+PKG_VERSION:=3.9.10
+PKG_RELEASE:=1
+
+PYPI_NAME:=orjson
+PKG_HASH:=9ebbdbd6a046c304b1845e96fbcc5559cd296b4dfd3ad2509e33c4d9ce07d6a1
+
+PKG_MAINTAINER:=Timothy Ace <openwrt@timothyace.com>
+PKG_LICENSE:=Apache-2.0 MIT
+PKG_LICENSE_FILES:=LICENSE-APACHE LICENSE-MIT
+
+PKG_BUILD_DEPENDS:=python-maturin/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-orjson
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Fast, correct Python JSON library
+  URL:=https://github.com/ijl/orjson
+  DEPENDS:= \
+       +python3-light \
+       $(RUST_ARCH_DEPENDS)
+endef
+
+define Package/python3-orjson/description
+Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy
+endef
+
+$(eval $(call Py3Package,python3-orjson))
+$(eval $(call BuildPackage,python3-orjson))
+$(eval $(call BuildPackage,python3-orjson-src))
index 3bcb1d9ca6b44ef5150ba6d459b610d7317f4e59..ab0d12aa44a749249d5b05de8982dc5127e0bbb2 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-poetry-core
-PKG_VERSION:=1.7.0
+PKG_VERSION:=1.8.1
 PKG_RELEASE:=1
 
 PYPI_NAME:=poetry-core
 PYPI_SOURCE_NAME:=poetry_core
-PKG_HASH:=8f679b83bd9c820082637beca1204124d5d2a786e4818da47ec8acefd0353b74
+PKG_HASH:=67a76c671da2a70e55047cddda83566035b701f7e463b32a2abfeac6e2a16376
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE
index 998a06a5713e57ac88fba3e543883c98456007ee..b44ea2a4241bdda51f2d650a3ddab79acd32f751 100644 (file)
@@ -8,11 +8,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-pyasn1
-PKG_VERSION:=0.5.0
+PKG_VERSION:=0.5.1
 PKG_RELEASE:=1
 
 PYPI_NAME:=pyasn1
-PKG_HASH:=97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde
+PKG_HASH:=6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c
 
 PKG_LICENSE:=BSD-2-Clause
 PKG_LICENSE_FILES:=LICENSE.rst
diff --git a/lang/python/python-pyasn1/test.sh b/lang/python/python-pyasn1/test.sh
new file mode 100644 (file)
index 0000000..2f13e5f
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+[ "$1" = python3-pyasn1 ] || exit 0
+
+python3 - << 'EOF'
+
+from collections import OrderedDict
+
+from pyasn1.type import namedtype
+from pyasn1.type import tag
+from pyasn1.type import univ
+from pyasn1.codec.der.encoder import encode as derEncode
+from pyasn1.codec.der.decoder import decode as derDecode
+from pyasn1.codec.native.encoder import encode as nativeEncode
+from pyasn1.codec.native.decoder import decode as nativeDecode
+
+class Record(univ.Sequence):
+    componentType = namedtype.NamedTypes(
+        namedtype.NamedType('id', univ.Integer()),
+        namedtype.OptionalNamedType(
+            'room', univ.Integer().subtype(
+                implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)
+            )
+        ),
+        namedtype.DefaultedNamedType(
+            'house', univ.Integer(0).subtype(
+                implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1)
+            )
+        )
+    )
+
+# encoding modifies the object (https://github.com/pyasn1/pyasn1/issues/53)
+# so test decoding before encoding
+
+record = Record()
+record['id'] = 123
+record['room'] = 321
+assert str(record) == 'Record:\n id=123\n room=321\n'
+
+substrate = b'0\x07\x02\x01{\x80\x02\x01A'
+
+received_record, _ = derDecode(substrate, asn1Spec=Record())
+assert received_record == record
+
+dict_record = nativeDecode({'id': 123, 'room': 321}, asn1Spec=Record())
+assert dict_record == record
+
+assert derEncode(record) == substrate
+assert nativeEncode(record) == OrderedDict([('id', 123), ('room', 321), ('house', 0)])
+
+EOF
diff --git a/lang/python/python-referencing/Makefile b/lang/python/python-referencing/Makefile
new file mode 100644 (file)
index 0000000..05f184a
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2023 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-referencing
+PKG_VERSION:=0.30.2
+PKG_RELEASE:=1
+
+PYPI_NAME:=referencing
+PKG_HASH:=794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=COPYING
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+
+PKG_BUILD_DEPENDS:=python-hatchling/host python-hatch-vcs/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-referencing
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=JSON Referencing + Python
+  URL:=https://github.com/python-jsonschema/referencing
+  DEPENDS:= \
+    +python3-light \
+    +python3-email \
+    +python3-urllib \
+    +python3-attrs \
+    +python3-rpds-py
+endef
+
+define Package/python3-referencing/description
+An implementation-agnostic implementation of JSON reference resolution.
+endef
+
+$(eval $(call Py3Package,python3-referencing))
+$(eval $(call BuildPackage,python3-referencing))
+$(eval $(call BuildPackage,python3-referencing-src))
diff --git a/lang/python/python-referencing/test.sh b/lang/python/python-referencing/test.sh
new file mode 100644 (file)
index 0000000..0517ba1
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+[ "$1" = python3-referencing ] || exit 0
+
+python3 - << 'EOF'
+
+from referencing import Registry, Resource
+import referencing.jsonschema
+
+schema = Resource.from_contents(  # Parse some contents into a 2020-12 JSON Schema
+    {
+        "$schema": "https://json-schema.org/draft/2020-12/schema",
+        "$id": "urn:example:a-202012-schema",
+        "$defs": {
+            "nonNegativeInteger": {
+                "$anchor": "nonNegativeInteger",
+                "type": "integer",
+                "minimum": 0,
+            },
+        },
+    }
+)
+registry = schema @ Registry()  # Add the resource to a new registry
+
+# From here forward, this would usually be done within a library wrapping this one,
+# like a JSON Schema implementation
+resolver = registry.resolver()
+resolved = resolver.lookup("urn:example:a-202012-schema#nonNegativeInteger")
+assert resolved.contents == {
+    "$anchor": "nonNegativeInteger",
+    "type": "integer",
+    "minimum": 0,
+}
+
+EOF
diff --git a/lang/python/python-rpds-py/Makefile b/lang/python/python-rpds-py/Makefile
new file mode 100644 (file)
index 0000000..c2aef84
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2023 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-rpds-py
+PKG_VERSION:=0.10.6
+PKG_RELEASE:=1
+
+PYPI_NAME:=rpds-py
+PYPI_SOURCE_NAME:=rpds_py
+PKG_HASH:=4ce5a708d65a8dbf3748d2474b580d606b1b9f91b5c6ab2a316e0b0cf7a4ba50
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+
+PKG_BUILD_DEPENDS:=python-maturin/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-rpds-py
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Bindings to Rust's persistent data structures
+  URL:=https://github.com/crate-py/rpds
+  DEPENDS:=+python3-light $(RUST_ARCH_DEPENDS)
+endef
+
+define Package/python3-rpds-py/description
+Python bindings to the Rust rpds crate for persistent data structures.
+endef
+
+$(eval $(call Py3Package,python3-rpds-py))
+$(eval $(call BuildPackage,python3-rpds-py))
+$(eval $(call BuildPackage,python3-rpds-py-src))
diff --git a/lang/python/python-rpds-py/test.sh b/lang/python/python-rpds-py/test.sh
new file mode 100644 (file)
index 0000000..d5dec8f
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+[ "$1" = python3-rpds-py ] || exit 0
+
+python3 - << 'EOF'
+
+from rpds import HashTrieMap, HashTrieSet, List
+
+m = HashTrieMap({"foo": "bar", "baz": "quux"})
+assert m.insert("spam", 37) == HashTrieMap({"foo": "bar", "baz": "quux", "spam": 37})
+assert m.remove("foo") == HashTrieMap({"baz": "quux"})
+
+s = HashTrieSet({"foo", "bar", "baz", "quux"})
+assert s.insert("spam") == HashTrieSet({"foo", "bar", "baz", "quux", "spam"})
+assert s.remove("foo") == HashTrieSet({"bar", "baz", "quux"})
+
+L = List([1, 3, 5])
+assert L.push_front(-1) == List([-1, 1, 3, 5])
+assert L.rest == List([3, 5])
+
+EOF
index 8138a9955648c3380e86b7fd47ab3f9b38f67de8..b2ebfa1c642a965a4a18cc3977fc17aca56b7d2d 100644 (file)
@@ -8,11 +8,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-setuptools
-PKG_VERSION:=68.2.2
+PKG_VERSION:=69.0.2
 PKG_RELEASE:=1
 
 PYPI_NAME:=setuptools
-PKG_HASH:=4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87
+PKG_HASH:=735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE
index 9691fd1590850a12957d3f7788c7c831c87de7ac..27e5e5729221c4ce1583f64cfa536b9ec98b11d2 100644 (file)
@@ -8,11 +8,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-trove-classifiers
-PKG_VERSION:=2023.10.18
+PKG_VERSION:=2023.11.14
 PKG_RELEASE:=1
 
 PYPI_NAME:=trove-classifiers
-PKG_HASH:=2cdfcc7f31f7ffdd57666a9957296089ac72daad4d11ab5005060e5cd7e29939
+PKG_HASH:=64b5e78305a5de347f2cd7ec8c12d704a3ef0cb85cc10c0ca5f73488d1c201f8
 
 PKG_LICENSE:=Apache-2.0
 PKG_LICENSE_FILES:=LICENSE
index 5befac2b3e081ef0c047369b7603890be10b3f33..79f2f2a237af8a8b4165540b15d6b698980ba3e6 100644 (file)
@@ -9,12 +9,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-twisted
-PKG_VERSION:=23.8.0
+PKG_VERSION:=23.10.0
 PKG_RELEASE:=1
 
 PYPI_NAME:=Twisted
 PYPI_SOURCE_NAME:=twisted
-PKG_HASH:=3c73360add17336a622c0d811c2a2ce29866b6e59b1125fd6509b17252098a24
+PKG_HASH:=987847a0790a2c597197613686e2784fd54167df3a55d0fb17c8412305d76ce5
 
 PKG_BUILD_DEPENDS:=libtirpc
 
index bf8873f41437b2d5083c9ba30d20be477d843252..d9ad0d59e2178b8cf096a5a02d983c7c880108f8 100644 (file)
@@ -1,6 +1,6 @@
 --- a/pyproject.toml
 +++ b/pyproject.toml
-@@ -150,7 +150,6 @@ ckeygen = "twisted.conch.scripts.ckeygen
+@@ -138,7 +138,6 @@ ckeygen = "twisted.conch.scripts.ckeygen
  conch = "twisted.conch.scripts.conch:run"
  mailmail = "twisted.mail.scripts.mailmail:run"
  pyhtmlizer = "twisted.scripts.htmlizer:run"
index 841b5e09e7c261d0d9358c30c1d1a426006c0e6f..ddf8f9e306c1aacb1a48bb99e292d8d339348926 100644 (file)
@@ -1,6 +1,6 @@
 --- a/pyproject.toml
 +++ b/pyproject.toml
-@@ -194,6 +194,7 @@ exclude = [
+@@ -182,6 +182,7 @@ exclude = [
      "*.pxi",
      "*.pyx",
      "build.bat",
diff --git a/lang/python/python-userpath/Makefile b/lang/python/python-userpath/Makefile
new file mode 100644 (file)
index 0000000..969a238
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2023 Jeffery To
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=python-userpath
+PKG_VERSION:=1.9.1
+PKG_RELEASE:=1
+
+PYPI_NAME:=userpath
+PKG_HASH:=ce8176728d98c914b6401781bf3b23fccd968d1647539c8788c7010375e02796
+
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE.txt
+PKG_MAINTAINER:=Jeffery To <jeffery.to@gmail.com>
+
+PKG_BUILD_DEPENDS:=python-hatchling/host
+
+include ../pypi.mk
+include $(INCLUDE_DIR)/package.mk
+include ../python3-package.mk
+
+define Package/python3-userpath
+  SECTION:=lang
+  CATEGORY:=Languages
+  SUBMENU:=Python
+  TITLE:=Cross-platform tool for modifying a user's PATH
+  URL:=https://github.com/ofek/userpath
+  DEPENDS:=+python3-light +python3-click +python3-psutil
+endef
+
+define Package/python3-userpath/description
+This is a tool for modifying a user's PATH.
+endef
+
+$(eval $(call Py3Package,python3-userpath))
+$(eval $(call BuildPackage,python3-userpath))
+$(eval $(call BuildPackage,python3-userpath-src))
diff --git a/lang/python/python-userpath/patches/0001-Handle-OSErrors-when-running-show-path-commands.patch b/lang/python/python-userpath/patches/0001-Handle-OSErrors-when-running-show-path-commands.patch
new file mode 100644 (file)
index 0000000..3a412e6
--- /dev/null
@@ -0,0 +1,31 @@
+From 9175a0a97c7bc2eeb995e53d50a07be6a7e834f0 Mon Sep 17 00:00:00 2001
+From: Jeffery To <jeffery.to@gmail.com>
+Date: Thu, 9 Nov 2023 14:20:58 +0800
+Subject: [PATCH] Handle OSErrors when running show path commands
+
+Bash may not always be installed, for example on OpenWrt, and attempting
+to call the show path commands for Bash will cause a FileNotFoundError
+to be raised.
+
+This wraps the subprocess call with a try statement and returns the
+empty string in the case of an OSError.
+---
+ userpath/utils.py | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/userpath/utils.py
++++ b/userpath/utils.py
+@@ -30,8 +30,11 @@ def ensure_parent_dir_exists(path):
+ def get_flat_output(command, sep=os.pathsep, **kwargs):
+-    process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
+-    output = process.communicate()[0].decode(locale.getpreferredencoding(False)).strip()
++    try:
++        process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
++        output = process.communicate()[0].decode(locale.getpreferredencoding(False)).strip()
++    except OSError:
++        return ''
+     # We do this because the output may contain new lines.
+     lines = [line.strip() for line in output.splitlines()]
diff --git a/lang/python/python-userpath/patches/0001-Use-Sh-as-base-class-for-Bash-and-Zsh.patch b/lang/python/python-userpath/patches/0001-Use-Sh-as-base-class-for-Bash-and-Zsh.patch
new file mode 100644 (file)
index 0000000..69dfde2
--- /dev/null
@@ -0,0 +1,89 @@
+From dffcc1c5823bcce10b420467db41e42ec41f4702 Mon Sep 17 00:00:00 2001
+From: Jeffery To <jeffery.to@gmail.com>
+Date: Thu, 9 Nov 2023 17:48:50 +0800
+Subject: [PATCH 1/2] Use Sh as base class for Bash and Zsh
+
+---
+ userpath/shells.py | 41 ++++++++++++++++++++++++++---------------
+ 1 file changed, 26 insertions(+), 15 deletions(-)
+
+--- a/userpath/shells.py
++++ b/userpath/shells.py
+@@ -12,24 +12,36 @@ class Shell(object):
+ class Sh(Shell):
+-    def config(self, location, front=True):
++    name = 'sh'
++
++    def _config_contents(self, location, front=True):
+         head, tail = (location, '$PATH') if front else ('$PATH', location)
+         new_path = '{}{}{}'.format(head, pathsep, tail)
++        return 'export PATH="{}"'.format(new_path)
++
++    def config(self, location, front=True):
++        contents = self._config_contents(location, front=front)
++        return {path.join(self.home, '.profile'): contents}
+-        return {path.join(self.home, '.profile'): 'PATH="{}"'.format(new_path)}
++    @classmethod
++    def _interactive_show_path_command(cls):
++        return [cls.name, '-i', '-c', 'echo $PATH']
++
++    @classmethod
++    def _interactive_login_show_path_command(cls):
++        return [cls.name, '-i', '-l', '-c', 'echo $PATH']
+     @classmethod
+     def show_path_commands(cls):
+         # TODO: Find out what file influences non-login shells. The issue may simply be our Docker setup.
+-        return [['sh', '-i', '-l', '-c', 'echo $PATH']]
++        return [cls._interactive_login_show_path_command()]
+-class Bash(Shell):
+-    def config(self, location, front=True):
+-        head, tail = (location, '$PATH') if front else ('$PATH', location)
+-        new_path = '{}{}{}'.format(head, pathsep, tail)
+-        contents = 'export PATH="{}"'.format(new_path)
++class Bash(Sh):
++    name = 'bash'
++    def config(self, location, front=True):
++        contents = self._config_contents(location, front=front)
+         configs = {path.join(self.home, '.bashrc'): contents}
+         # https://github.com/ofek/userpath/issues/3#issuecomment-492491977
+@@ -50,7 +62,7 @@ class Bash(Shell):
+     @classmethod
+     def show_path_commands(cls):
+-        return [['bash', '-i', '-c', 'echo $PATH'], ['bash', '-i', '-l', '-c', 'echo $PATH']]
++        return [cls._interactive_show_path_command(), cls._interactive_login_show_path_command()]
+ class Fish(Shell):
+@@ -88,18 +100,17 @@ class Xonsh(Shell):
+         return [['xonsh', '-i', '-c', command], ['xonsh', '-i', '--login', '-c', command]]
+-class Zsh(Shell):
+-    def config(self, location, front=True):
+-        head, tail = (location, '$PATH') if front else ('$PATH', location)
+-        new_path = '{}{}{}'.format(head, pathsep, tail)
+-        contents = 'export PATH="{}"'.format(new_path)
++class Zsh(Sh):
++    name = 'zsh'
++    def config(self, location, front=True):
++        contents = self._config_contents(location, front=front)
+         zdotdir = environ.get('ZDOTDIR', self.home)
+         return {path.join(zdotdir, '.zshrc'): contents, path.join(zdotdir, '.zprofile'): contents}
+     @classmethod
+     def show_path_commands(cls):
+-        return [['zsh', '-i', '-c', 'echo $PATH'], ['zsh', '-i', '-l', '-c', 'echo $PATH']]
++        return [cls._interactive_show_path_command(), cls._interactive_login_show_path_command()]
+ SHELLS = {
diff --git a/lang/python/python-userpath/patches/0002-Add-support-for-ash-Almquist-shell.patch b/lang/python/python-userpath/patches/0002-Add-support-for-ash-Almquist-shell.patch
new file mode 100644 (file)
index 0000000..2c1132e
--- /dev/null
@@ -0,0 +1,112 @@
+From 7823b9b39c486aedf830783329abdc3bd9664ba4 Mon Sep 17 00:00:00 2001
+From: Jeffery To <jeffery.to@gmail.com>
+Date: Thu, 9 Nov 2023 17:51:21 +0800
+Subject: [PATCH 2/2] Add support for ash (Almquist shell)
+
+---
+ tests/docker/debian |  2 +-
+ tests/test_ash.py   | 65 +++++++++++++++++++++++++++++++++++++++++++++
+ userpath/shells.py  |  5 ++++
+ 3 files changed, 71 insertions(+), 1 deletion(-)
+ create mode 100644 tests/test_ash.py
+
+--- a/tests/docker/debian
++++ b/tests/docker/debian
+@@ -2,7 +2,7 @@ ARG PYTHON_VERSION
+ FROM python:${PYTHON_VERSION}
+ RUN apt-get update \
+- && apt-get --no-install-recommends -y install fish zsh
++ && apt-get --no-install-recommends -y install ash fish zsh
+ COPY requirements.txt /
+ RUN pip install -r requirements.txt
+--- /dev/null
++++ b/tests/test_ash.py
+@@ -0,0 +1,65 @@
++import pytest
++import userpath
++
++from .utils import SKIP_WINDOWS_CI, get_random_path
++
++SHELL_NAME = 'ash'
++
++pytestmark = [SKIP_WINDOWS_CI, pytest.mark.ash]
++
++
++@pytest.mark.usefixtures('shell_test')
++class TestDebian(object):
++    DOCKERFILE = 'debian'
++
++    def test_prepend(self, request, shell_test):
++        if shell_test is None:
++            location = get_random_path()
++            assert not userpath.in_current_path(location)
++            assert userpath.prepend(location, check=True)
++            assert userpath.in_new_path(location)
++            assert userpath.need_shell_restart(location)
++        else:
++            process = shell_test(request.node.name)
++            stdout, stderr = process.communicate()
++
++            assert process.returncode == 0, (stdout + stderr).decode('utf-8')
++
++    def test_prepend_multiple(self, request, shell_test):
++        if shell_test is None:
++            locations = [get_random_path(), get_random_path()]
++            assert not userpath.in_current_path(locations)
++            assert userpath.prepend(locations, check=True)
++            assert userpath.in_new_path(locations)
++            assert userpath.need_shell_restart(locations)
++        else:
++            process = shell_test(request.node.name)
++            stdout, stderr = process.communicate()
++
++            assert process.returncode == 0, (stdout + stderr).decode('utf-8')
++
++    def test_append(self, request, shell_test):
++        if shell_test is None:
++            location = get_random_path()
++            assert not userpath.in_current_path(location)
++            assert userpath.append(location, check=True)
++            assert userpath.in_new_path(location)
++            assert userpath.need_shell_restart(location)
++        else:
++            process = shell_test(request.node.name)
++            stdout, stderr = process.communicate()
++
++            assert process.returncode == 0, (stdout + stderr).decode('utf-8')
++
++    def test_append_multiple(self, request, shell_test):
++        if shell_test is None:
++            locations = [get_random_path(), get_random_path()]
++            assert not userpath.in_current_path(locations)
++            assert userpath.append(locations, check=True)
++            assert userpath.in_new_path(locations)
++            assert userpath.need_shell_restart(locations)
++        else:
++            process = shell_test(request.node.name)
++            stdout, stderr = process.communicate()
++
++            assert process.returncode == 0, (stdout + stderr).decode('utf-8')
+--- a/userpath/shells.py
++++ b/userpath/shells.py
+@@ -37,6 +37,10 @@ class Sh(Shell):
+         return [cls._interactive_login_show_path_command()]
++class Ash(Sh):
++    name = 'ash'
++
++
+ class Bash(Sh):
+     name = 'bash'
+@@ -114,6 +118,7 @@ class Zsh(Sh):
+ SHELLS = {
++    'ash': Ash,
+     'bash': Bash,
+     'fish': Fish,
+     'sh': Sh,
diff --git a/lang/python/python-userpath/test.sh b/lang/python/python-userpath/test.sh
new file mode 100644 (file)
index 0000000..e87d325
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ "$1" = python3-userpath ] || exit 0
+
+userpath --version | grep -Fx "userpath, version $PKG_VERSION"
index 2b89d569e295c2d2fa976faa589e57e2807d0763..28f549b559201c1e41114e44a5ecbd4c2d2716bf 100644 (file)
@@ -8,11 +8,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=python-wheel
-PKG_VERSION:=0.41.2
+PKG_VERSION:=0.42.0
 PKG_RELEASE:=1
 
 PYPI_NAME:=wheel
-PKG_HASH:=0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985
+PKG_HASH:=c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE.txt
index 78d95d3d9ca5244a55803094d7f211655ceebeae..ba322cf1dcb8fb212ef2e2c5b586190d7174963c 100644 (file)
@@ -5,12 +5,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=rust
-PKG_VERSION:=1.73.0
-PKG_RELEASE:=2
+PKG_VERSION:=1.74.0
+PKG_RELEASE:=1
 
 PKG_SOURCE:=rustc-$(PKG_VERSION)-src.tar.gz
 PKG_SOURCE_URL:=https://static.rust-lang.org/dist/
-PKG_HASH:=96d62e6d1f2d21df7ac8acb3b9882411f9e7c7036173f7f2ede9e1f1f6b1bb3a
+PKG_HASH:=882b584bc321c5dcfe77cdaa69f277906b936255ef7808fcd5c7492925cf1049
 HOST_BUILD_DIR:=$(BUILD_DIR)/host/rustc-$(PKG_VERSION)-src
 
 PKG_MAINTAINER:=Luca Barbato <lu_zero@luminem.org>
index f2a40f76b9aa364c68c8bf74fb4c0fdfe5195fb6..a700a007d225fd7635f215332cb38667ca12ec00 100644 (file)
@@ -11,7 +11,7 @@ Subject: [PATCH] Update xz2 and use it static
 
 --- a/src/bootstrap/Cargo.lock
 +++ b/src/bootstrap/Cargo.lock
-@@ -434,9 +434,9 @@ dependencies = [
+@@ -424,9 +424,9 @@ dependencies = [
  
  [[package]]
  name = "lzma-sys"
@@ -23,7 +23,7 @@ Subject: [PATCH] Update xz2 and use it static
  dependencies = [
   "cc",
   "libc",
-@@ -903,9 +903,9 @@ dependencies = [
+@@ -871,9 +871,9 @@ dependencies = [
  
  [[package]]
  name = "xz2"
index f3e814e8ff52b12a5835a9729e3a192db741d7e3..d678a6dd8fcaced5cdb2e4beb7c06feaa0a143f5 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/bootstrap/bootstrap.py
 +++ b/src/bootstrap/bootstrap.py
-@@ -546,7 +546,7 @@ class RustBuild(object):
+@@ -557,7 +557,7 @@ class RustBuild(object):
                  shutil.rmtree(bin_root)
  
              key = self.stage0_compiler.date
@@ -11,7 +11,7 @@
                  os.makedirs(rustc_cache)
 --- a/src/bootstrap/download.rs
 +++ b/src/bootstrap/download.rs
-@@ -202,7 +202,13 @@ impl Config {
+@@ -211,7 +211,13 @@ impl Config {
              Some(other) => panic!("unsupported protocol {other} in {url}"),
              None => panic!("no protocol in {url}"),
          }
@@ -26,7 +26,7 @@
      }
  
      fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
-@@ -520,7 +526,10 @@ impl Config {
+@@ -529,7 +535,10 @@ impl Config {
          key: &str,
          destination: &str,
      ) {
@@ -38,7 +38,7 @@
          let cache_dir = cache_dst.join(key);
          if !cache_dir.exists() {
              t!(fs::create_dir_all(&cache_dir));
-@@ -647,7 +656,10 @@ download-rustc = false
+@@ -656,7 +665,10 @@ download-rustc = false
          let llvm_assertions = self.llvm_assertions;
  
          let cache_prefix = format!("llvm-{llvm_sha}-{llvm_assertions}");
index bd1c4b589adaad5a3f482b822e6ca98ff6a3dead..7d029167414ee79406e96c4991b5b942bf269181 100644 (file)
@@ -1,19 +1,19 @@
-This patch bumps all libc dependencies and checksums to 0.2.146, which includes the fix for musl 1.2.4.
+This patch bumps all libc dependencies and checksums to 0.2.147, which includes the fix for musl 1.2.4.
 
---- a/vendor/addr2line-0.20.0/Cargo.lock
-+++ b/vendor/addr2line-0.20.0/Cargo.lock
-@@ -246,9 +246,9 @@ checksum = "e2abad23fbc42b3700f2f279844d
+--- a/vendor/addr2line-0.19.0/Cargo.lock
++++ b/vendor/addr2line-0.19.0/Cargo.lock
+@@ -235,9 +235,9 @@ checksum = "e2abad23fbc42b3700f2f279844d
  
  [[package]]
  name = "libc"
--version = "0.2.141"
-+version = "0.2.146"
+-version = "0.2.126"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
--checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
+-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
- name = "libtest-mimic"
+ name = "memchr"
 --- a/vendor/backtrace-0.3.67/Cargo.lock
 +++ b/vendor/backtrace-0.3.67/Cargo.lock
 @@ -64,9 +64,9 @@ checksum = "dec7af912d60cdbd3677c1af9352
@@ -21,27 +21,13 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.138"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "libloading"
---- a/vendor/bstr/Cargo.lock
-+++ b/vendor/bstr/Cargo.lock
-@@ -34,9 +34,9 @@ dependencies = [
- [[package]]
- name = "libc"
--version = "0.2.138"
-+version = "0.2.146"
- source = "registry+https://github.com/rust-lang/crates.io-index"
--checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
- [[package]]
- name = "memchr"
 --- a/vendor/cranelift-jit/Cargo.lock
 +++ b/vendor/cranelift-jit/Cargo.lock
 @@ -224,9 +224,9 @@ dependencies = [
@@ -49,10 +35,10 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.141"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "log"
@@ -63,10 +49,10 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.141"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "num_cpus"
@@ -77,10 +63,10 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.140"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "lindera"
@@ -91,10 +77,10 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.140"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "lock_api"
@@ -105,10 +91,10 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.141"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "litemap"
@@ -119,38 +105,24 @@ This patch bumps all libc dependencies and checksums to 0.2.146, which includes
  [[package]]
  name = "libc"
 -version = "0.2.140"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
  name = "libffi"
---- a/vendor/terminal_size/Cargo.lock
-+++ b/vendor/terminal_size/Cargo.lock
-@@ -47,9 +47,9 @@ dependencies = [
- [[package]]
- name = "libc"
--version = "0.2.140"
-+version = "0.2.146"
- source = "registry+https://github.com/rust-lang/crates.io-index"
--checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
- [[package]]
- name = "linux-raw-sys"
 --- a/vendor/tracing-tree/Cargo.lock
 +++ b/vendor/tracing-tree/Cargo.lock
-@@ -100,9 +100,9 @@ checksum = "e2abad23fbc42b3700f2f279844d
+@@ -296,9 +296,9 @@ checksum = "e2abad23fbc42b3700f2f279844d
  
  [[package]]
  name = "libc"
 -version = "0.2.141"
-+version = "0.2.146"
++version = "0.2.147"
  source = "registry+https://github.com/rust-lang/crates.io-index"
 -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
-+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
  
  [[package]]
- name = "log"
+ name = "linux-raw-sys"
index 1ea497c561d51e8b656b18544e211a855902a67f..88b51c32b8158684342676690e9d141398cbb71f 100644 (file)
@@ -217,23 +217,6 @@ $(call Package/avahi/Default/description)
  For more information please see the avahi documentation.
 endef
 
-define Package/libavahi-compat-libdnssd
-  $(call Package/avahi/Default)
-  SECTION:=libs
-  CATEGORY:=Libraries
-  VARIANT:=dbus
-  DEPENDS:=+libavahi-client
-  TITLE+= (libdnssd)
-endef
-
-define Package/libavahi-compat-libdnssd/description
-$(call Package/avahi/Default/description)
- .
- This packages adds the libavahi-compat-libdnssd library.
- It also automatically adds the required libavahi-client package.
- For more information please see the avahi documentation.
-endef
-
 define Package/avahi-utils
   $(call Package/avahi/Default)
   SUBMENU:=IP Addresses and Names
@@ -294,10 +277,6 @@ CONFIGURE_ARGS += \
        --with-autoipd-group=nogroup
 
 ifeq ($(BUILD_VARIANT),dbus)
-ifneq ($(CONFIG_PACKAGE_libavahi-compat-libdnssd),)
-CONFIGURE_ARGS += \
-       --enable-compat-libdns_sd
-endif
 CONFIGURE_ARGS += \
        --enable-dbus
 else
@@ -314,11 +293,6 @@ define Build/InstallDev
        $(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
        $(INSTALL_DIR) $(1)/usr/lib
        $(CP) $(PKG_INSTALL_DIR)/usr/lib/libavahi-* $(1)/usr/lib/
-ifneq ($(CONFIG_PACKAGE_libavahi-compat-libdnssd),)
-ifeq ($(BUILD_VARIANT),dbus)
-       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libdns_sd* $(1)/usr/lib/
-endif
-endif
        $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
        $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/* $(1)/usr/lib/pkgconfig/
 endef
@@ -341,11 +315,6 @@ define Package/libavahi-client/install
        $(CP) $(PKG_INSTALL_DIR)/usr/lib/libavahi-client.so.* $(1)/usr/lib/
 endef
 
-define Package/libavahi-compat-libdnssd/install
-       $(INSTALL_DIR) $(1)/usr/lib
-       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libdns_sd.so* $(1)/usr/lib/
-endef
-
 define Package/avahi-utils/install
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin/
@@ -393,7 +362,6 @@ define Package/avahi-dnsconfd/install
 endef
 
 $(eval $(call BuildPackage,libavahi-client))
-$(eval $(call BuildPackage,libavahi-compat-libdnssd))
 $(eval $(call BuildPackage,avahi-utils))
 $(eval $(call BuildPackage,libavahi-dbus-support))
 $(eval $(call BuildPackage,libavahi-nodbus-support))
index d2a0e9601ff58dfe1bc5f0c4b79ad1396d648601..975882226b090d75229342f1dc594e6d7245b8f8 100644 (file)
@@ -15,7 +15,7 @@ PKG_NAME:=elektra
 PKG_LICENSE:=BSD-3-Clause
 PKG_LICENSE_FILES:=LICENSE.md
 PKG_VERSION:=0.9.7
-PKG_RELEASE:=4
+PKG_RELEASE:=5
 
 # Use this for official releasees
 PKG_HASH:=12b7b046004db29317b7b937dc794abf719c400ba3115af8d41849127b562681
diff --git a/libs/elektra/patches/010-gcc13.patch b/libs/elektra/patches/010-gcc13.patch
new file mode 100644 (file)
index 0000000..35195de
--- /dev/null
@@ -0,0 +1,19 @@
+From 19fe46ecb796c0d30d66dd7e7038fd7f2d6f9bf4 Mon Sep 17 00:00:00 2001
+From: Florian Lindner <florian.lindner@student.tuwien.ac.at>
+Date: Thu, 8 Jun 2023 16:55:34 +0200
+Subject: [PATCH] bindings: include <cstdint> in key.hpp for uint8_t
+
+---
+ src/bindings/cpp/include/key.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/src/bindings/cpp/include/key.hpp
++++ b/src/bindings/cpp/include/key.hpp
+@@ -10,6 +10,7 @@
+ #define ELEKTRA_KEY_HPP
+ #include <cstdarg>
++#include <cstdint>
+ #include <cstring>
+ #include <functional>
+ #include <locale>
index 310dc354cb4f32f58b19276840e7124e7859a2d6..0fddd5ffd5e8e18f8f65cd84f607fb9736e57294 100644 (file)
@@ -8,14 +8,14 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=icu4c
-MAJOR_VERSION:=73
-MINOR_VERSION:=2
+MAJOR_VERSION:=74
+MINOR_VERSION:=1
 PKG_VERSION:=$(MAJOR_VERSION).$(MINOR_VERSION)
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(MAJOR_VERSION)_$(MINOR_VERSION)-src.tgz
 PKG_SOURCE_URL:=https://github.com/unicode-org/icu/releases/download/release-$(MAJOR_VERSION)-$(MINOR_VERSION)
-PKG_HASH:=818a80712ed3caacd9b652305e01afc7fa167e6f2e94996da44b90c2ab604ce1
+PKG_HASH:=86ce8e60681972e60e4dcb2490c697463fcec60dd400a5f9bffba26d0b52b8d0
 
 PKG_LICENSE:=ICU
 PKG_LICENSE_FILES:=LICENSE
index 59caff9511bfa6d4fc8e47bba7b1d05d89702790..f5f91d8d2ae5826faf2e4d629316283a4d0e2443 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=libdaq3
-PKG_VERSION:=3.0.12
+PKG_VERSION:=3.0.13
 PKG_RELEASE:=1
 
 PKG_MAINTAINER:=W. Michael Petullo <mike@flyn.org>
@@ -17,7 +17,7 @@ PKG_LICENSE:=GPL-2.0-only
 
 PKG_SOURCE:=libdaq-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/snort3/libdaq/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=dedfdb88de151d61009bdb365322853687b1add4adec248952d2a93b70f584af
+PKG_HASH:=3a48b934bc45a1fe44b3887185d33a76a042c1d10aa177e3e7c417d83da67213
 PKG_BUILD_DIR:=$(BUILD_DIR)/libdaq-$(PKG_VERSION)
 
 PKG_FIXUP:=autoreconf
index 54e7f2b21d3d314fde1c7ca849c3a423020775be..f4ce5117ceeaa604e025dadc1a7dff7fa4eb9fe7 100644 (file)
@@ -1,23 +1,21 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=libnpupnp
-PKG_VERSION:=5.0.0
-PKG_RELEASE:=2
+PKG_VERSION:=5.1.2
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://www.lesbonscomptes.com/upmpdcli/downloads
-PKG_HASH:=2e5648cf180a425ef57b8c9c0d9dbd77f0314487ea0e0a85ebc6c3ef87cab05b
+PKG_HASH:=c1be8b2f654ef520791fbfaf13006fdd84522e6480a3126006e40caceea23552
 
 PKG_MAINTAINER:=
 PKG_LICENSE:=LGPL-2.1-or-later
 PKG_LICENSE_FILES:=COPYING
 
-PKG_INSTALL:=1
-PKG_BUILD_PARALLEL:=1
 PKG_BUILD_DEPENDS:=libmicrohttpd
-PKG_BUILD_FLAGS:=lto
 
 include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/meson.mk
 
 define Package/libnpupnp
   SECTION:=libs
@@ -33,6 +31,9 @@ venerable pupnp (https://github.com/pupnp/pupnp), based on its 1.6.x
 branch (around 1.6.25).
 endef
 
+MESON_OPTIONS += \
+       -Db_lto=true
+
 define Build/InstallDev
        $(INSTALL_DIR) $(1)/usr/include/npupnp
        $(CP) $(PKG_INSTALL_DIR)/usr/include/npupnp/* $(1)/usr/include/npupnp/
index 1690b67e23eefd064f9dccf3e791b3fbcd944bc4..1d76e81169cb11ecb18da4f0f36a77e57f47e498 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=libupnpp
-PKG_VERSION:=0.22.2
+PKG_VERSION:=0.24.1
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://www.lesbonscomptes.com/upmpdcli/downloads
-PKG_HASH:=90338c19383333fd4eeec8a866a8c4add1754ef9a6a720ddd9af97e6754ff849
+PKG_HASH:=f09d5162f237bcb971ef4bbd45de9e93a073d96555cd691374eb1a3f338b2d0b
 
 PKG_MAINTAINER:=
 PKG_LICENSE:=LGPL-2.1-or-later
index 08403d527b9f13d2f4c01b9798c497eeff577583..1896c6188ad20ad5f9323fd0093c90ef08db23ce 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=liburing
-PKG_VERSION:=2.4
+PKG_VERSION:=2.5
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://git.kernel.dk/cgit/liburing/snapshot
-PKG_HASH:=ca260e7a5820c2d0e737ec1e9b999f10776dbe84a169a02a0eff10c8eeaf3394
+PKG_HASH:=319ff9096a5655362a9741c5145b45494db810e38679a1de82e2f440c17181a6
 
 PKG_MAINTAINER:=Christian Lachner <gladiac@gmail.com>
 PKG_LICENSE:=MIT
index c481387285381cfa4c292888b619e1b957afe87b..656becde61847684d18b7347f3f3fb34fe2ed424 100644 (file)
@@ -6,12 +6,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=libzip
-PKG_VERSION:=1.9.2
+PKG_VERSION:=1.10.1
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://libzip.org/download/
-PKG_HASH:=c93e9852b7b2dc931197831438fee5295976ee0ba24f8524a8907be5c2ba5937
+PKG_HASH:=dc3c8d5b4c8bbd09626864f6bcf93de701540f761d76b85d7c7d710f4bd90318
 
 PKG_MAINTAINER:=Michael Heimpold <mhei@heimpold.de>
 
diff --git a/libs/libzip/patches/010-nossl.patch b/libs/libzip/patches/010-nossl.patch
deleted file mode 100644 (file)
index 6a68752..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
---- a/lib/zipint.h
-+++ b/lib/zipint.h
-@@ -180,8 +180,10 @@ zip_source_t *zip_source_pkware_decode(z
- zip_source_t *zip_source_pkware_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
- int zip_source_remove(zip_source_t *);
- zip_int64_t zip_source_supports(zip_source_t *src);
-+#ifdef HAVE_CRYPTO
- zip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
- zip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
-+#endif
- zip_source_t *zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes);
- zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
diff --git a/libs/quasselc/Makefile b/libs/quasselc/Makefile
deleted file mode 100644 (file)
index 7fd7295..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright (C) 2016 Ben Rosser <rosser.bjr@gmail.com>
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=quasselc
-PKG_SOURCE_DATE:=2017-01-11
-PKG_SOURCE_VERSION:=a0a1e6bd87d3eac68b5369972d1c2035cfe47e94
-PKG_RELEASE:=4
-
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_DATE).tar.gz
-PKG_SOURCE_URL:=https://codeload.github.com/phhusson/QuasselC/tar.gz/$(PKG_SOURCE_VERSION)?
-PKG_HASH:=fe7b48a13c0e6dad81cdae18069d4f5607af64d73a3201f42d79548170dde510
-PKG_BUILD_DIR:=$(BUILD_DIR)/QuasselC-$(PKG_SOURCE_VERSION)
-
-PKG_MAINTAINER:=Ben Rosser <rosser.bjr@gmail.com>
-PKG_LICENSE:=LGPL-3.0
-PKG_LICENSE_FILES:=COPYING.LESSER
-
-PKG_BUILD_PARALLEL:=1
-PKG_INSTALL:=1
-
-include $(INCLUDE_DIR)/package.mk
-include $(INCLUDE_DIR)/nls.mk
-
-MAKE_FLAGS += prefix=$(STAGING_DIR)/usr libdir=$(STAGING_DIR)/usr/lib includedir=$(STAGING_DIR)/usr/include
-MAKE_INSTALL_FLAGS += prefix=/usr libdir=/usr/lib includedir=/usr/include
-
-define Package/quasselc
-    SECTION:=libs
-    CATEGORY:=Libraries
-    DEPENDS:=+glib2
-    SUBMENU:=Instant Messaging
-    URL:=https://github.com/phhusson/QuasselC
-    TITLE:=API to access a Quassel Core in pure C
-endef
-
-define Package/quasselc/description
-  An implementation of the Quassel protocol in pure C.
-endef
-
-define Build/InstallDev
-       $(INSTALL_DIR) $(1)/usr/include/quasselc
-       $(CP) $(PKG_INSTALL_DIR)/usr/include/quasselc/* $(1)/usr/include/quasselc/
-
-       $(INSTALL_DIR) $(1)/usr/lib
-       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libquasselc.so* $(1)/usr/lib/
-       $(LN) libquasselc.so.0 $(1)/usr/lib/libquasselc.so
-
-       $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
-       $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/quasselc.pc $(1)/usr/lib/pkgconfig/
-endef
-
-define Package/quasselc/install
-       $(INSTALL_DIR) $(1)/usr/lib
-       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libquasselc.so* $(1)/usr/lib/
-endef
-
-$(eval $(call BuildPackage,quasselc))
diff --git a/libs/quasselc/patches/001-respect-cflags-ldflags.patch b/libs/quasselc/patches/001-respect-cflags-ldflags.patch
deleted file mode 100644 (file)
index e5c8f61..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/Makefile
-+++ b/Makefile
-@@ -2,11 +2,11 @@ prefix ?= /usr/local
- libdir ?= $(prefix)/lib
- includedir ?= $(prefix)/include
--CFLAGS:=-Wall -g -Wextra $(shell pkg-config glib-2.0 --cflags) -Wswitch-enum -std=gnu11 -O2 -fPIC
-+CFLAGS+=-Wall -g -Wextra $(shell pkg-config glib-2.0 --cflags) -Wswitch-enum -std=gnu11 -fPIC
- SO_VERSION = 0
- VERSION = 0
- INSTALL = install
--LDLIBS:=$(shell pkg-config glib-2.0 --libs) -lz
-+LDFLAGS+=$(shell pkg-config glib-2.0 --libs) -lz
- BOTLIBS := -Wl,-rpath,.
-@@ -15,10 +15,10 @@ lib_objects=setters.o getters.o main.o c
- all: bot libquasselc.so.$(VERSION) quasselc.pc
- libquasselc.so.$(VERSION): $(lib_objects)
--      $(CC) -shared -o $@ -Wl,-soname,libquasselc.so.$(SO_VERSION) $^ $(LDLIBS)
-+      $(CC) -shared -o $@ -Wl,-soname,libquasselc.so.$(SO_VERSION) $^ $(LDFLAGS)
- bot: bot.o display.o libquasselc.so.$(VERSION)
--      $(CC) -o $@ $^ $(LDLIBS) $(BOTLIBS)
-+      $(CC) -o $@ $^ $(LDFLAGS) $(BOTLIBS)
- clean:
-       rm -f *.o bot libquasselc.so.$(VERSION) quasselc.pc
index 7ec1274161d5fa894f979817627583a05ed8a4f6..145a0d37eb4c4674cf1d8cc3494b3926ec3cddac 100644 (file)
@@ -1,11 +1,11 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=yt-dlp
-PKG_VERSION:=2023.3.4
-PKG_RELEASE:=2
+PKG_VERSION:=2023.11.16
+PKG_RELEASE:=1
 
 PYPI_NAME:=yt-dlp
-PKG_HASH:=265d5da97a76c15d7d9a4088a67b78acd5dcf6f8cfd8257c52f581ff996ff515
+PKG_HASH:=f0ccdaf12e08b15902601a4671c7ab12906d7b11de3ae75fa6506811c24ec5da
 
 PKG_MAINTAINER:=Michal Vasilek <michal.vasilek@nic.cz>
 PKG_LICENSE:=Unlicense
index a97326f3470a6a2cc7bdbca16c269e70a62104b2..efbed1852560a26c7d1c79945b3ff9c11a48b7a9 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=acme-acmesh
-PKG_VERSION:=3.0.6
+PKG_VERSION:=3.0.7
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/acmesh-official/acme.sh/tar.gz/$(PKG_VERSION)?
-PKG_HASH:=4a8e44c27e2a8f01a978e8d15add8e9908b83f9b1555670e49a9b769421f5fa6
+PKG_HASH:=abd446d6bd45d0b44dca1dcbd931348797a3f82d1ed6fb171472eaf851a8d849
 PKG_BUILD_DIR:=$(BUILD_DIR)/acme.sh-$(PKG_VERSION)
 
 PKG_MAINTAINER:=Toke Høiland-Jørgensen <toke@toke.dk>
index 5c7936891c9bb944351a2c42c18cf33c61157f60..39800026b8d95f0b026bc2814d694f343380f021 100644 (file)
@@ -1,12 +1,12 @@
-# Copyright 2023 Stan Grishin (stangri@melmac.ca)
+# Copyright 2023 MOSSDeF, Stan Grishin (stangri@melmac.ca)
 # TLD optimization written by Dirk Brenken (dev@brenken.org)
 # This is free software, licensed under the GNU General Public License v3.
 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=adblock-fast
-PKG_VERSION:=1.0.0
-PKG_RELEASE:=7
+PKG_VERSION:=1.0.1
+PKG_RELEASE:=6
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
 PKG_LICENSE:=GPL-3.0-or-later
 
index e55475dd1a1db55ec816cc8c6ae9c3d0fec268c2..d2e41fb535ac6f1ba668caa5bf84d6cd9cf025ff 100644 (file)
@@ -31,6 +31,7 @@ config adblock-fast 'config'
        option parallel_downloads '1'
        option pause_timeout '20'
        option procd_trigger_wan6 '0'
+       option procd_boot_delay '0'
        option procd_boot_wan_timeout '60'
        option verbosity '2'
 
index 57fe5b93283cf2297e7dd65a560504fd31cb2d05..4837b7a3383e901d015995be608b1a2261866cdb 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh /etc/rc.common
 # Copyright 2023 MOSSDeF, Stan Grishin (stangri@melmac.ca)
-# shellcheck disable=SC1091,SC2015,SC2016,SC3037,SC3043,SC3045,SC3057,SC3060
+# shellcheck disable=SC3043
 
 # shellcheck disable=SC2034
 START=94
@@ -8,25 +8,6 @@ START=94
 USE_PROCD=1
 LC_ALL=C
 
-if type extra_command 1>/dev/null 2>&1; then
-       extra_command 'allow' 'Allows domain in current block-list and config'
-       extra_command 'check' 'Checks if specified domain is found in current block-list'
-       extra_command 'dl' 'Force-downloads all enabled block-list'
-       extra_command 'killcache' 'Delete all cached files'
-       extra_command 'pause' 'Pauses AdBlocking for specified number of seconds (default: 60)'
-       extra_command 'sizes' 'Displays the file-sizes of enabled block-lists'
-       extra_command 'version' 'Show version information'
-else
-# shellcheck disable=SC2034
-       EXTRA_COMMANDS='allow check dl killcache pause sizes status_service version'
-# shellcheck disable=SC2034
-       EXTRA_HELP='    allow   Allows domain(s) in current block-list and config
-       check   Checks if specified domain is found in current block-list
-       dl      Force-downloads all enabled block-list
-       pause   Pauses AdBlocking for specified number of seconds (default: 60)
-       sizes   Displays the file-sizes of enabled block-lists'
-fi
-
 readonly PKG_VERSION='dev-test'
 readonly packageName='adblock-fast'
 readonly serviceName="$packageName $PKG_VERSION"
@@ -67,11 +48,11 @@ readonly adBlockPlusFilter='/^#/d;/^!/d;s/[[:space:]]*#.*$//;s/^||//;s/\^$//;s/[
 readonly dnsmasqFileFilter='\|^server=/[[:alnum:]_.-].*/|!d;s|server=/||;s|/.*$||'
 readonly dnsmasq2FileFilter='\|^local=/[[:alnum:]_.-].*/|!d;s|local=/||;s|/.*$||'
 readonly dnsmasq3FileFilter='\|^address=/[[:alnum:]_.-].*/|!d;s|address=/||;s|/.*$||'
+readonly _ERROR_='\033[0;31mERROR\033[0m'
 readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
 readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
 readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
 readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
-readonly _ERROR_='\033[0;31mERROR\033[0m'
 readonly _WARNING_='\033[0;33mWARNING\033[0m'
 # shellcheck disable=SC2155
 readonly ipset="$(command -v ipset)"
@@ -93,7 +74,222 @@ load_environment_flag=
 allowed_url=
 blocked_url=
 
+# shellcheck disable=SC1091
+. /lib/functions.sh
+# shellcheck disable=SC1091
+. /lib/functions/network.sh
+# shellcheck disable=SC1091
+. /usr/share/libubox/jshn.sh
+
+append_newline() { is_newline_ending "$1" || echo '' >> "$1"; }
+check_ipset() { { command -v ipset && /usr/sbin/ipset help hash:net; } >/dev/null 2>&1; }
+check_nft() { command -v nft >/dev/null 2>&1; }
+check_dnsmasq() { command -v dnsmasq >/dev/null 2>&1; }
+check_dnsmasq_ipset() {
+       local o;
+       check_dnsmasq || return 1
+       o="$(dnsmasq -v 2>/dev/null)"
+       check_ipset && ! echo "$o" | grep -q 'no-ipset' && echo "$o" | grep -q 'ipset'
+}
+check_dnsmasq_nftset() {
+       local o;
+       check_dnsmasq || return 1
+       o="$(dnsmasq -v 2>/dev/null)"
+       check_nft && ! echo "$o" | grep -q 'no-nftset' && echo "$o" | grep -q 'nftset'
+}
+check_unbound() { command -v unbound >/dev/null 2>&1; }
 debug() { local i j; for i in "$@"; do eval "j=\$$i"; echo "${i}: ${j} "; done; }
+dnsmasq_hup() { killall -q -s HUP dnsmasq; }
+dnsmasq_kill() { killall -q -s KILL dnsmasq; }
+dnsmasq_restart() { /etc/init.d/dnsmasq restart >/dev/null 2>&1; }
+is_enabled() { uci -q get "${1}.config.enabled"; }
+is_integer() {
+       case "$1" in
+               (*[!0123456789]*) return 1;;
+               ('')              return 1;;
+               (*)               return 0;;
+       esac
+}
+is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
+is_greater_or_equal() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" = "$2"; }
+# shellcheck disable=SC3057
+is_https_url() { [ "${1:0:8}" = "https://" ]; }
+is_newline_ending() { [ "$(tail -c1 "$1" | wc -l)" -ne '0' ]; }
+is_present() { command -v "$1" >/dev/null 2>&1; }
+is_running() {
+       local i j
+       i="$(json 'get' 'status')"
+       j="$(ubus_get_data 'status')"
+       if [ "$i" = 'statusStopped' ] || [ -z "${i}${j}" ]; then
+               return 1
+       else
+               return 0
+       fi
+}
+ipset() { "$ipset" "$@" >/dev/null 2>&1; }
+get_version() { grep -m1 -A2 -w "^Package: $1$" /usr/lib/opkg/status | sed -n 's/Version: //p'; }
+get_ram_free() { ubus call system info | jsonfilter -e '@.memory.free'; }
+get_ram_total() { ubus call system info | jsonfilter -e '@.memory.total'; }
+led_on(){ if [ -n "${1}" ] && [ -e "${1}/trigger" ]; then echo 'default-on' > "${1}/trigger" 2>&1; fi; }
+led_off(){ if [ -n "${1}" ] &&  [ -e "${1}/trigger" ]; then echo 'none' > "${1}/trigger" 2>&1; fi; }
+logger() { /usr/bin/logger -t "$packageName" "$@"; }
+nft() { "$nft" "$@" >/dev/null 2>&1; }
+output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
+output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
+output_fail() { output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
+output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
+print_json_bool() { json_init; json_add_boolean "$1" "$2"; json_dump; json_cleanup; }
+print_json_int() { json_init; json_add_int "$1" "$2"; json_dump; json_cleanup; }
+print_json_string() { json_init; json_add_string "$1" "$2"; json_dump; json_cleanup; }
+sanitize_dir() { [ -d "$(readlink -fn "$1")" ] && readlink -fn "$1"; }
+str_contains() { test "$1" != "$(str_replace "$1" "$2" '')"; }
+str_contains_word() { echo "$1" | grep -q -w "$2"; }
+# shellcheck disable=SC2018,SC2019
+str_to_lower() { echo "$1" | tr 'A-Z' 'a-z'; }
+# shellcheck disable=SC2018,SC2019
+str_to_upper() { echo "$1" | tr 'a-z' 'A-Z'; }
+str_replace() { printf "%b" "$1" | sed -e "s/$(printf "%b" "$2")/$(printf "%b" "$3")/g"; }
+ubus_get_data() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "@['${packageName}'].instances.main.data.${1}"; }
+ubus_get_ports() { ubus call service list "{ 'name': '$packageName' }" | jsonfilter -e "@['${packageName}'].instances.main.data.firewall.*.dest_port"; }
+unbound_restart() { /etc/init.d/unbound restart >/dev/null 2>&1; }
+
+json() {
+# shellcheck disable=SC2034
+       local action="$1" param="$2" value="$3"
+       shift 3
+# shellcheck disable=SC2124
+       local extras="$@" line
+       local status message error stats
+       local reload restart curReload curRestart ret i
+       if [ -s "$jsonFile" ]; then
+               json_load_file "$jsonFile" 2>/dev/null
+               json_select 'data' 2>/dev/null
+               for i in status message error stats reload restart; do
+                       json_get_var "$i" "$i" 2>/dev/null
+               done
+       fi
+       case "$action" in
+               get)
+                       case "$param" in
+                               triggers)
+# shellcheck disable=SC2154
+                                       curReload="$parallel_downloads $debug $download_timeout \
+                                               $allowed_domain $blocked_domain $allowed_url $blocked_url $dns \
+                                               $config_update_enabled $config_update_url $dnsmasq_config_file_url \
+                                               $curl_additional_param $curl_max_file_size $curl_retry"
+# shellcheck disable=SC2154
+                                       curRestart="$compressed_cache $compressed_cache_dir $force_dns $led \
+                                               $force_dns_port"
+                                       if [ ! -s "$jsonFile" ]; then
+                                               ret='on_boot'
+                                       elif [ "$curReload" != "$reload" ]; then
+                                               ret='download'
+                                       elif [ "$curRestart" != "$restart" ]; then
+                                               ret='restart'
+                                       fi
+                                       printf "%b" "$ret"
+                                       return;;
+                               *)
+                                       printf "%b" "$(eval echo "\$$param")"; return;;
+                       esac
+               ;;
+               add)
+                       line="$(eval echo "\$$param")"
+                       eval "$param"='${line:+$line }${value}${extras:+|$extras}'
+               ;;
+               del)
+                       case "$param" in
+                               all)
+                                       unset status message error stats;;
+                               triggers) 
+                                       unset reload restart;;
+                               *)
+                                       unset "$param";;
+                       esac
+               ;;
+               set)
+                       case "$param" in
+                               triggers) 
+                                       reload="$parallel_downloads $debug $download_timeout \
+                                               $allowed_domain $blocked_domain $allowed_url $blocked_url $dns \
+                                               $config_update_enabled $config_update_url $dnsmasq_config_file_url \
+                                               $curl_additional_param $curl_max_file_size $curl_retry"
+                                       restart="$compressed_cache $compressed_cache_dir $force_dns $led \
+                                               $force_dns_port"
+                               ;;
+                               *)
+                                       eval "$param"='${value}${extras:+|$extras}';;
+                       esac
+               ;;
+       esac
+       json_init
+       json_add_object 'data'
+       json_add_string version "$PKG_VERSION"
+       json_add_string status "$status"
+       json_add_string message "$message"
+       json_add_string error "$error"
+       json_add_string stats "$stats"
+       json_add_string reload "$reload"
+       json_add_string restart "$restart"
+       json_close_object
+       mkdir -p "$(dirname "$jsonFile")"
+       json_dump > "$jsonFile"
+       sync
+}
+
+get_local_filesize() {
+       local file="$1" size
+       [ -f "$file" ] || return 0
+       if is_present stat; then
+               size="$(stat -c%s "$file")"
+       elif is_present wc; then
+               size="$(wc -c < "$file")"
+       fi
+# shellcheck disable=SC3037
+       echo -en "$size"
+}
+
+get_url_filesize() {
+       local url="$1" size size_command
+       [ -n "$url" ] || return 0
+       is_present 'curl' || return 0
+       size_command='curl --silent --insecure --fail --head --request GET'
+       size="$($size_command "$url" | grep -Po '^[cC]ontent-[lL]ength: \K\w+')"
+# shellcheck disable=SC3037
+       echo -en "$size"
+}
+
+output() {
+# Target verbosity level with the first parameter being an integer
+       is_integer() {
+               case "$1" in
+                       (*[!0123456789]*) return 1;;
+                       ('')              return 1;;
+                       (*)               return 0;;
+               esac
+       }
+       local msg memmsg logmsg text
+       local sharedMemoryOutput="/dev/shm/$packageName-output"
+       if [ -z "$verbosity" ] && [ -n "$packageName" ]; then
+               verbosity="$(uci -q get "$packageName.config.verbosity")"
+       fi
+       verbosity="${verbosity:-2}"
+       if [ $# -ne 1 ] && is_integer "$1"; then
+               if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; text="$*"; else return 0; fi
+       fi
+       text="${text:-$*}";
+       [ -t 1 ] && printf "%b" "$text"
+# shellcheck disable=SC3060
+       msg="${text//$serviceName /service }";
+       if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
+               [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
+               logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
+               logger -t "${packageName:-service} [$$]" "$(printf "%b" "$logmsg")"
+               rm -f "$sharedMemoryOutput"
+       else
+               printf "%b" "$msg" >> "$sharedMemoryOutput"
+       fi
+}
 
 uci_add_list_if_new() {
        local PACKAGE="$1"
@@ -107,6 +303,7 @@ uci_add_list_if_new() {
        done
        uci_add_list "$PACKAGE" "$CONFIG" "$OPTION" "$VALUE"
 }
+
 uci_changes() {
        local PACKAGE="$1"
        local CONFIG="$2"
@@ -114,8 +311,25 @@ uci_changes() {
        /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} changes "$PACKAGE${CONFIG:+.$CONFIG}${OPTION:+.$OPTION}"
 }
 
-ipset() { "$ipset" "$@" >/dev/null 2>&1; }
-nft() { "$nft" "$@" >/dev/null 2>&1; }
+if type extra_command 1>/dev/null 2>&1; then
+       extra_command 'allow' 'Allows domain in current block-list and config'
+       extra_command 'check' 'Checks if specified domain is found in current block-list'
+       extra_command 'check_lists' 'Checks if specified domain is found in enabled block-lists'
+       extra_command 'dl' 'Force-downloads all enabled block-list'
+       extra_command 'killcache' 'Delete all cached files'
+       extra_command 'pause' 'Pauses AdBlocking for specified number of seconds (default: 60)'
+       extra_command 'sizes' 'Displays the file-sizes of enabled block-lists'
+       extra_command 'version' 'Show version information'
+else
+# shellcheck disable=SC2034
+       EXTRA_COMMANDS='allow check dl killcache pause sizes status_service version'
+# shellcheck disable=SC2034
+       EXTRA_HELP='    allow   Allows domain(s) in current block-list and config
+       check   Checks if specified domain is found in current block-list
+       dl      Force-downloads all enabled block-list
+       pause   Pauses AdBlocking for specified number of seconds (default: 60)
+       sizes   Displays the file-sizes of enabled block-lists'
+fi
 
 get_text() {
        local r
@@ -154,6 +368,7 @@ get_text() {
                errorCreatingDirectory) r="failed to create output/cache/gzip file directory";;
                errorDetectingFileType) r="failed to detect format";;
                errorNothingToDo) r="no blocked list URLs nor blocked-domains enabled";;
+               errorTooLittleRam) r="free ram (%s) is not enough to process all enabled block-lists";;
 
                statusNoInstall) r="$serviceName is not installed or not found";;
                statusStopped) r="Stopped";;
@@ -162,56 +377,18 @@ get_text() {
                statusForceReloading) r="Force Reloading";;
                statusDownloading) r="Downloading";;
                statusProcessing) r="Processing";;
-               statusError) r="Error";;
-               statusWarning) r="Warning";;
-               statusFail) r="Fail";;
+               statusFail) r="failed to start";;
                statusSuccess) r="Success";;
 
                warningExternalDnsmasqConfig)
                        r="use of external dnsmasq config file detected, please set 'dns' option to 'dnsmasq.conf'";;
-               warningMissingRecommendedPackages) r="Some recommended packages are missing";;
+               warningMissingRecommendedPackages) r="some recommended packages are missing";;
                warningInvalidCompressedCacheDir) r="invalid compressed cache directory '%s'";;
+               warningFreeRamCheckFail) r="can't detect free RAM";;
        esac
-       echo "$r"
-}
-
-output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
-output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
-output_fail() { output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
-output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
-str_replace() { printf "%b" "$1" | sed -e "s/$(printf "%b" "$2")/$(printf "%b" "$3")/g"; }
-str_contains() { test "$1" != "$(str_replace "$1" "$2" '')"; }
-is_greater() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
-is_greater_or_equal() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" = "$2"; }
-is_chaos_calmer() { ubus -S call system board | grep -q 'Chaos Calmer'; }
-led_on(){ if [ -n "${1}" ] && [ -e "${1}/trigger" ]; then echo 'default-on' > "${1}/trigger" 2>&1; fi; }
-led_off(){ if [ -n "${1}" ] &&  [ -e "${1}/trigger" ]; then echo 'none' > "${1}/trigger" 2>&1; fi; }
-dnsmasq_hup() { killall -q -s HUP dnsmasq; }
-dnsmasq_kill() { killall -q -s KILL dnsmasq; }
-dnsmasq_restart() { /etc/init.d/dnsmasq restart >/dev/null 2>&1; }
-unbound_restart() { /etc/init.d/unbound restart >/dev/null 2>&1; }
-is_present() { command -v "$1" >/dev/null 2>&1; }
-sanitize_dir() { [ -d "$(readlink -fn "$1")" ] && readlink -fn "$1"; }
-
-output() {
-# Can take a single parameter (text) to be output at any verbosity
-# Or target verbosity level and text to be output at specifc verbosity
-       local msg memmsg logmsg
-       local sharedMemoryOutput="/dev/shm/$packageName-output"
-       verbosity="${verbosity:-2}"
-       if [ $# -ne 1 ]; then
-               if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then shift; else return 0; fi
-       fi
-       [ -t 1 ] && printf "%b" "$1"
-       msg="${1//$serviceName /service }";
-       if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
-               [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
-               logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
-               logger -t "${packageName:-service} [$$]" "$(printf "%b" "$logmsg")"
-               rm -f "$sharedMemoryOutput"
-       else
-               printf "%b" "$msg" >> "$sharedMemoryOutput"
-       fi
+       shift
+# shellcheck disable=SC2059
+       printf "$r" "$@"
 }
 
 load_network() {
@@ -252,14 +429,14 @@ load_network() {
                output "Waiting to discover $wan_if gateway...\\n"
                sleep 1
        done
-       json add error "errorNoWanGateway"
+       json add error 'errorNoWanGateway'
        output "${_ERROR_}: $(get_text 'errorNoWanGateway')!\\n"; return 1;
 }
 
 append_url() {
        local cfg="$1" var="$2"
        local en action url
-       config_get en "$cfg" enabled '1'
+       config_get_bool en "$cfg" enabled '1'
        config_get action "$cfg" action 'block'
        config_get url "$cfg" url
        if [ "$en" = '1' ]; then
@@ -271,37 +448,23 @@ append_url() {
        fi
 }
 
- detect_file_type() {
-       local file="$1"
-       if [ "$(head -1 "$file")" = '[Adblock Plus]' ] || \
-               grep -q '^||' "$file"; then
-               echo 'adblockplus'
-       elif grep -q '^server=' "$file"; then
-               echo 'dnsmasq'
-       elif grep -q '^local=' "$file"; then
-               echo 'dnsmasq2'
-       elif grep -q '^address=' "$file"; then
-               echo 'dnsmasq3'
-       elif grep -q '^0\.0\.0\.0' "$file" || grep -q '^127\.0\.0\.1' "$file"; then
-               echo 'hosts'
-       elif [ -n "$(sed "$domainsFilter" "$file" | head -1)" ]; then
-               echo 'domains'
-       fi
- }
-# detect_file_type() {
-#      local file="$1"
-#      if [ -n "$(sed "$adBlockPlusFilter" "$file" | head -1)" ]; then
-#              echo 'adblockplus'
-#      elif [ -n "$(sed "$dnsmasqFileFilter" "$file" | head -1)" ]; then
-#              echo 'dnsmasq'
-#      elif [ -n "$(sed "$dnsmasq2FileFilter" "$file" | head -1)" ]; then
-#              echo 'dnsmasq2'
-#      elif [ -n "$(sed "$hostsFilter" "$file" | head -1)" ]; then
-#              echo 'hosts'
-#      elif [ -n "$(sed "$domainsFilter" "$file" | head -1)" ]; then
-#              echo 'domains'
-#      fi
-# }
+detect_file_type() {
+       local file="$1"
+       if [ "$(head -1 "$file")" = '[Adblock Plus]' ] || \
+               grep -q '^||' "$file"; then
+               echo 'adblockplus'
+       elif grep -q '^server=' "$file"; then
+               echo 'dnsmasq'
+       elif grep -q '^local=' "$file"; then
+               echo 'dnsmasq2'
+       elif grep -q '^address=' "$file"; then
+               echo 'dnsmasq3'
+       elif grep -q '^0\.0\.0\.0' "$file" || grep -q '^127\.0\.0\.1' "$file"; then
+               echo 'hosts'
+       elif [ -n "$(sed "$domainsFilter" "$file" | head -1)" ]; then
+               echo 'domains'
+       fi
+}
 
 load_environment() {
        local i j
@@ -310,14 +473,14 @@ load_environment() {
        [ -z "$load_environment_flag" ] || return 0
 
        if [ "$validation_result" != '0' ]; then
-               json add error "errorConfigValidationFail"
+               json add error 'errorConfigValidationFail'
                output "${_ERROR_}: $(get_text 'errorConfigValidationFail')!\\n"
                output "Please check if the '$packageConfigFile' contains correct values for config options.\\n"
                return 1
        fi
 
        if [ "$enabled" -eq 0 ]; then
-               json add error "errorServiceDisabled"
+               json add error 'errorServiceDisabled'
                output "${_ERROR_}: $(get_text 'errorServiceDisabled')!\\n"
                output "Run the following commands before starting service again:\\n"
                output "uci set ${packageName}.config.enabled='1'; uci commit $packageName;\\n"
@@ -335,7 +498,7 @@ load_environment() {
                        dnsmasq.conf) :;;
                        *)
                                if [ "$param" != 'quiet' ]; then
-                                       json add warning "warningExternalDnsmasqConfig"
+                                       json add warning 'warningExternalDnsmasqConfig'
                                        output "${_WARNING_}: $(get_text 'warningExternalDnsmasqConfig')!\\n"
                                fi
                        ;;
@@ -356,14 +519,14 @@ load_environment() {
                dnsmasq.ipset)
                        if dnsmasq -v 2>/dev/null | grep -q 'no-ipset' || ! dnsmasq -v 2>/dev/null | grep -q -w 'ipset'; then
                                if [ "$param" != 'quiet' ]; then
-                                       json add error "errorNoDnsmasqIpset"
+                                       json add error 'errorNoDnsmasqIpset'
                                        output "${_ERROR_}: $(get_text 'errorNoDnsmasqIpset')!\\n"
                                fi
                                dns='dnsmasq.servers'
                        fi
                        if ! ipset help hash:net; then
                                if [ "$param" != 'quiet' ]; then
-                                       json add error "errorNoIpset"
+                                       json add error 'errorNoIpset'
                                        output "${_ERROR_}: $(get_text 'errorNoIpset')!\\n"
                                fi
                                dns='dnsmasq.servers'
@@ -372,14 +535,14 @@ load_environment() {
                dnsmasq.nftset)
                        if dnsmasq -v 2>/dev/null | grep -q 'no-nftset' || ! dnsmasq -v 2>/dev/null | grep -q -w 'nftset'; then
                                if [ "$param" != 'quiet' ]; then
-                                       json add error "errorNoDnsmasqNftset"
+                                       json add error 'errorNoDnsmasqNftset'
                                        output "${_ERROR_}: $(get_text 'errorNoDnsmasqNftset')!\\n"
                                fi
                                dns='dnsmasq.servers'
                        fi
                        if [ -z "$nft" ]; then
                                if [ "$param" != 'quiet' ]; then
-                                       json add error "errorNoNft"
+                                       json add error 'errorNoNft'
                                        output "${_ERROR_}: $(get_text 'errorNoNft')!\\n"
                                fi
                                dns='dnsmasq.servers'
@@ -393,6 +556,7 @@ load_environment() {
                compressed_cache_dir="$(sanitize_dir "$compressed_cache_dir")"
        else
                json add warning 'warningInvalidCompressedCacheDir' "$compressed_cache_dir"
+               output "${_WARNING_}: $(get_text 'warningInvalidCompressedCacheDir' "$compressed_cache_dir")!\\n"
                compressed_cache_dir="/etc"
        fi
 
@@ -475,7 +639,7 @@ load_environment() {
        for i in "$jsonFile" "$outputFile" "$outputCache" "$outputGzip"; do
                if ! mkdir -p "$(dirname "$i")"; then
                        if [ "$param" != 'quiet' ]; then
-                               json add error "errorOutputDirCreate" "$i"
+                               json add error 'errorOutputDirCreate' "$i"
                                output "${_ERROR_}: $(get_text 'errorOutputDirCreate' "$i")!\\n"
                        fi
                fi
@@ -484,15 +648,15 @@ load_environment() {
        is_present 'gawk' && awk='gawk'
        if ! is_present '/usr/libexec/grep-gnu' || ! is_present '/usr/libexec/sed-gnu' || \
                ! is_present '/usr/libexec/sort-coreutils' || ! is_present 'gawk'; then
-                       local s="opkg update; opkg --force-overwrite install"
-                       is_present 'gawk' || s="$gawk"
-                       is_present '/usr/libexec/grep-gnu' || s="$grep"
-                       is_present '/usr/libexec/sed-gnu' || s="$sed"
-                       is_present '/usr/libexec/sort-coreutils' || s="$coreutils-sort"
+                       local s
+                       is_present 'gawk' || s="${s:+$s }gawk"
+                       is_present '/usr/libexec/grep-gnu' || s="${s:+$s }grep"
+                       is_present '/usr/libexec/sed-gnu' || s="${s:+$s }sed"
+                       is_present '/usr/libexec/sort-coreutils' || s="${s:+$s }coreutils-sort"
                        if [ "$param" != 'quiet' ]; then
-                               json add warning "warningMissingRecommendedPackages" "${i}"
+                               json add warning 'warningMissingRecommendedPackages' "$s"
                                output "${_WARNING_}: $(get_text 'warningMissingRecommendedPackages'), install them by running:\\n"
-                               output "$s;\\n"
+                               output "opkg update; opkg --force-overwrite install $s;\\n"
                        fi
        fi
        # Prefer curl because it supports the file:// scheme.
@@ -543,67 +707,57 @@ load_environment() {
        fi
 }
 
-get_url_filesize() {
-       local url="$1" size size_command
-       [ -n "$url" ] || return 0
-       is_present 'curl' || return 0
-       size_command='curl --silent --insecure --fail --head --request GET'
-       size="$($size_command "$url" | grep -Po '^[cC]ontent-[lL]ength: \K\w+')"
-       echo -en "$size"
-}
-
-get_local_filesize() {
-       local file="$1" size
-       [ -f "$file" ] || return 0
-       if is_present stat; then
-               size="$(stat -c%s "$file")"
-       elif is_present wc; then
-               size="$(wc -c < "$file")"
-       fi
-       echo -en "$size"
-}
-
-resolver_config() {
-       local cfg="$1" param="$2"
-       case "$param" in
-               dnsmasq.addnhosts)
-                       if [ "$(uci_get 'dhcp' "$cfg" 'serversfile')" = "$dnsmasqServersFile" ]; then
-                               uci_remove 'dhcp' "$cfg" 'serversfile'
-                       fi
-                       uci_add_list_if_new 'dhcp' "$cfg" 'addnhosts' "$dnsmasqAddnhostsFile"
-               ;;
-               cleanup|dnsmasq.conf|dnsmasq.ipset|dnsmasq.nftset|unbound.adb_list)
-                       uci_remove_list 'dhcp' "$cfg" 'addnhosts' "$dnsmasqAddnhostsFile"
-                       if [ "$(uci_get 'dhcp' "$cfg" 'serversfile')" = "$dnsmasqServersFile" ]; then
-                               uci_remove 'dhcp' "$cfg" 'serversfile'
-                       fi
-               ;;
-               dnsmasq.servers)
-                       uci_remove_list 'dhcp' "$cfg" 'addnhosts' "$dnsmasqAddnhostsFile"
-                       if [ "$(uci_get 'dhcp' "$cfg" 'serversfile')" != "$dnsmasqServersFile" ]; then
-                               uci_set 'dhcp' "$cfg" 'serversfile' "$dnsmasqServersFile"
-                       fi
-               ;;
-       esac
-}
-
-dns() {
+resolver() {
+       _resolver_config() {
+               local cfg="$1" param="$2"
+               case "$param" in
+                       dnsmasq.addnhosts)
+                               if [ "$(uci_get 'dhcp' "$cfg" 'serversfile')" = "$dnsmasqServersFile" ]; then
+                                       uci_remove 'dhcp' "$cfg" 'serversfile'
+                               fi
+                               uci_add_list_if_new 'dhcp' "$cfg" 'addnhosts' "$dnsmasqAddnhostsFile"
+                       ;;
+                       cleanup|dnsmasq.conf|dnsmasq.ipset|dnsmasq.nftset|unbound.adb_list)
+                               uci_remove_list 'dhcp' "$cfg" 'addnhosts' "$dnsmasqAddnhostsFile"
+                               if [ "$(uci_get 'dhcp' "$cfg" 'serversfile')" = "$dnsmasqServersFile" ]; then
+                                       uci_remove 'dhcp' "$cfg" 'serversfile'
+                               fi
+                       ;;
+                       dnsmasq.servers)
+                               uci_remove_list 'dhcp' "$cfg" 'addnhosts' "$dnsmasqAddnhostsFile"
+                               if [ "$(uci_get 'dhcp' "$cfg" 'serversfile')" != "$dnsmasqServersFile" ]; then
+                                       uci_set 'dhcp' "$cfg" 'serversfile' "$dnsmasqServersFile"
+                               fi
+                       ;;
+               esac
+       }
        local param output_text i
        case $1 in
+               cleanup)
+                       rm -f "$dnsmasqAddnhostsFile" "$dnsmasqAddnhostsCache" "${compressed_cache_dir}/${dnsmasqAddnhostsGzip}"
+                       rm -f "$dnsmasqConfFile" "$dnsmasqConfCache" "${compressed_cache_dir}/${dnsmasqConfGzip}"
+                       rm -f "$dnsmasqIpsetFile" "$dnsmasqIpsetCache" "${compressed_cache_dir}/${dnsmasqIpsetGzip}"
+                       rm -f "$dnsmasqNftsetFile" "$dnsmasqNftsetCache" "${compressed_cache_dir}/${dnsmasqNftsetGzip}"
+                       rm -f "$dnsmasqServersFile" "$dnsmasqServersCache" "${compressed_cache_dir}/${dnsmasqServersGzip}"
+                       rm -f "$unboundFile" "$unboundCache" "$unboundGzip"
+                       config_load 'dhcp'
+                       config_foreach _resolver_config 'dnsmasq' 'cleanup'
+                       uci_commit 'dhcp'
+               ;;
                on_start)
                        if [ ! -s "$outputFile" ]; then
-                               json set status "statusFail"
-                               json add error "errorOutputFileCreate"
+                               json set status 'statusFail'
+                               json add error 'errorOutputFileCreate'
                                output "${_ERROR_}: $(get_text 'errorOutputFileCreate')!\\n"
                                return 1
                        fi
 
                        config_load 'dhcp'
                        if [ "$dnsmasq_instance" = "*" ]; then
-                               config_foreach resolver_config 'dnsmasq' "$dns"
+                               config_foreach _resolver_config 'dnsmasq' "$dns"
                        elif [ -n "$dnsmasq_instance" ]; then
                                for i in $dnsmasq_instance; do
-                                       resolver_config "@dnsmasq[$i]" "$dns" || resolver_config "$i" "$dns"
+                                       _resolver_config "@dnsmasq[$i]" "$dns" || _resolver_config "$i" "$dns"
                                done
                        fi
 
@@ -640,13 +794,13 @@ dns() {
                        output 2 "$output_text "
                        json set message "$output_text"
                        if eval "$param"; then
-                               json set status "statusSuccess"
+                               json set status 'statusSuccess'
                                led_on "$led"
                                output_okn
                        else 
                                output_fail
-                               json set status "statusFail"
-                               json add error "errorDNSReload"
+                               json set status 'statusFail'
+                               json add error 'errorDNSReload'
                                output "${_ERROR_}: $(get_text 'errorDNSReload')!\\n"
                                return 1
                        fi
@@ -674,7 +828,7 @@ dns() {
                        eval "$param"
                        return $?
                ;;
-               quiet)
+               quiet|quiet_restart)
                        case "$dns" in
                                dnsmasq.addnhosts|dnsmasq.conf|dnsmasq.ipset|dnsmasq.nftset|dnsmasq.servers)
                                        param=dnsmasq_restart
@@ -689,88 +843,6 @@ dns() {
        esac
 }
 
-json() {
-# shellcheck disable=SC2034
-       local action="$1" param="$2" value="$3"
-       shift 3
-# shellcheck disable=SC2124
-       local extras="$@" line
-       local status message error stats
-       local reload restart curReload curRestart ret i
-       if [ -s "$jsonFile" ]; then
-               json_load_file "$jsonFile" 2>/dev/null
-               json_select 'data' 2>/dev/null
-               for i in status message error stats reload restart; do
-                       json_get_var "$i" "$i" 2>/dev/null
-               done
-       fi
-       case "$action" in
-               get)
-                       case "$param" in
-                               triggers)
-                                       curReload="$parallel_downloads $debug $download_timeout \
-                                               $allowed_domain $blocked_domain $allowed_url $blocked_url $dns \
-                                               $config_update_enabled $config_update_url $dnsmasq_config_file_url \
-                                               $curl_additional_param $curl_max_file_size $curl_retry"
-                                       curRestart="$compressed_cache $compressed_cache_dir $force_dns $led \
-                                               $force_dns_port"
-                                       if [ ! -s "$jsonFile" ]; then
-                                               ret='on_boot'
-                                       elif [ "$curReload" != "$reload" ]; then
-                                               ret='download'
-                                       elif [ "$curRestart" != "$restart" ]; then
-                                               ret='restart'
-                                       fi
-                                       printf "%b" "$ret"
-                                       return;;
-                               *)
-                                       printf "%b" "$(eval echo "\$$param")"; return;;
-                       esac
-               ;;
-               add)
-                       line="$(eval echo "\$$param")"
-                       eval "$param"='${line:+$line }${value}${extras:+|$extras}'
-               ;;
-               del)
-                       case "$param" in
-                               all)
-                                       unset status message error stats;;
-                               triggers) 
-                                       unset reload restart;;
-                               *)
-                                       unset "$param";;
-                       esac
-               ;;
-               set)
-                       case "$param" in
-                               triggers) 
-                                       reload="$parallel_downloads $debug $download_timeout \
-                                               $allowed_domain $blocked_domain $allowed_url $blocked_url $dns \
-                                               $config_update_enabled $config_update_url $dnsmasq_config_file_url \
-                                               $curl_additional_param $curl_max_file_size $curl_retry"
-                                       restart="$compressed_cache $compressed_cache_dir $force_dns $led \
-                                               $force_dns_port"
-                               ;;
-                               *)
-                                       eval "$param"='${value}${extras:+|$extras}';;
-                       esac
-               ;;
-       esac
-       json_init
-       json_add_object 'data'
-       json_add_string version "$PKG_VERSION"
-       json_add_string status "$status"
-       json_add_string message "$message"
-       json_add_string error "$error"
-       json_add_string stats "$stats"
-       json_add_string reload "$reload"
-       json_add_string restart "$restart"
-       json_close_object
-       mkdir -p "$(dirname "$jsonFile")"
-       json_dump > "$jsonFile"
-       sync
-}
-
 cache() {
        local R_TMP
        case "$1" in
@@ -812,9 +884,9 @@ cache() {
        esac
 }
 
-_process_file_url() {
+process_file_url_wrapper() {
        if [ "$2" != '0' ]; then
-               json add error "errorConfigValidationFail"
+               json add error 'errorConfigValidationFail'
                output "${_ERROR_}: $(get_text 'errorConfigValidationFail')!\\n"
                output "Please check if the '$packageConfigFile' contains correct values for config options.\\n"
        fi
@@ -847,7 +919,7 @@ process_file_url() {
                file) type='File'; D_TMP="$B_TMP"
                ;;
        esac
-       if [ "${1:0:5}" = "https" ] && [ -z "$isSSLSupported" ]; then
+       if is_https_url "$url" && [ -z "$isSSLSupported" ]; then
                output 1 "$_FAIL_"
                output 2 "[DL] $type $label $__FAIL__\\n"
                echo "errorNoSSLSupport|${1}" >> "$sharedMemoryError"
@@ -862,6 +934,7 @@ process_file_url() {
                output 2 "[DL] $type $label $__FAIL__\\n"
                echo "errorDownloadingList|${url}" >> "$sharedMemoryError"
        else
+               append_newline "$R_TMP"
                [ -n "$cfg" ] && new_size="$(get_local_filesize "$R_TMP")"
                if [ -n "$new_size" ] && [ "$size" != "$new_size" ]; then
                        uci set "${packageName}.${cfg}.size=$size"
@@ -890,6 +963,7 @@ process_file_url() {
                        output 2 "[DL] $type $label ($format) $__FAIL__\\n"
                        echo "errorParsingList|${url}" >> "$sharedMemoryError"
                else
+                       append_newline "$R_TMP"
                        cat "${R_TMP}" >> "$D_TMP"
                        output 1 "$_OK_"
                        output 2 "[DL] $type $label ($format) $__OK__\\n"
@@ -902,13 +976,13 @@ process_file_url() {
 download_dnsmasq_file() {
        local hf allow_filter j=0 R_TMP
 
-       json set message "$(get_text "statusDownloading")..."
-       json set status "statusDownloading"
+       json set message "$(get_text 'statusDownloading')..."
+       json set status 'statusDownloading'
 
        rm -f "$A_TMP" "$B_TMP" "$outputFile" "$outputCache" "$outputGzip"
-       if [ "$($awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo")" -lt 32 ]; then
+       if [ "$(get_ram_free)" -lt 32 ]; then
                output 3 'Low free memory, restarting resolver '
-               if dns 'quiet'; then
+               if resolver 'quiet_restart'; then
                        output_okn
                else 
                        output_failn
@@ -929,21 +1003,51 @@ download_dnsmasq_file() {
                output 2 "$__OK__\\n"
        else
                output 2 "$__FAIL__\\n"
-               json add error "errorMovingDataFile"
+               json add error 'errorMovingDataFile'
        fi
        output 1 '\n'
 }
 
 download_lists() {
+       _ram_check() {
+               _config_calculate_sizes() {
+                       local cfg="$1"
+                       local en size url
+                       config_get_bool en "$cfg" enabled '1'
+                       config_get size "$cfg" size
+                       config_get url "$cfg" url
+                       [ "$en" = '0' ] && return 0
+                       [ -n "$size" ] || size="$(get_url_filesize "$url")"
+                       [ -n "$size" ] && total_sizes=$((total_sizes+size))
+               }
+               local i free_mem total_sizes
+               free_mem="$(get_ram_free)"
+               if [ -z "$free_mem" ]; then
+                       json add warnning 'warningFreeRamCheckFail'
+                       output "${_WARNING_}: $(get_text 'warningFreeRamCheckFail')!\\n"
+                       return 0
+               fi
+               config_load "$packageName"
+               config_foreach _config_calculate_sizes 'file_url'
+               if [ $((free_mem)) -lt $((total_sizes * 2)) ]; then
+                       json add error 'errorTooLittleRam' "$free_mem"
+                       output "${_ERROR_}: $(get_text 'errorTooLittleRam' "$free_mem")!\\n"
+                       return 1
+               else
+                       return 0
+               fi
+       }
        local hf allow_filter j=0 R_TMP
 
-       json set message "$(get_text "statusDownloading")..."
-       json set status "statusDownloading"
+       _ram_check || return 1
+
+       json set message "$(get_text 'statusDownloading')..."
+       json set status 'statusDownloading'
 
        rm -f "$A_TMP" "$B_TMP" "$outputFile" "$outputCache" "$outputGzip"
-       if [ "$($awk '/^MemFree/ {print int($2/1000)}' "/proc/meminfo")" -lt 32 ]; then
+       if [ "$(get_ram_total)" -lt 33554432 ]; then
                output 3 'Low free memory, restarting resolver '
-               if dns 'quiet'; then
+               if resolver 'quiet_restart'; then
                        output_okn
                else 
                        output_failn
@@ -953,11 +1057,11 @@ download_lists() {
        output 1 'Downloading lists '
        rm -f "$sharedMemoryError"
        config_load "$packageName"
-       config_foreach load_validate_file_url_section 'file_url' _process_file_url
+       config_foreach load_validate_file_url_section 'file_url' process_file_url_wrapper
        wait
        if [ -n "$(uci changes "$packageName")" ]; then 
                output 2 "Saving updated file size(s) "
-               uci commit "$packageName" && output_okn || output_failn
+               if uci commit "$packageName"; then output_okn; else output_failn; fi
        fi
        output 1 '\n'
 
@@ -975,7 +1079,10 @@ download_lists() {
                canaryDomains="${canaryDomains:+$canaryDomains }${canaryDomainsMozilla}"
        fi
 
-       for hf in $blocked_domain $canaryDomains; do echo "$hf" | sed "$domainsFilter" >> $B_TMP; done
+       append_newline "$B_TMP"
+       for hf in $blocked_domain $canaryDomains; do
+               printf "%s\n" "$(echo "$hf" | sed "$domainsFilter")" >> "$B_TMP"
+       done
        allowed_domain="${allowed_domain}
 $(cat $A_TMP)"
        for hf in ${allowed_domain}; do hf="$(echo "$hf" | sed 's/\./\\./g')"; allow_filter="$allow_filter/(^|\.)${hf}$/d;"; done
@@ -984,21 +1091,21 @@ $(cat $A_TMP)"
 
        output 1 'Processing downloads '
        output 2 'Sorting combined list '
-       json set status "statusProcessing"
-       json set message "$(get_text "statusProcessing"): sorting combined list"
+       json set status 'statusProcessing'
+       json set message "$(get_text 'statusProcessing'): sorting combined list"
        if [ "$allow_non_ascii" -gt 0 ]; then
                if sort -u "$B_TMP" > "$A_TMP"; then
                        output_ok
                else
                        output_failn
-                       json add error "errorSorting"
+                       json add error 'errorSorting'
                fi
        else
                if sort -u "$B_TMP" | grep -E -v '[^a-zA-Z0-9=/.-]' > "$A_TMP"; then
                        output_ok
                else
                        output_failn
-                       json add error "errorSorting"
+                       json add error 'errorSorting'
                fi
        fi
 
@@ -1009,8 +1116,9 @@ $(cat $A_TMP)"
                 [ "$dns" = 'unbound.adb_list' ]; then
                # TLD optimization written by Dirk Brenken (dev@brenken.org)
                output 2 'Optimizing combined list '
-               json set message "$(get_text "statusProcessing"): optimizing combined list"
+               json set message "$(get_text 'statusProcessing'): optimizing combined list"
 #      sed -E 'G;:t;s/(.*)(\.)(.*)(\n)(.*)/\1\4\5\2\3/;tt;s/(.*)\n(\.)(.*)/\3\2\1/' is actually slower than command below
+# shellcheck disable=SC2016
                if $awk -F "." '{for(f=NF;f>1;f--)printf "%s.",$f;print $1}' "$A_TMP" > "$B_TMP"; then
                        if sort "$B_TMP" > "$A_TMP"; then
                                if $awk '{if(NR=1){tld=$NF};while(getline){if($NF!~tld"\\."){print tld;tld=$NF}}print tld}' "$A_TMP" > "$B_TMP"; then
@@ -1019,25 +1127,25 @@ $(cat $A_TMP)"
                                                        output_ok
                                                else
                                                        output_failn
-                                                       json add error "errorOptimization"
+                                                       json add error 'errorOptimization'
                                                        mv "$A_TMP" "$B_TMP"
                                                fi
                                        else
                                                output_failn
-                                               json add error "errorOptimization"
+                                               json add error 'errorOptimization'
                                        fi
                                else
                                        output_failn
-                                       json add error "errorOptimization"
+                                       json add error 'errorOptimization'
                                        mv "$A_TMP" "$B_TMP"
                                fi
                        else
                                output_failn
-                               json add error "errorOptimization"
+                               json add error 'errorOptimization'
                        fi
                else
                        output_failn
-                       json add error "errorOptimization"
+                       json add error 'errorOptimization'
                        mv "$A_TMP" "$B_TMP"
                fi
        else
@@ -1046,22 +1154,22 @@ $(cat $A_TMP)"
 
        if [ -n "$allow_filter" ]; then
                output 2 'Allowing domains '
-               json set message "$(get_text "statusProcessing"): allowing domains"
+               json set message "$(get_text 'statusProcessing'): allowing domains"
                if sed -i -E "$allow_filter" "$B_TMP"; then
                        output_ok
                else
                        output_failn
-                       json add error "errorAllowListProcessing"
+                       json add error 'errorAllowListProcessing'
                fi
        fi
        output 2 'Formatting merged file '
-       json set message "$(get_text "statusProcessing"): formatting merged file"
+       json set message "$(get_text 'statusProcessing'): formatting merged file"
        if [ -z "$outputFilterIPv6" ]; then
                if sed "$outputFilter" "$B_TMP" > "$A_TMP"; then
                        output_ok
                else
                        output_failn
-                       json add error "errorDataFileFormatting"
+                       json add error 'errorDataFileFormatting'
                fi
        else
                case "$dns" in
@@ -1071,7 +1179,7 @@ $(cat $A_TMP)"
                                        output_ok
                                else
                                        output_failn
-                                       json add error "errorDataFileFormatting"
+                                       json add error 'errorDataFileFormatting'
                                fi
                        ;;
                esac
@@ -1080,27 +1188,27 @@ $(cat $A_TMP)"
        case "$dns" in
                dnsmasq.addnhosts)
                        output 2 'Creating dnsmasq addnhosts file '
-                       json set message "$(get_text "statusProcessing"): creating dnsmasq addnhosts file"
+                       json set message "$(get_text 'statusProcessing'): creating dnsmasq addnhosts file"
                ;;
                dnsmasq.conf)
                        output 2 'Creating dnsmasq config file '
-                       json set message "$(get_text "statusProcessing"): creating dnsmasq config file"
+                       json set message "$(get_text 'statusProcessing'): creating dnsmasq config file"
                ;;
                dnsmasq.ipset)
                        output 2 'Creating dnsmasq ipset file '
-                       json set message "$(get_text "statusProcessing"): creating dnsmasq ipset file"
+                       json set message "$(get_text 'statusProcessing'): creating dnsmasq ipset file"
                ;;
                dnsmasq.nftset)
                        output 2 'Creating dnsmasq nft set file '
-                       json set message "$(get_text "statusProcessing"): creating dnsmasq nft set file"
+                       json set message "$(get_text 'statusProcessing'): creating dnsmasq nft set file"
                ;;
                dnsmasq.servers)
                        output 2 'Creating dnsmasq servers file '
-                       json set message "$(get_text "statusProcessing"): creating dnsmasq servers file"
+                       json set message "$(get_text 'statusProcessing'): creating dnsmasq servers file"
                ;;
                unbound.adb_list)
                        output 2 'Creating Unbound adb_list file '
-                       json set message "$(get_text "statusProcessing"): creating Unbound adb_list file"
+                       json set message "$(get_text 'statusProcessing'): creating Unbound adb_list file"
                ;;
        esac
 
@@ -1108,28 +1216,28 @@ $(cat $A_TMP)"
                output_ok
        else
                output_failn
-               json add error "errorMovingDataFile"
+               json add error 'errorMovingDataFile'
        fi
        if [ "$compressed_cache" -gt 0 ]; then
                output 2 'Creating compressed cache '
-               json set message "$(get_text "statusProcessing"): creating compressed cache"
+               json set message "$(get_text 'statusProcessing'): creating compressed cache"
                if cache 'create_gzip'; then
                        output_ok
                else
                        output_failn
-                       json add error "errorCreatingCompressedCache"
+                       json add error 'errorCreatingCompressedCache'
                fi
        else
                rm -f "$outputGzip"
        fi
        output 2 'Removing temporary files '
-       json set message "$(get_text "statusProcessing"): removing temporary files"
+       json set message "$(get_text 'statusProcessing'): removing temporary files"
        rm -f "/tmp/${packageName}_tmp.*" "$A_TMP" "$B_TMP" "$outputCache" || j=1
        if [ $j -eq 0 ]; then
                output_ok
        else
                output_failn
-               json add error "errorRemovingTempFiles"
+               json add error 'errorRemovingTempFiles'
        fi
        output 1 '\n'
 }
@@ -1268,6 +1376,54 @@ adb_check() {
        done
 }
 
+adb_check_lists() {
+       _check_list() {
+               local cfg="$1"
+               local en size url R_TMP string c
+               config_get_bool en "$cfg" enabled '1'
+               config_get action "$cfg" action 'block'
+               config_get url "$cfg" url
+               [ "$en" = '0' ] && return 0
+               [ "$action" != 'block' ] && return 0
+               if is_https_url "$url" && [ -z "$isSSLSupported" ]; then
+                       output "[DL] $url $__FAIL__\\n"
+               fi
+               while [ -z "$R_TMP" ] || [ -e "$R_TMP" ]; do
+                       R_TMP="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
+               done
+               if [ -z "$url" ] || ! $dl_command "$url" "$dl_flag" "$R_TMP" 2>/dev/null || \
+                       [ ! -s "$R_TMP" ]; then
+                       output "[DL] $url $__FAIL__\\n"
+               else
+                       append_newline "$R_TMP"
+                       for string in ${param}; do
+                               c="$(grep -c "$string" "$R_TMP")"
+                               if [ "$c" -gt 0 ]; then
+                                       if [ "$c" -eq 1 ]; then
+                                               output "Found 1 match for '$string' in '$url'.\\n"
+                                       else
+                                               output "Found $c matches for '$string' in '$url'.\\n"
+                                       fi
+                                       grep "$string" "$R_TMP"
+                               else
+                                       output "The '$string' is not found in '$url'.\\n"
+                               fi
+                       done
+               rm -f "$R_TMP"
+               fi
+       }
+       local param="$1"
+       local validation_result="$3"
+       load_environment "$validation_result" 'quiet' || return 1
+       if [ -z "$param" ]; then
+               output "Usage: /etc/init.d/${packageName} check_lists 'domain' ...\\n"
+               return 0
+       fi
+       config_load "$packageName"
+       config_foreach _check_list 'file_url'
+       return 0
+}
+
 adb_config_update() {
        local R_TMP label
        local param validation_result="$3"
@@ -1289,9 +1445,10 @@ adb_config_update() {
                R_TMP="$(mktemp -u -q -t ${packageName}_tmp.XXXXXXXX)"
        done
        if ! $dl_command "$config_update_url" "$dl_flag" "$R_TMP" 2>/dev/null || [ ! -s "$R_TMP" ]; then
+               append_newline "$R_TMP"
                output 1 "$_FAIL_\\n"
                output 2 "[DL] Config  Update:  $label $__FAIL__\\n"
-               json add error "errorDownloadingConfigUpdate"
+               json add error 'errorDownloadingConfigUpdate'
        else
                if [ -s "$R_TMP" ] && sed -f "$R_TMP" -i "$packageConfigFile" 2>/dev/null; then
                        output 1 "$_OK_\\n"
@@ -1299,27 +1456,26 @@ adb_config_update() {
                else
                        output 1 "$_FAIL_\\n"
                        output 2 "[DL] Config  Update:  $label $__FAIL__\\n"
-                       json add error "errorParsingConfigUpdate"
+                       json add error 'errorParsingConfigUpdate'
                fi
        fi
        rm -f "$R_TMP"
        return 0
 }
 
-_config_add_url_size() {
-       local cfg="$1" url size
-       config_get url "$cfg" url
-       size="$(get_url_filesize "$url")"
-       output "$url${size:+: $size} "
-       if [ -n "$size" ]; then
-               uci set "${packageName}.${cfg}.size=$size"
-               output_okn
-       else
-               output_failn
-       fi
-}
-
 adb_sizes() {
+       _config_add_url_size() {
+               local cfg="$1" url size
+               config_get url "$cfg" url
+               size="$(get_url_filesize "$url")"
+               output "$url${size:+: $size} "
+               if [ -n "$size" ]; then
+                       uci set "${packageName}.${cfg}.size=$size"
+                       output_okn
+               else
+                       output_failn
+               fi
+       }
        local i
        local validation_result="$3"
        load_environment "$validation_result" 'quiet' || return 1
@@ -1358,7 +1514,7 @@ adb_start() {
        elif [ "$action" = 'restart' ] || [ "$param" = 'restart' ]; then
                action='restart'
        elif [ -s "$outputFile" ] && [ "$status" = "statusSuccess" ] && [ -z "$error" ]; then
-               status_service
+               status_service 'quiet'
                return 0
        else
                action='download'
@@ -1370,7 +1526,7 @@ adb_start() {
        if [ "$action" = 'restore' ]; then
                output 0 "Starting $serviceName... "
                output 3 "Starting $serviceName...\\n"
-               json set status "statusStarting"
+               json set status 'statusStarting'
                if cache 'test_gzip' && ! cache 'test' && [ ! -s "$outputFile" ]; then
                        output 3 'Found compressed cache file, unpacking it '
                        json set message 'found compressed cache file, unpacking it.'
@@ -1378,7 +1534,7 @@ adb_start() {
                                output_okn
                        else
                                output_failn
-                               json add error "errorRestoreCompressedCache"
+                               json add error 'errorRestoreCompressedCache'
                                output "${_ERROR_}: $(get_text 'errorRestoreCompressedCache')!\\n"
                                action='download'
                        fi
@@ -1388,10 +1544,10 @@ adb_start() {
                        json set message 'found cache file, reusing it.'
                        if cache 'restore'; then 
                                output_okn
-                               dns 'on_start'
+                               resolver 'on_start'
                        else
                                output_failn
-                               json add error "errorRestoreCache"
+                               json add error 'errorRestoreCache'
                                output "${_ERROR_}: $(get_text 'errorRestoreCache')!\\n"
                                action='download'
                        fi
@@ -1399,50 +1555,52 @@ adb_start() {
        fi
        if [ "$action" = 'download' ]; then
                if [ -z "$blocked_url" ] && [ -z "$blocked_domain" ]; then
-                       json set status "statusFail"
-                       json add error "errorNothingToDo"
+                       json set status 'statusFail'
+                       json add error 'errorNothingToDo'
                        output "${_ERROR_}: $(get_text 'errorNothingToDo')!\\n"
                else
                        if [ -s "$outputFile" ] || cache 'test' || cache 'test_gzip'; then
                                output 0 "Force-reloading $serviceName... "
                                output 3 "Force-reloading $serviceName...\\n"
-                               json set status "statusForceReloading"
+                               json set status 'statusForceReloading'
                        else
                                output 0 "Starting $serviceName... "
                                output 3 "Starting $serviceName...\\n"
-                               json set status "statusStarting"
+                               json set status 'statusStarting'
                        fi
+                       resolver 'cleanup'
                        if [ "$dns" = 'dnsmasq.conf' ] && [ -n "$dnsmasq_config_file_url" ]; then
                                download_dnsmasq_file
                        else
                                download_lists
                        fi
-                       dns 'on_start'
+                       resolver 'on_start'
                fi
        fi
        if [ "$action" = 'restart' ]; then
                output 0 "Restarting $serviceName... "
                output 3 "Restarting $serviceName...\\n"
-               json set status "statusRestarting"
-               dns 'on_start'
+               json set status 'statusRestarting'
+               resolver 'on_start'
        fi
        if [ "$action" = 'start' ]; then
                output 0 "Starting $serviceName... "
                output 3 "Starting $serviceName...\\n"
-               json set status "statusStarting"
-               dns 'on_start'
+               json set status 'statusStarting'
+               resolver 'on_start'
        fi
        if [ -s "$outputFile" ] && [ "$(json get status)" != "statusFail" ]; then
                output 0 "$__OK__\\n";
                json del message
-               json set status "statusSuccess"
+               json set status 'statusSuccess'
                json set stats "$serviceName is blocking $(wc -l < "$outputFile") domains (with ${dns})"
-               status_service
+               status_service 'quiet'
+
        else
                output 0 "$__FAIL__\\n";
-               json set status "statusFail"
-               json add error "errorOhSnap"
-               status_service
+               json set status 'statusFail'
+               json add error 'errorOhSnap'
+               status_service 'quiet'
        fi
 
        procd_open_instance 'main'
@@ -1460,6 +1618,7 @@ adb_start() {
        fi
        json_add_array firewall
        if [ "$force_dns" -ne 0 ]; then
+# shellcheck disable=SC3060
                for c in ${force_dns_port/,/ }; do
                        if netstat -tuln | grep LISTEN | grep ":${c}" >/dev/null 2>&1; then
                                json_add_object ""
@@ -1541,12 +1700,12 @@ adb_start() {
 }
 
 adb_status() {
-       local c url status message error stats
-       local validation_result="$3"
-       load_environment "$validation_result" 'quiet' || return 1
+       local param="$1"
+       local c status message error warning stats text
        status="$(json get status)"
        message="$(json get message)"
        error="$(json get error)"
+       warning="$(json get warning)"
        stats="$(json get stats)"
        if [ "$status" = "statusSuccess" ]; then
                output "$stats "; output_okn;
@@ -1555,19 +1714,20 @@ adb_status() {
                if [ -n "$status" ] && [ -n "$message" ]; then 
                        status="${status}: $message"
                fi
-               [ -n "$status" ] && output "$serviceName $status\\n"
+               [ -n "$status" ] && output "$serviceName $status!\\n"
        fi
-       if [ -n "$error" ]; then
+       if [ "$param" != 'quiet' ] && [ -n "$error" ]; then
                for c in $error; do
-                       url="${c##*|}"
-                       c="${c%|*}"
-                       case "$c" in
-                               errorDownloadingList|errorParsingList)
-                                       output "${_ERROR_}: $(get_text "$c") $url!\\n";;
-                               *)
-                                       output "${_ERROR_}: $(get_text "$c")!\\n";;
-                       esac
-                       n=$((n+1))
+                       local error_param="${c##*|}"
+                       local error_code="${c%|*}"
+                       output "${_ERROR_}: $(get_text "$error_code" "$error_param")!\\n"
+               done
+       fi
+       if [ "$param" != 'quiet' ] && [ -n "$warning" ]; then
+               for c in $warning; do
+                       local warning_param="${c##*|}"
+                       local warning_code="${c%|*}"
+                       output "${_WARNING_}: $(get_text "$warning_code" "$warning_param").\\n"
                done
        fi
        return 0
@@ -1580,19 +1740,19 @@ adb_stop() {
        if [ -s "$outputFile" ]; then
                output "Stopping $serviceName... "
                cache 'create'
-               if dns 'on_stop'; then
+               if resolver 'on_stop'; then
                        ipset -q -! flush adb
                        ipset -q -! destroy adb
                        nft delete set inet fw4 adb4
                        nft delete set inet fw4 adb6
                        led_off "$led"
                        output 0 "$__OK__\\n"; output_okn;
-                       json set status "statusStopped"
+                       json set status 'statusStopped'
                        json del message
                else 
                        output 0 "$__FAIL__\\n"; output_fail;
-                       json set status "statusFail"
-                       json add error "errorStopping"
+                       json set status 'statusFail'
+                       json add error 'errorStopping'
                        output "${_ERROR_}: $(get_text 'errorStopping')!\\n"
                fi
        fi
@@ -1604,7 +1764,7 @@ adb_pause() {
        local validation_result="$3"
        adb_stop 'on_pause' '' "$validation_result"
        output "Sleeping for $timeout seconds... "
-       if sleep "$timeout"; then
+       if is_integer "$timeout" && sleep "$timeout"; then
                output_okn
        else
                output_failn
@@ -1614,10 +1774,16 @@ adb_pause() {
 
 allow() { load_validate_config 'config' adb_allow "'$*'"; }
 boot() {
+       local procd_boot_delay
        ubus -t 30 wait_for network.interface 2>/dev/null
-       rc_procd start_service 'on_boot'
+       config_load "$packageName"
+       config_get procd_boot_delay 'config' 'procd_boot_delay' '0'
+# shellcheck disable=SC2154
+       { is_integer "$procd_boot_delay" && sleep "$procd_boot_delay"; \
+               rc_procd start_service 'on_boot' && service_started 'on_boot'; } &
 }
 check() { load_validate_config 'config' adb_check "'$*'"; }
+check_lists() { load_validate_config 'config' adb_check_lists "'$*'"; }
 dl() { rc_procd start_service 'download'; }
 killcache() {
        local compressed_cache_dir
@@ -1636,9 +1802,7 @@ killcache() {
        rm -f "$dnsmasqNftsetCache" "${compressed_cache_dir}/${dnsmasqNftsetGzip}"
        rm -f "$dnsmasqServersCache" "${compressed_cache_dir}/${dnsmasqServersGzip}"
        rm -f "$unboundCache" "$unboundGzip"
-       config_load 'dhcp'
-       config_foreach resolver_config 'dnsmasq' 'cleanup'
-       uci_commit 'dhcp'
+       resolver 'cleanup'
        return 0
 }
 reload_service() { rc_procd start_service 'restart'; }
@@ -1650,7 +1814,6 @@ service_triggers() {
        local procd_trigger_wan6
        config_load "$packageName"
        config_get_bool procd_trigger_wan6 'config' 'procd_trigger_wan6' '0'
-       . /lib/functions/network.sh
        network_flush_cache
        network_find_wan wan
        wan="${wan:-wan}"
@@ -1668,7 +1831,7 @@ start_service() {
        load_validate_config 'config' adb_config_update "'$*'"
        load_validate_config 'config' adb_start "'$*'"
 }
-status_service() { load_validate_config 'config' adb_status "''"; }
+status_service() { adb_status "$@"; }
 stop_service() { load_validate_config 'config' adb_stop "'$*'"; }
 pause() { load_validate_config 'config' adb_pause "'$*'"; }
 version() { echo "$PKG_VERSION"; }
@@ -1682,8 +1845,6 @@ load_validate_file_url_section() {
 }
 
 load_validate_config() {
-       . /lib/functions/network.sh
-       . /usr/share/libubox/jshn.sh
        local enabled
        local force_dns
        local force_dns_port
index 5366b46e64c055079cd771d4b68a3a27e7bf0173..0ba1f9a35cb6883fd81a32e754429681286ddd81 100644 (file)
@@ -1,51 +1,14 @@
 #!/bin/sh
 # Copyright 2023 MOSSDeF, Stan Grishin (stangri@melmac.ca)
-# shellcheck disable=SC1091,SC2015,SC3037,SC3043,SC2317,SC3060
+# shellcheck disable=SC2015,SC3043,SC3060
 
-readonly packageName='adblock-fast'
-readonly _OK_='\033[0;32m\xe2\x9c\x93\033[0m'
-readonly _FAIL_='\033[0;31m\xe2\x9c\x97\033[0m'
-readonly __OK__='\033[0;32m[\xe2\x9c\x93]\033[0m'
-readonly __FAIL__='\033[0;31m[\xe2\x9c\x97]\033[0m'
-readonly _ERROR_='\033[0;31mERROR\033[0m'
-readonly _WARNING_='\033[0;33mWARNING\033[0m'
-output() {
-# Can take a single parameter (text) to be output at any verbosity
-# Or target verbosity level and text to be output at specifc verbosity
-       local msg memmsg logmsg
-       local sharedMemoryOutput="/dev/shm/$packageName-output"
-       verbosity="${verbosity:-2}"
-       if [ "$#" -ne 1 ]; then
-               if [ $((verbosity & $1)) -gt 0 ] || [ "$verbosity" = "$1" ]; then
-                       shift
-               else
-                       return 0
-               fi
-       fi
-       [ -t 1 ] && printf "%b" "$1"
-       msg="$1";
-       if [ "$(printf "%b" "$msg" | wc -l)" -gt 0 ]; then
-               [ -s "$sharedMemoryOutput" ] && memmsg="$(cat "$sharedMemoryOutput")"
-               logmsg="$(printf "%b" "${memmsg}${msg}" | sed 's/\x1b\[[0-9;]*m//g')"
-               logger -t "${packageName:-service}" "$(printf "%b" "$logmsg")"
-               rm -f "$sharedMemoryOutput"
-       else
-               printf "%b" "$msg" >> "$sharedMemoryOutput"
-       fi
-}
-output_ok() { output 1 "$_OK_"; output 2 "$__OK__\\n"; }
-output_okn() { output 1 "$_OK_\\n"; output 2 "$__OK__\\n"; }
-output_fail() { output 1 "$_FAIL_"; output 2 "$__FAIL__\\n"; }
-output_failn() { output 1 "$_FAIL_\\n"; output 2 "$__FAIL__\\n"; }
-is_present() { command -v "$1" >/dev/null 2>&1; }
-get_url_filesize() {
-       local url="$1" size size_command
-       [ -n "$1" ] || return 0
-       is_present 'curl' || return 0
-       size_command='curl --silent --insecure --fail --head --request GET'
-       size="$($size_command "$url" | grep -Po '^[cC]ontent-[lL]ength: \K\w+')"
-       echo -en "$size"
-}
+readonly adbFunctionsFile='/etc/init.d/adblock-fast'
+if [ -s "$adbFunctionsFile" ]; then
+# shellcheck source=../../etc/init.d/adblock-fast
+       . "$adbFunctionsFile"
+else
+       printf "%b: adblock-fast init.d file (%s) not found! \n" '\033[0;31mERROR\033[0m' "$adbFunctionsFile"
+fi
 
 # Transition from simple-adblock
 _enable_url() {
index af441bf52678ff328443cdc18507411d1db9fa9a..6aee1cc9c44ddb81c757d7406dcbf2ae2c13c9a5 100644 (file)
@@ -7,12 +7,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=aria2
-PKG_VERSION:=1.36.0
-PKG_RELEASE:=2
+PKG_VERSION:=1.37.0
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://github.com/aria2/aria2/releases/download/release-$(PKG_VERSION)/
-PKG_HASH:=58d1e7608c12404f0229a3d9a4953d0d00c18040504498b483305bcb3de907a5
+PKG_HASH:=60a420ad7085eb616cb6e2bdf0a7206d68ff3d37fb5a956dc44242eb2f79b66b
 PKG_INSTALL:=1
 PKG_BUILD_PARALLEL:=1
 PKG_BUILD_FLAGS:=gc-sections lto
index ceadbc0fd85fd23632907d8eed4f6403b68613be..28b76bc86aa0de6bbfc18afe59cbe9763af18c52 100644 (file)
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=banip
 PKG_VERSION:=0.9.2
-PKG_RELEASE:=1
+PKG_RELEASE:=4
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
 
index c75a2b5648bfb2bfa0c953800b7e328646d57607..1a1266d03554897813d0fe15110bb9825de9a2b6 100644 (file)
@@ -194,10 +194,10 @@ f_rmpid() {
                for pid in ${pids}; do
                        pids="${pids} $(pgrep -P "${pid}" 2>/dev/null)"
                done
+               for pid in ${pids}; do
+                       kill -INT "${pid}" >/dev/null 2>&1
+               done
        fi
-       for pid in ${pids}; do
-               kill -INT "${pid}" >/dev/null 2>&1
-       done
        : >"${ban_rdapfile}"
        : >"${ban_pidfile}"
 }
@@ -674,8 +674,8 @@ f_down() {
 
        # restore local backups
        #
-       if { [ "${ban_action}" != "reload" ] || [ "${feed_url}" = "local" ] || [ -n "${ban_etagparm}" ]; } && [ "${feed%v*}" != "allowlist" ] && [ "${feed%v*}" != "blocklist" ]; then
-               if [ -n "${ban_etagparm}" ] && [ "${ban_action}" = "reload" ] && [ "${feed_url}" != "local" ]; then
+       if [ "${feed%v*}" != "blocklist" ]; then
+               if [ -n "${ban_etagparm}" ] && [ "${ban_action}" = "reload" ] && [ "${feed_url}" != "local" ] && [ "${feed%v*}" != "allowlist" ]; then
                        etag_rc="0"
                        if [ "${feed%v*}" = "country" ]; then
                                for country in ${ban_country}; do
@@ -697,16 +697,21 @@ f_down() {
                        fi
                fi
                if [ "${etag_rc}" = "0" ] || [ "${ban_action}" != "reload" ] || [ "${feed_url}" = "local" ]; then
-                       f_restore "${feed}" "${feed_url}" "${tmp_load}" "${etag_rc}"
+                       if [ "${feed%v*}" = "allowlist" ] && [ ! -f "${tmp_allow}" ]; then
+                               f_restore "allowlist" "-" "${tmp_allow}" "${etag_rc}"
+                       else
+                               f_restore "${feed}" "${feed_url}" "${tmp_load}" "${etag_rc}"
+                       fi
                        restore_rc="${?}"
                        feed_rc="${restore_rc}"
                fi
        fi
 
-       # prepare local allowlist
+       # prepare local/remote allowlist
        #
        if [ "${feed%v*}" = "allowlist" ] && [ ! -f "${tmp_allow}" ]; then
                "${ban_catcmd}" "${ban_allowlist}" 2>/dev/null >"${tmp_allow}"
+               feed_rc="${?}"
                for feed_url in ${ban_allowurl}; do
                        feed_log="$("${ban_fetchcmd}" ${ban_fetchparm} "${tmp_load}" "${feed_url}" 2>&1)"
                        feed_rc="${?}"
@@ -714,8 +719,15 @@ f_down() {
                                "${ban_catcmd}" "${tmp_load}" 2>/dev/null >>"${tmp_allow}"
                        else
                                f_log "info" "download for feed '${feed%v*}' failed (rc: ${feed_rc:-"-"}/log: ${feed_log})"
+                               break
                        fi
                done
+               if [ "${feed_rc}" = "0" ]; then
+                       f_backup "allowlist" "${tmp_allow}"
+               elif [ -z "${restore_rc}" ] && [ "${feed_rc}" != "0" ]; then
+                       f_restore "allowlist" "-" "${tmp_allow}" "${feed_rc}"
+               fi
+               feed_rc="${?}"
        fi
 
        # handle local feeds
@@ -980,7 +992,11 @@ f_down() {
        # load generated nft file in banIP table
        #
        if [ "${feed_rc}" = "0" ]; then
-               cnt_dl="$("${ban_awkcmd}" 'END{printf "%d",NR}' "${tmp_split}" 2>/dev/null)"
+               if [ "${feed%v*}" = "allowlist" ]; then
+                       cnt_dl="$("${ban_awkcmd}" 'END{printf "%d",NR}' "${tmp_allow}" 2>/dev/null)"
+               else
+                       cnt_dl="$("${ban_awkcmd}" 'END{printf "%d",NR}' "${tmp_split}" 2>/dev/null)"
+               fi
                if [ "${cnt_dl:-"0"}" -gt "0" ] || [ "${feed_url}" = "local" ] || [ "${feed%v*}" = "allowlist" ] || [ "${feed%v*}" = "blocklist" ]; then
                        feed_log="$("${ban_nftcmd}" -f "${tmp_nft}" 2>&1)"
                        feed_rc="${?}"
@@ -1098,7 +1114,7 @@ f_genstatus() {
                                cnt_elements="$((cnt_elements + $("${ban_nftcmd}" -j list set inet banIP "${object}" 2>/dev/null | "${ban_jsoncmd}" -qe '@.nftables[*].set.elem[*]' | wc -l 2>/dev/null)))"
                        done
                fi
-               runtime="action: ${ban_action:-"-"}, fetch: ${ban_fetchcmd##*/}, duration: ${duration:-"-"}, date: $(date "+%Y-%m-%d %H:%M:%S")"
+               runtime="action: ${ban_action:-"-"}, log: ${ban_logreadcmd##*/}, fetch: ${ban_fetchcmd##*/}, duration: ${duration:-"-"}, date: $(date "+%Y-%m-%d %H:%M:%S")"
        fi
        [ -s "${ban_customfeedfile}" ] && custom_feed="1"
        [ "${ban_splitsize:-"0"}" -gt "0" ] && split="1"
index cfe1a70cc690f4ed7f89433f4def2ec9226b5dfc..1adb11eb59adb6f481e10dd1dcb26a24469938ad 100644 (file)
        },
        "urlhaus":{
                "url_4": "https://urlhaus.abuse.ch/downloads/ids/",
-               "rule_4": "match($0,/(([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5]))/){printf \"%s,\\n\",substr($0,RSTART,RLENGTH)}",
+               "rule_4": "match($0,/(content:\"([0-9]{1,3}\\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5]))/){printf \"%s,\\n\",substr($0,RSTART+9,RLENGTH-9)}",
                "descr": "urlhaus IDS IPs"
        },
        "urlvir":{
index a934b4a9196708cebca58da85abebd74c800dad8..4ef70e3d0c0071a83194b403f9fd01b53b223cb7 100755 (executable)
@@ -22,6 +22,7 @@ ban_lock="/var/run/banip.lock"
 
 [ "${action}" = "boot" ] && "${ban_init}" running && exit 0
 { [ "${action}" = "stop" ] || [ "${action}" = "report" ] || [ "${action}" = "search" ] || [ "${action}" = "survey" ] || [ "${action}" = "lookup" ]; } && ! "${ban_init}" running && exit 0
+[ ! -r "${ban_funlib}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "stop" ] || [ "${action}" = "report" ] || [ "${action}" = "search" ] || [ "${action}" = "lookup" ] || [ "${action}" = "status" ]; } && exit 1
 [ -d "${ban_lock}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "lookup" ]; } && exit 1
 [ ! -d "${ban_lock}" ] && { [ "${action}" = "boot" ] || [ "${action}" = "start" ] || [ "${action}" = "restart" ] || [ "${action}" = "reload" ] || [ "${action}" = "lookup" ]; } && mkdir -p "${ban_lock}"
 
@@ -31,8 +32,8 @@ boot() {
 }
 
 start_service() {
+       [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
        if "${ban_init}" enabled; then
-               [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
                f_rmpid
                procd_open_instance "banip-service"
                procd_set_param command "${ban_service}" "${@:-"${action}"}"
@@ -43,7 +44,6 @@ start_service() {
                procd_set_param stderr 1
                procd_close_instance
        else
-               [ -z "$(command -v "f_system")" ] && . "${ban_funlib}"
                f_log "err" "banIP service autostart is disabled"
                rm -rf "${ban_lock}"
        fi
diff --git a/net/cni-protocol/Makefile b/net/cni-protocol/Makefile
deleted file mode 100644 (file)
index 3711452..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=cni-protocol
-PKG_VERSION:=20231008
-PKG_RELEASE:=1
-
-PKG_MAINTAINER:=Oskari Rauta <oskari.rauta@gmail.com>
-
-include $(INCLUDE_DIR)/package.mk
-
-define Package/cni-protocol
-  SECTION:=net
-  CATEGORY:=Network
-  TITLE:=cni netifd protocol
-  PKGARCH:=all
-endef
-
-define Package/cni-protocol/description
-  protocol support for netavark/cni networks for netifd
-  makes defining networks for podman and other similar
-  systems easier and simple.
-
-  with protocol, a network where firewall and portmapper
-  management is disabled, control of firewalling, whether
-  it was exposing ports, and forwarding to them from wan,
-  or limiting/accepting access to other networks such
-  as lan can made through openwrt's own firewalling
-  configuration.
-
-  example configuration could be as following:
-    - lan network: 10.0.0.0/16 (255.255.0.0)
-    - container network: 10.129.0.1/24 (255.255.255.0)
-
-  Add a network configuration for your container network
-  using cni protocol. Then create firewall zone for it.
-
-  You could create a new container/pod with static ip
-  address 10.129.0.2 (as 10.129.0.1 as container network's
-  gateway).
-
-  Easily define permissions so that local networks can
-  connect to cni network, but not the other way around.
-  Also you want to allow forwarding from/to wan.
-
-  Now, as cni cannot access local dns, make a rule for
-  your firewall to accept connections from cni network
-  to port 53 (dns).
-
-  Now all you have to do, is make redirects to your firewall
-  and point them to 10.129.0.2 and connections from wan are
-  redirectered to containers/pods.
-
-  Protocol has 2 settings: device and delay. Sometimes polling
-  interfaces takes some time, and in that case you might want
-  to add few seconds to delay. Otherwise, it can be excluded
-  from configuration.
-endef
-
-define Build/Configure
-endef
-
-define Build/Compile
-endef
-
-define Package/cni-protocol/install
-       $(INSTALL_DIR) $(1)/lib/netifd/proto
-       $(INSTALL_BIN) ./files/cni.sh $(1)/lib/netifd/proto/cni.sh
-endef
-
-$(eval $(call BuildPackage,cni-protocol))
diff --git a/net/cni-protocol/files/cni.sh b/net/cni-protocol/files/cni.sh
deleted file mode 100755 (executable)
index 73a3711..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh
-
-[ -n "$INCLUDE_ONLY" ] || {
-       . /lib/functions.sh
-       . ../netifd-proto.sh
-       init_proto "$@"
-}
-
-proto_cni_init_config() {
-       no_device=0
-       available=0
-
-       proto_config_add_string "device:device"
-       proto_config_add_int "delay"
-}
-
-proto_cni_setup() {
-       local cfg="$1"
-       local iface="$2"
-       local device delay
-
-       json_get_vars device delay
-
-       [ -n "$device" ] || {
-               echo "No cni interface specified"
-               proto_notify_error "$cfg" NO_DEVICE
-               proto_set_available "$cfg" 0
-               return 1
-       }
-
-       [ -n "$delay" ] && sleep "$delay"
-
-       [ -L "/sys/class/net/${iface}" ] || {
-               echo "The specified interface $iface is not present"
-               proto_notify_error "$cfg" NO_DEVICE
-               proto_set_available "$cfg" 0
-               return 1
-       }
-
-       local ipaddr netmask broadcast route routemask routesrc
-
-       ipaddr=$(ip -4 -o a show "$iface" | awk '{ print $4 }' | cut -d '/' -f1)
-       netmask=$(ip -4 -o a show "$iface" | awk '{ print $4 }' | cut -d '/' -f2)
-       broadcast=$(ip -4 -o a show "$iface" | awk '{ print $6 }')
-       route=$(ip -4 -o r show dev "$iface" | awk '{ print $1 }' | cut -d '/' -f1)
-       routemask=$(ip -4 -o r show dev "$iface" | awk '{ print $1 }' | cut -d '/' -f2)
-       routesrc=$(ip -4 -o r show dev "$iface" | awk '{ print $7 }')
-
-       [ -z "$ipaddr" ] && {
-               echo "interface $iface does not have ip address"
-               proto_notify_error "$cfg" NO_IPADDRESS
-               return 1
-       }
-
-       proto_init_update "$iface" 1
-       [ -n "$ipaddr" ] && proto_add_ipv4_address "$ipaddr" "$netmask" "$broadcast" ""
-       [ -n "$route" ] && proto_add_ipv4_route "$route" "$routemask" "" "$routesrc" ""
-       proto_send_update "$cfg"
-}
-
-proto_cni_teardown() {
-       local cfg="$1"
-       return 0
-}
-
-[ -n "$INCLUDE_ONLY" ] || {
-       add_protocol cni
-}
index eab3c8e70f5626d29d4db1713962dcee3f7250d0..c1c57904f71b124bb8b9a6fb7e6b5583be9ae426 100644 (file)
@@ -5,12 +5,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=croc
-PKG_VERSION:=9.6.5
+PKG_VERSION:=9.6.6
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/schollz/croc/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=2d3ba7bae3c49e3870e2f8523c6be00e92fe6e46828269a8cea34d4034102cad
+PKG_HASH:=9dd954e0068df2be416c71161665bfc283f150d30ba0bf96cee723701e93616f
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE
index 554669592bdc8fa2c1601b54ee0dde0a47e21601..48a0ac9e9bf27d1a962ea9bb8dc043497f7c95ff 100644 (file)
@@ -6,12 +6,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=crowdsec
-PKG_VERSION:=1.5.4
+PKG_VERSION:=1.5.5
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/crowdsecurity/crowdsec/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=afa4021f77e9cb87d7fd11cd86146770836dc15cad1ae8a4edce1314b14be98a
+PKG_HASH:=ec7b2815405be4c3a1c9c3dcb1110030c29b7408dbf2a82d25537843c8831329
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE
index 61ceef8632f2a26c5e76efc3d25414c59542ca26..607152a1c7d863297a56575751b5958d39960926 100644 (file)
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=ddns-scripts
 PKG_VERSION:=2.8.2
-PKG_RELEASE:=41
+PKG_RELEASE:=42
 
 PKG_LICENSE:=GPL-2.0
 
index 499f272031600aeea61ab2b184f860dba4188cdb..0d474051eed323380031de020d8cf33bfd4723b7 100644 (file)
 ENDPOINT="route53.amazonaws.com"
 RECORD_TTL=300
 RECORD_NAME="${lookup_host}."
+RECORD_VALUE="${__IP}"
 [ ${use_ipv6} -eq 0 ] && RECORD_TYPE="A"
 [ ${use_ipv6} -eq 1 ] && RECORD_TYPE="AAAA"
-RECORD_VALUE="${LOCAL_IP}"
+
 HOSTED_ZONE_ID="${domain}"
 API_PATH="/2013-04-01/hostedzone/${HOSTED_ZONE_ID}/rrset/"
 
diff --git a/net/dhtd/Makefile b/net/dhtd/Makefile
new file mode 100644 (file)
index 0000000..390ca02
--- /dev/null
@@ -0,0 +1,44 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dhtd
+PKG_VERSION:=0.2.5
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://codeload.github.com/mwarning/dhtd/tar.gz/v$(PKG_VERSION)?
+PKG_HASH:=0e239c969400537fda549b74f0555bddc2f1fe4ab3c00abe539970dfefab6599
+
+PKG_MAINTAINER:=Moritz Warning <moritzwarning@web.de>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/dhtd
+  SECTION:=net
+  CATEGORY:=Network
+  SUBMENU:=IP Addresses and Names
+  TITLE:=DHT Daemon
+  URL:=https://github.com/mwarning/dhtd
+endef
+
+define Package/dhtd/description
+  Standalone BitTorrent DHT daemon. Lookup and announce
+  hash identifiers via command line interface.
+endef
+
+MAKE_FLAGS += FEATURES="cli lpd"
+
+define Package/dhtd/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/build/dhtd $(1)/usr/bin/
+       $(LN) /usr/bin/dhtd $(1)/usr/bin/dhtd-ctl
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) files/dhtd.init $(1)/etc/init.d/dhtd
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_CONF) files/dhtd.config $(1)/etc/config/dhtd
+endef
+
+$(eval $(call BuildPackage,dhtd))
diff --git a/net/dhtd/files/dhtd.config b/net/dhtd/files/dhtd.config
new file mode 100644 (file)
index 0000000..e933e65
--- /dev/null
@@ -0,0 +1,34 @@
+##
+## DHTd is a distributed hash table daemon that uses the BitTorrent network.
+##
+
+config dhtd
+       option enabled 1
+
+## Add hashes to announce them to the network
+#      list announce '00112233445566778899aabbcceeff0011223344'
+
+## Load and store good nodes every 24h and on start/shutdown.
+#      option peerfile '/etc/dhtd/peers.txt'
+
+## Add static peer addresses.
+       list peer 'bttracker.debian.org:6881'
+       list peer 'router.bittorrent.com:6881'
+
+## Execute a script for each result
+#      option execute '/root/on_result.sh'
+
+## Bind the DHT to this port.
+#      option port '6881'
+
+## Limit DHT communication to this interface.
+#      option ifname 'lan'
+
+## Verbosity: quiet, verbose or debug
+#      option verbosity 'quiet'
+
+## Disable multicast peer discovery on the LAN.
+#      option lpd_disable '1'
+
+## Path for dhtd-cli to connect to.
+#      option cli_path '/tmp/dhtd.sock'
diff --git a/net/dhtd/files/dhtd.init b/net/dhtd/files/dhtd.init
new file mode 100755 (executable)
index 0000000..a3b1552
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/sh /etc/rc.common
+
+START=95
+USE_PROCD=1
+PROG=/usr/bin/dhtd
+OPTS=""
+
+
+boot() {
+       # Wait for the loopback interface to be ready
+       ubus -t 30 wait_for network.interface network.loopback 2>/dev/null
+       rc_procd start_service
+}
+
+xappend() {
+       local name="$2" value="$1"
+       OPTS="$OPTS\n--${name//_/-} ${value//'/\\'}"
+}
+
+append_opts_list() {
+       local name cfg="$1"; shift
+       for name in $*; do
+               config_list_foreach "$cfg" "$name" xappend "$name"
+       done
+}
+
+append_opts() {
+       local name value cfg="$1"; shift
+       for name in $*; do
+               config_get value "$cfg" "$name"
+               [ -n "$value" ] && xappend "$value" "$name"
+       done
+}
+
+append_opts_boolean() {
+       local name value cfg="$1"; shift
+       for name in $*; do
+               config_get_bool value "$cfg" "$name" 0
+               [ $value -gt 0 ] && xappend '' $name
+       done
+}
+
+section_enabled() {
+       config_get_bool enabled "$1" 'enabled' 0
+       [ $enabled -gt 0 ]
+}
+
+start_instance() {
+       local cfg="$1"
+       local CONFIG_FILE=/tmp/dhtd.${cfg}.conf
+
+       section_enabled "$cfg" || return
+       . /lib/functions/network.sh
+
+       OPTS=""
+
+       append_opts "$cfg" verbosity peerfile port execute
+
+       config_get ifname "$cfg" "ifname"
+       if network_get_device IFNAME "$ifname";then
+               xappend "$IFNAME" "ifname"
+       else
+               [ -n "$ifname" ] && xappend "$ifname" "ifname"
+       fi
+
+       append_opts_list "$cfg" announce peer
+
+       append_opts_boolean "$cfg" lpd_disable ipv4 ipv6
+
+       # Close stdin when command line interface is present
+       if [ $($PROG --version | grep -c cli) -eq 1 ]; then
+               xappend "" "cli_disable_stdin"
+       fi
+
+       echo -e "$OPTS" > $CONFIG_FILE
+
+       procd_open_instance
+       procd_set_param command $PROG
+       procd_set_param file $CONFIG_FILE
+       procd_set_param stderr 1
+       procd_set_param stdout 1
+       procd_append_param command --config $CONFIG_FILE
+       procd_close_instance
+}
+
+stop_instance() {
+       local cfg="$1"
+       local CONFIG_FILE=/tmp/dhtd.${cfg}.conf
+
+       rm -f $CONFIG_FILE
+}
+
+add_interface_trigger() {
+       local ifname
+
+       config_get ifname "$1" ifname
+
+       [ -n "$ifname" ] && procd_add_interface_trigger "interface.*" "$ifname" /etc/init.d/dhtd restart
+}
+
+service_triggers() {
+       procd_add_reload_trigger "dhtd"
+
+       config_load dhtd
+       config_foreach add_interface_trigger dhtd
+}
+
+start_service() {
+       config_load 'dhtd'
+       config_foreach start_instance 'dhtd'
+}
+
+stop_service() {
+       config_load 'dhtd'
+       config_foreach stop_instance 'dhtd'
+}
index 10dd9316c9f38704250fef5c523e0237479359eb..1a8a6441d5f053fdbc766fcbfeaa864a98ac0032 100644 (file)
@@ -5,12 +5,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=dnsproxy
-PKG_VERSION:=0.56.2
-PKG_RELEASE:=2
+PKG_VERSION:=0.59.1
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/dnsproxy/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=b20a77e88567fbcb80a07faa0f47aee7446b4d32ee7c17036fbdf07c03f05e3a
+PKG_HASH:=151616e2562b9bc8de85725293b264e7769d84fe1cd462e74be6fdc8505b0cbb
 
 PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
 PKG_LICENSE:=Apache-2.0
diff --git a/net/external-protocol/Makefile b/net/external-protocol/Makefile
new file mode 100644 (file)
index 0000000..2123060
--- /dev/null
@@ -0,0 +1,87 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=external-protocol
+PKG_VERSION:=20231119
+PKG_RELEASE:=1
+
+PKG_MAINTAINER:=Oskari Rauta <oskari.rauta@gmail.com>
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/external-protocol
+  SECTION:=net
+  CATEGORY:=Network
+  TITLE:=externally managed protocol
+  PKGARCH:=all
+endef
+
+define Package/external-protocol/description
+  external protocol is a general protocol for assisting
+  setup of many virtual devices that lack proper
+  protocol support in openwrt. Such as netavark, cni and
+  netbird for example. External protocol is supposed
+  to be managed with external software, not directly.
+
+  external protocol works automaticly on the background
+  and sets up netifd details when interface comes up or
+  goes down. This allows one to easily add interface to
+  a firewall zone.
+
+  as a example use case, podman, with network where it's
+  internal firewall and portmapper are disabled, control
+  of firewalling, whether it was exposing ports or
+  limiting/accepting access between networks, such as
+  lan can be made through openwrt's own firewalling
+  configuration if you used external protocol.
+
+  podman example configuration could be as following:
+    - lan network: 10.0.0.0/16 (255.255.0.0)
+    - container network: 10.129.0.1/24 (255.255.255.0)
+
+  Add a network configuration for your container network
+  using external protocol. Then create firewall zone for it.
+
+  You could create a new container/pod with static ip
+  address 10.129.0.2 (as 10.129.0.1 as container network's
+  gateway).
+
+  Easily define permissions so that local networks can
+  connect to container network, but not the other way around.
+  Also you want to allow forwarding from/to wan.
+
+  Now, as container cannot access local dns, make a rule for
+  your firewall to accept connections from container network
+  to port 53 (dns).
+
+  Now all you have to do, is make redirects to your firewall
+  and point them to 10.129.0.2 and connections from wan are
+  redirectered to containers/pods.
+
+  external protocol also works for other applications as
+  well that are using veth/tun/etc devices and don't have
+  a hand-tailored protocol available, such as vpn service
+  netbird.
+
+  Protocol has 3 settings: device, searchdomain and delay.
+  Sometimes polling interfaces takes some time, and in
+  that case you might want to add few seconds to delay.
+  Otherwise, it can be excluded from configuration.
+  Option for searchdomain is also completely optional.
+
+  package was previously known as cni protocol but as
+  it can be used on so many other things, naming became
+  mis-leading and it was renamed to external protocol.
+endef
+
+define Build/Configure
+endef
+
+define Build/Compile
+endef
+
+define Package/external-protocol/install
+       $(INSTALL_DIR) $(1)/lib/netifd/proto
+       $(INSTALL_BIN) ./files/external.sh $(1)/lib/netifd/proto/external.sh
+endef
+
+$(eval $(call BuildPackage,external-protocol))
diff --git a/net/external-protocol/files/external.sh b/net/external-protocol/files/external.sh
new file mode 100755 (executable)
index 0000000..5326159
--- /dev/null
@@ -0,0 +1,141 @@
+#!/bin/sh
+
+[ -n "$INCLUDE_ONLY" ] || {
+       . /lib/functions.sh
+       . ../netifd-proto.sh
+       init_proto "$@"
+}
+
+proto_external_init_config() {
+       no_device=0
+       available=0
+
+       proto_config_add_string "device:device"
+       proto_config_add_string "searchdomain"
+       proto_config_add_int "delay"
+}
+
+proto_external_setup() {
+       local cfg="$1"
+       local iface="$2"
+       local device searchdomain delay
+
+       json_get_vars device searchdomain delay
+
+       [ -n "$device" ] || {
+               echo "External protocol interface is not specified"
+               proto_notify_error "$cfg" NO_DEVICE
+               proto_set_available "$cfg" 0
+               return 1
+       }
+
+       [ -n "$delay" ] && sleep "$delay"
+
+       [ -L "/sys/class/net/${iface}" ] || {
+               echo "External protocol interface $iface is not present"
+               proto_notify_error "$cfg" NO_DEVICE
+               proto_set_available "$cfg" 0
+               return 1
+       }
+
+       IP4ADDRS=
+       IP6ADDRS=
+
+       local addresses="$(ip -json address list dev "$iface")"
+       json_init
+       json_load "{\"addresses\":${addresses}}"
+
+       if json_is_a addresses array; then
+               json_select addresses
+               json_select 1
+
+               if json_is_a addr_info array; then
+                       json_select addr_info
+
+                       local i=1
+                       while json_is_a ${i} object; do
+                               json_select ${i}
+                               json_get_vars scope family local prefixlen broadcast
+
+                               if [ "${scope}" == "global" ]; then
+                                       case "${family}" in
+                                               inet)
+                                                       append IP4ADDRS "$local/$prefixlen/$broadcast/"
+                                                       ;;
+
+                                               inet6)
+                                                       append IP6ADDRS "$local/$prefixlen/$broadcast///"
+                                                       ;;
+                                       esac
+                               fi
+
+                               json_select ..
+                               i=$(( i + 1 ))
+                       done
+               fi
+       fi
+
+       IP4ROUTES=
+       IP6ROUTES=
+
+       local routes="$(ip -json route list dev "$iface")"
+       json_init
+       json_load "{\"routes\":${routes}}"
+
+       if json_is_a routes array;then
+               json_select routes
+
+               local i=1
+               while json_is_a ${i} object; do
+                       json_select ${i}
+                       json_get_vars dst gateway metric prefsrc
+
+                       case "${dst}" in
+                               *:*/*)
+                                       append IP6ROUTES "$dst/$gateway/$metric///$prefsrc"
+                                       ;;
+                               *.*/*)
+                                       append IP4ROUTES "$dst/$gateway/$metric///$prefsrc"
+                                       ;;
+                               *:*)
+                                       append IP6ROUTES "$dst/128/$gateway/$metric///$prefsrc"
+                                       ;;
+                               *.*)
+                                       append IP4ROUTES "$dst/32/$gateway/$metric///$prefsrc"
+                                       ;;
+                       esac
+
+                       json_select ..
+                       i=$(( i + 1 ))
+               done
+       fi
+
+       [ -z "${IP4ADDRS}" -a -z "${IP6ADDRS}" ] && {
+               echo "interface $iface does not have ip address"
+               proto_notify_error "$cfg" NO_IPADDRESS
+               return 1
+       }
+
+       proto_init_update "$iface" 1
+
+       PROTO_IPADDR="${IP4ADDRS}"
+       PROTO_IP6ADDR="${IP6ADDRS}"
+
+       PROTO_ROUTE="${IP4ROUTES}"
+       PROTO_ROUTE6="${IP6ROUTES}"
+
+       [ -n "$searchdomain" ] && proto_add_dns_search "$searchdomain"
+
+       echo "$iface is up"
+
+       proto_send_update "$cfg"
+}
+
+proto_external_teardown() {
+       local cfg="$1"
+       return 0
+}
+
+[ -n "$INCLUDE_ONLY" ] || {
+       add_protocol external
+}
index 77568e908353674fca8d246125d6ba65b97f53c7..fba0a11df237fc4e5f0b2f7b73105ec4fd0be98b 100644 (file)
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fail2ban
 PKG_VERSION:=0.11.2
-PKG_RELEASE:=8
+PKG_RELEASE:=9
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/fail2ban/fail2ban/tar.gz/$(PKG_VERSION)?
diff --git a/net/fail2ban/patches/101-move-global-groups-to-start-of-expression-python-3.11-compat.patch b/net/fail2ban/patches/101-move-global-groups-to-start-of-expression-python-3.11-compat.patch
new file mode 100644 (file)
index 0000000..bd50c17
--- /dev/null
@@ -0,0 +1,44 @@
+From 7e2ab36d86998575853150c0a57de5e22518cf66 Mon Sep 17 00:00:00 2001
+From: sebres <info@sebres.de>
+Date: Tue, 21 Jun 2022 16:55:57 +0200
+Subject: [PATCH] move global groups to start of expression (python 3.11
+ compat)
+
+[remove change to regex not in 0.11.2]
+Signed-off-by: Jeffery To <jeffery.to@gmail.com>
+---
+ fail2ban/client/fail2banregex.py | 2 +-
+ fail2ban/server/datetemplate.py  | 8 ++++++++
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+--- a/fail2ban/server/datetemplate.py
++++ b/fail2ban/server/datetemplate.py
+@@ -35,6 +35,7 @@ logSys = getLogger(__name__)
+ # check already grouped contains "(", but ignores char "\(" and conditional "(?(id)...)":
+ RE_GROUPED = re.compile(r'(?<!(?:\(\?))(?<!\\)\((?!\?)')
+ RE_GROUP = ( re.compile(r'^((?:\(\?\w+\))?\^?(?:\(\?\w+\))?)(.*?)(\$?)$'), r"\1(\2)\3" )
++RE_GLOBALFLAGS = re.compile(r'((?:^|(?!<\\))\(\?[a-z]+\))')
+ RE_EXLINE_NO_BOUNDS = re.compile(r'^\{UNB\}')
+ RE_EXLINE_BOUND_BEG = re.compile(r'^\{\^LN-BEG\}')
+@@ -110,6 +111,11 @@ class DateTemplate(object):
+               # because it may be very slow in negative case (by long log-lines not matching pattern)
+               regex = regex.strip()
++              # cut global flags like (?iu) from RE in order to pre-set it after processing:
++              gf = RE_GLOBALFLAGS.search(regex)
++              if gf:
++                      regex = RE_GLOBALFLAGS.sub('', regex, count=1)
++              # check word boundaries needed:
+               boundBegin = wordBegin and not RE_NO_WRD_BOUND_BEG.search(regex)
+               boundEnd = wordEnd and not RE_NO_WRD_BOUND_END.search(regex)
+               # if no group add it now, should always have a group(1):
+@@ -135,6 +141,8 @@ class DateTemplate(object):
+                       self.flags |= DateTemplate.LINE_END
+               # remove possible special pattern "**" in front and end of regex:
+               regex = RE_DEL_WRD_BOUNDS[0].sub(RE_DEL_WRD_BOUNDS[1], regex)
++              if gf: # restore global flags:
++                      regex = gf.group(1) + regex
+               self._regex = regex
+               logSys.log(7, '  constructed regex %s', regex)
+               self._cRegex = None
diff --git a/net/fail2ban/patches/102-wrap-global-flags-to-local-flags-if-supported-by-RE-engine-in-the-python-version.patch b/net/fail2ban/patches/102-wrap-global-flags-to-local-flags-if-supported-by-RE-engine-in-the-python-version.patch
new file mode 100644 (file)
index 0000000..5a677c1
--- /dev/null
@@ -0,0 +1,36 @@
+From 4337e366163278815ea9fc6c952bffb579e885a0 Mon Sep 17 00:00:00 2001
+From: sebres <info@sebres.de>
+Date: Tue, 21 Jun 2022 16:56:57 +0200
+Subject: [PATCH] wrap global flags like ((?i)xxx) or (?:(?i)xxx) to local
+ flags (?i:xxx) if supported by RE-engine in the python version
+
+---
+ fail2ban/server/failregex.py | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/fail2ban/server/failregex.py
++++ b/fail2ban/server/failregex.py
+@@ -91,6 +91,13 @@ R_MAP = {
+       "port": "fport",
+ }
++# map global flags like ((?i)xxx) or (?:(?i)xxx) to local flags (?i:xxx) if supported by RE-engine in this python version:
++try:
++      re.search("^re(?i:val)$", "reVAL")
++      R_GLOB2LOCFLAGS = ( re.compile(r"(?<!\\)\((?:\?:)?(\(\?[a-z]+)\)"), r"\1:" )
++except:
++      R_GLOB2LOCFLAGS = ()
++
+ def mapTag2Opt(tag):
+       tag = tag.lower()
+       return R_MAP.get(tag, tag)
+@@ -128,6 +135,9 @@ class Regex:
+               #
+               if regex.lstrip() == '':
+                       raise RegexException("Cannot add empty regex")
++              # special handling wrapping global flags to local flags:
++              if R_GLOB2LOCFLAGS:
++                      regex = R_GLOB2LOCFLAGS[0].sub(R_GLOB2LOCFLAGS[1], regex)
+               try:
+                       self._regexObj = re.compile(regex, re.MULTILINE if multiline else 0)
+                       self._regex = regex
index 4a97b841455bcd1858021f85bbf8ccc31876362c..6939f85f4268b664b829ae3c74dc2e2e4d3719f3 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=freeradius3
 PKG_VERSION:=3.0.26
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 
 PKG_SOURCE:=freeradius-server-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://github.com/FreeRADIUS/freeradius-server/releases/download/release_$(subst .,_,$(PKG_VERSION))/
@@ -63,7 +63,7 @@ endef
 define Package/freeradius3-common
   $(call Package/freeradius3/Default)
   TITLE:=common files
-  DEPENDS:=+USE_GLIBC:libpthread +USE_GLIBC:libbsd +FREERADIUS3_OPENSSL:libopenssl +libcap +libpcap +libncurses +libpcre2 +libreadline +libtalloc +libatomic
+  DEPENDS:=+USE_GLIBC:libpthread +USE_GLIBC:libbsd +FREERADIUS3_OPENSSL:libopenssl +libcap +libpcap +libncurses +libreadline +libtalloc +libatomic
 endef
 
 define Package/freeradius3-default
@@ -499,6 +499,7 @@ CONFIGURE_ARGS+= \
        --with-radacctdir=/var/db/radacct \
        --with-logdir=/var/log \
        --without-edir \
+       --without-pcre \
        --without-snmp \
        --without-rlm_cache \
        --without-rlm_cache_memcached \
index 6fca78e9c9b94eff41e9bbf2cd210ded0f695d10..98b429d0df97d7396f409d3f7a12133beb86599b 100644 (file)
@@ -47,14 +47,17 @@ CONFIGURE_ARGS += \
        --$(if $(CONFIG_GENSIO_GLIB),with,without)-glib \
        --$(if $(CONFIG_GENSIO_TCL),with,without)-tcl \
        --without-afskmdm \
-       --without-ax25 \
        --without-alsa \
+       --without-ax25 \
+       --without-cm108gpio \
+       --without-dnssd \
        --without-go \
        --without-ipmisol \
        --without-kiss \
        --without-openipmi \
        --without-portaudio \
        --without-sound \
+       --without-udev \
        --with-cplusplus \
        --with-flock-locking \
        --with-uucp-locking \
@@ -74,6 +77,9 @@ CONFIGURE_VARS += \
        PYTHON_LIBS="$(shell $(STAGING_DIR)/host/bin/$(PYTHON3)-config --ldflags) -l${PYTHON3}" \
        PYTHON_CPPFLAGS="$(shell $(STAGING_DIR)/host/bin/$(PYTHON3)-config --includes)" \
        PYTHON="$(STAGING_DIR_HOSTPKG)/bin/$(PYTHON3)"
+
+MAKE_VARS += \
+       PYTHON_LIBS="$(shell $(STAGING_DIR)/host/bin/$(PYTHON3)-config --ldflags) -l${PYTHON3}"
 else
 CONFIGURE_ARGS += \
        --without-python \
diff --git a/net/gensio/patches/0001-Ensure-that-ax_python_devel_found-is-defined.patch b/net/gensio/patches/0001-Ensure-that-ax_python_devel_found-is-defined.patch
new file mode 100644 (file)
index 0000000..a21d516
--- /dev/null
@@ -0,0 +1,30 @@
+From 6bbc3056c4b9192010d888672d97810609ee23f9 Mon Sep 17 00:00:00 2001
+From: Michael Heimpold <mhei@heimpold.de>
+Date: Sat, 18 Nov 2023 21:46:15 +0100
+Subject: [PATCH] Ensure that $ax_python_devel_found is defined
+
+Otherwise in case of --without-python, it triggers an error like:
+-snip-
+...
+checking consistency of all components of python development environment... yes
+./configure: line 23729: test: =: unary operator expected
+...
+-snap-
+
+Signed-off-by: Michael Heimpold <mhei@heimpold.de>
+---
+ configure.ac | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/configure.ac
++++ b/configure.ac
+@@ -1997,6 +1997,9 @@ if test "x$trypython" = "xyes"; then
+       PYTHON_CPPFLAGS="$pythoncflags"
+    fi
+    AX_PYTHON_DEVEL([], [true])
++   ax_python_devel_found=yes
++else
++   ax_python_devel_found=no
+ fi
+ if test $ax_python_devel_found = yes; then
+    AX_PROG_PYTHON_VERSION([3.0.0],
diff --git a/net/gensio/patches/0002_ax_python_devel-fix-serial.patch b/net/gensio/patches/0002_ax_python_devel-fix-serial.patch
new file mode 100644 (file)
index 0000000..211f692
--- /dev/null
@@ -0,0 +1,11 @@
+--- a/m4/ax_python_devel.m4
++++ b/m4/ax_python_devel.m4
+@@ -72,7 +72,7 @@
+ #   modified version of the Autoconf Macro, you may extend this special
+ #   exception to the GPL to apply to your modified version as well.
+-#serial 34
++#serial 35
+ AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
+ AC_DEFUN([AX_PYTHON_DEVEL],[
diff --git a/net/gensio/patches/0003-Revert-ax_pkg_swig.m4-to-latest-vanilla-version.patch b/net/gensio/patches/0003-Revert-ax_pkg_swig.m4-to-latest-vanilla-version.patch
new file mode 100644 (file)
index 0000000..fb13df9
--- /dev/null
@@ -0,0 +1,144 @@
+From f53fc85ee9734dd21447ea3438b7ba1edcd1bcf8 Mon Sep 17 00:00:00 2001
+From: Michael Heimpold <mhei@heimpold.de>
+Date: Tue, 21 Nov 2023 23:27:45 +0100
+Subject: [PATCH] Revert ax_pkg_swig.m4 to latest vanilla version
+
+And instead of extending the macro, we can use the already
+create variable 'available_swig_vernum' to compare the
+required version number.
+
+Signed-off-by: Michael Heimpold <mhei@heimpold.de>
+---
+ configure.ac      | 26 ++++++++++++--------------
+ m4/ax_pkg_swig.m4 | 20 +++++++++-----------
+ 2 files changed, 21 insertions(+), 25 deletions(-)
+
+--- a/configure.ac
++++ b/configure.ac
+@@ -1956,21 +1956,19 @@ AC_CHECK_LIB(nsl, main, [HAVE_LIBNSL=1;
+ SWIG_DIR=
+ SWIG_CPP_DIR=
+ SWIG=
+-SWIG_NUMVERSION=0
++available_swig_vernum=0
+ if test "x$tryswig" = "xyes"; then
+    if test "x$swigprog" != "x"; then
+       SWIG="$swigprog"
+    fi
+-   AX_PKG_SWIG([1.3.21])
+-   if test "x$SWIG" != "x"; then
+-      AC_DEFINE([HAVE_SWIG], [], [Have swig installed])
+-      SWIG_DIR=swig
+-      if test $SWIG_NUMVERSION -ge 40100; then
+-          SWIG_CPP_DIR=swig
+-      else
+-          AC_MSG_WARN([SWIG version >= 4.1.0 is required for C++ swig.])
+-      fi
+-   fi
++   AX_PKG_SWIG(4.1.0,
++        [
++            AC_DEFINE([HAVE_SWIG], [], [Have swig installed])
++            SWIG_DIR=swig
++            SWIG_CPP_DIR=swig
++        ], [
++            AC_MSG_WARN([SWIG version >= 4.1.0 is required for C++ swig.])
++        ])
+ fi
+ AC_SUBST(SWIG_DIR)
+ AC_SUBST(SWIG_CPP_DIR)
+@@ -2055,7 +2053,7 @@ AC_SUBST(PYTHON_UNDEF_LIBS)
+ PYTHON_EXECUTABLE="${PYTHON}"
+ AC_SUBST(PYTHON_EXECUTABLE)
+-if test $SWIG_NUMVERSION -ge 40100 -a "${enable_shared}" = yes; then
++if test $available_swig_vernum -ge 40100 -a "${enable_shared}" = yes; then
+    trygo=yes
+ else
+    trygo=no
+@@ -2076,7 +2074,7 @@ AC_ARG_WITH(go,
+    fi,
+ )
+-if test $trygo = yes -a $SWIG_NUMVERSION -lt 40100; then
++if test $trygo = yes -a $available_swig_vernum -lt 40100; then
+    AC_MSG_ERROR([Go enabled, but swig version must be >= 4.1.0 for that])
+ fi
+ GODIR=
+@@ -2363,7 +2361,7 @@ pr_op  "  shared libraries:      " $enable_sh
+ pr_op  "  sctp sendv:         " $ac_cv_lib_sctp_sctp_sendv
+ pr_vop "  python:             " "$ax_python_version"
+ if test "$SWIG_CPP_DIR" = "swig"; then
+-  prrw "  swig:                       " "$SWIG_NUMVERSION"
++  prrw "  swig:                       " "$available_swig_vernum"
+ else
+   prrw "  swig:                       " "no"
+ fi
+--- a/m4/ax_pkg_swig.m4
++++ b/m4/ax_pkg_swig.m4
+@@ -19,11 +19,6 @@
+ #   1.3.17), AX_PKG_SWIG checks that the swig package is this version number
+ #   or higher.
+ #
+-#   If successful, SWIG_NUMVERSION is set to a numeric value for the
+-#   version found in the format NNnnpp where NN is the major version,
+-#   nn is the minor version, and pp is the patch version.  This is
+-#   easy to directly compare with a number.
+-#
+ #   As usual, action-if-found is executed if SWIG is found, otherwise
+ #   action-if-not-found is executed.
+ #
+@@ -41,6 +36,8 @@
+ #   Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
+ #   Copyright (c) 2008 Andrew Collier
+ #   Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
++#   Copyright (c) 2018 Reini Urban <rurban@cpan.org>
++#   Copyright (c) 2021 Vincent Danjean <Vincent.Danjean@ens-lyon.org>
+ #
+ #   This program is free software; you can redistribute it and/or modify it
+ #   under the terms of the GNU General Public License as published by the
+@@ -68,14 +65,16 @@
+ #   modified version of the Autoconf Macro, you may extend this special
+ #   exception to the GPL to apply to your modified version as well.
+-#serial 13
++#serial 15
+ AC_DEFUN([AX_PKG_SWIG],[
+         # Find path to the "swig" executable.
+         AC_PATH_PROGS([SWIG],[swig swig3.0 swig2.0])
+         if test -z "$SWIG" ; then
+                 m4_ifval([$3],[$3],[:])
+-        elif test -n "$1" ; then
++        elif test -z "$1" ; then
++                m4_ifval([$2],[$2],[:])
++      else
+                 AC_MSG_CHECKING([SWIG version])
+                 [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
+                 AC_MSG_RESULT([$swig_version])
+@@ -86,12 +85,12 @@ AC_DEFUN([AX_PKG_SWIG],[
+                         if test -z "$required_major" ; then
+                                 [required_major=0]
+                         fi
+-                        [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
++                        [required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
+                         [required_minor=`echo $required | sed 's/[^0-9].*//'`]
+                         if test -z "$required_minor" ; then
+                                 [required_minor=0]
+                         fi
+-                        [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
++                        [required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
+                         [required_patch=`echo $required | sed 's/[^0-9].*//'`]
+                         if test -z "$required_patch" ; then
+                                 [required_patch=0]
+@@ -126,10 +125,9 @@ AC_DEFUN([AX_PKG_SWIG],[
+                                 m4_ifval([$3],[$3],[])
+                         else
+                                 AC_MSG_CHECKING([for SWIG library])
+-                                SWIG_LIB=`$SWIG -swiglib | tail -1`
++                                SWIG_LIB=`$SWIG -swiglib | tr '\r\n' '  '`
+                                 AC_MSG_RESULT([$SWIG_LIB])
+                                 m4_ifval([$2],[$2],[])
+-                                SWIG_NUMVERSION=$available_swig_vernum
+                         fi
+                 else
+                         AC_MSG_WARN([cannot determine SWIG version])
index 182f51718cee3897c0fef5ae7723170ba9bba8d2..4cc22bd92b5816428826755875b9e68f4bd5e92e 100644 (file)
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=haproxy
-PKG_VERSION:=2.8.3
-PKG_RELEASE:=2
+PKG_VERSION:=2.8.4
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://www.haproxy.org/download/2.8/src
-PKG_HASH:=9ecc6ffe67a977d1ed279107bbdab790d73ae2a626bc38eee23fa1f6786a759e
+PKG_HASH:=81bacbf50ec6d0f7ecaaad7c03e59978b00322fbdad6ed4a989dd31754b6f25d
 
 PKG_MAINTAINER:=Thomas Heil <heil@terminal-consulting.de>, \
                Christian Lachner <gladiac@gmail.com>
index 8f4d9e0aff712cf644932c800781963a1340d8e5..97665fc03089d750a3c3045a81f709c33fbb65ce 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 CLONEURL=https://git.haproxy.org/git/haproxy-2.8.git
-BASE_TAG=v2.8.3
+BASE_TAG=v2.8.4
 TMP_REPODIR=tmprepo
 PATCHESDIR=patches
 
index 022f03c52ae6d8ecfca5b3b82f661a1bf358ef0f..c05bd5fda2de5e523c0ed38049d5c9915f64fb4b 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=hcxdumptool
-PKG_VERSION:=6.2.4
+PKG_VERSION:=6.3.2
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/zerbea/hcxdumptool/tar.gz/$(PKG_VERSION)?
-PKG_HASH:=cadeb4b2f00da3a1df65cb53080e134f201ef73825d35049110764faf699028d
+PKG_HASH:=1f6fe2b4757a5f20adeb6cc469693b4d0e8c49ba290450e10a37699d9f9a2a42
 
 PKG_MAINTAINER:=Andreas Nilsen <adde88@gmail.com>
 PKG_LICENSE:=MIT
diff --git a/net/hcxdumptool/patches/010-openssl.patch b/net/hcxdumptool/patches/010-openssl.patch
deleted file mode 100644 (file)
index 6e2b04f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
---- a/hcxdumptool.c
-+++ b/hcxdumptool.c
-@@ -571,10 +571,6 @@ if(rebootflag == true)
-               }
-       }
--EVP_cleanup();
--CRYPTO_cleanup_all_ex_data();
--ERR_free_strings();
--
- if(errorcount != 0) exit(EXIT_FAILURE);
- if(totflag == true) exit(USER_EXIT_TOT);
- exit(EXIT_SUCCESS);
-@@ -7777,8 +7773,6 @@ return true;
- /*===========================================================================*/
- static inline bool tlsinit()
- {
--SSL_load_error_strings();
--OpenSSL_add_ssl_algorithms();
- if((tlsctx = SSL_CTX_new(SSLv23_server_method())) == NULL)
-       {
-       fprintf(stderr, "OpenSSl can't create SSL context\n");
-@@ -7797,7 +7791,6 @@ if(SSL_CTX_use_PrivateKey_file(tlsctx, e
- if((eaptlsctx = (eaptlsctx_t*)malloc(EAPTLSCTX_SIZE)) == NULL) return false;
- memset(eaptlsctx, 0, EAPTLSCTX_SIZE);
- SSL_CTX_set_session_cache_mode(tlsctx, SSL_SESS_CACHE_OFF);
--SSL_CTX_set_ecdh_auto(tlsctx, 1);
- SSL_CTX_set_verify(tlsctx, (SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE), eap_tls_clientverify_cb);
- #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- SSL_CTX_set_min_proto_version(tlsctx, TLS1_VERSION);
-@@ -7872,8 +7865,6 @@ if(gpiostatusled > 0)
-       }
--ERR_load_crypto_strings();
--OpenSSL_add_all_algorithms();
- opensslversion = OpenSSL_version_num();
- opensslversionmajor = (opensslversion & 0x10000000L) >> 28;
- opensslversionminor = (opensslversion & 0x01100000L) >> 20;
index 36e7d95013e397183fd26aed7816707a6884b534..c829806e9d52cb67cbb957b1b1163d84b3379da3 100644 (file)
@@ -8,18 +8,19 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=hcxtools
-PKG_VERSION:=6.2.4
+PKG_VERSION:=6.3.2
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/zerbea/hcxtools/tar.gz/$(PKG_VERSION)?
-PKG_HASH:=74299313dd15ed38f07b42201903ab85ebbc3ad220a01fff1bd5c967cfea817d
+PKG_HASH:=555e46a59df6a77c5aa73b99ffa8c1e84fa79e24ffaf5180de1d3a7f4ab7a470
 
 PKG_MAINTAINER:=Andreas Nilsen <adde88@gmail.com>
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=license.txt
 
 include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/meson.mk
 
 define Package/hcxtools
   SECTION:=net
@@ -35,27 +36,17 @@ define Package/hcxtools/description
   for the use with latest hashcat or John the Ripper.
 endef
 
-define Build/Compile
-       $(MAKE) -C $(PKG_BUILD_DIR)/ \
-               $(TARGET_CONFIGURE_OPTS) \
-               CFLAGS="$(TARGET_CFLAGS)"
-endef
-
 define Package/hcxtools/install
-       $(INSTALL_DIR) $(1)/sbin
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxeiutool      $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxessidtool    $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxhash2cap     $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxhashcattool  $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxhashtool     $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxmactool      $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxpcapngtool   $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxpmkidtool    $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxpmktool      $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxpsktool      $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/hcxwltool       $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/whoismac        $(1)/sbin/
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/wlancap2wpasec  $(1)/sbin/
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxeiutool            $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxhash2cap           $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxhashtool           $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxpcapngtool         $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxpmktool            $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxpsktool            $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/hcxwltool             $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/whoismac              $(1)/usr/bin/
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/wlancap2wpasec        $(1)/usr/bin/
 endef
 
 $(eval $(call BuildPackage,hcxtools))
diff --git a/net/hcxtools/patches/010-openssl.patch b/net/hcxtools/patches/010-openssl.patch
deleted file mode 100644 (file)
index 9122368..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
---- a/hcxhashtool.c
-+++ b/hcxhashtool.c
-@@ -107,9 +107,6 @@ static void closelists()
- {
- if(hashlist != NULL) free(hashlist);
- if(ouilist != NULL) free(ouilist);
--EVP_cleanup();
--CRYPTO_cleanup_all_ex_data();
--ERR_free_strings();
- return;
- }
- /*===========================================================================*/
-@@ -128,8 +125,6 @@ eapolwrittencount = 0;
- essidwrittencount = 0;
- hccapxwrittencount = 0;
- hccapwrittencount = 0;
--ERR_load_crypto_strings();
--OpenSSL_add_all_algorithms();
- if((hashlist = (hashlist_t*)calloc(hashlistcount, HASHLIST_SIZE)) == NULL) return false;
- if((ouilist = (ouilist_t*)calloc(ouilistcount, OUILIST_SIZE)) == NULL) return false;
- return true;
---- a/hcxpcapngtool.c
-+++ b/hcxpcapngtool.c
-@@ -366,9 +366,6 @@ if(eapmschapv2msglist != NULL) free(eapm
- if(eapmschapv2hashlist != NULL) free(eapmschapv2hashlist);
- if(tacacsplist != NULL) free(tacacsplist);
--EVP_cleanup();
--CRYPTO_cleanup_all_ex_data();
--ERR_free_strings();
- return;
- }
- /*===========================================================================*/
-@@ -377,8 +374,6 @@ static bool initlists()
- static unsigned long opensslversion;
- static const char nastring[] = { "N/A" };
--ERR_load_crypto_strings();
--OpenSSL_add_all_algorithms();
- opensslversion = OpenSSL_version_num();
- opensslversionmajor = (opensslversion & 0x10000000L) >> 28;
- opensslversionminor = (opensslversion & 0x01100000L) >> 20;
---- a/hcxpmktool.c
-+++ b/hcxpmktool.c
-@@ -923,8 +923,6 @@ while((auswahl = getopt_long(argc, argv,
-               }
-       }
--ERR_load_crypto_strings();
--OpenSSL_add_all_algorithms();
- printf("\n");
- if((essidstring != NULL) && (pskstring != NULL) && (pmkstring == NULL) && (hashlinestring == NULL))
-       {
-@@ -956,9 +954,6 @@ else if((essidstring != NULL) && (pskstr
-       }
- printf("\n");
--EVP_cleanup();
--CRYPTO_cleanup_all_ex_data();
--ERR_free_strings();
- return EXIT_SUCCESS;
- }
- /*===========================================================================*/
---- a/hcxpsktool.c
-+++ b/hcxpsktool.c
-@@ -63,8 +63,6 @@ essidglen = 32;
- t = time(NULL);
- tm = localtime(&t);
- thisyear = tm->tm_year +1900;
--ERR_load_crypto_strings();
--OpenSSL_add_all_algorithms();
- return;
- }
- /*===========================================================================*/
-@@ -2832,10 +2830,6 @@ if(pskname != NULL)
-       fclose(fhpsk);
-       }
--EVP_cleanup();
--CRYPTO_cleanup_all_ex_data();
--ERR_free_strings();
--
- return EXIT_SUCCESS;
- }
- /*===========================================================================*/
index e66f8e5bd54dcb4ad8428eaa8763194992250352..69b6bbe8783e3e2faf9c5106543d82260862518e 100644 (file)
@@ -2,13 +2,14 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=https-dns-proxy
 PKG_VERSION:=2023-10-25
-PKG_RELEASE:=1
+PKG_RELEASE:=4
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL:=https://github.com/aarond10/https_dns_proxy/
 PKG_SOURCE_DATE:=$(PKG_VERSION)
 PKG_SOURCE_VERSION:=977341a4e35a37ee454e97e82caf4276b1b4961a
 PKG_MIRROR_HASH:=8622846f1038ac05436a48d9b36a07c516cbb6504ce68e7ee8c5529788fac39b
+
 PKG_MAINTAINER:=Stan Grishin <stangri@melmac.ca>
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE
index 5679f6349890094e4709041008737cbe688cd487..c9e38cca9ae7def6f7bcdde77f03730a6c6034f3 100755 (executable)
@@ -30,10 +30,11 @@ readonly canaryDomainsiCloud='mask.icloud.com mask-h2.icloud.com'
 
 on_boot_trigger=
 
-str_contains() { [ -n "$1" ] &&[ -n "$2" ] && [ "${1//$2}" != "$1" ]; }
+dnsmasq_restart() { [ -x /etc/init.d/dnsmasq ] || return 1; /etc/init.d/dnsmasq restart >/dev/null 2>&1; }
 is_mac_address() { expr "$1" : '[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]$' >/dev/null; }
 is_ipv4() { expr "$1" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null; }
 is_ipv6() { ! is_mac_address "$1" && str_contains "$1" ":"; }
+is_resolver_working() { resolveip -t 3 one.one.one.one >/dev/null 2>&1; }
 output() {
        local msg memmsg logmsg
        local sharedMemoryOutput="/dev/shm/$packageName-output"
@@ -52,6 +53,7 @@ output_ok() { output "$_OK_"; }
 output_okn() { output "${_OK_}\\n"; }
 output_fail() { output "$_FAIL_"; }
 output_failn() { output "${_FAIL_}\\n"; }
+str_contains() { [ -n "$1" ] &&[ -n "$2" ] && [ "${1//$2}" != "$1" ]; }
 uci_add_list_if_new() {
        local PACKAGE="$1"
        local CONFIG="$2"
@@ -70,9 +72,6 @@ uci_changes() {
        local OPTION="$3"
        /sbin/uci ${UCI_CONFIG_DIR:+-c $UCI_CONFIG_DIR} changes "$PACKAGE${CONFIG:+.$CONFIG}${OPTION:+.$OPTION}"
 }
-
-dnsmasq_restart() { [ -x /etc/init.d/dnsmasq ] || return 1; /etc/init.d/dnsmasq restart >/dev/null 2>&1; }
-
 version() { echo "$PKG_VERSION"; }
 
 xappend() { PROG_param="$PROG_param $1"; }
@@ -131,13 +130,11 @@ append_bootstrap() {
        [ "$ipv6_resolvers_only" -eq 0 ] && xappend '-4'
 }
 
-resolver_health_check() { resolveip -t 3 one.one.one.one >/dev/null 2>&1; }
-
 boot() {
        ubus -t 30 wait_for network.interface 2>/dev/null
        on_boot_trigger=1
-       rc_procd start_service 'on_boot' && rc_procd service_started 'on_boot'
-       resolver_health_check || rc_procd stop_service 'on_boot'
+       rc_procd start_service 'on_boot' && service_started 'on_boot'
+       is_resolver_working || { rc_procd stop_service 'on_boot' && service_stopped 'on_boot'; }
 }
 
 start_instance() {
@@ -203,7 +200,8 @@ start_instance() {
        procd_close_data
        procd_close_instance
 
-       if [ "$?" ]; then
+# shellcheck disable=SC2181
+       if [ "$?" -eq 0 ]; then
                config_get listen_addr "$cfg" 'listen_addr' '127.0.0.1'
                config_get listen_port "$cfg" 'listen_port' "$port"
                if [ "$dnsmasq_config_update" = '*' ]; then
index d34621793548545371dcbf6a8ac5fefb650f2349..8f3b9dfa24e0ab441db6b75468802d1fd1e96c5f 100644 (file)
@@ -5,7 +5,7 @@
    return SW_VERSION;
  #else
 -  return "2023.10.10-atLeast";  // update date sometimes, like 1-2 times a year
-+  return "2023-10-25-1";  // update date sometimes, like 1-2 times a year
++  return "2023-10-25-4";  // update date sometimes, like 1-2 times a year
  #endif
  }
  
index fa41fd54535f3966e20c6e5dd8fe3abb7b6cf631..2bd9275cb926264879d8eb878a8f6e8b9356af7e 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=iperf
 PKG_VERSION:=3.15
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://downloads.es.net/pub/iperf
@@ -46,6 +46,7 @@ $(call Package/iperf3/default)
   TITLE+= with iperf_auth support
   VARIANT:=ssl
   DEPENDS:=+libopenssl
+  CONFLICTS:=iperf3
 endef
 
 define Package/libiperf3
index 729564d429034c57d4f58726c4b9014bdd275a6e..606f16c5121d9561cd4c70306d2dc4737812b2a8 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=netbird
-PKG_VERSION:=0.23.9
+PKG_VERSION:=0.24.2
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/netbirdio/netbird/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=1b037f35d3e426d8cbeba17e4d89d12265cd7e6fbd7c975ce552293e468db35a
+PKG_HASH:=7fd90c6004c7fde6393bd618e106410e708f2d84f7884055acda6b016be42858
 
 PKG_MAINTAINER:=Oskari Rauta <oskari.rauta@gmail.com>
 PKG_LICENSE:=BSD-3-Clause
@@ -33,10 +33,10 @@ define Package/netbird
 endef
 
 define Package/netbird/description
-  NetBird is an open-source VPN management platform built on top of WireGuard® making it easy to create 
+  NetBird is an open-source VPN management platform built on top of WireGuard® making it easy to create
   secure private networks for your organization or home.
 
-  It requires zero configuration effort leaving behind the hassle of opening ports, complex firewall rules, VPN 
+  It requires zero configuration effort leaving behind the hassle of opening ports, complex firewall rules, VPN
   gateways, and so forth.
 endef
 
@@ -44,6 +44,12 @@ define Package/netbird/conffiles
 /etc/netbird/config.json
 endef
 
+# Workaround for musl 1.2.4 compability in mattn/go-sqlite3
+# https://github.com/mattn/go-sqlite3/issues/1164
+ifneq ($(CONFIG_USE_MUSL),)
+       TARGET_CFLAGS += -D_LARGEFILE64_SOURCE
+endif
+
 define Package/netbird/install
        $(call GoPackage/Package/Install/Bin,$(PKG_INSTALL_DIR))
        $(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d
index b7ccd2d4b253e70b3c5a96a704ec6ba7d857e3e8..87427c4061c2041588d7cf16003944066e972971 100755 (executable)
@@ -1,11 +1,19 @@
 #!/bin/sh /etc/rc.common
 
+. /lib/netifd/netifd-proto.sh
+
 START=99
 STOP=10
 
 USE_PROCD=1
 
+service_triggers() {
+       procd_add_interface_trigger "interface.*" "wan" /etc/init.d/netbird restart
+}
+
 start_service() {
+       local device
+
        procd_open_instance
        procd_set_param command /usr/bin/netbird
        procd_append_param command service run
index 8f79f2b10b861c797a608c686b0772c1250c6c24..903af60d23b18a040c5094020497a03313c6b8a8 100644 (file)
@@ -9,14 +9,14 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=openvpn
 
-PKG_VERSION:=2.6.6
+PKG_VERSION:=2.6.8
 PKG_RELEASE:=1
 
 PKG_SOURCE_URL:=\
        https://build.openvpn.net/downloads/releases/ \
        https://swupdate.openvpn.net/community/releases/
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_HASH:=3b074f392818b31aa529b84f76e8b5e4ad03fca764924f46d906bceaaf421034
+PKG_HASH:=5ede1565c8a6d880100f7f235317a7ee9eea83d5052db5547f13a9e76af7805d
 
 PKG_MAINTAINER:=Magnus Kroken <mkroken@gmail.com>
 
index c54277006d067044bba9d131ffb8dcc9f839664a..6ac30df594743d1db6d2793830c70c0c91bb0835 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/openvpn/ssl_mbedtls.c
 +++ b/src/openvpn/ssl_mbedtls.c
-@@ -1535,7 +1535,7 @@ const char *
+@@ -1533,7 +1533,7 @@ const char *
  get_ssl_library_version(void)
  {
      static char mbedtls_version[30];
index 0a45ea49e535a000bab28e2f611f4de8402ba46b..e5b103bc59d460ec76e7210d02f6e2c04dc4501d 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/openvpn/crypto_openssl.c
 +++ b/src/openvpn/crypto_openssl.c
-@@ -51,7 +51,7 @@
+@@ -49,7 +49,7 @@
  #include <openssl/rand.h>
  #include <openssl/ssl.h>
  
@@ -9,8 +9,8 @@
  #include <openssl/kdf.h>
  #endif
  #if OPENSSL_VERSION_NUMBER >= 0x30000000L
-@@ -1436,7 +1436,7 @@ engine_load_key(const char *file, SSL_CT
- #endif /* if HAVE_OPENSSL_ENGINE */
+@@ -1374,7 +1374,7 @@ memcmp_constant_time(const void *a, cons
+     return CRYPTO_memcmp(a, b, size);
  }
  
 -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
index f0e7361f2565b27285cd669a90bc1b19bcd5ce11..50834b3bb77c0e59078b0622631534041f8630b2 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/openvpn/ssl_openssl.c
 +++ b/src/openvpn/ssl_openssl.c
-@@ -1351,7 +1351,7 @@ err:
+@@ -1347,7 +1347,7 @@ err:
      return 0;
  }
  
@@ -9,7 +9,7 @@
  
  /* called when EC_KEY is destroyed */
  static void
-@@ -1512,7 +1512,7 @@ tls_ctx_use_management_external_key(stru
+@@ -1508,7 +1508,7 @@ tls_ctx_use_management_external_key(stru
              goto cleanup;
          }
      }
index 30e1822a1ce2a2e583cea60a2c83a9c477753592..690521ee649d73219a70bbd05a11c4797b62fe39 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/openvpn/ssl_verify_openssl.c
 +++ b/src/openvpn/ssl_verify_openssl.c
-@@ -269,6 +269,9 @@ backend_x509_get_username(char *common_n
+@@ -267,6 +267,9 @@ backend_x509_get_username(char *common_n
              return FAILURE;
          }
      }
index f0820f378b104ecbca02a89c5d51f4c0a8024fab..0642c34597c86658a35060cd44c8ea1e086d6d27 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pdns-recursor
-PKG_VERSION:=4.9.1
+PKG_VERSION:=4.9.2
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://downloads.powerdns.com/releases/
-PKG_HASH:=0a1edc13e8f2bd661f39e316387d941e22de6a03b8a7a2fc662fdf8b942ea2be
+PKG_HASH:=4cb8180458ecfb528a3d9a34ba2844b6cd2ed69ca1c461dde24a0ebd66829144
 
 PKG_MAINTAINER:=Peter van Dijk <peter.van.dijk@powerdns.com>
 PKG_LICENCE:=GPL-2.0-only
@@ -35,7 +35,7 @@ define Package/pdns-recursor/description
 endef
 
 define Package/pdns-recursor/conffiles
-/etc/powerdns/pdns-recursor.conf
+/etc/powerdns/recursor.conf
 /etc/init.d/pdns-recursor
 endef
 
index 6c90f4f492b74153d6c020b74a47fd0659083e8d..4892a3e9b06949ba6c7d0b814e337db3a617c46c 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pptpd
 PKG_VERSION:=1.4.0
-PKG_RELEASE:=5
+PKG_RELEASE:=6
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=@SF/poptop
index 322eaaf1b5ef3f0db786a1caab4cc1ce41653429..ae39c0fd577ef432fee4e9a2355363bd73b14213 100644 (file)
@@ -18,11 +18,11 @@ validate_login_section() {
 
 validate_pptpd_section() {
        uci_load_validate pptpd service "$1" "$2" \
-               'enabled:uinteger' \
+               'enabled:bool:1' \
                'localip:string' \
                'remoteip:string' \
                'mppe:list(string):required no40 no56 stateless' \
-               'logwtmp:uinteger'
+               'logwtmp:bool:0'
 }
 
 setup_login() {
diff --git a/net/quassel-irssi/Makefile b/net/quassel-irssi/Makefile
deleted file mode 100644 (file)
index 8b850be..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# Copyright (C) 2016 Ben Rosser <rosser.bjr@gmail.com>
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=quassel-irssi
-PKG_SOURCE_DATE:=2017-11-30
-PKG_SOURCE_VERSION:=079be662dde374a383646256108a4974c2bc7796
-PKG_RELEASE:=3
-
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_DATE).tar.gz
-PKG_SOURCE_URL:=https://codeload.github.com/phhusson/quassel-irssi/tar.gz/$(PKG_SOURCE_VERSION)?
-PKG_HASH:=c276a92a47f8edf5ae1d9db0e72a69d078f2f3f80e055853fc6d06099d898966
-PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_SOURCE_VERSION)
-
-PKG_MAINTAINER:=Ben Rosser <rosser.bjr@gmail.com>
-PKG_LICENSE:=GPL-3.0-or-later
-PKG_LICENSE_FILES:=core/COPYING
-
-PKG_BUILD_PARALLEL:=1
-PKG_INSTALL:=1
-
-include $(INCLUDE_DIR)/package.mk
-include $(INCLUDE_DIR)/nls.mk
-
-MAKE_PATH := core
-MAKE_VARS += SYSTEM_QUASSELC=1 IRSSI_CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" IRSSI_INCLUDE=$(STAGING_DIR)/usr/include/irssi
-
-define Package/quassel-irssi
-    SECTION:=net
-    CATEGORY:=Network
-    DEPENDS:=+irssi +quasselc
-    SUBMENU:=Instant Messaging
-    URL:=https://github.com/phhusson/quassel-irssi
-    TITLE:=An irssi plugin to connect to quassel core
-endef
-
-define Package/quassel-irssi/description
-  An irssi plugin that supports connecting to a quassel core.
-endef
-
-define Package/quassel-irssi/install
-       $(INSTALL_DIR) $(1)/usr/lib/irssi/modules/
-       $(CP) $(PKG_INSTALL_DIR)/usr/lib/irssi/modules/libquassel_core.so* $(1)/usr/lib/irssi/modules/
-endef
-
-$(eval $(call BuildPackage,quassel-irssi))
diff --git a/net/quassel-irssi/patches/001-respect-cflags.patch b/net/quassel-irssi/patches/001-respect-cflags.patch
deleted file mode 100644 (file)
index 291bed4..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
---- a/core/Makefile
-+++ b/core/Makefile
-@@ -3,7 +3,7 @@ DESTDIR ?=
- LIBDIR ?= /usr/lib
- #IRSSI_INCLUDE:=/home/phh/irssi-0.8.16-rc1.phh/
--IRSSI_INCLUDE:=/usr/include/irssi/
-+IRSSI_INCLUDE?=/usr/include/irssi/
- IRSSI_LIB?=$(DESTDIR)/$(LIBDIR)/irssi
- IRSSI_CFLAGS+=-I$(IRSSI_INCLUDE)/src/
- IRSSI_CFLAGS+=-I$(IRSSI_INCLUDE)/src/core/
-@@ -28,7 +28,7 @@ else
-     LDFLAGS += -lquasselc
- endif
--CFLAGS=-std=gnu11 -Wall -Wextra -Werror -g -O2 $(IRSSI_CFLAGS) $(QUASSELC_FLAGS) -Wmissing-prototypes -Wmissing-declarations
-+CFLAGS+=-std=gnu11 -Wall -Wextra -g $(IRSSI_CFLAGS) $(QUASSELC_FLAGS) -Wmissing-prototypes -Wmissing-declarations
- CFLAGS += $(SSL_CFLAGS)
- LDFLAGS+= $(SSL_LDLAGS)
diff --git a/net/quassel-irssi/patches/002-use-cc-var.patch b/net/quassel-irssi/patches/002-use-cc-var.patch
deleted file mode 100644 (file)
index aa73850..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/core/Makefile
-+++ b/core/Makefile
-@@ -49,7 +49,7 @@ irssi/network-openssl.o: CFLAGS:=$(IRSSI
- quasselc-connector.o: CFLAGS:=$(CFLAGS)
- $(TARGET): $(OBJECTS)
--      gcc -shared $^ -o $@ -lz $(LDFLAGS)
-+      $(CC) -shared $^ -o $@ -lz $(LDFLAGS)
- install: $(TARGET)
-       $(INSTALL) -d $(IRSSI_LIB)/modules
diff --git a/net/quassel-irssi/patches/003-use-pkgconfig-ldflags-quasselc.patch b/net/quassel-irssi/patches/003-use-pkgconfig-ldflags-quasselc.patch
deleted file mode 100644 (file)
index ddf313a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/core/Makefile
-+++ b/core/Makefile
-@@ -25,7 +25,7 @@ ifndef SYSTEM_QUASSELC
-     QUASSELC_FLAGS:=-Ilib
- else
-     QUASSELC_FLAGS:=$(shell pkg-config --cflags quasselc)
--    LDFLAGS += -lquasselc
-+    LDFLAGS += $(shell pkg-config --libs quasselc)
- endif
- CFLAGS+=-std=gnu11 -Wall -Wextra -g $(IRSSI_CFLAGS) $(QUASSELC_FLAGS) -Wmissing-prototypes -Wmissing-declarations
diff --git a/net/quassel-irssi/patches/010-Get-compatible-with-potential-irssi-abi-8-and-drop-p.patch b/net/quassel-irssi/patches/010-Get-compatible-with-potential-irssi-abi-8-and-drop-p.patch
deleted file mode 100644 (file)
index 5c84128..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-From 19e810405789a35b92026b56ea49d01a3f544b07 Mon Sep 17 00:00:00 2001
-From: Pierre-Hugues Husson <phh@phh.me>
-Date: Tue, 17 Jan 2017 23:09:24 +0100
-Subject: [PATCH] Get compatible with potential irssi abi 8, and drop polling
-
----
- core/Makefile      |  1 -
- core/quassel-net.c | 64 ++++++++++++++++++++++++++++++++++++++--------
- 2 files changed, 53 insertions(+), 10 deletions(-)
-
---- a/core/Makefile
-+++ b/core/Makefile
-@@ -16,7 +16,6 @@ SSL_CFLAGS=$(shell pkg-config --cflags o
- SSL_LDLAGS=$(shell pkg-config --libs openssl)
- OBJECTS:=quasselc-connector.o quassel-core.o
- OBJECTS+=quassel-net.o quassel-msgs.o quassel-cmds.o
--OBJECTS+=irssi/network-openssl.o
- OBJECTS+=quassel-fe-window.o quassel-fe-level.o quassel-cfg.o
- LDFLAGS ?=
---- a/core/quassel-net.c
-+++ b/core/quassel-net.c
-@@ -132,10 +132,10 @@ static SERVER_REC* quassel_server_init_c
-       ret->got = 0;
-       server_connect_ref(SERVER_CONNECT(conn));
--      if(conn->use_ssl) {
-+      if(conn->use_tls) {
-               ret->ssl = 1;
-       }
--      ret->connrec->use_ssl = 0;
-+      ret->connrec->use_tls = 0;
-       ret->channels_join = quassel_irssi_channels_join;
-       ret->send_message = quassel_irssi_send_message;
-@@ -161,12 +161,59 @@ void quassel_net_init(CHAT_PROTOCOL_REC*
-       signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
- }
--GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_REC *server);
-+static void quassel_net_final_setup(SERVER_REC* server, GIOChannel *handle) {
-+      quassel_login(handle, server->connrec->nick, server->connrec->password);
-+      server->handle->handle = handle;
-+
-+      server->readtag =
-+              g_input_add(handle,
-+                          G_INPUT_READ,
-+                          (GInputFunction) quassel_parse_incoming, server);
-+}
-+
-+static void quassel_net_ssl_callback(SERVER_REC *server, GIOChannel *handle) {
-+      int error;
-+
-+      g_return_if_fail(IS_SERVER(server));
-+
-+      error = irssi_ssl_handshake(handle);
-+      if (error == -1) {
-+              server->connection_lost = TRUE;
-+              server_connect_failed(server, NULL);
-+              return;
-+      }
-+      if (error & 1) {
-+              if (server->connect_tag != -1)
-+                      g_source_remove(server->connect_tag);
-+              server->connect_tag = g_input_add(handle, error == 1 ? G_INPUT_READ : G_INPUT_WRITE,
-+                                                (GInputFunction)
-+                                                quassel_net_ssl_callback,
-+                                                server);
-+              return;
-+      }
-+
-+      if (server->connect_tag != -1) {
-+              g_source_remove(server->connect_tag);
-+              server->connect_tag = -1;
-+      }
-+
-+      quassel_net_final_setup(server, handle);
-+}
-+
- void quassel_irssi_init_ack(void *arg) {
-       Quassel_SERVER_REC *server = (Quassel_SERVER_REC*)arg;
--      if(!server->ssl)
--              goto login;
--      GIOChannel* ssl_handle = irssi_ssl_get_iochannel(server->handle->handle, 1337, SERVER(server));
-+      GIOChannel* ssl_handle = net_start_ssl((SERVER_REC*)server);
-+
-+      if(server->readtag != -1) {
-+              g_source_remove(server->readtag);
-+              server->readtag = -1;
-+      }
-+
-+      if(!server->ssl) {
-+              quassel_net_final_setup((SERVER_REC*)server, server->handle->handle);
-+              return;
-+      }
-+
-       int error;
-       //That's polling, and that's really bad...
-       while( (error=irssi_ssl_handshake(ssl_handle)) & 1) {
-@@ -175,10 +222,7 @@ void quassel_irssi_init_ack(void *arg) {
-                       return;
-               }
-       }
--      server->handle->handle = ssl_handle;
--
--login:
--      quassel_login(server->handle->handle, server->connrec->nick, server->connrec->password);
-+      quassel_net_ssl_callback((SERVER_REC*)server, ssl_handle);
- }
- void quassel_irssi_init_nack(void *arg) {
index 229dc2e6704ff2a7051605536d4b7e8b970ac9df..5d491c3226f513b1f19ebaa12b39b799895f14d0 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=sing-box
-PKG_VERSION:=1.6.0
+PKG_VERSION:=1.6.6
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=3272c9ac447d009749429f38d76e9879609c0c321442c3235ba806d995c0838a
+PKG_HASH:=88c8825f6e8af2e46a16e8a85ceb5e1c7c0795b59cad93c8327288ec7b8249e0
 
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_LICENSE_FILES:=LICENSE
index 33b879777c5d13349b865a41cb5bc3268b1c4836..5e452d18031207580be5dcdefb8e417daea7f929 100644 (file)
@@ -6,12 +6,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=snort3
-PKG_VERSION:=3.1.73.0
-PKG_RELEASE:=1
+PKG_VERSION:=3.1.74.0
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://github.com/snort3/snort3/archive/refs/tags/
-PKG_HASH:=d04edf07e9b695fb22de73f0987537d35b4c8466119940e39a056d1a13888b27
+PKG_HASH:=4a4529e74bc202303c0330ae8b2317f0bef3ac92ae7216df8cfedfce24ddd129
 
 PKG_MAINTAINER:=W. Michael Petullo <mike@flyn.org>
 PKG_LICENSE:=GPL-2.0-only
diff --git a/net/snort3/patches/010-gcc13.patch b/net/snort3/patches/010-gcc13.patch
new file mode 100644 (file)
index 0000000..4bfaee1
--- /dev/null
@@ -0,0 +1,14 @@
+--- a/src/network_inspectors/packet_capture/packet_capture.h
++++ b/src/network_inspectors/packet_capture/packet_capture.h
+@@ -20,9 +20,10 @@
+ #ifndef PACKET_CAPTURE_H
+ #define PACKET_CAPTURE_H
++#include <cstdint>
+ #include <string>
+-void packet_capture_enable(const std::string&, const int16_t g = -1);
++void packet_capture_enable(const std::string&, const std::int16_t g = -1);
+ void packet_capture_disable();
+ #endif
index 7010fba520d4e58fbff8f4447048d0baed71e6ca..8d7ff0738c2375e7a78b02d37e145cf741c686a1 100644 (file)
@@ -8,17 +8,19 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=sstp-client
-PKG_VERSION:=1.0.15
+PKG_VERSION:=1.0.19
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=@SF/sstp-client/$(PKG_VERSION)
-PKG_HASH:=8484aa51fbfbe418a0ebad58ad20a8ee1c46ed71f800be18bcd23b42e6baad64
+PKG_SOURCE_URL:=https://gitlab.com/sstp-project/sstp-client/-/archive/1.0.19/
+PKG_HASH:=e2652365f69f5037102e78f4e115ff764a390b27bb3fd513a8a50b10a61bb613
 
 PKG_MAINTAINER:=Federico Di Marco <fededim@gmail.com>
 PKG_LICENSE:=GPL-2.0-or-later
 PKG_LICENSE_FILES:=COPYING
 
+PKG_FIXUP:=autoreconf
+
 include $(INCLUDE_DIR)/package.mk
 
 define Package/sstp-client
index 3d2eb9462c991076c981266b35e4fc440a3df970..a9d5683eac1e8b2a5c652ddafa05cd3352069277 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/sstp-client.c
 +++ b/src/sstp-client.c
-@@ -542,6 +542,7 @@ static status_t sstp_init_ssl(sstp_clien
+@@ -546,6 +546,7 @@ static status_t sstp_init_ssl(sstp_clien
      int retval = SSTP_FAIL;
      int status = 0;
  
@@ -8,7 +8,7 @@
      /* Initialize the OpenSSL library */
      status = SSL_library_init();
      if (status != 1)
-@@ -555,6 +556,9 @@ static status_t sstp_init_ssl(sstp_clien
+@@ -575,6 +576,9 @@ static status_t sstp_init_ssl(sstp_clien
  
      /* Create a new crypto context */
      client->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
index d175b4c4b8edae5a17417b26c8e4d58b2cefb0eb..15fdedcab3e0c9889b9081cc788b193ccf1e4c42 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=strongswan
-PKG_VERSION:=5.9.11
-PKG_RELEASE:=2
+PKG_VERSION:=5.9.12
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=https://download.strongswan.org/ https://download2.strongswan.org/
-PKG_HASH:=ddf53f1f26ad26979d5f55e8da95bd389552f5de3682e35593f9a70b2584ed2d
+PKG_HASH:=5e6018b07cbe9f72c044c129955a13be3e2f799ceb53f53a4459da6a922b95e5
 PKG_LICENSE:=GPL-2.0-or-later
 PKG_MAINTAINER:=Philip Prindeville <philipp@redfish-solutions.com>, Noel Kuntze <noel.kuntze@thermi.consulting>
 PKG_CPE_ID:=cpe:/a:strongswan:strongswan
index dcc065d2ea1b07fc957f24e8684e424315714984..289e7ff567aa17c986212fb297306426cd691f16 100644 (file)
@@ -244,6 +244,7 @@ config_child() {
        local lifebytes
        local rekeypackets
        local lifepackets
+       local replay_window
 
        config_get startaction "$conf" startaction "route"
        config_get local_nat "$conf" local_nat ""
@@ -262,6 +263,7 @@ config_child() {
        config_get lifebytes "$conf" lifebytes ""
        config_get rekeypackets "$conf" rekeypackets ""
        config_get lifepackets "$conf" lifepackets ""
+       config_get replay_window "$conf" replay_window ""
 
        config_list_foreach "$conf" local_subnet append_var local_subnet ","
        config_list_foreach "$conf" remote_subnet append_var remote_subnet ","
@@ -370,6 +372,7 @@ config_child() {
 
        [ -n "$updown" ] && swanctl_xappend4 "updown = $updown"
        [ -n "$dpdaction" ] && swanctl_xappend4 "dpd_action = $dpdaction"
+       [ -n "$replay_window" ] && swanctl_xappend4 "replay_window = $replay_window"
 
         swanctl_xappend3 "}"
 }
index 4323cd56348af049165dc54584a47a966197efaa..91e6afbe2a889014b46439bd0c3da35bdaab4662 100644 (file)
@@ -48,7 +48,7 @@ Subject: [PATCH 900/904] src: Patch for building with musl on openwrt (taken
  #include <linux/rtnetlink.h>
 --- a/src/libstrongswan/library.h
 +++ b/src/libstrongswan/library.h
-@@ -120,6 +120,7 @@
+@@ -121,6 +121,7 @@
  #include "utils/leak_detective.h"
  #include "plugins/plugin_loader.h"
  #include "settings/settings.h"
index ded7b21a4f7531117579fbc1002ee27da5e9350f..b81138c564853f599f330ad2b57ae58a22fda92c 100644 (file)
@@ -26,7 +26,7 @@ Subject: [PATCH 904/904] gmpdh: Plugin that implements gmp DH functions in an
  ARG_DISBL_SET([curve25519],     [disable Curve25519 Diffie-Hellman plugin.])
  ARG_DISBL_SET([hmac],           [disable HMAC crypto implementation plugin.])
  ARG_DISBL_SET([kdf],            [disable KDF (prf+) implementation plugin.])
-@@ -1565,6 +1566,7 @@ ADD_PLUGIN([pkcs8],                [s ch
+@@ -1574,6 +1575,7 @@ ADD_PLUGIN([pkcs8],                [s ch
  ADD_PLUGIN([af-alg],               [s charon pki scripts medsrv attest nm cmd aikgen])
  ADD_PLUGIN([fips-prf],             [s charon nm cmd])
  ADD_PLUGIN([gmp],                  [s charon pki scripts manager medsrv attest nm cmd aikgen fuzz])
@@ -34,7 +34,7 @@ Subject: [PATCH 904/904] gmpdh: Plugin that implements gmp DH functions in an
  ADD_PLUGIN([curve25519],           [s charon pki scripts nm cmd])
  ADD_PLUGIN([agent],                [s charon nm cmd])
  ADD_PLUGIN([keychain],             [s charon cmd])
-@@ -1706,6 +1708,7 @@ AM_CONDITIONAL(USE_SHA3, test x$sha3 = x
+@@ -1716,6 +1718,7 @@ AM_CONDITIONAL(USE_SHA3, test x$sha3 = x
  AM_CONDITIONAL(USE_MGF1, test x$mgf1 = xtrue)
  AM_CONDITIONAL(USE_FIPS_PRF, test x$fips_prf = xtrue)
  AM_CONDITIONAL(USE_GMP, test x$gmp = xtrue)
@@ -42,7 +42,7 @@ Subject: [PATCH 904/904] gmpdh: Plugin that implements gmp DH functions in an
  AM_CONDITIONAL(USE_CURVE25519, test x$curve25519 = xtrue)
  AM_CONDITIONAL(USE_RDRAND, test x$rdrand = xtrue)
  AM_CONDITIONAL(USE_AESNI, test x$aesni = xtrue)
-@@ -1983,6 +1986,7 @@ AC_CONFIG_FILES([
+@@ -1996,6 +1999,7 @@ AC_CONFIG_FILES([
        src/libstrongswan/plugins/mgf1/Makefile
        src/libstrongswan/plugins/fips_prf/Makefile
        src/libstrongswan/plugins/gmp/Makefile
@@ -52,7 +52,7 @@ Subject: [PATCH 904/904] gmpdh: Plugin that implements gmp DH functions in an
        src/libstrongswan/plugins/aesni/Makefile
 --- a/src/libstrongswan/Makefile.am
 +++ b/src/libstrongswan/Makefile.am
-@@ -353,6 +353,13 @@ if MONOLITHIC
+@@ -357,6 +357,13 @@ if MONOLITHIC
  endif
  endif
  
index d787ee25d64a507fa3d05fa1f503c709dd569b7d..a1efec68610b856118ffe3c38cc58b31292e693d 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=tailscale
-PKG_VERSION:=1.50.1
+PKG_VERSION:=1.54.0
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/tailscale/tailscale/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=183a7d559590a759dd77aa9c2b65486ab6e13c26f3c07fad0b536e318ad5e233
+PKG_HASH:=c895a0f489706535ed400b0599d7d932d9eebc5f1bad2c236408a1e4b86620e7
 
 PKG_MAINTAINER:=Jan Pavlinec <jan.pavlinec1@gmail.com>
 PKG_LICENSE:=BSD-3-Clause
index 45b9ceb310bbeaac04edad9e2224f5b44d1b69cb..ef0bf2779b3bc11d835f22ed004b761aa2ea1468 100644 (file)
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=travelmate
 PKG_VERSION:=2.1.1
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
 
diff --git a/net/travelmate/files/hreward.login b/net/travelmate/files/hreward.login
new file mode 100755 (executable)
index 0000000..01342a1
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+# captive portal auto-login script for H-Reward Hotelss
+# This is free software, licensed under the GNU General Public License v3.
+
+# set (s)hellcheck exceptions
+# shellcheck disable=1091,2039,3040
+#
+#
+# Username and password can be passed to the script, to get fast wifi
+# If not provided, the option with the slower wifi will be selected
+
+
+. "/lib/functions.sh"
+
+
+export LC_ALL=C
+export PATH="/usr/sbin:/usr/bin:/sbin:/bin"
+
+
+# From https://stackoverflow.com/a/17336953/819367 converted to sh
+rawurlencode() {
+  string="$1"
+  strlen=${#string}
+  encoded=""
+  pos=0
+  c=""
+  o=""
+
+  while [ $pos -lt $strlen ]; do
+    c=$(expr substr "$string" $((pos + 1)) 1)
+    case "$c" in
+      [-_.~a-zA-Z0-9] ) o="${c}" ;;
+      * )               o=$(printf '%%%02x' "'$c")
+    esac
+    encoded="${encoded}${o}"
+    pos=$((pos + 1))
+  done
+
+  echo "${encoded}"
+}
+
+user=$(rawurlencode "${1}")
+password=$(rawurlencode "${2}")
+
+successUrl="https://hrewards.com/en"
+trm_useragent="$(uci_get travelmate global trm_useragent "Mozilla/5.0 (Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0")"
+trm_maxwait="$(uci_get travelmate global trm_maxwait "30")"
+
+set -e
+
+
+session_key="$(curl -sL --user-agent "${trm_useragent}" \
+                       --connect-timeout $((trm_maxwait / 6)) \
+                       "http://nossl.com/?cmd=redirect&arubalp=12345" \
+                        | awk -F 'name="session_key" value="' 'NF>1{split($2,a,"\""); print a[1]; exit}')"
+
+if [ -n "$user" ] && [ -n "$password" ]; then
+       response="$(curl -sL --user-agent "${trm_useragent}" \
+                       --connect-timeout $((trm_maxwait / 6)) \
+                       -w %{url_effective} \
+                       -o /dev/null \
+                       --header "Content-Type:application/x-www-form-urlencoded" \
+                       --data "session_key=${session_key}&accept_terms=1&email=${user}&password=${password}&password_reset_form_email=&password_update_form_password=&password_update_form_password_repeat=&room_number=&last_name=&voucher=" \
+                       "https://cp.deutschehospitality.com/aruba/login?lang=en")"
+else
+       response="$(curl -sL --user-agent "${trm_useragent}" \
+                       --connect-timeout $((trm_maxwait / 6)) \
+                       -w %{url_effective} \
+                       -o /dev/null \
+                       --header "Content-Type:application/x-www-form-urlencoded" \
+                       --data "session_key=${session_key}&email=&password=&accept_terms=1&password_reset_form_email=&password_update_form_password=&password_update_form_password_repeat=&room_number=&last_name=&voucher=" \
+                       "https://cp.deutschehospitality.com/aruba/skip-registration?lang=en")"
+fi
+
+if [ "$response" != "$successUrl" ]; then
+    exit 255
+fi
index 8f120d944147a9c6ca451ac43857019c3588b375..4e47aea6e6f3e442b771b956e7c2db4302e517ad 100644 (file)
@@ -1,7 +1,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=udp-broadcast-relay-redux
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 PKG_LICENSE:=GPL-2.0
 
 PKG_SOURCE_PROTO:=git
index 6694215885ee46f4fa646feec8b0278b1384de6f..cafa4efa4e1c4807e9674c540940bd240b73a730 100644 (file)
@@ -15,7 +15,8 @@ validate_section_udp_broadcast_relay_redux()
        'port:port' \
        'network:list(string)' \
        'src_override:ip4addr' \
-       'dest_override:ip4addr'
+       'dest_override:ip4addr' \
+       'multicast:ip4addr'
 
     [ -z "$id" ] && return 1
 
@@ -27,7 +28,7 @@ validate_section_udp_broadcast_relay_redux()
 }
 
 udp_broadcast_relay_redux_instance() {
-    local net network ifname id port src_override dest_override
+    local net network ifname id port src_override dest_override multicast
 
     validate_section_udp_broadcast_relay_redux "${1}" || {
        echo "Validation failed"
@@ -58,6 +59,10 @@ udp_broadcast_relay_redux_instance() {
         procd_append_param command "-t" "$dest_override"
     fi
 
+    if [ -n "$multicast" ] ; then
+        procd_append_param command "--multicast" "$multicast"
+    fi
+
     procd_add_jail ubr-${PIDCOUNT} cgroupsns
     procd_close_instance
 }
index f7164bd680942cf1d9f221709fa2b6be4962f96a..6ba4de2209a491f74ecdc585275534b5ae65942b 100644 (file)
@@ -4,3 +4,4 @@
 #       list network lan
 #       list network vpnsrv
 #       option dest_override 10.66.2.13
+#       option multicast 239.255.255.250
index d0cb41fac52eb6dae135839dcff5169e2227d5dc..3a7a27cbf7b681bdefe1bc1cad6d5c79a0a07bb9 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=unbound
-PKG_VERSION:=1.18.0
-PKG_RELEASE:=1
+PKG_VERSION:=1.19.0
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://nlnetlabs.nl/downloads/unbound
-PKG_HASH:=3da95490a85cff6420f26fae0b84a49f5112df1bf1b7fc34f8724f02082cb712
+PKG_HASH:=a97532468854c61c2de48ca4170de854fd3bc95c8043bb0cfb0fe26605966624
 
 PKG_MAINTAINER:=Eric Luehrsen <ericluehrsen@gmail.com>
 PKG_LICENSE:=BSD-3-Clause
index eae8dae9889e197fa4ff075a680488948db9bcb3..28f3c86dcf9fb66ae318f475c44c9cde7e54ed5d 100644 (file)
@@ -69,7 +69,7 @@ create_local_zone() {
 
 ##############################################################################
 
-create_host_record() {
+create_host_record_from_domain() {
   local cfg="$1"
   local ip name debug_ip
 
@@ -102,6 +102,35 @@ create_host_record() {
 
 ##############################################################################
 
+create_host_record_from_host() {
+  local cfg="$1"
+  local dns ip name
+
+  # basefiles dhcp "host" clause which means host A and PTR records
+  config_get dns  "$cfg" dns 0
+  config_get ip   "$cfg" ip
+  config_get name "$cfg" name
+
+
+  if [ -n "$name" ] && [ -n "$ip" ] && [ $dns -eq 1 ] ; then
+    case $name in
+      *.*)
+        # domain present, do nothing
+        ;;
+      *)
+        name="$name.$UB_TXT_DOMAIN"
+        ;;
+    esac
+
+
+    create_local_zone "$name"
+    DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $name.@@300@@IN@@A@@$ip"
+    DM_LIST_LOCAL_PTR="$DM_LIST_LOCAL_PTR $ip@@300@@$name"
+  fi
+}
+
+##############################################################################
+
 create_mx_record() {
   local cfg="$1"
   local domain relay pref record
@@ -215,7 +244,8 @@ dnsmasq_inactive() {
     # Parasite from the uci.dhcp.domain clauses
     DM_LIST_KNOWN_ZONES="$DM_LIST_KNOWN_ZONES $UB_TXT_DOMAIN"
     config_load dhcp
-    config_foreach create_host_record domain
+    config_foreach create_host_record_from_domain domain
+    config_foreach create_host_record_from_host host
 
 
     if [ $UB_D_EXTRA_DNS -gt 1 ] ; then
index f53962fcd45a3006a51084ffb2900aa1705da6d4..098f2785c40bb148624b4c777feb993f3c552af4 100644 (file)
@@ -3,7 +3,7 @@ Fix cross compile errors by inserting an environment variable for the
 target. Use "uname" on host only if "UNAME" variable is empty.
 --- a/configure.ac
 +++ b/configure.ac
-@@ -840,7 +840,7 @@ if test x_$ub_test_python != x_no; then
+@@ -842,7 +842,7 @@ if test x_$ub_test_python != x_no; then
     fi
  fi
  
index 68fbd4083ab6de808c5c279f9209212226af9050..21737dd37f112df3b94132aa98093d953b404937 100644 (file)
@@ -5,12 +5,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=v2ray-core
-PKG_VERSION:=5.11.0
+PKG_VERSION:=5.12.1
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/v2fly/v2ray-core/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=c25490d6b0600cd316409f112d39e10f5d7c66bb89f18dafcd3a95d26f889bc2
+PKG_HASH:=fa1845d42b46c6b5046a8f95d49cc7a9175e40efc5c13b95174b4c556567aca1
 
 PKG_LICENSE:=MIT
 PKG_LICENSE_FILES:=LICENSE
index 89e737b55b4b2b18d2c8d54632a6d81d290385e8..b61769c56d612e47784c8745fcb9cb994d01a2dc 100644 (file)
@@ -12,31 +12,31 @@ PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
 
 include $(INCLUDE_DIR)/package.mk
 
-GEOIP_VER:=202310120354
+GEOIP_VER:=202311160040
 GEOIP_FILE:=geoip.dat.$(GEOIP_VER)
 define Download/geoip
   URL:=https://github.com/v2fly/geoip/releases/download/$(GEOIP_VER)/
   URL_FILE:=geoip.dat
   FILE:=$(GEOIP_FILE)
-  HASH:=7107cfe4e211d4df5234d0d2b1c47bdcd19f6602c2b7969f3a5e12f7cf48692e
+  HASH:=fe44648629b12e4818eae1a9f703e83f02261e7dcc91b06edf531f343bf16170
 endef
 
-GEOSITE_VER:=20231015073627
+GEOSITE_VER:=20231118232758
 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
 define Download/geosite
   URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
   URL_FILE:=dlc.dat
   FILE:=$(GEOSITE_FILE)
-  HASH:=2042c47d520634236fbf238a4168196bea64a2d61ca5e6cbab9fd0ac37c7e659
+  HASH:=91844afa5918b0465b2ffaaf9ee35d09bffd0a2b47b669afdf77ff576262b048
 endef
 
-GEOSITE_IRAN_VER:=202310160024
+GEOSITE_IRAN_VER:=202311130025
 GEOSITE_IRAN_FILE:=iran.dat.$(GEOSITE_IRAN_VER)
 define Download/geosite-ir
   URL:=https://github.com/bootmortis/iran-hosted-domains/releases/download/$(GEOSITE_IRAN_VER)/
   URL_FILE:=iran.dat
   FILE:=$(GEOSITE_IRAN_FILE)
-  HASH:=70db057c5c1d07de251c4543e6c20ff0a352c95977e120d1522a7f826ff08cf2
+  HASH:=286b48d780010349ce759daba30a05e550ea7e3f45082026d2e5f53803223f90
 endef
 
 define Package/v2ray-geodata/template
index eec759a7b328fb6307214b505f11abad3ad318b0..8074bb9543f4a73a9b46c1e6a19bf9caf74f8515 100644 (file)
@@ -5,12 +5,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=v2rayA
-PKG_VERSION:=2.2.4
+PKG_VERSION:=2.2.4.1
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=844da2a4c1ac1f7eae02519a0833255a63938f08a554cbea043606b28ee6ebed
+PKG_HASH:=e0d8a2250f9933ca1d1efe023a7ec7d6d5f9a4d058a8a7270c457a8d1e0b4ab9
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/service
 
 PKG_LICENSE:=AGPL-3.0-only
@@ -59,7 +59,7 @@ define Download/v2raya-web
        URL:=https://github.com/v2rayA/v2rayA/releases/download/v$(PKG_VERSION)/
        URL_FILE:=web.zip
        FILE:=$(WEB_FILE)
-       HASH:=2699dacdf39137af408a9ffcb91734e5af487bef4dccaa51f1bb3de6c4d3e8fe
+       HASH:=76735aa46253dc29b9605798173fafc3ae545089e3da8090f76d6a3f65780e37
 endef
 
 define Build/Prepare
index 971a8a78de7ac9b9288f51774d5f4161caf98791..fb0f89a231d1587230fba3f22952cdb5941b9501 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=xray-core
-PKG_VERSION:=1.8.4
+PKG_VERSION:=1.8.6
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/XTLS/Xray-core/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=89f73107abba9bd438111edfe921603ddb3c2b631b2716fbdc6be78552f0d322
+PKG_HASH:=d828296c9f29f9e59a61ab73d44f072ab2a30fe979679e39aea43b33ddb7d6bf
 
 PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
 PKG_LICENSE:=MPL-2.0
index ed1cfcac3341f518bbaf1c2480f52b15c045547b..9c1606dabaac6b1b43c7f0fb7bda382a3c32a2d2 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pulseaudio
 PKG_VERSION:=16.1
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://freedesktop.org/software/pulseaudio/releases
@@ -122,7 +122,9 @@ MESON_ARGS += \
        -Dx11=disabled \
        -Dadrian-aec=true \
        -Dwebrtc-aec=disabled \
-        -Ddoxygen=false
+        -Ddoxygen=false \
+        -Dtcpwrap=disabled \
+        -Dbluez5-gstreamer=disabled 
 
 ifeq ($(BUILD_VARIANT),avahi)
 MESON_ARGS += \
diff --git a/sound/shairplay/Makefile b/sound/shairplay/Makefile
deleted file mode 100644 (file)
index 0b303da..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Copyright (C) 2014-2016 OpenWrt.org
-#
-# This is free software, licensed under the GNU General Public License v2.
-# See /LICENSE for more information.
-#
-
-include $(TOPDIR)/rules.mk
-
-PKG_NAME:=shairplay
-PKG_SOURCE_DATE:=2018-08-24
-PKG_SOURCE_VERSION:=096b61ad14c90169f438e690d096e3fcf87e504e
-PKG_RELEASE:=2
-
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_SOURCE_DATE).tar.gz
-PKG_SOURCE_URL:=https://codeload.github.com/juhovh/shairplay/tar.gz/$(PKG_SOURCE_VERSION)?
-PKG_HASH:=7e2b013ffe75ea2f13fb12b1aa38b8e2e8b1899ac292d57f05d7b352a3a181cf
-PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_SOURCE_VERSION)
-
-PKG_MAINTAINER:=Álvaro Fernández Rojas <noltari@gmail.com>
-PKG_LICENSE:=MIT
-PKG_LICENSE_FILES:=LICENSE
-
-PKG_FIXUP:=autoreconf
-PKG_BUILD_PARALLEL:=1
-
-include $(INCLUDE_DIR)/package.mk
-
-define Package/shairplay
-  SECTION:=sound
-  CATEGORY:=Sound
-  DEPENDS:=+libao +libavahi-compat-libdnssd +libltdl +libpthread
-  TITLE:=Shairplay
-endef
-
-define Package/shairplay/description
-  Free portable AirPlay server implementation similar to ShairPort.
-endef
-
-define Package/shairplay/conffiles
-/etc/config/shairplay
-endef
-
-define Package/shairplay/install
-       $(INSTALL_DIR) $(1)/usr/bin
-       $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/shairplay $(1)/usr/bin/
-       $(INSTALL_DIR) $(1)/usr/share/shairplay
-       $(INSTALL_DATA) $(PKG_BUILD_DIR)/airport.key $(1)/usr/share/shairplay/
-       $(INSTALL_DIR) $(1)/etc/init.d
-       $(INSTALL_BIN) files/shairplay.init $(1)/etc/init.d/shairplay
-       $(INSTALL_DIR) $(1)/etc/config
-       $(INSTALL_CONF) files/shairplay.config $(1)/etc/config/shairplay
-endef
-
-$(eval $(call BuildPackage,shairplay))
diff --git a/sound/shairplay/files/shairplay.config b/sound/shairplay/files/shairplay.config
deleted file mode 100644 (file)
index 6e1f939..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-config shairplay main
-       option disabled '1'
-       option respawn '1'
-       option apname 'AirPlay'
-       option port '5000'
-       option password ''
-       option hwaddr ''
-       option ao_driver 'oss'
-       option ao_devicename ''
-       option ao_deviceid ''
diff --git a/sound/shairplay/files/shairplay.init b/sound/shairplay/files/shairplay.init
deleted file mode 100644 (file)
index 093a168..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/sh /etc/rc.common
-# Copyright (C) 2014 OpenWrt.org
-
-START=90
-USE_PROCD=1
-
-append_arg() {
-       local cfg="$1"
-       local var="$2"
-       local opt="$3"
-       local def="$4"
-       local val
-
-       config_get val "$cfg" "$var"
-       [ -n "$val" -o -n "$def" ] && procd_append_param command $opt="${val:-$def}"
-}
-
-start_instance() {
-       local cfg="$1"
-       local aux
-
-       config_get_bool aux "$cfg" 'disabled' '0'
-       [ "$aux" = 1 ] && return 1
-
-       procd_open_instance
-
-       procd_set_param command /usr/bin/shairplay
-
-       append_arg "$cfg" apname "--apname" "AirPlay"
-       append_arg "$cfg" port "--server_port"
-       append_arg "$cfg" password "--password"
-       append_arg "$cfg" hwaddr "--hwaddr"
-
-       append_arg "$cfg" ao_driver "--ao_driver"
-       append_arg "$cfg" ao_devicename "--ao_devicename"
-       append_arg "$cfg" ao_deviceid "--ao_deviceid"
-
-       config_get_bool aux "$cfg" 'respawn' '0'
-       [ "$aux" = 1 ] && procd_set_param respawn
-
-       procd_close_instance
-}
-
-service_triggers() { 
-       procd_add_reload_trigger "shairplay" 
-}
-
-start_service() {
-       config_load shairplay
-       config_foreach start_instance shairplay
-}
diff --git a/sound/shairplay/patches/001-key_file_dir.patch b/sound/shairplay/patches/001-key_file_dir.patch
deleted file mode 100644 (file)
index af9bd84..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/src/shairplay.c
-+++ b/src/shairplay.c
-@@ -350,7 +350,7 @@ main(int argc, char *argv[])
-       raop_cbs.audio_destroy = audio_destroy;
-       raop_cbs.audio_set_volume = audio_set_volume;
--      raop = raop_init_from_keyfile(10, &raop_cbs, "airport.key", NULL);
-+      raop = raop_init_from_keyfile(10, &raop_cbs, "/usr/share/shairplay/airport.key", NULL);
-       if (raop == NULL) {
-               fprintf(stderr, "Could not initialize the RAOP service\n");
-               fprintf(stderr, "Please make sure the airport.key file is in the current directory.\n");
diff --git a/sound/shairplay/patches/003-fix_big-endian.patch b/sound/shairplay/patches/003-fix_big-endian.patch
deleted file mode 100644 (file)
index 4db204e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/src/lib/alac/alac.c
-+++ b/src/lib/alac/alac.c
-@@ -29,7 +29,7 @@
-  *
-  */
--static const int host_bigendian = 0;
-+#define host_bigendian (htonl(42) == 42)
- #include <stdio.h>
- #include <stdlib.h>
diff --git a/sound/shairplay/patches/010-configure-only-check-for-dns_sd.h-in-case-libdl-was-.patch b/sound/shairplay/patches/010-configure-only-check-for-dns_sd.h-in-case-libdl-was-.patch
deleted file mode 100644 (file)
index 84db6b8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-From 031c3d802e51bbc233b1044f812402a66bfcf237 Mon Sep 17 00:00:00 2001
-From: Memphiz <memphis@machzwo.de>
-Date: Fri, 21 Dec 2018 20:39:11 +0100
-Subject: [PATCH] [configure] - only check for dns_sd.h in case libdl was not
- found
-
----
- configure.ac | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/configure.ac
-+++ b/configure.ac
-@@ -19,7 +19,7 @@ LT_LIB_DLLOAD
- # Checks for header files.
- AC_HEADER_STDC
--if test yes = "$libltdl_cv_func_dlopen" || test yes = "$libltdl_cv_lib_dl_dlopen"
-+if test no = "$libltdl_cv_func_dlopen" && test no = "$libltdl_cv_lib_dl_dlopen"
- then
-   AC_CHECK_HEADERS([dns_sd.h], [],
-                    [AC_MSG_ERROR([Could not find dns_sd.h header, please install libavahi-compat-libdnssd-dev or equivalent.])])
index 6d7a0626c4f3b226ddbcad9317589a688b54b108..b46318513220cf8ef9101c1ac8b8641425ca8f00 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=upmpdcli
-PKG_VERSION:=1.5.19
+PKG_VERSION:=1.8.6
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://www.lesbonscomptes.com/upmpdcli/downloads
-PKG_HASH:=67fa1f5c06fecd404f3414b25a070c9deabe917241ed6881b7a8e41e8379ed09
+PKG_HASH:=55e3d27bea5bef4560f319137f1a5c7d08abbba5a9aae90ee3240903fdb8c3e4
 
 PKG_MAINTAINER:=
 PKG_LICENSE:=LGPL-2.1-or-later
index 2f134c300ad9d254ba0c613c3a98eaa7ffb3caf6..5a09ef79c65965c91d87674effb311680e067b2d 100644 (file)
@@ -1,14 +1,14 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=compose
-PKG_VERSION:=2.23.0
+PKG_VERSION:=2.23.3
 PKG_RELEASE:=1
 PKG_LICENSE:=Apache-2.0
 PKG_LICENSE_FILES:=LICENSE
 
 PKG_SOURCE:=v$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/docker/compose/tar.gz/v${PKG_VERSION}?
-PKG_HASH:=805ff38df265d05c7b0c9d5df1b77e9391f7995ac5ec66bde0325b03563e7b23
+PKG_HASH:=29ba96c8d398fbc6f7c791c65e70b97e7df116223f2996062441093258d914fe
 
 PKG_MAINTAINER:=Javier Marcet <javier@marcet.info>
 
index 7d1f5ce3986cc9fd45f283f5cf83d4d5ede4aa19..9e8a012e1a3d0e7218a25bf916b576920c0bec0f 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=domoticz
-PKG_VERSION:=2022.1
-PKG_RELEASE:=5
+PKG_VERSION:=2023.2
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/domoticz/domoticz/tar.gz/$(PKG_VERSION)?
-PKG_HASH:=8282cb71c924b6ef92503976d50f966f2c785eab8f8cffa1136ac133f0241157
+PKG_HASH:=32bcf49df8c80c470352e63004a82d9601b90ccf406096099656250a4515ac28
 
 PKG_MAINTAINER:=David Woodhouse <dwmw2@infradead.org>
 PKG_LICENSE:=GPL-3.0
diff --git a/utils/domoticz/patches/010-gcc12.patch b/utils/domoticz/patches/010-gcc12.patch
deleted file mode 100644 (file)
index 676e6a3..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 2975b1113d9540f39b6bade3b6d459b61c2e5007 Mon Sep 17 00:00:00 2001
-From: Arjen de Korte <build+github@de-korte.org>
-Date: Sun, 15 May 2022 19:00:02 +0200
-Subject: [PATCH] Fix compilation with GCC12
-
-Building domoticz fails under GCC12 with the following error:
-
-In file included from /usr/include/c++/12/utility:68,
-                 from /home/abuild/rpmbuild/BUILD/domoticz-2022.1/main/LuaTable.cpp:10:
-/usr/include/c++/12/bits/stl_relops.h:86:5: error: template with C linkage
-   86 |     template <class _Tp>
-      |     ^~~~~~~~
----
- main/LuaTable.cpp | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/main/LuaTable.cpp
-+++ b/main/LuaTable.cpp
-@@ -6,9 +6,9 @@ extern "C" {
- #include <lua.h>
- #include <lualib.h>
- #include <lauxlib.h>
-+}
- #include <utility>
--}
- CLuaTable::CLuaTable(lua_State *lua_state, const std::string &Name)
- {
diff --git a/utils/domoticz/patches/012-minizip-overflow.patch b/utils/domoticz/patches/012-minizip-overflow.patch
deleted file mode 100644 (file)
index 570ebfc..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-From 3c23a7863c0b01273d4c36423769443ea7e4a7bb Mon Sep 17 00:00:00 2001
-From: David Woodhouse <dwmw2@infradead.org>
-Date: Fri, 5 Jun 2020 15:02:41 +0100
-Subject: [PATCH 1/2] unzip: reduce file name size to 65535 to work with
- external minizip
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The external minizip project has changed the unzGetCurrentFileInfo()
-function to take a uint16_t as the filename size, instead of a uLong
-as in the original version in zlib.
-
-(Reported as https://github.com/nmoinvaz/minizip/issues/490 but it
-was 3½ years ago and might be too late to fix it now, although changing
-it back to a *larger* type is a lot safer than reducing the size, and
-perhaps they should.)
-
-This means that our 65536-byte buffer gets truncated to zero, as the
-compiler tells us when we build agaisnt the external minizip:
-
-domoticz/main/unzip_stream.h:140:50: warning: conversion from ‘long unsigned int’ to ‘uint16_t’ {aka ‘short unsigned int’} changes value from ‘65536’ to ‘0’ [-Woverflow]
-  140 |     unzGetCurrentFileInfo(handler_, &info, path, sizeof(path), NULL, 0, NULL, 0);
-      |                                                  ^~~~~~~~~~~~
-
-Reduce the buffer size to 65535 bytes instead.
----
- main/unzip_stream.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/main/unzip_stream.h
-+++ b/main/unzip_stream.h
-@@ -143,7 +143,7 @@ namespace clx {
-               basic_unzip_stream& open(handler_type h) {
-                       handler_ = h;
-                       if (handler_) {
--                              char path[65536];
-+                              char path[65535];
-                               unz_file_info info;
-                               unzGetCurrentFileInfo(handler_, &info, path, sizeof(path), NULL, 0, NULL, 0);
-                               path_ = path;
diff --git a/utils/domoticz/patches/990-python3.10_fix.patch b/utils/domoticz/patches/990-python3.10_fix.patch
deleted file mode 100644 (file)
index 8f0c867..0000000
+++ /dev/null
@@ -1,4364 +0,0 @@
-From 8f01ed77d5831090f34ad59d22ef1f7cd4d740f2 Mon Sep 17 00:00:00 2001
-From: dnpwwo <kendel.boul@gmail.com>
-Date: Mon, 21 Feb 2022 10:27:06 +1100
-Subject: [PATCH] Convert Python implementation to use Python's stable ABI
-
----
- hardware/plugins/DelayedLink.h        | 199 +++---
- hardware/plugins/PluginManager.cpp    |  17 +-
- hardware/plugins/PluginMessages.h     |   1 -
- hardware/plugins/PluginProtocols.cpp  | 356 ++++++-----
- hardware/plugins/PluginTransports.cpp |  64 +-
- hardware/plugins/Plugins.cpp          | 883 +++++++++-----------------
- hardware/plugins/Plugins.h            |  37 +-
- hardware/plugins/PythonObjectEx.cpp   |  60 +-
- hardware/plugins/PythonObjectEx.h     |  83 +--
- hardware/plugins/PythonObjects.cpp    | 147 +++--
- hardware/plugins/PythonObjects.h      | 119 ----
- main/EventSystem.cpp                  |   3 +-
- main/EventsPythonDevice.cpp           |  12 +-
- main/EventsPythonDevice.h             |  42 +-
- main/EventsPythonModule.cpp           | 321 ++++++----
- main/SQLHelper.cpp                    |   2 +-
- 16 files changed, 980 insertions(+), 1366 deletions(-)
-
---- a/hardware/plugins/DelayedLink.h
-+++ b/hardware/plugins/DelayedLink.h
-@@ -9,10 +9,19 @@
- #ifdef WITH_THREAD
- #    undefine WITH_THREAD
- #endif
-+
-+#pragma push_macro("_DEBUG")
-+#ifdef _DEBUG
-+#    undef _DEBUG   // Not compatible with Py_LIMITED_API
-+#endif
-+#define Py_LIMITED_API 0x03040000 
- #include <Python.h>
- #include <structmember.h>
--#include <frameobject.h>
--#include "../../main/Helper.h"
-+#include "../../main/Logger.h"
-+
-+#ifndef WIN32
-+#     include "../../main/Helper.h"
-+#endif
- namespace Plugins {
-@@ -29,6 +38,8 @@ namespace Plugins {
- #define DECLARE_PYTHON_SYMBOL(type, symbol, params)   typedef type (PYTHON_CALL symbol##_t)(params); symbol##_t  symbol
- #define RESOLVE_PYTHON_SYMBOL(symbol)  symbol = (symbol##_t)RESOLVE_SYMBOL(shared_lib_, #symbol)
-+#undef Py_None
-+
-       struct SharedLibraryProxy
-       {
- #ifdef WIN32
-@@ -36,6 +47,8 @@ namespace Plugins {
- #else
-               void* shared_lib_;
- #endif
-+              PyObject* Py_None;
-+                      
-               // Shared library interface begin.
-               DECLARE_PYTHON_SYMBOL(const char*, Py_GetVersion, );
-               DECLARE_PYTHON_SYMBOL(int, Py_IsInitialized, );
-@@ -50,6 +63,9 @@ namespace Plugins {
-               DECLARE_PYTHON_SYMBOL(wchar_t*, Py_GetProgramFullPath, );
-               DECLARE_PYTHON_SYMBOL(int, PyImport_AppendInittab, const char *COMMA PyObject *(*initfunc)());
-               DECLARE_PYTHON_SYMBOL(int, PyType_Ready, PyTypeObject*);
-+              DECLARE_PYTHON_SYMBOL(PyObject*, PyObject_Type, PyObject*);
-+              DECLARE_PYTHON_SYMBOL(PyObject*, PyType_FromSpec, PyType_Spec*);
-+              DECLARE_PYTHON_SYMBOL(void*, PyType_GetSlot, PyTypeObject* COMMA int);
-               DECLARE_PYTHON_SYMBOL(int, PyCallable_Check, PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyObject_GetAttrString, PyObject* pObj COMMA const char*);
-               DECLARE_PYTHON_SYMBOL(int, PyObject_HasAttrString, PyObject* COMMA const char *);
-@@ -60,7 +76,6 @@ namespace Plugins {
-               DECLARE_PYTHON_SYMBOL(wchar_t*, PyUnicode_AsWideCharString, PyObject* COMMA Py_ssize_t*);
-               DECLARE_PYTHON_SYMBOL(const char*, PyUnicode_AsUTF8, PyObject*);
-               DECLARE_PYTHON_SYMBOL(char*, PyByteArray_AsString, PyObject*);
--              DECLARE_PYTHON_SYMBOL(PyObject*, PyUnicode_FromKindAndData, int COMMA const void* COMMA Py_ssize_t);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyLong_FromLong, long);
-               DECLARE_PYTHON_SYMBOL(PY_LONG_LONG, PyLong_AsLongLong, PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyModule_GetDict, PyObject*);
-@@ -91,8 +106,6 @@ namespace Plugins {
-               DECLARE_PYTHON_SYMBOL(PyObject *, PyImport_ImportModule, const char *);
-               DECLARE_PYTHON_SYMBOL(int, PyObject_RichCompareBool, PyObject* COMMA PyObject* COMMA int);
-               DECLARE_PYTHON_SYMBOL(PyObject *, PyObject_CallObject, PyObject *COMMA PyObject *);
--              DECLARE_PYTHON_SYMBOL(PyObject *, PyObject_CallNoArgs, PyObject *);                                             // Python 3.9 !!!!
--              DECLARE_PYTHON_SYMBOL(int, PyFrame_GetLineNumber, PyFrameObject*);
-               DECLARE_PYTHON_SYMBOL(void, PyEval_InitThreads, );
-               DECLARE_PYTHON_SYMBOL(int, PyEval_ThreadsInitialized, );
-               DECLARE_PYTHON_SYMBOL(PyThreadState*, PyThreadState_Get, );
-@@ -102,17 +115,12 @@ namespace Plugins {
-               DECLARE_PYTHON_SYMBOL(void, PyEval_RestoreThread, PyThreadState *);
-               DECLARE_PYTHON_SYMBOL(void, PyEval_ReleaseLock, );
-               DECLARE_PYTHON_SYMBOL(PyThreadState*, PyThreadState_Swap, PyThreadState*);
--              DECLARE_PYTHON_SYMBOL(int, PyGILState_Check, );
-               DECLARE_PYTHON_SYMBOL(void, _Py_NegativeRefcount, const char* COMMA int COMMA PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject *, _PyObject_New, PyTypeObject *);
-               DECLARE_PYTHON_SYMBOL(int, PyObject_IsInstance, PyObject* COMMA PyObject*);
-               DECLARE_PYTHON_SYMBOL(int, PyObject_IsSubclass, PyObject *COMMA PyObject *);
-               DECLARE_PYTHON_SYMBOL(PyObject *, PyObject_Dir, PyObject *);
--#ifdef _DEBUG
--              DECLARE_PYTHON_SYMBOL(PyObject*, PyModule_Create2TraceRefs, struct PyModuleDef* COMMA int);
--#else
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyModule_Create2, struct PyModuleDef* COMMA int);
--#endif
-               DECLARE_PYTHON_SYMBOL(int, PyModule_AddObject, PyObject* COMMA const char* COMMA PyObject*);
-               DECLARE_PYTHON_SYMBOL(int, PyArg_ParseTuple, PyObject* COMMA const char* COMMA ...);
-               DECLARE_PYTHON_SYMBOL(int, PyArg_ParseTupleAndKeywords, PyObject* COMMA PyObject* COMMA const char* COMMA char*[] COMMA ...);
-@@ -120,8 +128,6 @@ namespace Plugins {
-               DECLARE_PYTHON_SYMBOL(PyObject*, Py_BuildValue, const char* COMMA ...);
-               DECLARE_PYTHON_SYMBOL(void, PyMem_Free, void*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyBool_FromLong, long);
--        DECLARE_PYTHON_SYMBOL(int, PyRun_SimpleStringFlags, const char* COMMA PyCompilerFlags*);
--        DECLARE_PYTHON_SYMBOL(int, PyRun_SimpleFileExFlags, FILE* COMMA const char* COMMA int COMMA PyCompilerFlags*);
-               DECLARE_PYTHON_SYMBOL(void*, PyCapsule_Import, const char *name COMMA int);
-               DECLARE_PYTHON_SYMBOL(void*, PyType_GenericAlloc, const PyTypeObject * COMMA Py_ssize_t);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyUnicode_DecodeUTF8, const char * COMMA Py_ssize_t COMMA const char *);
-@@ -132,44 +138,32 @@ namespace Plugins {
-               DECLARE_PYTHON_SYMBOL(long, PyLong_AsLong, PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyUnicode_AsUTF8String, PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyImport_AddModule, const char*);
--              DECLARE_PYTHON_SYMBOL(void, PyEval_SetProfile, Py_tracefunc COMMA PyObject*);
--              DECLARE_PYTHON_SYMBOL(void, PyEval_SetTrace, Py_tracefunc COMMA PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyObject_Str, PyObject*);
-               DECLARE_PYTHON_SYMBOL(int, PyObject_IsTrue, PyObject*);
-               DECLARE_PYTHON_SYMBOL(double, PyFloat_AsDouble, PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyObject_GetIter, PyObject*);
-               DECLARE_PYTHON_SYMBOL(PyObject*, PyIter_Next, PyObject*);
-               DECLARE_PYTHON_SYMBOL(void, PyErr_SetString, PyObject* COMMA const char*);
--
--#ifdef _DEBUG
--              // In a debug build dealloc is a function but for release builds its a macro
-+              DECLARE_PYTHON_SYMBOL(PyObject*, PyObject_CallFunctionObjArgs, PyObject* COMMA ...);
-+              DECLARE_PYTHON_SYMBOL(PyObject*, Py_CompileString, const char* COMMA const char* COMMA int);
-+              DECLARE_PYTHON_SYMBOL(PyObject*, PyEval_EvalCode, PyObject* COMMA PyObject* COMMA PyObject*);
-+              DECLARE_PYTHON_SYMBOL(long, PyType_GetFlags, PyTypeObject*);
-               DECLARE_PYTHON_SYMBOL(void, _Py_Dealloc, PyObject*);
--#endif
--              Py_ssize_t              _Py_RefTotal;
--              PyObject                _Py_NoneStruct;
--              PyObject *              dzPy_None;
-               SharedLibraryProxy() {
-+                      Py_None = nullptr;
-                       shared_lib_ = nullptr;
--                      _Py_RefTotal = 0;
-                       if (!shared_lib_) {
- #ifdef WIN32
--#     ifdef _DEBUG
--                              if (!shared_lib_) shared_lib_ = LoadLibrary("python39_d.dll");
--                              if (!shared_lib_) shared_lib_ = LoadLibrary("python38_d.dll");
--                              if (!shared_lib_) shared_lib_ = LoadLibrary("python37_d.dll");
--                              if (!shared_lib_) shared_lib_ = LoadLibrary("python36_d.dll");
--                              if (!shared_lib_) shared_lib_ = LoadLibrary("python35_d.dll");
--                              if (!shared_lib_) shared_lib_ = LoadLibrary("python34_d.dll");
--#     else
-+                              if (!shared_lib_) shared_lib_ = LoadLibrary("python310.dll");
-                               if (!shared_lib_) shared_lib_ = LoadLibrary("python39.dll");
-                               if (!shared_lib_) shared_lib_ = LoadLibrary("python38.dll");
-                               if (!shared_lib_) shared_lib_ = LoadLibrary("python37.dll");
-                               if (!shared_lib_) shared_lib_ = LoadLibrary("python36.dll");
-                               if (!shared_lib_) shared_lib_ = LoadLibrary("python35.dll");
-                               if (!shared_lib_) shared_lib_ = LoadLibrary("python34.dll");
--#     endif
- #else
-+                              if (!shared_lib_) FindLibrary("python3.10", true);
-                               if (!shared_lib_) FindLibrary("python3.9", true);
-                               if (!shared_lib_) FindLibrary("python3.8", true);
-                               if (!shared_lib_) FindLibrary("python3.7", true);
-@@ -198,6 +192,9 @@ namespace Plugins {
-                                       RESOLVE_PYTHON_SYMBOL(Py_GetProgramFullPath);
-                                       RESOLVE_PYTHON_SYMBOL(PyImport_AppendInittab);
-                                       RESOLVE_PYTHON_SYMBOL(PyType_Ready);
-+                                      RESOLVE_PYTHON_SYMBOL(PyObject_Type);
-+                                      RESOLVE_PYTHON_SYMBOL(PyType_FromSpec);
-+                                      RESOLVE_PYTHON_SYMBOL(PyType_GetSlot);
-                                       RESOLVE_PYTHON_SYMBOL(PyCallable_Check);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_GetAttrString);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_HasAttrString);
-@@ -208,7 +205,6 @@ namespace Plugins {
-                                       RESOLVE_PYTHON_SYMBOL(PyUnicode_AsWideCharString);
-                                       RESOLVE_PYTHON_SYMBOL(PyUnicode_AsUTF8);
-                                       RESOLVE_PYTHON_SYMBOL(PyByteArray_AsString);
--                                      RESOLVE_PYTHON_SYMBOL(PyUnicode_FromKindAndData);
-                                       RESOLVE_PYTHON_SYMBOL(PyLong_FromLong);
-                                       RESOLVE_PYTHON_SYMBOL(PyLong_AsLongLong);
-                                       RESOLVE_PYTHON_SYMBOL(PyModule_GetDict);
-@@ -239,8 +235,6 @@ namespace Plugins {
-                                       RESOLVE_PYTHON_SYMBOL(PyImport_ImportModule);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_RichCompareBool);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_CallObject);
--                                      RESOLVE_PYTHON_SYMBOL(PyObject_CallNoArgs);
--                                      RESOLVE_PYTHON_SYMBOL(PyFrame_GetLineNumber);
-                                       RESOLVE_PYTHON_SYMBOL(PyEval_InitThreads);
-                                       RESOLVE_PYTHON_SYMBOL(PyEval_ThreadsInitialized);
-                                       RESOLVE_PYTHON_SYMBOL(PyThreadState_Get);
-@@ -250,28 +244,18 @@ namespace Plugins {
-                                       RESOLVE_PYTHON_SYMBOL(PyEval_RestoreThread);
-                                       RESOLVE_PYTHON_SYMBOL(PyEval_ReleaseLock);
-                                       RESOLVE_PYTHON_SYMBOL(PyThreadState_Swap);
--                                      RESOLVE_PYTHON_SYMBOL(PyGILState_Check);
-                                       RESOLVE_PYTHON_SYMBOL(_Py_NegativeRefcount);
-                                       RESOLVE_PYTHON_SYMBOL(_PyObject_New);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_IsInstance);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_IsSubclass);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_Dir);
--#ifdef _DEBUG
--                                      RESOLVE_PYTHON_SYMBOL(PyModule_Create2TraceRefs);
--#else
-                                       RESOLVE_PYTHON_SYMBOL(PyModule_Create2);
--#endif
-                                       RESOLVE_PYTHON_SYMBOL(PyModule_AddObject);
-                                       RESOLVE_PYTHON_SYMBOL(PyArg_ParseTuple);
-                                       RESOLVE_PYTHON_SYMBOL(PyArg_ParseTupleAndKeywords);
-                                       RESOLVE_PYTHON_SYMBOL(PyUnicode_FromFormat);
-                                       RESOLVE_PYTHON_SYMBOL(Py_BuildValue);
-                                       RESOLVE_PYTHON_SYMBOL(PyMem_Free);
--#ifdef _DEBUG
--                                      RESOLVE_PYTHON_SYMBOL(_Py_Dealloc);
--#endif
--                    RESOLVE_PYTHON_SYMBOL(PyRun_SimpleFileExFlags);
--                    RESOLVE_PYTHON_SYMBOL(PyRun_SimpleStringFlags);
-                                       RESOLVE_PYTHON_SYMBOL(PyBool_FromLong);
-                                       RESOLVE_PYTHON_SYMBOL(PyCapsule_Import);
-                                       RESOLVE_PYTHON_SYMBOL(PyType_GenericAlloc);
-@@ -283,17 +267,19 @@ namespace Plugins {
-                                       RESOLVE_PYTHON_SYMBOL(PyLong_AsLong);
-                                       RESOLVE_PYTHON_SYMBOL(PyUnicode_AsUTF8String);
-                                       RESOLVE_PYTHON_SYMBOL(PyImport_AddModule);
--                                      RESOLVE_PYTHON_SYMBOL(PyEval_SetProfile);
--                                      RESOLVE_PYTHON_SYMBOL(PyEval_SetTrace);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_Str);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_IsTrue);
-                                       RESOLVE_PYTHON_SYMBOL(PyFloat_AsDouble);
-                                       RESOLVE_PYTHON_SYMBOL(PyObject_GetIter);
-                                       RESOLVE_PYTHON_SYMBOL(PyIter_Next);
-                                       RESOLVE_PYTHON_SYMBOL(PyErr_SetString);
-+                                      RESOLVE_PYTHON_SYMBOL(PyObject_CallFunctionObjArgs);
-+                                      RESOLVE_PYTHON_SYMBOL(Py_CompileString);
-+                                      RESOLVE_PYTHON_SYMBOL(PyEval_EvalCode);
-+                                      RESOLVE_PYTHON_SYMBOL(PyType_GetFlags);
-+                                      RESOLVE_PYTHON_SYMBOL(_Py_Dealloc);
-                               }
-                       }
--                      _Py_NoneStruct.ob_refcnt = 1;
-               };
-               ~SharedLibraryProxy() = default;
-@@ -412,15 +398,7 @@ namespace Plugins {
- extern        SharedLibraryProxy* pythonLib;
--// Create local pointer to Py_None, required to work around build complaints
--#ifdef Py_None
--      #undef Py_None
--#endif
--#define Py_None                                       pythonLib->dzPy_None
--#ifdef Py_RETURN_NONE
--      #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
--#endif
--#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-+#define       Py_None                                 pythonLib->Py_None
- #define       Py_LoadLibrary                  pythonLib->Py_LoadLibrary
- #define       Py_GetVersion                   pythonLib->Py_GetVersion
- #define       Py_IsInitialized                pythonLib->Py_IsInitialized
-@@ -435,6 +413,9 @@ extern     SharedLibraryProxy* pythonLib;
- #define       Py_GetProgramFullPath   pythonLib->Py_GetProgramFullPath
- #define       PyImport_AppendInittab  pythonLib->PyImport_AppendInittab
- #define       PyType_Ready                    pythonLib->PyType_Ready
-+#define       PyObject_Type                   pythonLib->PyObject_Type
-+#define       PyType_FromSpec                 pythonLib->PyType_FromSpec
-+#define       PyType_GetSlot                  pythonLib->PyType_GetSlot
- #define       PyCallable_Check                pythonLib->PyCallable_Check
- #define       PyObject_GetAttrString  pythonLib->PyObject_GetAttrString
- #define       PyObject_HasAttrString  pythonLib->PyObject_HasAttrString
-@@ -446,7 +427,6 @@ extern     SharedLibraryProxy* pythonLib;
- #define PyUnicode_AsWideCharString    pythonLib->PyUnicode_AsWideCharString
- #define PyUnicode_AsUTF8              pythonLib->PyUnicode_AsUTF8
- #define PyByteArray_AsString  pythonLib->PyByteArray_AsString
--#define PyUnicode_FromKindAndData  pythonLib->PyUnicode_FromKindAndData
- #define PyLong_FromLong                       pythonLib->PyLong_FromLong
- #define PyLong_AsLongLong             pythonLib->PyLong_AsLongLong
- #define PyModule_GetDict              pythonLib->PyModule_GetDict
-@@ -460,7 +440,7 @@ extern     SharedLibraryProxy* pythonLib;
- #define PyDict_SetItem                        pythonLib->PyDict_SetItem
- #define PyDict_DelItem                        pythonLib->PyDict_DelItem
- #define PyDict_DelItemString  pythonLib->PyDict_DelItemString
--#define PyDict_Next pythonLib->PyDict_Next
-+#define PyDict_Next                           pythonLib->PyDict_Next
- #define PyDict_Items                  pythonLib->PyDict_Items
- #define PyList_New                            pythonLib->PyList_New
- #define PyList_Size                           pythonLib->PyList_Size
-@@ -477,8 +457,6 @@ extern     SharedLibraryProxy* pythonLib;
- #define PyImport_ImportModule pythonLib->PyImport_ImportModule
- #define PyObject_RichCompareBool pythonLib->PyObject_RichCompareBool
- #define PyObject_CallObject           pythonLib->PyObject_CallObject
--#define PyObject_CallNoArgs           pythonLib->PyObject_CallNoArgs
--#define PyFrame_GetLineNumber pythonLib->PyFrame_GetLineNumber
- #define       PyEval_InitThreads              pythonLib->PyEval_InitThreads
- #define       PyEval_ThreadsInitialized       pythonLib->PyEval_ThreadsInitialized
- #define       PyThreadState_Get               pythonLib->PyThreadState_Get
-@@ -488,7 +466,6 @@ extern     SharedLibraryProxy* pythonLib;
- #define PyEval_RestoreThread  pythonLib->PyEval_RestoreThread
- #define PyEval_ReleaseLock            pythonLib->PyEval_ReleaseLock
- #define PyThreadState_Swap            pythonLib->PyThreadState_Swap
--#define PyGILState_Check              pythonLib->PyGILState_Check
- #define _Py_NegativeRefcount  pythonLib->_Py_NegativeRefcount
- #define _PyObject_New                 pythonLib->_PyObject_New
- #define PyObject_IsInstance           pythonLib->PyObject_IsInstance
-@@ -497,22 +474,10 @@ extern   SharedLibraryProxy* pythonLib;
- #define PyArg_ParseTuple              pythonLib->PyArg_ParseTuple
- #define Py_BuildValue                 pythonLib->Py_BuildValue
- #define PyMem_Free                            pythonLib->PyMem_Free
--#ifdef _DEBUG
--#     define PyModule_Create2TraceRefs pythonLib->PyModule_Create2TraceRefs
--#else
--#     define PyModule_Create2         pythonLib->PyModule_Create2
--#endif
-+#define PyModule_Create2              pythonLib->PyModule_Create2
- #define PyModule_AddObject            pythonLib->PyModule_AddObject
- #define PyArg_ParseTupleAndKeywords pythonLib->PyArg_ParseTupleAndKeywords
--
--#ifdef _DEBUG
--#     define _Py_Dealloc                      pythonLib->_Py_Dealloc
--#endif
--
- #define _Py_RefTotal                  pythonLib->_Py_RefTotal
--#define _Py_NoneStruct                        pythonLib->_Py_NoneStruct
--#define PyRun_SimpleStringFlags pythonLib->PyRun_SimpleStringFlags
--#define PyRun_SimpleFileExFlags pythonLib->PyRun_SimpleFileExFlags
- #define PyBool_FromLong                       pythonLib->PyBool_FromLong
- #define PyCapsule_Import              pythonLib->PyCapsule_Import
- #define PyType_GenericAlloc           pythonLib->PyType_GenericAlloc
-@@ -524,80 +489,88 @@ extern   SharedLibraryProxy* pythonLib;
- #define PyLong_AsLong                 pythonLib->PyLong_AsLong
- #define PyUnicode_AsUTF8String        pythonLib->PyUnicode_AsUTF8String
- #define PyImport_AddModule            pythonLib->PyImport_AddModule
--#define PyEval_SetProfile             pythonLib->PyEval_SetProfile
--#define PyEval_SetTrace                       pythonLib->PyEval_SetTrace
- #define PyObject_Str                  pythonLib->PyObject_Str
- #define       PyObject_IsTrue                 pythonLib->PyObject_IsTrue
- #define PyFloat_AsDouble              pythonLib->PyFloat_AsDouble
- #define       PyObject_GetIter                pythonLib->PyObject_GetIter
- #define       PyIter_Next                             pythonLib->PyIter_Next
- #define PyErr_SetString                       pythonLib->PyErr_SetString
--
--#ifndef _Py_DEC_REFTOTAL
--/* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 */
--#ifdef Py_REF_DEBUG
--#define _Py_DEC_REFTOTAL _Py_RefTotal--
-+#define       PyObject_CallFunctionObjArgs    pythonLib->PyObject_CallFunctionObjArgs
-+#define       Py_CompileString                pythonLib->Py_CompileString
-+#define       PyEval_EvalCode                 pythonLib->PyEval_EvalCode
-+#define       PyType_GetFlags                 pythonLib->PyType_GetFlags
-+#ifdef WIN32  
-+#     define  _Py_Dealloc                             pythonLib->_Py_Dealloc          // Builds against a low Python version
-+#elif PY_VERSION_HEX < 0x03090000
-+#     define  _Py_Dealloc                             pythonLib->_Py_Dealloc
- #else
--#define _Py_DEC_REFTOTAL
--#define _Py_Dealloc
--#endif
-+#     ifndef _Py_DEC_REFTOTAL
-+      /* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by: https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924 */
-+#             ifdef Py_REF_DEBUG
-+#                     define _Py_DEC_REFTOTAL _Py_RefTotal--
-+#             else
-+#                     define _Py_DEC_REFTOTAL
-+#                     define _Py_Dealloc
-+#             endif
-+#     endif
- #endif
- #if PY_VERSION_HEX >= 0x030800f0
--      static inline void py3__Py_INCREF(PyObject *op)
--      {
-+static inline void py3__Py_INCREF(PyObject* op)
-+{
- #ifdef Py_REF_DEBUG
--              _Py_RefTotal++;
-+      _Py_RefTotal++;
- #endif
--              op->ob_refcnt++;
--      }
-+      op->ob_refcnt++;
-+}
- #undef Py_INCREF
- #define Py_INCREF(op) py3__Py_INCREF(_PyObject_CAST(op))
--      static inline void py3__Py_XINCREF(PyObject *op)
-+static inline void py3__Py_XINCREF(PyObject* op)
-+{
-+      if (op != NULL)
-       {
--              if (op != NULL)
--              {
--                      Py_INCREF(op);
--              }
-+              Py_INCREF(op);
-       }
-+}
- #undef Py_XINCREF
- #define Py_XINCREF(op) py3__Py_XINCREF(_PyObject_CAST(op))
--      static inline void py3__Py_DECREF(const char *filename, int lineno, PyObject *op)
-+static inline void py3__Py_DECREF(const char* filename, int lineno, PyObject* op)
-+{
-+      (void)filename; /* may be unused, shut up -Wunused-parameter */
-+      (void)lineno;   /* may be unused, shut up -Wunused-parameter */
-+      _Py_DEC_REFTOTAL;
-+      if (--op->ob_refcnt != 0)
-       {
--              (void)filename; /* may be unused, shut up -Wunused-parameter */
--              (void)lineno;   /* may be unused, shut up -Wunused-parameter */
--              _Py_DEC_REFTOTAL;
--              if (--op->ob_refcnt != 0)
--              {
- #ifdef Py_REF_DEBUG
--                      if (op->ob_refcnt < 0)
--                      {
--                              _Py_NegativeRefcount(filename, lineno, op);
--                      }
--#endif
--              }
--              else
-+              if (op->ob_refcnt < 0)
-               {
--                      _Py_Dealloc(op);
-+                      _Py_NegativeRefcount(filename, lineno, op);
-               }
-+#endif
-+      }
-+      else
-+      {
-+              _Py_Dealloc(op);
-       }
-+}
- #undef Py_DECREF
- #define Py_DECREF(op) py3__Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
--      static inline void py3__Py_XDECREF(PyObject *op)
-+static inline void py3__Py_XDECREF(PyObject* op)
-+{
-+      if (op != nullptr)
-       {
--              if (op != nullptr)
--              {
--                      Py_DECREF(op);
--              }
-+              Py_DECREF(op);
-       }
-+}
- #undef Py_XDECREF
- #define Py_XDECREF(op) py3__Py_XDECREF(_PyObject_CAST(op))
- #endif
-+#pragma pop_macro("_DEBUG")
- } // namespace Plugins
---- a/hardware/plugins/PluginManager.cpp
-+++ b/hardware/plugins/PluginManager.cpp
-@@ -31,7 +31,9 @@
- #include "DelayedLink.h"
- #include "../../main/EventsPythonModule.h"
--#define MINIMUM_PYTHON_VERSION "3.4.0"
-+// Python version constants
-+#define MINIMUM_MAJOR_VERSION 3
-+#define MINIMUM_MINOR_VERSION 4
- #define ATTRIBUTE_VALUE(pElement, Name, Value) \
-               {       \
-@@ -105,9 +107,18 @@ namespace Plugins {
-                       }
-                       std::string sVersion = szPyVersion.substr(0, szPyVersion.find_first_of(' '));
--                      if (sVersion < MINIMUM_PYTHON_VERSION)
-+
-+                      std::string sMajorVersion = sVersion.substr(0, sVersion.find_first_of('.'));
-+                      if (std::stoi(sMajorVersion) < MINIMUM_MAJOR_VERSION)
-+                      {
-+                              _log.Log(LOG_STATUS, "PluginSystem: Invalid Python version '%s' found, Major version '%d' or above required.", sVersion.c_str(), MINIMUM_MAJOR_VERSION);
-+                              return false;
-+                      }
-+
-+                      std::string sMinorVersion = sVersion.substr(sMajorVersion.length()+1);
-+                      if (std::stoi(sMinorVersion) < MINIMUM_MINOR_VERSION)
-                       {
--                              _log.Log(LOG_STATUS, "PluginSystem: Invalid Python version '%s' found, '%s' or above required.", sVersion.c_str(), MINIMUM_PYTHON_VERSION);
-+                              _log.Log(LOG_STATUS, "PluginSystem: Invalid Python version '%s' found, Minor version '%d.%d' or above required.", sVersion.c_str(), MINIMUM_MAJOR_VERSION, MINIMUM_MINOR_VERSION);
-                               return false;
-                       }
---- a/hardware/plugins/PluginMessages.h
-+++ b/hardware/plugins/PluginMessages.h
-@@ -60,7 +60,6 @@ namespace Plugins {
-               InitializeMessage() : CPluginMessageBase() { m_Name = __func__; };
-               void Process(CPlugin* pPlugin) override
-               {
--                      //std::lock_guard<std::mutex> l(PythonMutex);
-                       pPlugin->Initialise();
-               };
-               void ProcessLocked(CPlugin* pPlugin) override{};
---- a/hardware/plugins/PluginProtocols.cpp
-+++ b/hardware/plugins/PluginProtocols.cpp
-@@ -5,6 +5,7 @@
- //
- #ifdef ENABLE_PYTHON
-+#include "../../main/Helper.h"
- #include "PluginMessages.h"
- #include "PluginProtocols.h"
- #include "../../main/Helper.h"
-@@ -52,32 +53,37 @@ namespace Plugins {
-       std::vector<byte> CPluginProtocol::ProcessOutbound(const WriteDirective* WriteMessage)
-       {
-               std::vector<byte>       retVal;
-+              PyBorrowedRef   pObject(WriteMessage->m_Object);
-               // Handle Bytes objects
--              if ((((PyObject*)WriteMessage->m_Object)->ob_type->tp_flags & (Py_TPFLAGS_BYTES_SUBCLASS)) != 0)
-+              if (pObject.IsBytes())
-               {
--                      const char* pData = PyBytes_AsString(WriteMessage->m_Object);
--                      int                     iSize = PyBytes_Size(WriteMessage->m_Object);
-+                      const char* pData = PyBytes_AsString(pObject);
-+                      int                     iSize = PyBytes_Size(pObject);
-                       retVal.reserve((size_t)iSize);
-                       retVal.assign(pData, pData + iSize);
-               }
-               // Handle ByteArray objects
--              else if ((((PyObject*)WriteMessage->m_Object)->ob_type->tp_name == std::string("bytearray")))
-+              else if (pObject.IsByteArray())
-               {
--                      size_t  len = PyByteArray_Size(WriteMessage->m_Object);
--                      char* data = PyByteArray_AsString(WriteMessage->m_Object);
-+                      size_t  len = PyByteArray_Size(pObject);
-+                      char* data = PyByteArray_AsString(pObject);
-                       retVal.reserve(len);
-                       retVal.assign((const byte*)data, (const byte*)data + len);
-               }
--              // Handle String objects
--              else if ((((PyObject*)WriteMessage->m_Object)->ob_type->tp_flags & (Py_TPFLAGS_UNICODE_SUBCLASS)) != 0)
-+              // Try forcing a String conversion
-+              else
-               {
--                      std::string     sData = PyUnicode_AsUTF8(WriteMessage->m_Object);
--                      retVal.reserve((size_t)sData.length());
--                      retVal.assign((const byte*)sData.c_str(), (const byte*)sData.c_str() + sData.length());
-+                      PyNewRef        pStr = PyObject_Str(pObject);
-+                      if (pStr)
-+                      {
-+                              std::string     sData = PyUnicode_AsUTF8(pStr);
-+                              retVal.reserve((size_t)sData.length());
-+                              retVal.assign((const byte*)sData.c_str(), (const byte*)sData.c_str() + sData.length());
-+                      }
-+                      else
-+                              _log.Log(LOG_ERROR, "(%s) Unable to convert data (%s) to string representation, ignored.", __func__, pObject.Type().c_str());
-               }
--              else
--                      _log.Log(LOG_ERROR, "(%s) Send request Python object parameter was not of type Unicode or Byte, ignored.", __func__);
-               return retVal;
-       }
-@@ -120,7 +126,7 @@ namespace Plugins {
-               if (PyDict_SetItemString(pDict, key, pObj) == -1)
-                       _log.Log(LOG_ERROR, "(%s) failed to add key '%s', value '%s' to dictionary.", __func__, key, value.c_str());
-       }
--
-+      
-       static void AddStringToDict(PyObject* pDict, const char* key, const std::string& value)
-       {
-               PyNewRef pObj = Py_BuildValue("s#", value.c_str(), value.length());
-@@ -166,7 +172,7 @@ namespace Plugins {
-                       Py_ssize_t      Index = 0;
-                       for (auto &pRef : *pJSON)
-                       {
--                              // PyList_SetItem 'steal' a reference so use PyBorrowedRef instead of PyNewRef
-+                              // PyList_SetItem 'steals' a reference so use PyBorrowedRef instead of PyNewRef
-                               if (pRef.isArray() || pRef.isObject())
-                               {
-                                       PyBorrowedRef pObj = JSONtoPython(&pRef);
-@@ -239,7 +245,7 @@ namespace Plugins {
-               bool bRet = ParseJSon(sData, root);
-               if ((!bRet) || (!root.isObject()))
-               {
--                      _log.Log(LOG_ERROR, "JSON Protocol: Parse Error on '%s'", sData.c_str());
-+                      _log.Log(LOG_ERROR, "(%s) Parse Error on '%s'", __func__, sData.c_str());
-                       Py_RETURN_NONE;
-               }
-               else
-@@ -253,66 +259,77 @@ namespace Plugins {
-       std::string CPluginProtocolJSON::PythontoJSON(PyObject* pObject)
-       {
-               std::string     sJson;
-+              PyBorrowedRef   pObj(pObject);
--              if (PyUnicode_Check(pObject))
--              {
--                      sJson += '"' + std::string(PyUnicode_AsUTF8(pObject)) + '"';
--              }
--              else if (pObject->ob_type->tp_name == std::string("bool"))
--              {
--                      sJson += (PyObject_IsTrue(pObject) ? "true" : "false");
--              }
--              else if (PyLong_Check(pObject))
--              {
--                      sJson += std::to_string(PyLong_AsLong(pObject));
--              }
--              else if (PyBytes_Check(pObject))
--              {
--                      sJson += '"' + std::string(PyBytes_AsString(pObject)) + '"';
--              }
--              else if (pObject->ob_type->tp_name == std::string("bytearray"))
--              {
--                      sJson += '"' + std::string(PyByteArray_AsString(pObject)) + '"';
--              }
--              else if (pObject->ob_type->tp_name == std::string("float"))
--              {
--                      sJson += std::to_string(PyFloat_AsDouble(pObject));
--              }
--              else if (PyDict_Check(pObject))
-+              if (pObj.IsDict())
-               {
-                       sJson += "{ ";
-                       PyObject* key, * value;
-                       Py_ssize_t pos = 0;
--                      while (PyDict_Next(pObject, &pos, &key, &value))
-+                      while (PyDict_Next(pObj, &pos, &key, &value))
-                       {
-                               sJson += PythontoJSON(key) + ':' + PythontoJSON(value) + ',';
-                       }
-                       sJson[sJson.length() - 1] = '}';
-               }
--              else if (PyList_Check(pObject))
-+              else if (pObj.IsList())
-               {
-                       sJson += "[ ";
--                      for (Py_ssize_t i = 0; i < PyList_Size(pObject); i++)
-+                      for (Py_ssize_t i = 0; i < PyList_Size(pObj); i++)
-                       {
--                              sJson += PythontoJSON(PyList_GetItem(pObject, i)) + ',';
-+                              sJson += PythontoJSON(PyList_GetItem(pObj, i)) + ',';
-                       }
-                       sJson[sJson.length() - 1] = ']';
-               }
--              else if (PyTuple_Check(pObject))
-+              else if (pObj.IsTuple())
-               {
-                       sJson += "[ ";
--                      for (Py_ssize_t i = 0; i < PyTuple_Size(pObject); i++)
-+                      for (Py_ssize_t i = 0; i < PyTuple_Size(pObj); i++)
-                       {
--                              sJson += PythontoJSON(PyTuple_GetItem(pObject, i)) + ',';
-+                              sJson += PythontoJSON(PyTuple_GetItem(pObj, i)) + ',';
-                       }
-                       sJson[sJson.length() - 1] = ']';
-               }
-+              else if (pObj.IsBool())
-+              {
-+                      sJson += (PyObject_IsTrue(pObj) ? "true" : "false");
-+              }
-+              else if (pObj.IsLong())
-+              {
-+                      sJson += std::to_string(PyLong_AsLong(pObj));
-+              }
-+              else if (pObj.IsFloat())
-+              {
-+                      sJson += std::to_string(PyFloat_AsDouble(pObj));
-+              }
-+              else if (pObj.IsBytes())
-+              {
-+                      sJson += '"' + std::string(PyBytes_AsString(pObj)) + '"';
-+              }
-+              else if (pObj.IsByteArray())
-+              {
-+                      sJson += '"' + std::string(PyByteArray_AsString(pObj)) + '"';
-+              }
-+              else
-+              {
-+                      // Try forcing a String conversion
-+                      PyNewRef        pStr = PyObject_Str(pObject);
-+                      if (pStr)
-+                      {
-+                              sJson += '"' + std::string(PyUnicode_AsUTF8(pStr)) + '"';
-+                      }
-+                      else
-+                              _log.Log(LOG_ERROR, "(%s) Unable to convert data type (%s) to string representation, ignored.", __func__, pObj.Type().c_str());
-+              }
-               return sJson;
-       }
-       void CPluginProtocolJSON::ProcessInbound(const ReadEvent* Message)
-       {
-+              CConnection* pConnection = Message->m_pConnection;
-+              CPlugin* pPlugin = pConnection->pPlugin;
-+
-               //
-               //      Handles the cases where a read contains a partial message or multiple messages
-               //
-@@ -332,13 +349,13 @@ namespace Plugins {
-                                       bool bRet = ParseJSon(sData, root);
-                                       if ((!bRet) || (!root.isObject()))
-                                       {
--                                              _log.Log(LOG_ERROR, "JSON Protocol: Parse Error on '%s'", sData.c_str());
--                                              Message->m_pConnection->pPlugin->MessagePlugin(new onMessageCallback(Message->m_pConnection, sData));
-+                                              pPlugin->Log(LOG_ERROR, "(%s) Parse Error on '%s'", __func__, sData.c_str());
-+                                              pPlugin->MessagePlugin(new onMessageCallback(pConnection, sData));
-                                       }
-                                       else
-                                       {
-                                               PyObject* pMessage = JSONtoPython(&root);
--                                              Message->m_pConnection->pPlugin->MessagePlugin(new onMessageCallback(Message->m_pConnection, pMessage));
-+                                              pPlugin->MessagePlugin(new onMessageCallback(pConnection, pMessage));
-                                       }
-                                       sData.clear();
-                               }
-@@ -350,13 +367,13 @@ namespace Plugins {
-                               bool bRet = ParseJSon(sMessage, root);
-                               if ((!bRet) || (!root.isObject()))
-                               {
--                                      _log.Log(LOG_ERROR, "JSON Protocol: Parse Error on '%s'", sData.c_str());
--                                      Message->m_pConnection->pPlugin->MessagePlugin(new onMessageCallback(Message->m_pConnection, sMessage));
-+                                      pPlugin->Log(LOG_ERROR, "(%s) Parse Error on '%s'", __func__, sData.c_str());
-+                                      pPlugin->MessagePlugin(new onMessageCallback(pConnection, sMessage));
-                               }
-                               else
-                               {
-                                       PyObject* pMessage = JSONtoPython(&root);
--                                      Message->m_pConnection->pPlugin->MessagePlugin(new onMessageCallback(Message->m_pConnection, pMessage));
-+                                      pPlugin->MessagePlugin(new onMessageCallback(pConnection, pMessage));
-                               }
-                       }
-               }
-@@ -467,7 +484,7 @@ namespace Plugins {
-                       {
-                               PyObject* pListObj = pPrevObj;
-                               // First duplicate? Create a list and add previous value
--                              if (!PyList_Check(pListObj))
-+                              if (!pPrevObj.IsList())
-                               {
-                                       pListObj = PyList_New(1);
-                                       if (!pListObj)
-@@ -732,7 +749,7 @@ namespace Plugins {
-               std::string     sHttp;
-               // Sanity check input
--              if (!WriteMessage->m_Object || !PyDict_Check(WriteMessage->m_Object))
-+              if (PyBorrowedRef(WriteMessage->m_Object).Type() != "dict")
-               {
-                       _log.Log(LOG_ERROR, "(%s) HTTP Send parameter was not a dictionary, ignored. See Python Plugin wiki page for help.", __func__);
-                       return retVal;
-@@ -763,7 +780,7 @@ namespace Plugins {
-                       //
-                       // param1=value&param2=other+value
--                      if (!PyUnicode_Check(pVerb))
-+                      if (!pVerb.IsString())
-                       {
-                               _log.Log(LOG_ERROR, "(%s) HTTP 'Verb' dictionary entry not a string, ignored. See Python Plugin wiki page for help.", __func__);
-                               return retVal;
-@@ -774,7 +791,7 @@ namespace Plugins {
-                       PyBorrowedRef   pURL = PyDict_GetItemString(WriteMessage->m_Object, "URL");
-                       std::string     sHttpURL = "/";
--                      if (pURL && PyUnicode_Check(pURL))
-+                      if (pURL.IsString())
-                       {
-                               sHttpURL = PyUnicode_AsUTF8(pURL);
-                       }
-@@ -840,7 +857,7 @@ namespace Plugins {
-                       //      </body>
-                       //      </html>
--                      if (!PyUnicode_Check(pStatus))
-+                      if (!pStatus.IsString())
-                       {
-                               _log.Log(LOG_ERROR, "(%s) HTTP 'Status' dictionary entry was not a string, ignored. See Python Plugin wiki page for help.", __func__);
-                               return retVal;
-@@ -886,53 +903,53 @@ namespace Plugins {
-                       // Did we get headers to send?
-                       if (pHeaders)
-                       {
--                              if (PyDict_Check(pHeaders))
-+                              if (pHeaders.IsDict())
-                               {
-                                       PyObject* key, * value;
-                                       Py_ssize_t pos = 0;
-                                       while (PyDict_Next(pHeaders, &pos, &key, &value))
-                                       {
-                                               std::string     sKey = PyUnicode_AsUTF8(key);
--                                              if (PyUnicode_Check(value))
-+                                              PyBorrowedRef   pValue(value);
-+                                              if (pValue.IsString())
-                                               {
-                                                       std::string     sValue = PyUnicode_AsUTF8(value);
-                                                       sHttp += sKey + ": " + sValue + "\r\n";
-                                               }
--                                              else if (PyBytes_Check(value))
-+                                              else if (pValue.IsBytes())
-                                               {
-                                                       const char* pBytes = PyBytes_AsString(value);
-                                                       sHttp += sKey + ": " + pBytes + "\r\n";
-                                               }
--                                              else if (value->ob_type->tp_name == std::string("bytearray"))
-+                                              else if (pValue.IsByteArray())
-                                               {
-                                                       const char* pByteArray = PyByteArray_AsString(value);
-                                                       sHttp += sKey + ": " + pByteArray + "\r\n";
-                                               }
--                                              else if (PyList_Check(value))
-+                                              else if (pValue.IsList())
-                                               {
--                                                      PyObject* iterator = PyObject_GetIter(value);
--                                                      PyObject* item;
--                                                      while ((item = PyIter_Next(iterator)))
-+                                                      PyNewRef        iterator = PyObject_GetIter(value);
-+                                                      PyObject*       item;
-+                                                      while (item = PyIter_Next(iterator))
-                                                       {
--                                                              if (PyUnicode_Check(item))
-+                                                              PyBorrowedRef   pItem(item);
-+                                                              if (pItem.IsString())
-                                                               {
-                                                                       std::string     sValue = PyUnicode_AsUTF8(item);
-                                                                       sHttp += sKey + ": " + sValue + "\r\n";
-                                                               }
--                                                              else if (PyBytes_Check(item))
-+                                                              else if (pItem.IsBytes())
-                                                               {
-                                                                       const char* pBytes = PyBytes_AsString(item);
-                                                                       sHttp += sKey + ": " + pBytes + "\r\n";
-                                                               }
--                                                              else if (item->ob_type->tp_name == std::string("bytearray"))
-+                                                              else if (pItem.IsByteArray())
-                                                               {
-                                                                       const char* pByteArray = PyByteArray_AsString(item);
-                                                                       sHttp += sKey + ": " + pByteArray + "\r\n";
-                                                               }
-                                                               Py_DECREF(item);
-                                                       }
--
--                                                      Py_DECREF(iterator);
-                                               }
-                                       }
-                               }
-@@ -949,11 +966,11 @@ namespace Plugins {
-                       if (!pLength && pData && !pChunk)
-                       {
-                               Py_ssize_t iLength = 0;
--                              if (PyUnicode_Check(pData))
-+                              if (pData.IsString())
-                                       iLength = PyUnicode_GetLength(pData);
--                              else if (pData->ob_type->tp_name == std::string("bytearray"))
-+                              else if (pData.IsByteArray())
-                                       iLength = PyByteArray_Size(pData);
--                              else if (PyBytes_Check(pData))
-+                              else if (pData.IsBytes())
-                                       iLength = PyBytes_Size(pData);
-                               sHttp += "Content-Length: " + std::to_string(iLength) + "\r\n";
-                       }
-@@ -977,15 +994,12 @@ namespace Plugins {
-               if (pChunk)
-               {
-                       long    lChunkLength = 0;
--                      if (pData)
--                      {
--                              if (PyUnicode_Check(pData))
--                                      lChunkLength = PyUnicode_GetLength(pData);
--                              else if (pData->ob_type->tp_name == std::string("bytearray"))
--                                      lChunkLength = PyByteArray_Size(pData);
--                              else if (PyBytes_Check(pData))
--                                      lChunkLength = PyBytes_Size(pData);
--                      }
-+                      if (pData.IsString())
-+                              lChunkLength = PyUnicode_GetLength(pData);
-+                      else if (pData.IsByteArray())
-+                              lChunkLength = PyByteArray_Size(pData);
-+                      else if (pData.IsBytes())
-+                              lChunkLength = PyBytes_Size(pData);
-                       std::stringstream stream;
-                       stream << std::hex << lChunkLength;
-                       sHttp += std::string(stream.str());
-@@ -993,13 +1007,13 @@ namespace Plugins {
-               }
-               // Append data if supplied (for POST) or Response
--              if (pData && PyUnicode_Check(pData))
-+              if (pData.IsString())
-               {
-                       sHttp += PyUnicode_AsUTF8(pData);
-                       retVal.reserve(sHttp.length() + 2);
-                       retVal.assign(sHttp.c_str(), sHttp.c_str() + sHttp.length());
-               }
--              else if (pData && (pData->ob_type->tp_name == std::string("bytearray")))
-+              else if (pData.IsByteArray())
-               {
-                       retVal.reserve(sHttp.length() + PyByteArray_Size(pData) + 2);
-                       retVal.assign(sHttp.c_str(), sHttp.c_str() + sHttp.length());
-@@ -1010,7 +1024,7 @@ namespace Plugins {
-                               retVal.push_back(pByteArray[i]);
-                       }
-               }
--              else if (pData && PyBytes_Check(pData))
-+              else if (pData.IsBytes())
-               {
-                       retVal.reserve(sHttp.length() + PyBytes_Size(pData) + 2);
-                       retVal.assign(sHttp.c_str(), sHttp.c_str() + sHttp.length());
-@@ -1700,7 +1714,7 @@ namespace Plugins {
-               std::vector<byte>       retVal;
-               // Sanity check input
--              if (!WriteMessage->m_Object || !PyDict_Check(WriteMessage->m_Object))
-+              if (!PyBorrowedRef(WriteMessage->m_Object).IsDict())
-               {
-                       _log.Log(LOG_ERROR, "(%s) MQTT Send parameter was not a dictionary, ignored. See Python Plugin wiki page for help.", __func__);
-                       return retVal;
-@@ -1710,7 +1724,7 @@ namespace Plugins {
-               PyBorrowedRef pVerb = PyDict_GetItemString(WriteMessage->m_Object, "Verb");
-               if (pVerb)
-               {
--                      if (!PyUnicode_Check(pVerb))
-+                      if (!pVerb.IsString())
-                       {
-                               _log.Log(LOG_ERROR, "(%s) MQTT 'Verb' dictionary entry not a string, ignored. See Python Plugin wiki page for help.", __func__);
-                               return retVal;
-@@ -1726,7 +1740,7 @@ namespace Plugins {
-                               // Client Identifier
-                               PyBorrowedRef pID = PyDict_GetItemString(WriteMessage->m_Object, "ID");
--                              if (pID && PyUnicode_Check(pID))
-+                              if (pID.IsString())
-                               {
-                                       MQTTPushBackStringWLen(std::string(PyUnicode_AsUTF8(pID)), vPayload);
-                               }
-@@ -1735,7 +1749,7 @@ namespace Plugins {
-                               byte    bCleanSession = 1;
-                               PyBorrowedRef pCleanSession = PyDict_GetItemString(WriteMessage->m_Object, "CleanSession");
--                              if (pCleanSession && PyLong_Check(pCleanSession))
-+                              if (pCleanSession.IsLong())
-                               {
-                                       bCleanSession = (byte)PyLong_AsLong(pCleanSession);
-                               }
-@@ -1743,7 +1757,7 @@ namespace Plugins {
-                               // Will topic
-                               PyBorrowedRef pTopic = PyDict_GetItemString(WriteMessage->m_Object, "WillTopic");
--                              if (pTopic && PyUnicode_Check(pTopic))
-+                              if (pTopic.IsString())
-                               {
-                                       MQTTPushBackStringWLen(std::string(PyUnicode_AsUTF8(pTopic)), vPayload);
-                                       bControlFlags |= 4;
-@@ -1753,14 +1767,14 @@ namespace Plugins {
-                               if (bControlFlags & 4)
-                               {
-                                       PyBorrowedRef pQoS = PyDict_GetItemString(WriteMessage->m_Object, "WillQoS");
--                                      if (pQoS && PyLong_Check(pQoS))
-+                                      if (pQoS.IsLong())
-                                       {
-                                               byte bQoS = (byte)PyLong_AsLong(pQoS);
-                                               bControlFlags |= (bQoS & 3) << 3; // Set QoS flag
-                                       }
-                                       PyBorrowedRef pRetain = PyDict_GetItemString(WriteMessage->m_Object, "WillRetain");
--                                      if (pRetain && PyLong_Check(pRetain))
-+                                      if (pRetain.IsLong())
-                                       {
-                                               byte bRetain = (byte)PyLong_AsLong(pRetain);
-                                               bControlFlags |= (bRetain & 1) << 5; // Set retain flag
-@@ -1770,11 +1784,11 @@ namespace Plugins {
-                                       PyBorrowedRef pPayload = PyDict_GetItemString(WriteMessage->m_Object, "WillPayload");
-                                       // Support both string and bytes
-                                       //if (pPayload && PyByteArray_Check(pPayload)) // Gives linker error, why?
--                                      if (pPayload && pPayload->ob_type->tp_name == std::string("bytearray"))
-+                                      if (pPayload.IsByteArray())
-                                       {
-                                               sPayload = std::string(PyByteArray_AsString(pPayload), PyByteArray_Size(pPayload));
-                                       }
--                                      else if (pPayload && PyUnicode_Check(pPayload))
-+                                      else if (pPayload.IsString())
-                                       {
-                                               sPayload = std::string(PyUnicode_AsUTF8(pPayload));
-                                       }
-@@ -1786,7 +1800,7 @@ namespace Plugins {
-                               std::string             Pass;
-                               PyObject* pModule = (PyObject*)WriteMessage->m_pConnection->pPlugin->PythonModule();
-                               PyNewRef        pDict = PyObject_GetAttrString(pModule, "Parameters");
--                              if (pDict)
-+                              if (pDict.IsDict())
-                               {
-                                       PyBorrowedRef   pUser = PyDict_GetItemString(pDict, "Username");
-                                       if (pUser) User = PyUnicode_AsUTF8(pUser);
-@@ -1829,7 +1843,7 @@ namespace Plugins {
-                               // Connect Reason Code
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "ReasonCode");
-                               byteValue = 0;
--                              if (pDictEntry && PyLong_Check(pDictEntry))
-+                              if (pDictEntry.IsLong())
-                               {
-                                       byteValue = PyLong_AsLong(pDictEntry) & 0xFF;
-                               }
-@@ -1838,35 +1852,35 @@ namespace Plugins {
-                               // CONNACK Properties
-                               std::vector<byte> vProperties;
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "SessionExpiryInterval");
--                              if (pDictEntry && PyLong_Check(pDictEntry))
-+                              if (pDictEntry.IsLong())
-                               {
-                                       vProperties.push_back(17);
-                                       MQTTPushBackLong(PyLong_AsLong(pDictEntry), vProperties);
-                               }
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "MaximumQoS");
--                              if (pDictEntry && PyLong_Check(pDictEntry))
-+                              if (pDictEntry.IsLong())
-                               {
-                                       vProperties.push_back(36);
-                                       vProperties.push_back((byte)PyLong_AsLong(pDictEntry));
-                               }
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "RetainAvailable");
--                              if (pDictEntry && PyLong_Check(pDictEntry))
-+                              if (pDictEntry.IsLong())
-                               {
-                                       vProperties.push_back(37);
-                                       vProperties.push_back((byte)PyLong_AsLong(pDictEntry));
-                               }
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "MaximumPacketSize");
--                              if (pDictEntry && PyLong_Check(pDictEntry))
-+                              if (pDictEntry.IsLong())
-                               {
-                                       vProperties.push_back(39);
-                                       MQTTPushBackLong(PyLong_AsLong(pDictEntry), vProperties);
-                               }
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "AssignedClientID");
--                              if (pDictEntry && (pDictEntry != Py_None))
-+                              if (pDictEntry && !pDictEntry.IsNone())
-                               {
-                                       PyNewRef pStr = PyObject_Str(pDictEntry);
-                                       vProperties.push_back(18);
-@@ -1874,7 +1888,7 @@ namespace Plugins {
-                               }
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "ReasonString");
--                              if (pDictEntry && (pDictEntry != Py_None))
-+                              if (pDictEntry && !pDictEntry.IsNone())
-                               {
-                                       PyNewRef pStr = PyObject_Str(pDictEntry);
-                                       vProperties.push_back(26);
-@@ -1882,7 +1896,7 @@ namespace Plugins {
-                               }
-                               pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "ResponseInformation");
--                              if (pDictEntry && (pDictEntry != Py_None))
-+                              if (pDictEntry && !pDictEntry.IsNone())
-                               {
-                                       PyNewRef pStr = PyObject_Str(pDictEntry);
-                                       vProperties.push_back(18);
-@@ -1904,7 +1918,7 @@ namespace Plugins {
-                               // If supplied then use it otherwise create one
-                               PyBorrowedRef pID = PyDict_GetItemString(WriteMessage->m_Object, "PacketIdentifier");
-                               long    iPacketIdentifier = 0;
--                              if (pID && PyLong_Check(pID))
-+                              if (pID.IsLong())
-                               {
-                                       iPacketIdentifier = PyLong_AsLong(pID);
-                               }
-@@ -1913,25 +1927,25 @@ namespace Plugins {
-                               // Payload is list of topics and QoS numbers
-                               PyBorrowedRef pTopicList = PyDict_GetItemString(WriteMessage->m_Object, "Topics");
--                              if (!pTopicList || !PyList_Check(pTopicList))
-+                              if (!pTopicList.IsList())
-                               {
-                                       _log.Log(LOG_ERROR, "(%s) MQTT Subscribe: No 'Topics' list present, nothing to subscribe to. See Python Plugin wiki page for help.", __func__);
-                                       return retVal;
-                               }
-                               for (Py_ssize_t i = 0; i < PyList_Size(pTopicList); i++)
-                               {
--                                      PyObject* pTopicDict = PyList_GetItem(pTopicList, i);
--                                      if (!pTopicDict || !PyDict_Check(pTopicDict))
-+                                      PyBorrowedRef pTopicDict = PyList_GetItem(pTopicList, i);
-+                                      if (!pTopicDict.IsDict())
-                                       {
-                                               _log.Log(LOG_ERROR, "(%s) MQTT Subscribe: Topics list entry is not a dictionary (Topic, QoS), nothing to subscribe to. See Python Plugin wiki page for help.", __func__);
-                                               return retVal;
-                                       }
-                                       PyBorrowedRef pTopic = PyDict_GetItemString(pTopicDict, "Topic");
--                                      if (pTopic && PyUnicode_Check(pTopic))
-+                                      if (pTopic.IsString())
-                                       {
-                                               MQTTPushBackStringWLen(std::string(PyUnicode_AsUTF8(pTopic)), vPayload);
-                                               PyBorrowedRef pQoS = PyDict_GetItemString(pTopicDict, "QoS");
--                                              if (pQoS && PyLong_Check(pQoS))
-+                                              if (pQoS.IsLong())
-                                               {
-                                                       vPayload.push_back((byte)PyLong_AsLong(pQoS));
-                                               }
-@@ -1949,7 +1963,7 @@ namespace Plugins {
-                       // Variable Header
-                       PyBorrowedRef pID = PyDict_GetItemString(WriteMessage->m_Object, "PacketIdentifier");
-                       long iPacketIdentifier = 0;
--                      if (pID && PyLong_Check(pID))
-+                      if (pID.IsLong())
-                       {
-                               iPacketIdentifier = PyLong_AsLong(pID);
-                               MQTTPushBackNumber((int)iPacketIdentifier, vVariableHeader);
-@@ -1961,7 +1975,7 @@ namespace Plugins {
-                       }
-                       PyBorrowedRef pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "QoS");
--                      if (pDictEntry && PyLong_Check(pDictEntry))
-+                      if (pDictEntry.IsLong())
-                       {
-                               vPayload.push_back((byte)PyLong_AsLong(pDictEntry));
-                       }
-@@ -1978,7 +1992,7 @@ namespace Plugins {
-                               // Variable Header
-                               PyBorrowedRef pID = PyDict_GetItemString(WriteMessage->m_Object, "PacketIdentifier");
-                               long    iPacketIdentifier = 0;
--                              if (pID && PyLong_Check(pID))
-+                              if (pID.IsLong())
-                               {
-                                       iPacketIdentifier = PyLong_AsLong(pID);
-                               }
-@@ -1987,15 +2001,15 @@ namespace Plugins {
-                               // Payload is a Python list of topics
-                               PyBorrowedRef pTopicList = PyDict_GetItemString(WriteMessage->m_Object, "Topics");
--                              if (!pTopicList || !PyList_Check(pTopicList))
-+                              if (!pTopicList.IsList())
-                               {
-                                       _log.Log(LOG_ERROR, "(%s) MQTT Subscribe: No 'Topics' list present, nothing to unsubscribe from. See Python Plugin wiki page for help.", __func__);
-                                       return retVal;
-                               }
-                               for (Py_ssize_t i = 0; i < PyList_Size(pTopicList); i++)
-                               {
--                                      PyObject* pTopic = PyList_GetItem(pTopicList, i);
--                                      if (pTopic && PyUnicode_Check(pTopic))
-+                                      PyBorrowedRef pTopic = PyList_GetItem(pTopicList, i);
-+                                      if (pTopic.IsString())
-                                       {
-                                               MQTTPushBackStringWLen(std::string(PyUnicode_AsUTF8(pTopic)), vPayload);
-                                       }
-@@ -2009,7 +2023,7 @@ namespace Plugins {
-                               // Fixed Header
-                               PyBorrowedRef pDUP = PyDict_GetItemString(WriteMessage->m_Object, "Duplicate");
--                              if (pDUP && PyLong_Check(pDUP))
-+                              if (pDUP.IsLong())
-                               {
-                                       long    bDUP = PyLong_AsLong(pDUP);
-                                       if (bDUP) bByte0 |= 0x08; // Set duplicate flag
-@@ -2017,14 +2031,14 @@ namespace Plugins {
-                               PyBorrowedRef pQoS = PyDict_GetItemString(WriteMessage->m_Object, "QoS");
-                               long    iQoS = 0;
--                              if (pQoS && PyLong_Check(pQoS))
-+                              if (pQoS.IsLong())
-                               {
-                                       iQoS = PyLong_AsLong(pQoS);
-                                       bByte0 |= ((iQoS & 3) << 1); // Set QoS flag
-                               }
-                               PyBorrowedRef pRetain = PyDict_GetItemString(WriteMessage->m_Object, "Retain");
--                              if (pRetain && PyLong_Check(pRetain))
-+                              if (pRetain.IsLong())
-                               {
-                                       long    bRetain = PyLong_AsLong(pRetain);
-                                       bByte0 |= (bRetain & 1); // Set retain flag
-@@ -2032,7 +2046,7 @@ namespace Plugins {
-                               // Variable Header
-                               PyBorrowedRef pTopic = PyDict_GetItemString(WriteMessage->m_Object, "Topic");
--                              if (pTopic && PyUnicode_Check(pTopic))
-+                              if (pTopic && pTopic.IsString())
-                               {
-                                       MQTTPushBackStringWLen(std::string(PyUnicode_AsUTF8(pTopic)), vVariableHeader);
-                               }
-@@ -2046,7 +2060,7 @@ namespace Plugins {
-                               if (iQoS)
-                               {
-                                       long    iPacketIdentifier = 0;
--                                      if (pID && PyLong_Check(pID))
-+                                      if (pID.IsLong())
-                                       {
-                                               iPacketIdentifier = PyLong_AsLong(pID);
-                                       }
-@@ -2062,20 +2076,22 @@ namespace Plugins {
-                               PyBorrowedRef pPayload = PyDict_GetItemString(WriteMessage->m_Object, "Payload");
-                               // Support both string and bytes
-                               //if (pPayload && PyByteArray_Check(pPayload)) // Gives linker error, why?
--                              if (pPayload) {
--                                      _log.Debug(DEBUG_NORM, "(%s) MQTT Publish: payload %p (%s)", __func__, (PyObject*)pPayload, pPayload->ob_type->tp_name);
-+                              if (pPayload)
-+                              {
-+                                      PyNewRef        pName = PyObject_GetAttrString((PyObject*)pPayload->ob_type, "__name__");
-+                                      _log.Debug(DEBUG_NORM, "(%s) MQTT Publish: payload %p (%s)", __func__, (PyObject*)pPayload, ((std::string)pName).c_str());
-                               }
--                              if (pPayload && pPayload->ob_type->tp_name == std::string("bytearray"))
-+                              if (pPayload.IsByteArray())
-                               {
-                                       std::string sPayload = std::string(PyByteArray_AsString(pPayload), PyByteArray_Size(pPayload));
-                                       MQTTPushBackString(sPayload, vPayload);
-                               }
--                              else if (pPayload && PyUnicode_Check(pPayload))
-+                              else if (pPayload.IsString())
-                               {
-                                       std::string sPayload = std::string(PyUnicode_AsUTF8(pPayload));
-                                       MQTTPushBackString(sPayload, vPayload);
-                               }
--                              else if (pPayload && PyLong_Check(pPayload))
-+                              else if (pPayload.IsLong())
-                               {
-                                       MQTTPushBackLong(PyLong_AsLong(pPayload), vPayload);
-                               }
-@@ -2086,7 +2102,7 @@ namespace Plugins {
-                               // Variable Header
-                               PyBorrowedRef pID = PyDict_GetItemString(WriteMessage->m_Object, "PacketIdentifier");
-                               long    iPacketIdentifier = 0;
--                              if (pID && PyLong_Check(pID))
-+                              if (pID.IsLong())
-                               {
-                                       iPacketIdentifier = PyLong_AsLong(pID);
-                                       MQTTPushBackNumber((int)iPacketIdentifier, vVariableHeader);
-@@ -2104,7 +2120,7 @@ namespace Plugins {
-                               // Variable Header
-                               PyBorrowedRef pID = PyDict_GetItemString(WriteMessage->m_Object, "PacketIdentifier");
-                               long iPacketIdentifier = 0;
--                              if (pID && PyLong_Check(pID))
-+                              if (pID.IsLong())
-                               {
-                                       iPacketIdentifier = PyLong_AsLong(pID);
-                                       MQTTPushBackNumber((int)iPacketIdentifier, vVariableHeader);
-@@ -2117,7 +2133,7 @@ namespace Plugins {
-                               // Connect Reason Code
-                               PyBorrowedRef   pDictEntry = PyDict_GetItemString(WriteMessage->m_Object, "ReasonCode");
--                              if (pDictEntry && PyLong_Check(pDictEntry))
-+                              if (pDictEntry.IsLong())
-                               {
-                                       vVariableHeader.push_back((byte)PyLong_AsLong(pDictEntry));
-                               }
-@@ -2381,7 +2397,7 @@ namespace Plugins {
-               //      Parameters need to be in a dictionary.
-               //      if a 'URL' key is found message is assumed to be HTTP otherwise WebSocket is assumed
-               //
--              if (!WriteMessage->m_Object || !PyDict_Check(WriteMessage->m_Object))
-+              if (!PyBorrowedRef(WriteMessage->m_Object).IsDict())
-               {
-                       _log.Log(LOG_ERROR, "(%s) Dictionary parameter expected.", __func__);
-               }
-@@ -2444,7 +2460,7 @@ namespace Plugins {
-                       if (pOperation)
-                       {
--                              if (!PyUnicode_Check(pOperation))
-+                              if (!pOperation.IsString())
-                               {
-                                       _log.Log(LOG_ERROR, "(%s) Expected dictionary 'Operation' key to have a string value.", __func__);
-                                       return retVal;
-@@ -2466,36 +2482,33 @@ namespace Plugins {
-                       }
-                       // If there is no specific OpCode then set it from the payload datatype
--                      if (pPayload)
-+                      if (pPayload.IsString())
-                       {
--                              if (PyUnicode_Check(pPayload))
--                              {
--                                      lPayloadLength = PyUnicode_GetLength(pPayload);
--                                      if (!iOpCode)
--                                              iOpCode = 0x01; // Text message
--                              }
--                              else if (PyBytes_Check(pPayload))
--                              {
--                                      lPayloadLength = PyBytes_Size(pPayload);
--                                      if (!iOpCode)
--                                              iOpCode = 0x02; // Binary message
--                              }
--                              else if (pPayload->ob_type->tp_name == std::string("bytearray"))
--                              {
--                                      lPayloadLength = PyByteArray_Size(pPayload);
--                                      if (!iOpCode)
--                                              iOpCode = 0x02; // Binary message
--                              }
-+                              lPayloadLength = PyUnicode_GetLength(pPayload);
-+                              if (!iOpCode)
-+                                      iOpCode = 0x01; // Text message
-+                      }
-+                      else if (pPayload.IsBytes())
-+                      {
-+                              lPayloadLength = PyBytes_Size(pPayload);
-+                              if (!iOpCode)
-+                                      iOpCode = 0x02; // Binary message
-+                      }
-+                      else if (pPayload.IsByteArray())
-+                      {
-+                              lPayloadLength = PyByteArray_Size(pPayload);
-+                              if (!iOpCode)
-+                                      iOpCode = 0x02; // Binary message
-                       }
-                       if (pMask)
-                       {
--                              if (PyLong_Check(pMask))
-+                              if (pMask.IsLong())
-                               {
-                                       lMaskingKey = PyLong_AsLong(pMask);
-                                       bMaskBit = 0x80; // Set mask bit in header
-                               }
--                              else if (PyUnicode_Check(pMask))
-+                              else if (pMask.IsString())
-                               {
-                                       std::string sMask = PyUnicode_AsUTF8(pMask);
-                                       lMaskingKey = atoi(sMask.c_str());
-@@ -2503,7 +2516,7 @@ namespace Plugins {
-                               }
-                               else
-                               {
--                                      _log.Log(LOG_ERROR, "(%s) Invalid mask, expected number (integer or string).", __func__);
-+                                      _log.Log(LOG_ERROR, "(%s) Invalid mask, expected number (integer or string) but got '%s'.", __func__, pMask.Type().c_str());
-                                       return retVal;
-                               }
-                       }
-@@ -2534,31 +2547,28 @@ namespace Plugins {
-                               retVal.push_back(lMaskingKey & 0xFF); // Encode mask
-                       }
--                      if (pPayload)
-+                      if (pPayload.IsString())
-                       {
--                              if (PyUnicode_Check(pPayload))
-+                              std::string sPayload = PyUnicode_AsUTF8(pPayload);
-+                              for (int i = 0; i < lPayloadLength; i++)
-                               {
--                                      std::string sPayload = PyUnicode_AsUTF8(pPayload);
--                                      for (int i = 0; i < lPayloadLength; i++)
--                                      {
--                                              retVal.push_back(sPayload[i] ^ pbMask[i % 4]);
--                                      }
-+                                      retVal.push_back(sPayload[i] ^ pbMask[i % 4]);
-                               }
--                              else if (PyBytes_Check(pPayload))
-+                      }
-+                      else if (pPayload.IsBytes())
-+                      {
-+                              byte *pByte = (byte *)PyBytes_AsString(pPayload);
-+                              for (int i = 0; i < lPayloadLength; i++)
-                               {
--                                      byte *pByte = (byte *)PyBytes_AsString(pPayload);
--                                      for (int i = 0; i < lPayloadLength; i++)
--                                      {
--                                              retVal.push_back(pByte[i] ^ pbMask[i % 4]);
--                                      }
-+                                      retVal.push_back(pByte[i] ^ pbMask[i % 4]);
-                               }
--                              else if (pPayload->ob_type->tp_name == std::string("bytearray"))
-+                      }
-+                      else if (pPayload.IsByteArray())
-+                      {
-+                              byte *pByte = (byte *)PyByteArray_AsString(pPayload);
-+                              for (int i = 0; i < lPayloadLength; i++)
-                               {
--                                      byte *pByte = (byte *)PyByteArray_AsString(pPayload);
--                                      for (int i = 0; i < lPayloadLength; i++)
--                                      {
--                                              retVal.push_back(pByte[i] ^ pbMask[i % 4]);
--                                      }
-+                                      retVal.push_back(pByte[i] ^ pbMask[i % 4]);
-                               }
-                       }
-               }
---- a/hardware/plugins/PluginTransports.cpp
-+++ b/hardware/plugins/PluginTransports.cpp
-@@ -15,6 +15,8 @@
- namespace Plugins {
-+      extern PyTypeObject* CConnectionType;
-+
-       void CPluginTransport::configureTimeout()
-       {
-               if (m_pConnection->Timeout)
-@@ -198,8 +200,6 @@ namespace Plugins {
-       {
-               try
-               {
--                      PyType_Ready(&CConnectionType);
--
-                       if (!m_Socket)
-                       {
-                               if (!m_Acceptor)
-@@ -239,8 +239,21 @@ namespace Plugins {
-                       std::string sAddress = remote_ep.address().to_string();
-                       std::string sPort = std::to_string(remote_ep.port());
--                      CConnection *pConnection
--                              = (CConnection *)CConnection_new(&CConnectionType, (PyObject *)nullptr, (PyObject *)nullptr);
-+                      PyNewRef nrArgList = Py_BuildValue("(sssss)",
-+                              std::string(sAddress+":"+sPort).c_str(),
-+                              PyUnicode_AsUTF8(((CConnection*)m_pConnection)->Transport),
-+                              PyUnicode_AsUTF8(((CConnection*)m_pConnection)->Protocol),
-+                              sAddress.c_str(),
-+                              sPort.c_str());
-+                      if (!nrArgList)
-+                      {
-+                              pPlugin->Log(LOG_ERROR, "Building connection argument list failed for TCP %s:%s.", sAddress.c_str(), sPort.c_str());
-+                      }
-+                      CConnection* pConnection = (CConnection*)PyObject_CallObject((PyObject*)CConnectionType, nrArgList);
-+                      if (!pConnection)
-+                      {
-+                              pPlugin->Log(LOG_ERROR, "Connection object creation failed for TCP %s:%s.", sAddress.c_str(), sPort.c_str());
-+                      }
-                       CPluginTransportTCP* pTcpTransport = new CPluginTransportTCP(m_HwdID, pConnection, sAddress, sPort);
-                       Py_DECREF(pConnection);
-@@ -252,20 +265,10 @@ namespace Plugins {
-                       // Configure Python Connection object
-                       pConnection->pTransport = pTcpTransport;
--                      Py_XDECREF(pConnection->Name);
--                      pConnection->Name = PyUnicode_FromString(std::string(sAddress+":"+sPort).c_str());
--                      Py_XDECREF(pConnection->Address);
--                      pConnection->Address = PyUnicode_FromString(sAddress.c_str());
--                      Py_XDECREF(pConnection->Port);
--                      pConnection->Port = PyUnicode_FromString(sPort.c_str());
-                       Py_XDECREF(pConnection->Parent);
-                       pConnection->Parent = (PyObject*)m_pConnection;
-                       Py_INCREF(m_pConnection);
--                      pConnection->Transport = ((CConnection*)m_pConnection)->Transport;
--                      Py_INCREF(pConnection->Transport);
--                      pConnection->Protocol = ((CConnection*)m_pConnection)->Protocol;
--                      Py_INCREF(pConnection->Protocol);
-                       pConnection->Target = ((CConnection *)m_pConnection)->Target;
-                       if (pConnection->Target)
-                               Py_INCREF(pConnection->Target);
-@@ -626,8 +629,6 @@ namespace Plugins {
-       {
-               try
-               {
--                      PyType_Ready(&CConnectionType);
--
-                       if (!m_Socket)
-                       {
-                               boost::system::error_code ec;
-@@ -680,21 +681,22 @@ namespace Plugins {
-                       std::string sAddress = m_remote_endpoint.address().to_string();
-                       std::string sPort = std::to_string(m_remote_endpoint.port());
--                      CConnection *pConnection
--                              = (CConnection *)CConnection_new(&CConnectionType, (PyObject *)nullptr, (PyObject *)nullptr);
-+                      PyNewRef nrArgList = Py_BuildValue("(sssss)", 
-+                                                                                              PyUnicode_AsUTF8(((CConnection*)m_pConnection)->Name), 
-+                                                                                              PyUnicode_AsUTF8(((CConnection*)m_pConnection)->Transport),
-+                                                                                              PyUnicode_AsUTF8(((CConnection*)m_pConnection)->Protocol),
-+                                                                                              sAddress.c_str(),
-+                                                                                              sPort.c_str());
-+                      if (!nrArgList)
-+                      {
-+                              pPlugin->Log(LOG_ERROR, "Building connection argument list failed for UDP %s:%s.", sAddress.c_str(), sPort.c_str());
-+                      }
-+                      CConnection* pConnection = (CConnection*)PyObject_CallObject((PyObject*)CConnectionType, nrArgList);
-+                      if (!pConnection)
-+                      {
-+                              pPlugin->Log(LOG_ERROR, "Connection object creation failed for UDP %s:%s.", sAddress.c_str(), sPort.c_str());
-+                      }
--                      // Configure temporary Python Connection object
--                      Py_XDECREF(pConnection->Name);
--                      pConnection->Name = ((CConnection*)m_pConnection)->Name;
--                      Py_INCREF(pConnection->Name);
--                      Py_XDECREF(pConnection->Address);
--                      pConnection->Address = PyUnicode_FromString(sAddress.c_str());
--                      Py_XDECREF(pConnection->Port);
--                      pConnection->Port = PyUnicode_FromString(sPort.c_str());
--                      pConnection->Transport = ((CConnection*)m_pConnection)->Transport;
--                      Py_INCREF(pConnection->Transport);
--                      pConnection->Protocol = ((CConnection*)m_pConnection)->Protocol;
--                      Py_INCREF(pConnection->Protocol);
-                       pConnection->Target = ((CConnection *)m_pConnection)->Target;
-                       if (pConnection->Target)
-                               Py_INCREF(pConnection->Target);
---- a/hardware/plugins/Plugins.cpp
-+++ b/hardware/plugins/Plugins.cpp
-@@ -5,6 +5,8 @@
- //
- #ifdef ENABLE_PYTHON
-+#include "../../main/Helper.h"
-+
- #include "Plugins.h"
- #include "PluginMessages.h"
- #include "PluginProtocols.h"
-@@ -41,44 +43,22 @@ extern MainWorker m_mainworker;
- namespace Plugins
- {
--      std::mutex              AccessPython::PythonMutex;
--      volatile bool   AccessPython::m_bHasThreadState = false;
-+      extern PyTypeObject* CDeviceType;
-+      extern PyTypeObject* CConnectionType;
-+      extern PyTypeObject* CImageType;
--      AccessPython::AccessPython(CPlugin* pPlugin, const char* sWhat) : m_Python(NULL)
-+      AccessPython::AccessPython(CPlugin* pPlugin, const char* sWhat) 
-       {
-               m_pPlugin = pPlugin;
-               m_Text = sWhat;
--              m_Lock = new std::unique_lock<std::mutex>(PythonMutex, std::defer_lock);
--              if (!m_Lock->try_lock())
--              {
--                      if (m_pPlugin)
--                      {
--                              if (m_pPlugin->m_bDebug & PDM_LOCKING)
--                              {
--                                      _log.Log(LOG_NORM, "(%s) Requesting lock for '%s', waiting...", m_pPlugin->m_Name.c_str(), m_Text);
--                              }
--                      }
--                      else _log.Log(LOG_NORM, "Python lock requested for '%s' in use, will wait.", m_Text);
--                      m_Lock->lock();
--              }
--
--              if (pPlugin)
-+              if (m_pPlugin)
-               {
--                      if (pPlugin->m_bDebug & PDM_LOCKING)
--                      {
--                              _log.Log(LOG_NORM, "(%s) Acquiring lock for '%s'", pPlugin->m_Name.c_str(), m_Text);
--                      }
--                      m_Python = pPlugin->PythonInterpreter();
--                      if (m_Python)
-+                      if (m_pPlugin->m_bDebug & PDM_LOCKING)
-                       {
--                              PyEval_RestoreThread(m_Python);
--                              m_bHasThreadState = true;
--                      }
--                      else
--                      {
--                              _log.Log(LOG_ERROR, "Attempt to aquire the GIL with NULL Interpreter details.");
-+                              m_pPlugin->Log(LOG_NORM, "Acquiring GIL for '%s'", m_Text.c_str());
-                       }
-+                      m_pPlugin->RestoreThread();
-               }
-               else
-               {
-@@ -88,215 +68,39 @@ namespace Plugins
-       AccessPython::~AccessPython()
-       {
--              if (m_Python && m_pPlugin)
-+              if (m_pPlugin)
-               {
-                       if (PyErr_Occurred())
-                       {
--                              _log.Log(LOG_NORM, "(%s) Python error was set during unlock for '%s'", m_pPlugin->m_Name.c_str(), m_Text);
-+                              m_pPlugin->Log(LOG_NORM, "Python error was set during unlock for '%s'", m_Text.c_str());
-                               m_pPlugin->LogPythonException();
-                               PyErr_Clear();
-                       }
--
--                      m_bHasThreadState = false;
--                      if (m_pPlugin->PythonInterpreter() && !PyEval_SaveThread())
--                      {
--                              _log.Log(LOG_ERROR, "(%s) Python Save state returned NULL value for '%s'", m_pPlugin->m_Name.c_str(), m_Text);
--                      }
--              }
--              if (m_Lock)
--              {
--                      if (m_pPlugin && m_pPlugin->m_bDebug & PDM_LOCKING)
--                      {
--                              _log.Log(LOG_NORM, "(%s) Releasing lock for '%s'", m_pPlugin->m_Name.c_str(), m_Text);
--                      }
--                      delete m_Lock;
--              }
--      }
--
--      void LogPythonException(CPlugin *pPlugin, const std::string &sHandler)
--      {
--              PyTracebackObject *pTraceback;
--              PyNewRef                        pExcept;
--              PyNewRef                        pValue;
--              PyTypeObject *TypeName;
--              PyBytesObject *pErrBytes = nullptr;
--              const char *pTypeText = nullptr;
--              std::string Name = "Unknown";
--
--              if (pPlugin)
--                      Name = pPlugin->m_Name;
--
--              PyErr_Fetch(&pExcept, &pValue, (PyObject **)&pTraceback);
--
--              if (pExcept)
--              {
--                      TypeName = (PyTypeObject *)pExcept;
--                      pTypeText = TypeName->tp_name;
--              }
--              if (pValue)
--              {
--                      pErrBytes = (PyBytesObject *)PyUnicode_AsASCIIString(pValue);
--              }
--              if (pTypeText && pErrBytes)
--              {
--                      if (pPlugin)
--                              pPlugin->Log(LOG_ERROR, "'%s' failed '%s':'%s'.", sHandler.c_str(), pTypeText, pErrBytes->ob_sval);
--                      else
--                              _log.Log(LOG_ERROR, "'%s' failed '%s':'%s'.", sHandler.c_str(), pTypeText, pErrBytes->ob_sval);
--              }
--              if (pTypeText && !pErrBytes)
--              {
--                      if (pPlugin)
--                              pPlugin->Log(LOG_ERROR, "'%s' failed '%s'.", sHandler.c_str(), pTypeText);
--                      else
--                              _log.Log(LOG_ERROR, "'%s' failed '%s'.", sHandler.c_str(), pTypeText);
--              }
--              if (!pTypeText && pErrBytes)
--              {
--                      if (pPlugin)
--                              pPlugin->Log(LOG_ERROR, "'%s' failed '%s'.", sHandler.c_str(), pErrBytes->ob_sval);
--                      else
--                              _log.Log(LOG_ERROR, "'%s' failed '%s'.", sHandler.c_str(), pErrBytes->ob_sval);
--              }
--              if (!pTypeText && !pErrBytes)
--              {
--                      if (pPlugin)
--                              pPlugin->Log(LOG_ERROR, "'%s' failed, unable to determine error.", sHandler.c_str());
--                      else
--                              _log.Log(LOG_ERROR, "'%s' failed, unable to determine error.", sHandler.c_str());
--              }
--              if (pErrBytes)
--                      Py_XDECREF(pErrBytes);
--
--              // Log a stack trace if there is one
--              if (pPlugin && pTraceback)
--                      pPlugin->LogTraceback(pTraceback);
--
--              if (!pExcept && !pValue && !pTraceback)
--              {
--                      if (pPlugin)
--                              pPlugin->Log(LOG_ERROR, "Call to message handler '%s' failed, unable to decode exception.", sHandler.c_str());
--                      else
--                              _log.Log(LOG_ERROR, "Call to message handler '%s' failed, unable to decode exception.", sHandler.c_str());
--              }
--
--              if (pTraceback)
--                      Py_XDECREF(pTraceback);
--      }
--
--      int PyDomoticz_ProfileFunc(PyObject *self, PyFrameObject *frame, int what, PyObject *arg)
--      {
--              module_state *pModState = CPlugin::FindModule();
--              if (!pModState)
--              {
--                      return 0;
--              }
--              else if (!pModState->pPlugin)
--              {
--                      _log.Log(LOG_ERROR, "CPlugin:%s, illegal operation, Plugin has not started yet.", __func__);
--              }
--              else
--              {
--                      int lineno = PyFrame_GetLineNumber(frame);
--                      std::string sFuncName = "Unknown";
--                      PyCodeObject *pCode = frame->f_code;
--                      if (pCode && pCode->co_filename)
--                      {
--                              sFuncName = (std::string)PyBorrowedRef(pCode->co_filename);
--                      }
--                      if (pCode && pCode->co_name)
--                      {
--                              if (!sFuncName.empty())
--                                      sFuncName += "\\";
--                              sFuncName += (std::string)PyBorrowedRef(pCode->co_name);
--                      }
--
--                      switch (what)
--                      {
--                              case PyTrace_CALL:
--                                      pModState->pPlugin->Log(LOG_NORM, "Calling function at line %d in '%s'", lineno, sFuncName.c_str());
--                                      break;
--                              case PyTrace_RETURN:
--                                      pModState->pPlugin->Log(LOG_NORM, "Returning from line %d in '%s'", lineno, sFuncName.c_str());
--                                      break;
--                              case PyTrace_EXCEPTION:
--                                      pModState->pPlugin->Log(LOG_NORM, "Exception at line %d in '%s'", lineno, sFuncName.c_str());
--                                      break;
--                      }
--              }
--
--              return 0;
--      }
--
--      int PyDomoticz_TraceFunc(PyObject *self, PyFrameObject *frame, int what, PyObject *arg)
--      {
--              module_state *pModState = CPlugin::FindModule();
--              if (!pModState)
--              {
--                      return 0;
--              }
--              else if (!pModState->pPlugin)
--              {
--                      _log.Log(LOG_ERROR, "CPlugin:%s, illegal operation, Plugin has not started yet.", __func__);
--              }
--              else
--              {
--                      int lineno = PyFrame_GetLineNumber(frame);
--                      std::string sFuncName = "Unknown";
--                      PyCodeObject *pCode = frame->f_code;
--                      if (pCode && pCode->co_filename)
--                      {
--                              sFuncName = (std::string)PyBorrowedRef(pCode->co_filename);
--                      }
--                      if (pCode && pCode->co_name)
--                      {
--                              if (!sFuncName.empty())
--                                      sFuncName += "\\";
--                              sFuncName += (std::string)PyBorrowedRef(pCode->co_name);
--                      }
--
--                      switch (what)
--                      {
--                              case PyTrace_CALL:
--                                      pModState->pPlugin->Log(LOG_NORM, "Calling function at line %d in '%s'", lineno, sFuncName.c_str());
--                                      break;
--                              case PyTrace_LINE:
--                                      pModState->pPlugin->Log(LOG_NORM, "Executing line %d in '%s'", lineno, sFuncName.c_str());
--                                      break;
--                              case PyTrace_EXCEPTION:
--                                      pModState->pPlugin->Log(LOG_NORM, "Exception at line %d in '%s'", lineno, sFuncName.c_str());
--                                      break;
--                      }
-+                      m_pPlugin->ReleaseThread();
-               }
--
--              return 0;
-       }
-       static PyObject *PyDomoticz_Debug(PyObject *self, PyObject *args)
-       {
--              module_state *pModState = CPlugin::FindModule();
--              if (!pModState)
-+              CPlugin* pPlugin = CPlugin::FindPlugin();
-+              if (!pPlugin)
-               {
--                      Py_RETURN_NONE;
--              }
--              else if (!pModState->pPlugin)
--              {
--                      _log.Log(LOG_ERROR, "CPlugin:%s, illegal operation, Plugin has not started yet.", __func__);
-+                      _log.Log(LOG_ERROR, "%s, illegal operation, Plugin has not started yet.", __func__);
-               }
-               else
-               {
--                      if (pModState->pPlugin->m_bDebug & PDM_PYTHON)
-+                      if (pPlugin->m_bDebug & PDM_PYTHON)
-                       {
-                               char *msg;
-                               if (!PyArg_ParseTuple(args, "s", &msg))
-                               {
-                                       // TODO: Dump data to aid debugging
--                                      pModState->pPlugin->Log(LOG_ERROR, "PyDomoticz_Debug failed to parse parameters: string expected.");
--                                      LogPythonException(pModState->pPlugin, std::string(__func__));
-+                                      pPlugin->Log(LOG_ERROR, "%s failed to parse parameters: string expected.", __func__);
-+                                      pPlugin->LogPythonException(std::string(__func__));
-                               }
-                               else
-                               {
--                                      pModState->pPlugin->Log(LOG_NORM, (std::string)msg);
-+                                      pPlugin->Log(LOG_NORM, (std::string)msg);
-                               }
-                       }
-               }
-@@ -306,12 +110,8 @@ namespace Plugins
-       static PyObject *PyDomoticz_Log(PyObject *self, PyObject *args)
-       {
--              module_state *pModState = CPlugin::FindModule();
--              if (!pModState)
--              {
--                      Py_RETURN_NONE;
--              }
--              else if (!pModState->pPlugin)
-+              CPlugin* pPlugin = CPlugin::FindPlugin();
-+              if (!pPlugin)
-               {
-                       _log.Log(LOG_ERROR, "CPlugin:%s, illegal operation, Plugin has not started yet.", __func__);
-               }
-@@ -320,12 +120,12 @@ namespace Plugins
-                       char *msg;
-                       if (!PyArg_ParseTuple(args, "s", &msg))
-                       {
--                              pModState->pPlugin->Log(LOG_ERROR, "PyDomoticz_Log failed to parse parameters: string expected.");
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
-+                              pPlugin->Log(LOG_ERROR, "%s failed to parse parameters: string expected.", __func__);
-+                              pPlugin->LogPythonException(std::string(__func__));
-                       }
-                       else
-                       {
--                              pModState->pPlugin->Log(LOG_NORM, (std::string)msg);
-+                              pPlugin->Log(LOG_NORM, (std::string)msg);
-                       }
-               }
-@@ -334,26 +134,22 @@ namespace Plugins
-       static PyObject *PyDomoticz_Status(PyObject *self, PyObject *args)
-       {
--              module_state *pModState = CPlugin::FindModule();
--              if (!pModState)
-+              CPlugin* pPlugin = CPlugin::FindPlugin();
-+              if (!pPlugin)
-               {
--                      Py_RETURN_NONE;
--              }
--              else if (!pModState->pPlugin)
--              {
--                      _log.Log(LOG_ERROR, "CPlugin:%s, illegal operation, Plugin has not started yet.", __func__);
-+                      _log.Log(LOG_ERROR, "%s, illegal operation, Plugin has not started yet.", __func__);
-               }
-               else
-               {
-                       char *msg;
-                       if (!PyArg_ParseTuple(args, "s", &msg))
-                       {
--                              pModState->pPlugin->Log(LOG_ERROR, "%s failed to parse parameters: string expected.", std::string(__func__).c_str());
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
-+                              pPlugin->Log(LOG_ERROR, "%s failed to parse parameters: string expected.", __func__);
-+                              pPlugin->LogPythonException(std::string(__func__));
-                       }
-                       else
-                       {
--                              pModState->pPlugin->Log(LOG_STATUS, (std::string)msg);
-+                              pPlugin->Log(LOG_STATUS, (std::string)msg);
-                       }
-               }
-@@ -362,14 +158,10 @@ namespace Plugins
-       static PyObject *PyDomoticz_Error(PyObject *self, PyObject *args)
-       {
--              module_state *pModState = CPlugin::FindModule();
--              if (!pModState)
--              {
--                      Py_RETURN_NONE;
--              }
--              else if (!pModState->pPlugin)
-+              CPlugin* pPlugin = CPlugin::FindPlugin();
-+              if (!pPlugin)
-               {
--                      _log.Log(LOG_ERROR, "CPlugin:%s, illegal operation, Plugin has not started yet.", __func__);
-+                      _log.Log(LOG_ERROR, "%s, illegal operation, Plugin has not started yet.", __func__);
-               }
-               else
-               {
-@@ -377,12 +169,12 @@ namespace Plugins
-                       if ((PyTuple_Size(args) != 1) || !PyArg_ParseTuple(args, "s", &msg))
-                       {
-                               // TODO: Dump data to aid debugging
--                              pModState->pPlugin->Log(LOG_ERROR, "PyDomoticz_Error failed to parse parameters: string expected.");
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
-+                              pPlugin->Log(LOG_ERROR, "%s failed to parse parameters: string expected.", __func__);
-+                              pPlugin->LogPythonException(std::string(__func__));
-                       }
-                       else
-                       {
--                              pModState->pPlugin->Log(LOG_ERROR, (std::string)msg);
-+                              pPlugin->Log(LOG_ERROR, (std::string)msg);
-                       }
-               }
-@@ -406,7 +198,7 @@ namespace Plugins
-                       if (!PyArg_ParseTuple(args, "i", &type))
-                       {
-                               pModState->pPlugin->Log(LOG_ERROR, "Failed to parse parameters, integer expected.");
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
-+                              pModState->pPlugin->LogPythonException(std::string(__func__));
-                       }
-                       else
-                       {
-@@ -440,12 +232,12 @@ namespace Plugins
-               else
-               {
-                       iPollinterval = pModState->pPlugin->PollInterval(0);
--                      if (PyTuple_Check(args) && PyTuple_Size(args))
-+                      if (PyBorrowedRef(args).IsTuple() && PyTuple_Size(args))
-                       {
-                               if (!PyArg_ParseTuple(args, "i", &iPollinterval))
-                               {
-                                       pModState->pPlugin->Log(LOG_ERROR, "failed to parse parameters, integer expected.");
--                                      LogPythonException(pModState->pPlugin, std::string(__func__));
-+                                      pModState->pPlugin->LogPythonException(std::string(__func__));
-                               }
-                               else
-                               {
-@@ -475,7 +267,7 @@ namespace Plugins
-                       if (!PyArg_ParseTuple(args, "s", &szNotifier))
-                       {
-                               pModState->pPlugin->Log(LOG_ERROR, "Failed to parse parameters, Notifier Name expected.");
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
-+                              pModState->pPlugin->LogPythonException(std::string(__func__));
-                       }
-                       else
-                       {
-@@ -508,28 +300,7 @@ namespace Plugins
-               }
-               else
-               {
--                      int bTrace = 0;
--                      if (!PyArg_ParseTuple(args, "p", &bTrace))
--                      {
--                              pModState->pPlugin->Log(LOG_ERROR, "Failed to parse parameter, True/False expected.");
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
--                      }
--                      else
--                      {
--                              pModState->pPlugin->m_bTracing = (bool)bTrace;
--                              pModState->pPlugin->Log(LOG_NORM, "Low level Python tracing %s.", (pModState->pPlugin->m_bTracing ? "ENABLED" : "DISABLED"));
--
--                              if (pModState->pPlugin->m_bTracing)
--                              {
--                                      PyEval_SetProfile(PyDomoticz_ProfileFunc, self);
--                                      PyEval_SetTrace(PyDomoticz_TraceFunc, self);
--                              }
--                              else
--                              {
--                                      PyEval_SetProfile(nullptr, nullptr);
--                                      PyEval_SetTrace(nullptr, nullptr);
--                              }
--                      }
-+                      pModState->pPlugin->Log(LOG_ERROR, "CPlugin:%s, Low level trace functions have been removed.", __func__);
-               }
-               Py_RETURN_NONE;
-@@ -554,7 +325,7 @@ namespace Plugins
-                       if (PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &pNewConfig))
-                       {
-                               // Python object supplied if it is not a dictionary
--                              if (!PyDict_Check(pNewConfig))
-+                              if (!PyBorrowedRef(pNewConfig).IsDict())
-                               {
-                                       pModState->pPlugin->Log(LOG_ERROR, "CPlugin:%s, Function expects no parameter or a Dictionary.", __func__);
-                                       Py_RETURN_NONE;
-@@ -603,46 +374,26 @@ namespace Plugins
-                       {
-                               if (pDeviceClass)
-                               {
--                                      PyTypeObject *pBaseClass = pDeviceClass->tp_base;
--                                      while (pBaseClass)
-+                                      if (!PyType_IsSubtype(pDeviceClass, pModState->pDeviceClass))
-                                       {
--                                              if (pBaseClass->tp_name == pModState->pDeviceClass->tp_name)
--                                              {
--                                                      //_log.Log((_eLogLevel)LOG_NORM, "Class '%s' registered to override '%s'.", pDeviceClass->tp_name, pModState->pDeviceClass->tp_name);
--                                                      pModState->pDeviceClass = pDeviceClass;
--                                                      break;
--                                              }
--                                              pBaseClass = pBaseClass->tp_base;
-+                                              pModState->pPlugin->Log(LOG_ERROR, "Device class registration failed, Supplied class is not derived from 'DomoticzEx.Device'");
-                                       }
--                                      if (pDeviceClass->tp_name != pModState->pDeviceClass->tp_name)
-+                                      else
-                                       {
--                                              pModState->pPlugin->Log(LOG_ERROR, "Class '%s' registration failed, Device is not derived from '%s'", pDeviceClass->tp_name, pModState->pDeviceClass->tp_name);
-+                                              pModState->pDeviceClass = pDeviceClass;
-+                                              PyType_Ready(pModState->pDeviceClass);
-                                       }
-                               }
-                               if (pUnitClass)
-                               {
--                                      if (pModState->pUnitClass)
-+                                      if (!PyType_IsSubtype(pUnitClass, pModState->pUnitClass))
-                                       {
--                                              PyTypeObject *pBaseClass = pUnitClass->tp_base;
--                                              while (pBaseClass)
--                                              {
--                                                      if (pBaseClass->tp_name == pModState->pUnitClass->tp_name)
--                                                      {
--                                                              //_log.Log((_eLogLevel)LOG_NORM, "Class '%s' registered to override '%s'.", pDeviceClass->tp_name, pModState->pUnitClass->tp_name);
--                                                              pModState->pUnitClass = pUnitClass;
--                                                              break;
--                                                      }
--                                                      pBaseClass = pBaseClass->tp_base;
--                                              }
--                                              if (pUnitClass->tp_name != pModState->pUnitClass->tp_name)
--                                              {
--                                                      pModState->pPlugin->Log(LOG_ERROR, "Class '%s' registration failed, Unit is not derived from '%s'", pUnitClass->tp_name,
--                                                               pModState->pDeviceClass->tp_name);
--                                              }
-+                                              pModState->pPlugin->Log(LOG_ERROR, "Unit class registration failed, Supplied class is not derived from 'DomoticzEx.Unit'");
-                                       }
-                                       else
-                                       {
--                                              pModState->pPlugin->Log(LOG_ERROR, "Class '%s' registration failed, imported Domoticz module does not support Unit objects", pUnitClass->tp_name);
-+                                              pModState->pUnitClass = pUnitClass;
-+                                              PyType_Ready(pModState->pUnitClass);
-                                       }
-                               }
-                       }
-@@ -669,12 +420,12 @@ namespace Plugins
-                       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pTarget))
-                       {
-                               pModState->pPlugin->Log(LOG_ERROR, "%s failed to parse parameters: Object expected (Optional).", __func__);
--                              LogPythonException(pModState->pPlugin, std::string(__func__));
-+                              pModState->pPlugin->LogPythonException(std::string(__func__));
-                       }
-                       else
-                       {
-                               PyNewRef pLocals = PyObject_Dir(pModState->lastCallback);
--                              if (PyList_Check(pLocals)) // && PyIter_Check(pLocals))  // Check fails but iteration works??!?
-+                              if (pLocals.IsList()) // && PyIter_Check(pLocals))  // Check fails but iteration works??!?
-                               {
-                                       pModState->pPlugin->Log(LOG_NORM, "Context dump:");
-                                       PyNewRef pIter = PyObject_GetIter(pLocals);
-@@ -702,7 +453,7 @@ namespace Plugins
-                                       }
-                               }
-                               PyBorrowedRef pLocalVars = PyEval_GetLocals();
--                              if (PyDict_Check(pLocalVars))
-+                              if (pLocalVars.IsDict())
-                               {
-                                       pModState->pPlugin->Log(LOG_NORM, "Locals dump:");
-                                       PyBorrowedRef key;
-@@ -717,7 +468,7 @@ namespace Plugins
-                                       }
-                               }
-                               PyBorrowedRef pGlobalVars = PyEval_GetGlobals();
--                              if (PyDict_Check(pGlobalVars))
-+                              if (pGlobalVars.IsDict())
-                               {
-                                       pModState->pPlugin->Log(LOG_NORM, "Globals dump:");
-                                       PyBorrowedRef key;
-@@ -753,6 +504,30 @@ namespace Plugins
-                                                { "Dump", (PyCFunction)PyDomoticz_Dump, METH_VARARGS | METH_KEYWORDS, "Dump string values of an object or all locals to the log." },
-                                                { nullptr, nullptr, 0, nullptr } };
-+      PyType_Slot ConnectionSlots[] = {
-+              { Py_tp_doc, (void*)"Domoticz Connection" },
-+              { Py_tp_new, (void*)CConnection_new },
-+              { Py_tp_init, (void*)CConnection_init },
-+              { Py_tp_dealloc, (void*)CConnection_dealloc },
-+              { Py_tp_members, CConnection_members },
-+              { Py_tp_methods, CConnection_methods },
-+              { Py_tp_str, (void*)CConnection_str },
-+              { 0 },
-+      };
-+      PyType_Spec ConnectionSpec = { "Domoticz.Connection", sizeof(CConnection), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE, ConnectionSlots };
-+
-+      PyType_Slot ImageSlots[] = {
-+              { Py_tp_doc, (void*)"Domoticz Image" },
-+              { Py_tp_new, (void*)CImage_new },
-+              { Py_tp_init, (void*)CImage_init },
-+              { Py_tp_dealloc, (void*)CImage_dealloc },
-+              { Py_tp_members, CImage_members },
-+              { Py_tp_methods, CImage_methods },
-+              { Py_tp_str, (void*)CImage_str },
-+              { 0 },
-+      };
-+      PyType_Spec ImageSpec = { "Domoticz.Image", sizeof(CImage), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE, ImageSlots };
-+
-       static int DomoticzTraverse(PyObject *m, visitproc visit, void *arg)
-       {
-               Py_VISIT(GETSTATE(m)->error);
-@@ -769,37 +544,46 @@ namespace Plugins
-       PyMODINIT_FUNC PyInit_Domoticz(void)
-       {
--
-               // This is called during the import of the plugin module
-               // triggered by the "import Domoticz" statement
-               PyObject *pModule = PyModule_Create2(&DomoticzModuleDef, PYTHON_API_VERSION);
-               module_state *pModState = ((struct module_state *)PyModule_GetState(pModule));
--              if (PyType_Ready(&CDeviceType) < 0)
-+              if (!CDeviceType)
-               {
--                      _log.Log(LOG_ERROR, "%s, Device Type not ready.", __func__);
--                      return pModule;
-+                      PyType_Slot DeviceSlots[] = {
-+                              { Py_tp_doc, (void*)"Domoticz Device" },
-+                              { Py_tp_new, (void*)CDevice_new },
-+                              { Py_tp_init, (void*)CDevice_init },
-+                              { Py_tp_dealloc, (void*)CDevice_dealloc },
-+                              { Py_tp_members, CDevice_members },
-+                              { Py_tp_methods, CDevice_methods },
-+                              { Py_tp_str, (void*)CDevice_str },
-+                              { 0 },
-+                      };
-+                      PyType_Spec DeviceSpec = { "Domoticz.Device", sizeof(CDevice), 0,
-+                                                                Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE, DeviceSlots };
-+
-+                      CDeviceType = (PyTypeObject*)PyType_FromSpec(&DeviceSpec);
-+                      PyType_Ready(CDeviceType);
-               }
--              Py_INCREF((PyObject *)&CDeviceType);
--              PyModule_AddObject(pModule, "Device", (PyObject *)&CDeviceType);
--              pModState->pDeviceClass = &CDeviceType;
-+              pModState->pDeviceClass = CDeviceType;
-               pModState->pUnitClass = nullptr;
-+              PyModule_AddObject(pModule, "Device", (PyObject*)CDeviceType);
--              if (PyType_Ready(&CConnectionType) < 0)
-+              if (!CConnectionType)
-               {
--                      _log.Log(LOG_ERROR, "%s, Connection Type not ready.", __func__);
--                      return pModule;
-+                      CConnectionType = (PyTypeObject*)PyType_FromSpec(&ConnectionSpec);
-+                      PyType_Ready(CConnectionType);
-               }
--              Py_INCREF((PyObject *)&CConnectionType);
--              PyModule_AddObject(pModule, "Connection", (PyObject *)&CConnectionType);
-+              PyModule_AddObject(pModule, "Connection", (PyObject*)CConnectionType);
--              if (PyType_Ready(&CImageType) < 0)
-+              if (!CImageType)
-               {
--                      _log.Log(LOG_ERROR, "%s, Image Type not ready.", __func__);
--                      return pModule;
-+                      CImageType = (PyTypeObject*)PyType_FromSpec(&ImageSpec);
-+                      PyType_Ready(CImageType);
-               }
--              Py_INCREF((PyObject *)&CImageType);
--              PyModule_AddObject(pModule, "Image", (PyObject *)&CImageType);
-+              PyModule_AddObject(pModule, "Image", (PyObject*)CImageType);
-               return pModule;
-       }
-@@ -808,45 +592,58 @@ namespace Plugins
-       PyMODINIT_FUNC PyInit_DomoticzEx(void)
-       {
--
-               // This is called during the import of the plugin module
--              // triggered by the "import Domoticz" statement
-+              // triggered by the "import DomoticzEx" statement
-               PyObject *pModule = PyModule_Create2(&DomoticzExModuleDef, PYTHON_API_VERSION);
-               module_state *pModState = ((struct module_state *)PyModule_GetState(pModule));
--              if (PyType_Ready(&CDeviceExType) < 0)
--              {
--                      _log.Log(LOG_ERROR, "%s, Device Type not ready.", __func__);
--                      return pModule;
--              }
--              Py_INCREF((PyObject *)&CDeviceExType);
--              PyModule_AddObject(pModule, "Device", (PyObject *)&CDeviceExType);
--              pModState->pDeviceClass = &CDeviceExType;
--
--              if (PyType_Ready(&CUnitExType) < 0)
--              {
--                      _log.Log(LOG_ERROR, "%s, Unit Type not ready.", __func__);
--                      return pModule;
--              }
--              Py_INCREF((PyObject *)&CUnitExType);
--              PyModule_AddObject(pModule, "Unit", (PyObject *)&CUnitExType);
--              pModState->pUnitClass = &CUnitExType;
--
--              if (PyType_Ready(&CConnectionType) < 0)
--              {
--                      _log.Log(LOG_ERROR, "%s, Connection Type not ready.", __func__);
--                      return pModule;
-+              PyType_Slot DeviceExSlots[] = {
-+                      { Py_tp_doc, (void*)"DomoticzEx Device" },
-+                      { Py_tp_new, (void*)CDeviceEx_new },
-+                      { Py_tp_init, (void*)CDeviceEx_init },
-+                      { Py_tp_dealloc, (void*)CDeviceEx_dealloc },
-+                      { Py_tp_members, CDeviceEx_members },
-+                      { Py_tp_methods, CDeviceEx_methods },
-+                      { Py_tp_str, (void*)CDeviceEx_str },
-+                      { 0 },
-+              };
-+              PyType_Spec DeviceExSpec = { "DomoticzEx.Device", sizeof(CDeviceEx), 0,
-+                                                        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE, DeviceExSlots };
-+
-+              pModState->pDeviceClass = (PyTypeObject*)PyType_FromSpec(&DeviceExSpec);        // Calls PyType_Ready internally from, 3.9 onwards
-+              PyModule_AddObject(pModule, "Device", (PyObject *)pModState->pDeviceClass);
-+              PyType_Ready(pModState->pDeviceClass);
-+
-+              PyType_Slot UnitExSlots[] = {
-+                      { Py_tp_doc, (void*)"DomoticzEx Unit" },
-+                      { Py_tp_new, (void*)CUnitEx_new },
-+                      { Py_tp_init, (void*)CUnitEx_init },
-+                      { Py_tp_dealloc, (void*)CUnitEx_dealloc },
-+                      { Py_tp_members, CUnitEx_members },
-+                      { Py_tp_methods, CUnitEx_methods },
-+                      { Py_tp_str, (void*)CUnitEx_str },
-+                      { 0 },
-+              };
-+              PyType_Spec UnitExSpec = { "DomoticzEx.Unit", sizeof(CUnitEx), 0,
-+                                                              Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE, UnitExSlots };
-+
-+              pModState->pUnitClass = (PyTypeObject*)PyType_FromSpec(&UnitExSpec);
-+              PyModule_AddObject(pModule, "Unit", (PyObject*)pModState->pUnitClass);
-+              PyType_Ready(pModState->pUnitClass);
-+
-+              if (!CConnectionType)
-+              {
-+                      CConnectionType = (PyTypeObject*)PyType_FromSpec(&ConnectionSpec);
-+                      PyType_Ready(CConnectionType);
-               }
--              Py_INCREF((PyObject *)&CConnectionType);
--              PyModule_AddObject(pModule, "Connection", (PyObject *)&CConnectionType);
-+              PyModule_AddObject(pModule, "Connection", (PyObject*)CConnectionType);
--              if (PyType_Ready(&CImageType) < 0)
-+              if (!CImageType)
-               {
--                      _log.Log(LOG_ERROR, "%s, Image Type not ready.", __func__);
--                      return pModule;
-+                      CImageType = (PyTypeObject*)PyType_FromSpec(&ImageSpec);
-+                      PyType_Ready(CImageType);
-               }
--              Py_INCREF((PyObject *)&CImageType);
--              PyModule_AddObject(pModule, "Image", (PyObject *)&CImageType);
-+              PyModule_AddObject(pModule, "Image", (PyObject*)CImageType);
-               return pModule;
-       }
-@@ -900,8 +697,7 @@ namespace Plugins
-               module_state *pModState = ((struct module_state *)PyModule_GetState(brModule));
-               if (!pModState)
-               {
--                      _log.Log(LOG_ERROR, "CPlugin:%s, unable to obtain module state.", __func__);
--                      return nullptr;
-+                      _log.Log(LOG_ERROR, "%s, unable to obtain module state.", __func__);
-               }
-               return pModState;
-@@ -910,205 +706,76 @@ namespace Plugins
-       CPlugin *CPlugin::FindPlugin()
-       {
-               module_state *pModState = FindModule();
--              if (!pModState)
--                      return nullptr;
--              return pModState->pPlugin;
-+              return pModState ? pModState->pPlugin : nullptr;
-       }
--      void CPlugin::LogTraceback(PyTracebackObject *pTraceback)
--      {
--              if (pTraceback)
--              {
--                      Log(LOG_ERROR, "Exception traceback:");
--              }
--              else
--              {
--                      Log(LOG_ERROR, "No traceback available");
--              }
--
--              // Log a stack trace if there is one
--              PyTracebackObject *pTraceFrame = pTraceback;
--              while (pTraceFrame)
--              {
--                      PyFrameObject *frame = pTraceFrame->tb_frame;
--                      if (frame)
--                      {
--                              int lineno = PyFrame_GetLineNumber(frame);
--                              PyCodeObject *pCode = frame->f_code;
--                              std::string FileName;
--                              if (pCode->co_filename)
--                              {
--                                      FileName = (std::string)PyBorrowedRef(pCode->co_filename);
--                              }
--                              std::string FuncName = "Unknown";
--                              if (pCode->co_name)
--                              {
--                                      FuncName = (std::string)PyBorrowedRef(pCode->co_name);
--                              }
--                              if (!FileName.empty())
--                                      Log(LOG_ERROR, " ----> Line %d in '%s', function %s", lineno, FileName.c_str(), FuncName.c_str());
--                              else
--                                      Log(LOG_ERROR, " ----> Line %d in '%s'", lineno, FuncName.c_str());
--                      }
--                      pTraceFrame = pTraceFrame->tb_next;
--              }
--      }
--              
-       void CPlugin::LogPythonException()
-       {
--              PyTracebackObject *pTraceback;
-+              PyNewRef        pTraceback;
-               PyNewRef        pExcept;
-               PyNewRef        pValue;
--              PyErr_Fetch(&pExcept, &pValue, (PyObject **)&pTraceback);
--              PyErr_NormalizeException(&pExcept, &pValue, (PyObject **)&pTraceback);
--              PyErr_Clear();
-+              PyErr_Fetch(&pExcept, &pValue, &pTraceback);
-+              PyErr_NormalizeException(&pExcept, &pValue, &pTraceback);
--              if (pExcept)
-+              if (!pExcept && !pValue && !pTraceback)
-               {
--                      Log(LOG_ERROR, "Module Import failed, exception: '%s'", ((PyTypeObject *)pExcept)->tp_name);
-+                      Log(LOG_ERROR, "Unable to decode exception.");
-               }
--              if (pValue)
-+              else
-               {
--                      std::string sError;
--                      PyNewRef        pErrBytes = PyUnicode_AsASCIIString(pValue); // Won't normally return text for Import related errors
--                      if (!pErrBytes)
-+                      std::string     sTypeText("Unknown");
-+                      if (pExcept)
-                       {
--                              // ImportError has name and path attributes
--                              PyErr_Clear();
--                              if (PyObject_HasAttrString(pValue, "path"))
--                              {
--                                      std::string sPath = PyNewRef(PyObject_GetAttrString(pValue, "path"));
--                                      if (sPath.length() && (sPath != "None"))
--                                      {
--                                              sError += "Path: " + sPath;
--                                      }
--                              }
--                              PyErr_Clear();
--                              if (PyObject_HasAttrString(pValue, "name"))
--                              {
--                                      std::string sName = PyNewRef(PyObject_GetAttrString(pValue, "name"));
--                                      if (sName.length() && (sName != "None"))
--                                      {
--                                              sError += " Name: " + sName;
--                                      }
--                              }
--                              if (!sError.empty())
--                              {
--                                      Log(LOG_ERROR, "Module Import failed: '%s'", sError.c_str());
--                                      sError = "";
--                              }
--
--                              // SyntaxError, IndentationError & TabError have filename, lineno, offset and text attributes
--                              PyErr_Clear();
--                              if (PyObject_HasAttrString(pValue, "filename"))
--                              {
--                                      std::string sName = PyNewRef(PyObject_GetAttrString(pValue, "name"));
--                                      sError += "File: " + sName;
--                              }
--                              long long lineno = -1;
--                              long long offset = -1;
--                              PyErr_Clear();
--                              if (PyObject_HasAttrString(pValue, "lineno"))
--                              {
--                                      PyNewRef pString = PyObject_GetAttrString(pValue, "lineno");
--                                      lineno = PyLong_AsLongLong(pString);
--                              }
--                              PyErr_Clear();
--                              if (PyObject_HasAttrString(pValue, "offset"))
--                              {
--                                      PyNewRef pString = PyObject_GetAttrString(pValue, "offset");
--                                      offset = PyLong_AsLongLong(pString);
--                              }
-+                              PyTypeObject* TypeName = (PyTypeObject*)pExcept;
-+                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)TypeName, "__name__");
-+                              sTypeText = (std::string)pName;
-+                      }
--                              if (!sError.empty())
--                              {
--                                      if ((lineno > 0) && (lineno < 1000))
-+                      /* See if we can get a full traceback */
-+                      PyNewRef        pModule = PyImport_ImportModule("traceback");
-+                      if (pModule)
-+                      {
-+                              PyNewRef        pFunc = PyObject_GetAttrString(pModule, "format_exception");
-+                              if (pFunc && PyCallable_Check(pFunc)) {
-+                                      PyNewRef        pList = PyObject_CallFunctionObjArgs(pFunc, pExcept, pValue, pTraceback, NULL);
-+                                      if (pList)
-                                       {
--                                              Log(LOG_ERROR, "Import detail: %s, Line: %lld, offset: %lld", sError.c_str(), lineno, offset);
-+                                              for (Py_ssize_t i = 0; i < PyList_Size(pList); i++)
-+                                              {
-+                                                      PyBorrowedRef   pPyStr = PyList_GetItem(pList, i);
-+                                                      std::string             pStr(pPyStr);
-+                                                      size_t pos = 0;
-+                                                      std::string token;
-+                                                      while ((pos = pStr.find('\n')) != std::string::npos) {
-+                                                              token = pStr.substr(0, pos);
-+                                                              Log(LOG_ERROR, "%s", token.c_str());
-+                                                              pStr.erase(0, pos + 1);
-+                                                      }
-+                                              }
-                                       }
-                                       else
-                                       {
--                                              Log(LOG_ERROR, "Import detail: %s, Line: %lld", sError.c_str(), offset);
-+                                              Log(LOG_ERROR, "Exception: '%s'.  No traceback available.", sTypeText.c_str());
-                                       }
--                                      sError = "";
--                              }
--
--                              PyErr_Clear();
--                              if (PyObject_HasAttrString(pValue, "text"))
--                              {
--                                      std::string sUTF = PyNewRef(PyObject_GetAttrString(pValue, "text"));
--                                      Log(LOG_ERROR, "Error Line '%s'", sUTF.c_str());
-                               }
-                               else
-                               {
--                                      Log(LOG_ERROR, "Error Line details not available.");
--                              }
--
--                              if (!sError.empty())
--                              {
--                                      Log(LOG_ERROR, "Import detail: %s", sError.c_str());
-+                                      Log(LOG_ERROR, "'format_exception' lookup failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-                               }
-                       }
-                       else
--                              Log(LOG_ERROR, "Module Import failed '%s'", std::string(pErrBytes).c_str());
--              }
--
--              // Log a stack trace if there is one
--              LogTraceback(pTraceback);
--
--              if (!pExcept && !pValue && !pTraceback)
--              {
--                      Log(LOG_ERROR, "Call to import module failed, unable to decode exception.");
-+                      {
-+                              Log(LOG_ERROR, "'Traceback' module import failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-+                      }
-               }
--
--              if (pTraceback)
--                      Py_XDECREF(pTraceback);
-+              PyErr_Clear();
-       }
-       void CPlugin::LogPythonException(const std::string &sHandler)
-       {
--              PyTracebackObject *pTraceback;
--              PyNewRef        pExcept;
--              PyNewRef        pValue;
--              PyTypeObject *TypeName;
--              PyNewRef pErrBytes;
--              const char *pTypeText = nullptr;
--
--              PyErr_Fetch(&pExcept, &pValue, (PyObject **)&pTraceback);
--
--              if (pExcept)
--              {
--                      TypeName = (PyTypeObject *)pExcept;
--                      pTypeText = TypeName->tp_name;
--              }
--              if (pTypeText && pValue)
--              {
--                      Log(LOG_ERROR, "'%s' failed '%s':'%s'.", sHandler.c_str(), pTypeText, std::string(pValue).c_str());
--              }
--              if (pTypeText && !pValue)
--              {
--                      Log(LOG_ERROR, "'%s' failed '%s'.", sHandler.c_str(), pTypeText);
--              }
--              if (!pTypeText && pValue)
--              {
--                      Log(LOG_ERROR, "'%s' failed '%s'.",sHandler.c_str(), std::string(pValue).c_str());
--              }
--              if (!pTypeText && !pValue)
--              {
--                      Log(LOG_ERROR, "'%s' failed, unable to determine error.", sHandler.c_str());
--              }
--
--              // Log a stack trace if there is one
--              LogTraceback(pTraceback);
--
--              if (!pExcept && !pValue && !pTraceback)
--              {
--                      Log(LOG_ERROR, "Call to message handler '%s' failed, unable to decode exception.", sHandler.c_str());
--              }
--
--              if (pTraceback)
--                      Py_XDECREF(pTraceback);
-+              Log(LOG_ERROR, "Call to function '%s' failed, exception details:", sHandler.c_str());
-+              LogPythonException();
-       }
-       int CPlugin::PollInterval(int Interval)
-@@ -1222,7 +889,6 @@ namespace Plugins
-                                               // Tell transport to disconnect if required
-                                               if (pPluginTransport)
-                                               {
--                                                      // std::lock_guard<std::mutex> l(PythonMutex); // Take mutex to guard access to CPluginTransport::m_pConnection
-                                                       MessagePlugin(new DisconnectDirective(pPluginTransport->Connection()));
-                                               }
-                                       }
-@@ -1314,25 +980,26 @@ namespace Plugins
-                                       {
-                                               if (m_bDebug & PDM_QUEUE)
-                                               {
--                                                      Log(LOG_NORM, "(" + m_Name + ") Processing '" + std::string(Message->Name()) + "' message");
-+                                                      Log(LOG_NORM, "Processing '" + std::string(Message->Name()) + "' message");
-                                               }
-                                               Message->Process(this);
-                                       }
-                                       catch (...)
-                                       {
--                                              Log(LOG_ERROR, "PluginSystem: Exception processing message.");
-+                                              Log(LOG_ERROR, "Exception processing '%s' message.", Message->Name());
-+                                      }
-+
-+                                      // Free the memory for the message
-+                                      if (!m_PyInterpreter)
-+                                      {
-+                                              // Can't lock because there is no interpreter to lock
-+                                              delete Message;
-+                                      }
-+                                      else
-+                                      {
-+                                              AccessPython    Guard(this, Message->Name());
-+                                              delete Message;
-                                       }
--                              }
--                              // Free the memory for the message
--                              if (!m_PyInterpreter)
--                              {
--                                      // Can't lock because there is no interpreter to lock
--                                      delete Message;
--                              }
--                              else
--                              {
--                                      AccessPython    Guard(this, m_Name.c_str());
--                                      delete Message;
-                               }
-                       }
-@@ -1351,7 +1018,6 @@ namespace Plugins
-                               {
-                                       for (const auto &pPluginTransport : m_Transports)
-                                       {
--                                              // std::lock_guard<std::mutex> l(PythonMutex); // Take mutex to guard access to CPluginTransport::m_pConnection
-                                               pPluginTransport->VerifyConnection();
-                                       }
-                               }
-@@ -1371,6 +1037,7 @@ namespace Plugins
-               try
-               {
-+                      // Only initialise one plugin at a time to prevent issues with module creation
-                       PyEval_RestoreThread((PyThreadState *)m_mainworker.m_pluginsystem.PythonThread());
-                       m_PyInterpreter = Py_NewInterpreter();
-                       if (!m_PyInterpreter)
-@@ -1379,10 +1046,6 @@ namespace Plugins
-                               goto Error;
-                       }
--                      // Get an instance of the single, central Py_None to use in local code
--                      PyBorrowedRef globalNone = Py_BuildValue("");
--                      Py_None = globalNone;
--
-                       // Prepend plugin directory to path so that python will search it early when importing
- #ifdef WIN32
-                       std::wstring sSeparator = L";";
-@@ -1433,7 +1096,7 @@ namespace Plugins
-                                                       for (Py_ssize_t i = 0; i < PyList_Size(pSites); i++)
-                                                       {
-                                                               PyBorrowedRef   pSite = PyList_GetItem(pSites, i);
--                                                              if (pSite && PyUnicode_Check(pSite))
-+                                                              if (pSite.IsString())
-                                                               {
-                                                                       std::wstringstream ssPath;
-                                                                       ssPath << ((std::string)PyBorrowedRef(pSite)).c_str();
-@@ -1501,6 +1164,25 @@ namespace Plugins
-                       }
-                       pModState->pPlugin = this;
-+                      // Get reference to global 'Py_None' instance for comparisons
-+                      if (!Py_None)
-+                      {
-+                              PyBorrowedRef   global_dict = PyModule_GetDict(m_PyModule);
-+                              PyNewRef                local_dict = PyDict_New();
-+                              PyNewRef                pCode = Py_CompileString("# Eval will return 'None'\n", "<domoticz>", Py_file_input);
-+                              if (pCode)
-+                              {
-+                                      PyNewRef        pEval = PyEval_EvalCode(pCode, global_dict, local_dict);
-+                                      Py_None = pEval;
-+                                      Py_INCREF(Py_None);
-+                              }
-+                              else
-+                              {
-+                                      Log(LOG_ERROR, "Failed to compile script to set global Py_None");
-+                              }
-+                      }
-+
-+
-                       //      Add start command to message queue
-                       MessagePlugin(new onStartCallback());
-@@ -1611,7 +1293,7 @@ namespace Plugins
-                               }
-                       }
--                      m_DeviceDict = (PyDictObject*)PyDict_New();
-+                      m_DeviceDict = PyDict_New();
-                       if (PyDict_SetItemString(pModuleDict, "Devices", (PyObject *)m_DeviceDict) == -1)
-                       {
-                               Log(LOG_ERROR, "(%s) failed to add Device dictionary.", m_PluginKey.c_str());
-@@ -1647,7 +1329,6 @@ namespace Plugins
-                       // load associated devices to make them available to python
-                       if (!result.empty())
-                       {
--                              PyType_Ready(pModState->pDeviceClass);
-                               // Add device objects into the device dictionary with Unit as the key
-                               for (const auto &sd : result)
-                               {
-@@ -1689,7 +1370,7 @@ namespace Plugins
-                               }
-                       }
--                      m_ImageDict = (PyDictObject *)PyDict_New();
-+                      m_ImageDict = PyDict_New();
-                       if (PyDict_SetItemString(pModuleDict, "Images", (PyObject *)m_ImageDict) == -1)
-                       {
-                               Log(LOG_ERROR, "(%s) failed to add Image dictionary.", m_PluginKey.c_str());
-@@ -1700,11 +1381,10 @@ namespace Plugins
-                       result = m_sql.safe_query("SELECT ID, Base, Name, Description FROM CustomImages WHERE Base LIKE '%q%%' ORDER BY ID ASC", m_PluginKey.c_str());
-                       if (!result.empty())
-                       {
--                              PyType_Ready(&CImageType);
-                               // Add image objects into the image dictionary with ID as the key
-                               for (const auto &sd : result)
-                               {
--                                      CImage *pImage = (CImage *)CImage_new(&CImageType, (PyObject *)nullptr, (PyObject *)nullptr);
-+                                      CImage *pImage = (CImage *)CImage_new(CImageType, (PyObject *)nullptr, (PyObject *)nullptr);
-                                       PyNewRef        pKey = PyUnicode_FromString(sd[1].c_str());
-                                       if (PyDict_SetItem((PyObject *)m_ImageDict, pKey, (PyObject *)pImage) == -1)
-@@ -2098,7 +1778,7 @@ namespace Plugins
-               }
-               else
-               {
--                      CDevice *pDevice = (CDevice *)CDevice_new(&CDeviceType, (PyObject *)nullptr, (PyObject *)nullptr);
-+                      CDevice *pDevice = (CDevice *)CDevice_new(CDeviceType, (PyObject *)nullptr, (PyObject *)nullptr);
-                       PyNewRef pKey = PyLong_FromLong(Unit);
-                       if (PyDict_SetItem((PyObject *)m_DeviceDict, pKey, (PyObject *)pDevice) == -1)
-@@ -2250,13 +1930,24 @@ namespace Plugins
-       void CPlugin::RestoreThread()
-       {
-               if (m_PyInterpreter)
--                      PyEval_RestoreThread((PyThreadState *)m_PyInterpreter);
-+              {
-+                      PyEval_RestoreThread((PyThreadState*)m_PyInterpreter);
-+              }
-+              else
-+              {
-+                      Log(LOG_ERROR, "Attempt to aquire the GIL with NULL Interpreter details.");
-+              }
-       }
-       void CPlugin::ReleaseThread()
-       {
-               if (m_PyInterpreter)
--                      PyEval_SaveThread();
-+              {
-+                      if (!PyEval_SaveThread())
-+                      {
-+                              Log(LOG_ERROR, "Attempt to release GIL returned NULL value");
-+                      }
-+              }
-       }
-       void CPlugin::Callback(PyObject *pTarget, const std::string &sHandler, PyObject *pParams)
-@@ -2294,7 +1985,11 @@ namespace Plugins
-                                       }
-                                       if (m_bDebug & PDM_QUEUE)
--                                              Log(LOG_NORM, "Calling message handler '%s' on '%s' type object.", sHandler.c_str(), pTarget->ob_type->tp_name);
-+                                      {
-+                                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)(pTarget->ob_type), "__name__");
-+                                              if (pName)
-+                                                      Log(LOG_NORM, "Calling message handler '%s' on '%s' type object.", sHandler.c_str(), (std::string(pName).c_str()));
-+                                      }
-                                       PyErr_Clear();
-@@ -2315,7 +2010,7 @@ namespace Plugins
-                                               {
-                                                       // See if additional information is available
-                                                       PyNewRef pLocals = PyObject_Dir(pTarget);
--                                                      if (PyList_Check(pLocals))  // && PyIter_Check(pLocals))  // Check fails but iteration works??!?
-+                                                      if (pLocals.IsList())  // && PyIter_Check(pLocals))  // Check fails but iteration works??!?
-                                                       {
-                                                               Log(LOG_NORM, "Local context:");
-                                                               PyNewRef pIter = PyObject_GetIter(pLocals);
-@@ -2391,7 +2086,7 @@ namespace Plugins
-                               module_state *pModState = ((struct module_state *)PyModule_GetState(brModule));
-                               if (!pModState)
-                               {
--                                      Log(LOG_ERROR, "CPlugin:%s, unable to obtain module state.", __func__);
-+                                      Log(LOG_ERROR, "%s, unable to obtain module state.", __func__);
-                                       return;
-                               }
-@@ -2409,7 +2104,8 @@ namespace Plugins
-                                       }
-                                       else if (isDevice == 0)
-                                       {
--                                              Log(LOG_NORM, "%s: Device dictionary contained non-Device entry '%s'.", __func__, pDevice->ob_type->tp_name);
-+                                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)pDevice->ob_type, "__name__");
-+                                              Log(LOG_NORM, "%s: Device dictionary contained non-Device entry '%s'.", __func__, ((std::string)pName).c_str());
-                                       }
-                                       else
-                                       {
-@@ -2430,7 +2126,8 @@ namespace Plugins
-                                                               }
-                                                               else if (isValue == 0)
-                                                               {
--                                                                      _log.Log(LOG_NORM, "%s: Unit dictionary contained non-Unit entry '%s'.", __func__, pUnit->ob_type->tp_name);
-+                                                                      PyNewRef        pName = PyObject_GetAttrString((PyObject*)pUnit->ob_type, "__name__");
-+                                                                      _log.Log(LOG_NORM, "%s: Unit dictionary contained non-Unit entry '%s'.", __func__, ((std::string)pName).c_str());
-                                                               }
-                                                               else
-                                                               {
-@@ -2520,7 +2217,7 @@ namespace Plugins
-               PyBorrowedRef   pModuleDict = PyModule_GetDict(PythonModule()); // returns a borrowed referece to the __dict__ object for the module
-               if (m_SettingsDict)
-                       Py_XDECREF(m_SettingsDict);
--              m_SettingsDict = (PyDictObject *)PyDict_New();
-+              m_SettingsDict = PyDict_New();
-               if (PyDict_SetItemString(pModuleDict, "Settings", (PyObject *)m_SettingsDict) == -1)
-               {
-                       Log(LOG_ERROR, "(%s) failed to add Settings dictionary.", m_PluginKey.c_str());
-@@ -2532,7 +2229,6 @@ namespace Plugins
-               result = m_sql.safe_query("SELECT Key, nValue, sValue FROM Preferences");
-               if (!result.empty())
-               {
--                      PyType_Ready(&CDeviceType);
-                       // Add settings strings into the settings dictionary with Unit as the key
-                       for (const auto &sd : result)
-                       {
-@@ -2617,12 +2313,15 @@ namespace Plugins
-               if (!m_DeviceDict)
-                       return true;
-+              return false;
-+
-               PyObject *key, *value;
-               Py_ssize_t pos = 0;
-               while (PyDict_Next((PyObject *)m_DeviceDict, &pos, &key, &value))
-               {
-                       // Handle different Device dictionaries types
--                      if (PyUnicode_Check(key))
-+                      PyBorrowedRef   pKeyType(key);
-+                      if (pKeyType.IsString())
-                       {
-                               // Version 2+ of the framework, keyed by DeviceID
-                               std::string sKey = PyUnicode_AsUTF8(key);
-@@ -2632,7 +2331,7 @@ namespace Plugins
-                                       return (pDevice->TimedOut != 0);
-                               }
-                       }
--                      else
-+                      else if (pKeyType.IsLong())
-                       {
-                               // Version 1 of the framework, keyed by Unit
-                               long iKey = PyLong_AsLong(key);
-@@ -2648,6 +2347,10 @@ namespace Plugins
-                                       return (pDevice->TimedOut != 0);
-                               }
-                       }
-+                      else
-+                      {
-+                              Log(LOG_ERROR, "'%s' Invalid Node key type.", __func__);
-+                      }
-               }
-               return false;
-@@ -2655,7 +2358,7 @@ namespace Plugins
-       PyBorrowedRef CPlugin::FindDevice(const std::string &Key)
-       {
--              if (m_DeviceDict && PyDict_Check(m_DeviceDict))
-+              if (m_DeviceDict && PyBorrowedRef(m_DeviceDict).IsDict())
-               {
-                       return PyDict_GetItemString((PyObject*)m_DeviceDict, Key.c_str());
-               }
-@@ -2934,5 +2637,47 @@ namespace Plugins
-               return true;
-       }
-+
-+      bool PyBorrowedRef::TypeCheck(long PyType)
-+      {
-+              if (m_pObject)
-+              {
-+                      PyNewRef        pType = PyObject_Type(m_pObject);
-+                      return pType && (PyType_GetFlags((PyTypeObject*)pType) & PyType);
-+              }
-+              return false;
-+      }
-+
-+      std::string PyBorrowedRef::Attribute(const char* name)
-+      {
-+              std::string     sAttr = "";
-+              if (m_pObject)
-+              {
-+                      try
-+                      {
-+                              if (PyObject_HasAttrString(m_pObject, name))
-+                              {
-+                                      PyNewRef        pAttr = PyObject_GetAttrString(m_pObject, name);
-+                                      sAttr = (std::string)pAttr;
-+                              }
-+                      }
-+                      catch (...)
-+                      {
-+                              _log.Log(LOG_ERROR, "[%s] Exception determining Python object attribute '%s'.", __func__, name);
-+                      }
-+              }
-+              return sAttr;
-+      }
-+
-+      std::string PyBorrowedRef::Type()
-+      {
-+              std::string     sType = "";
-+              if (m_pObject)
-+              {
-+                      PyNewRef        pType = PyObject_Type(m_pObject);
-+                      sType = pType.Attribute("__name__");
-+              }
-+              return sType;
-+      }
- } // namespace Plugins
- #endif
---- a/hardware/plugins/Plugins.h
-+++ b/hardware/plugins/Plugins.h
-@@ -62,8 +62,6 @@ namespace Plugins {
-               void Do_Work();
--              void LogPythonException(const std::string &);
--
-       public:
-         CPlugin(int HwdID, const std::string &Name, const std::string &PluginKey);
-         ~CPlugin() override;
-@@ -75,7 +73,7 @@ namespace Plugins {
-         bool StopHardware() override;
-         void LogPythonException();
--        void LogTraceback(PyTracebackObject *pTraceback);
-+        void LogPythonException(const std::string&);
-         int PollInterval(int Interval = -1);
-         PyObject*     PythonModule() { return m_PyModule; };
-@@ -119,9 +117,9 @@ namespace Plugins {
-         PyBorrowedRef FindUnitInDevice(const std::string &deviceKey, const int unitKey);
-         std::string m_PluginKey;
--        PyDictObject* m_DeviceDict;
--        PyDictObject* m_ImageDict;
--        PyDictObject* m_SettingsDict;
-+        PyObject*     m_DeviceDict;
-+        PyObject* m_ImageDict;
-+        PyObject* m_SettingsDict;
-         std::string m_HomeFolder;
-         PluginDebugMask m_bDebug;
-         bool m_bTracing;
-@@ -147,16 +145,29 @@ namespace Plugins {
-       //
-       class PyBorrowedRef
-       {
--            protected:
-+      protected:
-               PyObject *m_pObject;
-+              bool            TypeCheck(long);
--            public:
-+      public:
-               PyBorrowedRef()
-                       : m_pObject(NULL){};
-               PyBorrowedRef(PyObject *pObject)
-               {
-                       m_pObject = pObject;
-               };
-+              std::string     Attribute(const char* name);
-+              std::string     Type();
-+              bool            IsDict() { return TypeCheck(Py_TPFLAGS_DICT_SUBCLASS); };
-+              bool            IsList() { return TypeCheck(Py_TPFLAGS_LIST_SUBCLASS); };
-+              bool            IsLong() { return TypeCheck(Py_TPFLAGS_LONG_SUBCLASS); };
-+              bool            IsTuple() { return TypeCheck(Py_TPFLAGS_TUPLE_SUBCLASS); };
-+              bool            IsString() { return TypeCheck(Py_TPFLAGS_UNICODE_SUBCLASS); };
-+              bool            IsBytes() { return TypeCheck(Py_TPFLAGS_BYTES_SUBCLASS); };
-+              bool            IsByteArray() { return Type() == "bytearray"; };
-+              bool            IsFloat() { return Type() == "float"; };
-+              bool            IsBool() { return Type() == "bool"; };
-+              bool            IsNone() { return m_pObject && (m_pObject == Py_None); };
-               operator PyObject *() const
-               {
-                       return m_pObject;
-@@ -165,10 +176,6 @@ namespace Plugins {
-               {
-                       return (PyTypeObject *)m_pObject;
-               }
--              operator PyBytesObject *() const
--              {
--                      return (PyBytesObject *)m_pObject;
--              }
-               operator bool() const
-               {
-                       return (m_pObject != NULL);
-@@ -283,12 +290,8 @@ namespace Plugins {
-       class AccessPython
-       {
-       private:
--              static  std::mutex                      PythonMutex;
--              static  volatile bool           m_bHasThreadState;
--              std::unique_lock<std::mutex>* m_Lock;
--              PyThreadState* m_Python;
-               CPlugin* m_pPlugin;
--              const char* m_Text;
-+              std::string m_Text;
-       public:
-               AccessPython(CPlugin* pPlugin, const char* sWhat);
---- a/hardware/plugins/PythonObjectEx.cpp
-+++ b/hardware/plugins/PythonObjectEx.cpp
-@@ -8,7 +8,6 @@
- #include "../../main/Logger.h"
- #include "../../main/SQLHelper.h"
- #include "../../hardware/hardwaretypes.h"
--#include "../../main/localtime_r.h"
- #include "../../main/mainstructs.h"
- #include "../../main/mainworker.h"
- #include "../../main/EventSystem.h"
-@@ -23,19 +22,22 @@
- namespace Plugins {
-       extern struct PyModuleDef DomoticzExModuleDef;
--      extern void LogPythonException(CPlugin *pPlugin, const std::string &sHandler);
-       extern void maptypename(const std::string &sTypeName, int &Type, int &SubType, int &SwitchType, std::string &sValue, PyObject *OptionsIn, PyObject *OptionsOut);
-       void CDeviceEx_dealloc(CDeviceEx *self)
-       {
-               Py_XDECREF(self->DeviceID);
-               Py_XDECREF(self->m_UnitDict);
--              Py_TYPE(self)->tp_free((PyObject *)self);
-+
-+              PyNewRef        pType = PyObject_Type((PyObject*)self);
-+              freefunc pFree = (freefunc)PyType_GetSlot(pType, Py_tp_free);
-+              pFree((PyObject*)self);
-       }
-       PyObject *CDeviceEx_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-       {
--              CDeviceEx *self = (CDeviceEx *)type->tp_alloc(type, 0);
-+              allocfunc pAlloc = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
-+              CDeviceEx* self = (CDeviceEx*)pAlloc(type, 0);
-               try
-               {
-@@ -95,11 +97,8 @@ namespace Plugins {
-                       if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &DeviceID))
-                       {
--                              CPlugin *pPlugin = nullptr;
--                              if (pModState)
--                                      pPlugin = pModState->pPlugin;
-                               pModState->pPlugin->Log(LOG_ERROR, R"(Expected: myVar = Domoticz.DeviceEx(DeviceID='xxxx'))");
--                              LogPythonException(pPlugin, __func__);
-+                              pModState->pPlugin->LogPythonException(__func__);
-                       }
-                       else
-                       {
-@@ -108,7 +107,7 @@ namespace Plugins {
-                               {
-                                       self->DeviceID = PyUnicode_FromString(DeviceID);
-                               }
--                              self->m_UnitDict = (PyDictObject *)PyDict_New();
-+                              self->m_UnitDict = (PyObject *)PyDict_New();
-                       }
-                       return true;
-@@ -147,7 +146,6 @@ namespace Plugins {
-               if (!result.empty())
-               {
--                      PyType_Ready(&CUnitExType);
-                       // Create Unit objects and add the Units dictionary with Unit number as the key
-                       for (auto itt = result.begin(); itt != result.end(); ++itt)
-                       {
-@@ -236,12 +234,16 @@ namespace Plugins {
-               Py_XDECREF(self->Options);
-               Py_XDECREF(self->Color);
-               Py_XDECREF(self->Parent);
--              Py_TYPE(self)->tp_free((PyObject *)self);
-+
-+              PyNewRef        pType = PyObject_Type((PyObject*)self);
-+              freefunc pFree = (freefunc)PyType_GetSlot(pType, Py_tp_free);
-+              pFree((PyObject*)self);
-       }
-       PyObject *CUnitEx_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-       {
--              CUnitEx *self = (CUnitEx *)type->tp_alloc(type, 0);
-+              allocfunc pAlloc = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
-+              CUnitEx *self = (CUnitEx*)pAlloc(type, 0);
-               try
-               {
-@@ -380,7 +382,6 @@ namespace Plugins {
-                               else
-                               {
-                                       // Create a temporary one
--                                      PyType_Ready(pModState->pDeviceClass);
-                                       PyNewRef nrArgList = Py_BuildValue("(s)", DeviceID);
-                                       if (!nrArgList)
-                                       {
-@@ -411,43 +412,40 @@ namespace Plugins {
-                                       self->Image = Image;
-                               if (Used == 1)
-                                       self->Used = Used;
--                              if (Options && PyDict_Check(Options) && PyDict_Size(Options) > 0)
-+                              if (Options && PyBorrowedRef(Options).IsDict() && PyDict_Size(Options) > 0)
-                               {
-                                       PyObject *pKey, *pValue;
-                                       Py_ssize_t pos = 0;
-                                       PyDict_Clear(self->Options);
-                                       while (PyDict_Next(Options, &pos, &pKey, &pValue))
-                                       {
--                                              if (PyUnicode_Check(pValue))
-+                                              PyNewRef        pKeyDict = PyObject_Str(pKey);
-+                                              PyNewRef        pValueDict = PyObject_Str(pValue);
-+
-+                                              if (pKeyDict && pValueDict)
-                                               {
--                                                      PyNewRef        pKeyDict = PyUnicode_FromKindAndData(PyUnicode_KIND(pKey), PyUnicode_DATA(pKey), PyUnicode_GET_LENGTH(pKey));
--                                                      PyNewRef        pValueDict = PyUnicode_FromKindAndData(PyUnicode_KIND(pValue), PyUnicode_DATA(pValue), PyUnicode_GET_LENGTH(pValue));
-                                                       if (PyDict_SetItem(self->Options, pKeyDict, pValueDict) == -1)
-                                                       {
--                                                              _log.Log(LOG_ERROR, "(%s) Failed to initialize Options dictionary for Hardware/Unit combination (%d:%d).",
--                                                                              pModState->pPlugin->m_Name.c_str(), pModState->pPlugin->m_HwdID, self->Unit);
-+                                                              pModState->pPlugin->Log(LOG_ERROR, "(%s) Failed to initialize Options dictionary for Hardware/Unit combination (%d:%d).",
-+                                                                      pModState->pPlugin->m_Name.c_str(), pModState->pPlugin->m_HwdID, self->Unit);
-                                                               break;
-                                                       }
-                                               }
-                                               else
-                                               {
--                                                      _log.Log(
-+                                                      PyNewRef        pName = PyObject_GetAttrString((PyObject*)pValue->ob_type, "__name__");
-+                                                      pModState->pPlugin->Log(
-                                                               LOG_ERROR,
--                                                              R"((%s) Failed to initialize Options dictionary for Hardware/Unit combination (%d:%d): Only "string" type dictionary entries supported, but entry has type "%s")",
--                                                              pModState->pPlugin->m_Name.c_str(), pModState->pPlugin->m_HwdID, self->Unit, pValue->ob_type->tp_name);
-+                                                              "(%s) Failed to initialize Options dictionary for Hardware / Unit combination(%d:%d): Unable to convert to string.)",
-+                                                              pModState->pPlugin->m_Name.c_str(), pModState->pPlugin->m_HwdID, self->Unit);
-                                               }
-                                       }
-                               }
-                       }
-                       else
-                       {
--                              CPlugin *pPlugin = nullptr;
--                              if (pModState)
--                              {
--                                      pPlugin = pModState->pPlugin;
--                                      _log.Log(LOG_ERROR, R"(Expected: myVar = DomoticzEx.Unit(Name="myDevice", DeviceID="", Unit=0, TypeName="", Type=0, Subtype=0, Switchtype=0, Image=0, Options={}, Used=1, Description=""))");
--                                      LogPythonException(pPlugin, __func__);
--                              }
-+                              pModState->pPlugin->Log(LOG_ERROR, R"(Expected: myVar = DomoticzEx.Unit(Name="myDevice", DeviceID="", Unit=0, TypeName="", Type=0, Subtype=0, Switchtype=0, Image=0, Options={}, Used=1, Description=""))");
-+                              pModState->pPlugin->LogPythonException(__func__);
-                       }
-               }
-               catch (std::exception *e)
-@@ -756,7 +754,7 @@ namespace Plugins {
-                       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ps", kwlist, &bWriteLog, &TypeName))
-                       {
-                               pModState->pPlugin->Log(LOG_ERROR, "(%s) Failed to parse parameters: 'Log' and/or 'TypeName' expected.", __func__);
--                              LogPythonException(pModState->pPlugin, __func__);
-+                              pModState->pPlugin->LogPythonException(__func__);
-                               Py_RETURN_NONE;
-                       }
-@@ -789,7 +787,7 @@ namespace Plugins {
-                       // Options provided, assume change
-                       std::string sOptionValue;
--                      if (pOptionsDict && PyDict_Check(pOptionsDict))
-+                      if (pOptionsDict && pOptionsDict.IsDict())
-                       {
-                               if (self->SubType != sTypeCustom)
-                               {
---- a/hardware/plugins/PythonObjectEx.h
-+++ b/hardware/plugins/PythonObjectEx.h
-@@ -12,7 +12,7 @@ namespace Plugins {
-               PyObject_HEAD
-               PyObject*               DeviceID;
-               int                             TimedOut;
--              PyDictObject*   m_UnitDict;
-+              PyObject*               m_UnitDict;
-               static bool isInstance(PyObject *pObject);
-       };
-@@ -36,46 +36,6 @@ namespace Plugins {
-               { nullptr } /* Sentinel */
-       };
--      static PyTypeObject CDeviceExType = {
--              PyVarObject_HEAD_INIT(nullptr, 0) "DomoticzEx.Device", /* tp_name */
--              sizeof(CDeviceEx),                              /* tp_basicsize */
--              0,                                                              /* tp_itemsize */
--              (destructor)CDeviceEx_dealloc,  /* tp_dealloc */
--              0,                                                              /* tp_print */
--              nullptr,                                            /* tp_getattr */
--              nullptr,                                            /* tp_setattr */
--              nullptr,                                            /* tp_reserved */
--              nullptr,                                            /* tp_repr */
--              nullptr,                                            /* tp_as_number */
--              nullptr,                                            /* tp_as_sequence */
--              nullptr,                                            /* tp_as_mapping */
--              nullptr,                                            /* tp_hash  */
--              nullptr,                                            /* tp_call */
--              (reprfunc)CDeviceEx_str,                /* tp_str */
--              nullptr,                                            /* tp_getattro */
--              nullptr,                                            /* tp_setattro */
--              nullptr,                                            /* tp_as_buffer */
--              Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,            /* tp_flags */
--              "DomoticzEx Device",                    /* tp_doc */
--              nullptr,                                            /* tp_traverse */
--              nullptr,                                            /* tp_clear */
--              nullptr,                                            /* tp_richcompare */
--              0,                                                              /* tp_weaklistoffset */
--              nullptr,                                            /* tp_iter */
--              nullptr,                                            /* tp_iternext */
--              CDeviceEx_methods,                              /* tp_methods */
--              CDeviceEx_members,                              /* tp_members */
--              nullptr,                                            /* tp_getset */
--              nullptr,                                            /* tp_base */
--              nullptr,                                            /* tp_dict */
--              nullptr,                                            /* tp_descr_get */
--              nullptr,                                            /* tp_descr_set */
--              0,                                                              /* tp_dictoffset */
--              (initproc)CDeviceEx_init,               /* tp_init */
--              nullptr,                                            /* tp_alloc */
--              CDeviceEx_new                                   /* tp_new */
--      };
--
-       class CUnitEx
-       {
-       public:
-@@ -146,44 +106,5 @@ namespace Plugins {
-               { "Touch", (PyCFunction)CUnitEx_touch, METH_NOARGS, "Notify Domoticz that device has been seen." },
-               { nullptr } /* Sentinel */
-       };
--
--      static PyTypeObject CUnitExType = {
--              PyVarObject_HEAD_INIT(nullptr, 0) "DomoticzEx.Unit", /* tp_name */
--              sizeof(CUnitEx),                                /* tp_basicsize */
--              0,                                                              /* tp_itemsize */
--              (destructor)CUnitEx_dealloc,    /* tp_dealloc */
--              0,                                                              /* tp_print */
--              nullptr,                                            /* tp_getattr */
--              nullptr,                                            /* tp_setattr */
--              nullptr,                                            /* tp_reserved */
--              nullptr,                                            /* tp_repr */
--              nullptr,                                            /* tp_as_number */
--              nullptr,                                            /* tp_as_sequence */
--              nullptr,                                            /* tp_as_mapping */
--              nullptr,                                            /* tp_hash  */
--              nullptr,                                            /* tp_call */
--              (reprfunc)CUnitEx_str,                  /* tp_str */
--              nullptr,                                            /* tp_getattro */
--              nullptr,                                            /* tp_setattro */
--              nullptr,                                            /* tp_as_buffer */
--              Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,            /* tp_flags */
--              "DomoticzEx Unit",                              /* tp_doc */
--              nullptr,                                            /* tp_traverse */
--              nullptr,                                            /* tp_clear */
--              nullptr,                                            /* tp_richcompare */
--              0,                                                              /* tp_weaklistoffset */
--              nullptr,                                            /* tp_iter */
--              nullptr,                                            /* tp_iternext */
--              CUnitEx_methods,                                /* tp_methods */
--              CUnitEx_members,                                /* tp_members */
--              nullptr,                                            /* tp_getset */
--              nullptr,                                            /* tp_base */
--              nullptr,                                            /* tp_dict */
--              nullptr,                                            /* tp_descr_get */
--              nullptr,                                            /* tp_descr_set */
--              0,                                                              /* tp_dictoffset */
--              (initproc)CUnitEx_init,                 /* tp_init */
--              nullptr,                                            /* tp_alloc */
--              CUnitEx_new                                         /* tp_new */
--      };
-+      
- } // namespace Plugins
---- a/hardware/plugins/PythonObjects.cpp
-+++ b/hardware/plugins/PythonObjects.cpp
-@@ -8,7 +8,6 @@
- #include "../../main/Logger.h"
- #include "../../main/SQLHelper.h"
- #include "../../hardware/hardwaretypes.h"
--#include "../../main/localtime_r.h"
- #include "../../main/mainstructs.h"
- #include "../../main/mainworker.h"
- #include "../../main/EventSystem.h"
-@@ -22,21 +21,28 @@
- namespace Plugins {
-+      PyTypeObject* CDeviceType = nullptr;
-+      PyTypeObject* CConnectionType = nullptr;
-+      PyTypeObject* CImageType = nullptr;
-+
-       extern struct PyModuleDef DomoticzModuleDef;
-       extern struct PyModuleDef DomoticzExModuleDef;
--      extern void LogPythonException(CPlugin *pPlugin, const std::string &sHandler);
-       void CImage_dealloc(CImage* self)
-       {
-               Py_XDECREF(self->Base);
-               Py_XDECREF(self->Name);
-               Py_XDECREF(self->Description);
--              Py_TYPE(self)->tp_free((PyObject*)self);
-+
-+              PyNewRef        pType = PyObject_Type((PyObject*)self);
-+              freefunc pFree = (freefunc)PyType_GetSlot(pType, Py_tp_free);
-+              pFree((PyObject*)self);
-       }
-       PyObject* CImage_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-       {
--              CImage *self = (CImage *)type->tp_alloc(type, 0);
-+              allocfunc pAlloc = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
-+              CImage *self = (CImage *)pAlloc(type, 0);
-               try
-               {
-@@ -130,10 +136,8 @@ namespace Plugins {
-                       }
-                       else
-                       {
--                              CPlugin *pPlugin = nullptr;
--                              if (pModState) pPlugin = pModState->pPlugin;
--                              _log.Log(LOG_ERROR, "Expected: myVar = Domoticz.Image(Filename=\"MyImages.zip\")");
--                              LogPythonException(pPlugin, __func__);
-+                              pModState->pPlugin->Log(LOG_ERROR, "Expected: myVar = Domoticz.Image(Filename=\"MyImages.zip\")");
-+                              pModState->pPlugin->LogPythonException(__func__);
-                       }
-               }
-               catch (std::exception *e)
-@@ -177,11 +181,10 @@ namespace Plugins {
-                                               std::vector<std::vector<std::string> > result = m_sql.safe_query("SELECT max(ID), Base, Name, Description FROM CustomImages");
-                                               if (!result.empty())
-                                               {
--                                                      PyType_Ready(&CImageType);
-                                                       // Add image objects into the image dictionary with ID as the key
-                                                       for (const auto &sd : result)
-                                                       {
--                                                              CImage *pImage = (CImage *)CImage_new(&CImageType, (PyObject *)nullptr,
-+                                                              CImage *pImage = (CImage *)CImage_new(CImageType, (PyObject *)nullptr,
-                                                                                                     (PyObject *)nullptr);
-                                                               PyObject*       pKey = PyUnicode_FromString(sd[1].c_str());
-@@ -226,7 +229,7 @@ namespace Plugins {
-                       {
-                               if (self->pPlugin->m_bDebug & PDM_IMAGE)
-                               {
--                                      _log.Log(LOG_NORM, "(%s) Deleting Image '%s'.", self->pPlugin->m_Name.c_str(), sName.c_str());
-+                                      _log.Log(LOG_NORM, "Deleting Image '%s'.", sName.c_str());
-                               }
-                               std::vector<std::vector<std::string> > result;
-@@ -238,19 +241,18 @@ namespace Plugins {
-                                       PyNewRef        pKey = PyLong_FromLong(self->ImageID);
-                                       if (PyDict_DelItem((PyObject*)self->pPlugin->m_ImageDict, pKey) == -1)
-                                       {
--                                              _log.Log(LOG_ERROR, "(%s) failed to delete image '%d' from images dictionary.", self->pPlugin->m_Name.c_str(), self->ImageID);
--                                              Py_INCREF(Py_None);
--                                              return Py_None;
-+                                              self->pPlugin->Log(LOG_ERROR, "Failed to delete image '%d' from images dictionary.", self->ImageID);
-+                                              Py_RETURN_NONE;
-                                       }
-                               }
-                               else
-                               {
--                                      _log.Log(LOG_ERROR, "(%s) Image deletion failed, Image %d not found in Domoticz.", self->pPlugin->m_Name.c_str(), self->ImageID);
-+                                      self->pPlugin->Log(LOG_ERROR, "Image deletion failed, Image %d not found in Domoticz.", self->ImageID);
-                               }
-                       }
-                       else
-                       {
--                              _log.Log(LOG_ERROR, "(%s) Image deletion failed, '%s' does not represent a Image in Domoticz.", self->pPlugin->m_Name.c_str(), sName.c_str());
-+                              self->pPlugin->Log(LOG_ERROR, "Image deletion failed, '%s' does not represent a Image in Domoticz.", sName.c_str());
-                       }
-               }
-               else
-@@ -278,12 +280,16 @@ namespace Plugins {
-               PyDict_Clear(self->Options);
-               Py_XDECREF(self->Options);
-               Py_XDECREF(self->Color);
--              Py_TYPE(self)->tp_free((PyObject*)self);
-+
-+              PyNewRef        pType = PyObject_Type((PyObject*)self);
-+              freefunc pFree = (freefunc)PyType_GetSlot(pType, Py_tp_free);
-+              pFree((PyObject*)self);
-       }
-       PyObject* CDevice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-       {
--              CDevice *self = (CDevice *)type->tp_alloc(type, 0);
-+              allocfunc pAlloc = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
-+              CDevice *self = (CDevice*)pAlloc(type, 0);
-               try
-               {
-@@ -473,7 +479,7 @@ namespace Plugins {
-               }
-               else if (sTypeName == "Selector Switch")
-               {
--                      if (!OptionsIn || !PyDict_Check(OptionsIn)) {
-+                      if (!OptionsIn || !PyBorrowedRef(OptionsIn).IsDict()) {
-                               PyDict_Clear(OptionsOut);
-                               PyDict_SetItemString(OptionsOut, "LevelActions", PyUnicode_FromString("|||"));
-                               PyDict_SetItemString(OptionsOut, "LevelNames", PyUnicode_FromString("Off|Level1|Level2|Level3"));
-@@ -517,7 +523,7 @@ namespace Plugins {
-               else if (sTypeName == "Custom")
-               {
-                       SubType = sTypeCustom;
--                      if (!OptionsIn || !PyDict_Check(OptionsIn)) {
-+                      if (!OptionsIn || !PyBorrowedRef(OptionsIn).IsDict()) {
-                               PyDict_Clear(OptionsOut);
-                               PyDict_SetItemString(OptionsOut, "Custom", PyUnicode_FromString("1"));
-                       }
-@@ -615,42 +621,39 @@ namespace Plugins {
-                               if (SwitchType != -1) self->SwitchType = SwitchType;
-                               if (Image != -1) self->Image = Image;
-                               if (Used == 1) self->Used = Used;
--                              if (Options && PyDict_Check(Options) && PyDict_Size(Options) > 0) {
-+                              if (Options && PyBorrowedRef(Options).IsDict() && PyDict_Size(Options) > 0) {
-                                       PyObject *pKey, *pValue;
-                                       Py_ssize_t pos = 0;
-                                       PyDict_Clear(self->Options);
--                                      while(PyDict_Next(Options, &pos, &pKey, &pValue))
-+                                      while (PyDict_Next(Options, &pos, &pKey, &pValue))
-                                       {
--                                              if (PyUnicode_Check(pValue))
-+                                              PyNewRef        pKeyDict = PyObject_Str(pKey);
-+                                              PyNewRef        pValueDict = PyObject_Str(pValue);
-+
-+                                              if (pKeyDict && pValueDict)
-                                               {
--                                                      PyObject *pKeyDict = PyUnicode_FromKindAndData(PyUnicode_KIND(pKey), PyUnicode_DATA(pKey), PyUnicode_GET_LENGTH(pKey));
--                                                      PyObject *pValueDict = PyUnicode_FromKindAndData(PyUnicode_KIND(pValue), PyUnicode_DATA(pValue), PyUnicode_GET_LENGTH(pValue));
-                                                       if (PyDict_SetItem(self->Options, pKeyDict, pValueDict) == -1)
-                                                       {
--                                                              _log.Log(LOG_ERROR, "(%s) Failed to initialize Options dictionary for Hardware/Unit combination (%d:%d).", self->pPlugin->m_Name.c_str(), self->HwdID, self->Unit);
--                                                              Py_XDECREF(pKeyDict);
--                                                              Py_XDECREF(pValueDict);
-+                                                              pModState->pPlugin->Log(LOG_ERROR, "(%s) Failed to initialize Options dictionary for Hardware/Unit combination (%d:%d).",
-+                                                                      pModState->pPlugin->m_Name.c_str(), pModState->pPlugin->m_HwdID, self->Unit);
-                                                               break;
-                                                       }
--                                                      Py_XDECREF(pKeyDict);
--                                                      Py_XDECREF(pValueDict);
-                                               }
-                                               else
-                                               {
--                                                      _log.Log(
-+                                                      PyNewRef        pName = PyObject_GetAttrString((PyObject*)pValue->ob_type, "__name__");
-+                                                      pModState->pPlugin->Log(
-                                                               LOG_ERROR,
--                                                              R"((%s) Failed to initialize Options dictionary for Hardware/Unit combination (%d:%d): Only "string" type dictionary entries supported, but entry has type "%s")",
--                                                              self->pPlugin->m_Name.c_str(), self->HwdID, self->Unit, pValue->ob_type->tp_name);
-+                                                              "(%s) Failed to initialize Options dictionary for Hardware / Unit combination(%d:%d): Unable to convert to string.)",
-+                                                              pModState->pPlugin->m_Name.c_str(), pModState->pPlugin->m_HwdID, self->Unit);
-                                               }
-                                       }
-                               }
-                       }
-                       else
-                       {
--                              CPlugin *pPlugin = nullptr;
--                              if (pModState) pPlugin = pModState->pPlugin;
--                              _log.Log(LOG_ERROR, R"(Expected: myVar = Domoticz.Device(Name="myDevice", Unit=0, TypeName="", Type=0, Subtype=0, Switchtype=0, Image=0, Options={}, Used=1))");
--                              LogPythonException(pPlugin, __func__);
-+                              pModState->pPlugin->Log(LOG_ERROR, R"(Expected: myVar = Domoticz.Device(Name="myDevice", Unit=0, TypeName="", Type=0, Subtype=0, Switchtype=0, Image=0, Options={}, Used=1))");
-+                              pModState->pPlugin->LogPythonException(__func__);
-                       }
-               }
-               catch (std::exception *e)
-@@ -745,12 +748,12 @@ namespace Plugins {
-                       {
-                               if (self->pPlugin->m_bDebug & PDM_DEVICE)
-                               {
--                                      _log.Log(LOG_NORM, "(%s) Creating device '%s'.", self->pPlugin->m_Name.c_str(), sName.c_str());
-+                                      self->pPlugin->Log(LOG_NORM, "Creating device '%s'.", sName.c_str());
-                               }
-                               if (!m_sql.m_bAcceptNewHardware)
-                               {
--                                      _log.Log(LOG_ERROR, "(%s) Device creation failed, Domoticz settings prevent accepting new devices.", self->pPlugin->m_Name.c_str());
-+                                      self->pPlugin->Log(LOG_ERROR, "Device creation failed, Domoticz settings prevent accepting new devices.");
-                               }
-                               else
-                               {
-@@ -792,9 +795,8 @@ namespace Plugins {
-                                                       PyNewRef        pKey = PyLong_FromLong(self->Unit);
-                                                       if (PyDict_SetItem((PyObject*)self->pPlugin->m_DeviceDict, pKey, (PyObject*)self) == -1)
-                                                       {
--                                                              _log.Log(LOG_ERROR, "(%s) failed to add unit '%d' to device dictionary.", self->pPlugin->m_Name.c_str(), self->Unit);
--                                                              Py_INCREF(Py_None);
--                                                              return Py_None;
-+                                                              self->pPlugin->Log(LOG_ERROR, "Failed to add unit '%d' to device dictionary.", self->Unit);
-+                                                              Py_RETURN_NONE;
-                                                       }
-                                                       // Device successfully created, now set the options when supplied
-@@ -817,18 +819,18 @@ namespace Plugins {
-                                               }
-                                               else
-                                               {
--                                                      _log.Log(LOG_ERROR, "(%s) Device creation failed, Hardware/Unit combination (%d:%d) not found in Domoticz.", self->pPlugin->m_Name.c_str(), self->HwdID, self->Unit);
-+                                                      self->pPlugin->Log(LOG_ERROR, "Device creation failed, Hardware/Unit combination (%d:%d) not found in Domoticz.", self->HwdID, self->Unit);
-                                               }
-                                       }
-                                       else
-                                       {
--                                              _log.Log(LOG_ERROR, "(%s) Device creation failed, Hardware/Unit combination (%d:%d) already exists in Domoticz.", self->pPlugin->m_Name.c_str(), self->HwdID, self->Unit);
-+                                              self->pPlugin->Log(LOG_ERROR, "Device creation failed, Hardware/Unit combination (%d:%d) already exists in Domoticz.", self->HwdID, self->Unit);
-                                       }
-                               }
-                       }
-                       else
-                       {
--                              _log.Log(LOG_ERROR, "(%s) Device creation failed, '%s' already exists in Domoticz with Device ID '%d'.", self->pPlugin->m_Name.c_str(), sName.c_str(), self->ID);
-+                              self->pPlugin->Log(LOG_ERROR, "Device creation failed, '%s' already exists in Domoticz with Device ID '%d'.", sName.c_str(), self->ID);
-                       }
-               }
-               else
-@@ -874,11 +876,10 @@ namespace Plugins {
-                       // Try to extract parameters needed to update device settings
-                       if (!PyArg_ParseTupleAndKeywords(args, kwds,   "is|iiiOissiiiissp", kwlist, &nValue, &sValue, &iImage, &iSignalLevel, &iBatteryLevel, &pOptionsDict, &iTimedOut, &Name, &TypeName, &iType, &iSubType, &iSwitchType, &iUsed, &Description, &Color, &SuppressTriggers))
--                              {
--                              _log.Log(LOG_ERROR, "(%s) %s: Failed to parse parameters: 'nValue', 'sValue', 'Image', 'SignalLevel', 'BatteryLevel', 'Options', 'TimedOut', 'Name', 'TypeName', 'Type', 'Subtype', 'Switchtype', 'Used', 'Description', 'Color' or 'SuppressTriggers' expected.", __func__, sName.c_str());
--                              LogPythonException(self->pPlugin, __func__);
--                              Py_INCREF(Py_None);
--                              return Py_None;
-+                      {
-+                              self->pPlugin->Log(LOG_ERROR, "(%s) %s: Failed to parse parameters: 'nValue', 'sValue', 'Image', 'SignalLevel', 'BatteryLevel', 'Options', 'TimedOut', 'Name', 'TypeName', 'Type', 'Subtype', 'Switchtype', 'Used', 'Description', 'Color' or 'SuppressTriggers' expected.", __func__, sName.c_str());
-+                              self->pPlugin->LogPythonException(__func__);
-+                              Py_RETURN_NONE;
-                       }
-                       std::string sID = std::to_string(self->ID);
-@@ -979,7 +980,7 @@ namespace Plugins {
-                       }
-                       // Options provided, assume change
--                      if (pOptionsDict && PyDict_Check(pOptionsDict))
-+                      if (pOptionsDict && PyBorrowedRef(pOptionsDict).IsDict())
-                       {
-                               if (self->SubType != sTypeCustom)
-                               {
-@@ -1094,7 +1095,7 @@ namespace Plugins {
-                       {
-                               if (self->pPlugin->m_bDebug & PDM_DEVICE)
-                               {
--                                      _log.Log(LOG_NORM, "(%s) Deleting device '%s'.", self->pPlugin->m_Name.c_str(), sName.c_str());
-+                                      self->pPlugin->Log(LOG_NORM, "Deleting device '%s'.", sName.c_str());
-                               }
-                               std::vector<std::vector<std::string> > result;
-@@ -1106,19 +1107,18 @@ namespace Plugins {
-                                       PyNewRef        pKey = PyLong_FromLong(self->Unit);
-                                       if (PyDict_DelItem((PyObject*)self->pPlugin->m_DeviceDict, pKey) == -1)
-                                       {
--                                              _log.Log(LOG_ERROR, "(%s) failed to delete unit '%d' from device dictionary.", self->pPlugin->m_Name.c_str(), self->Unit);
--                                              Py_INCREF(Py_None);
--                                              return Py_None;
-+                                              self->pPlugin->Log(LOG_ERROR, "Failed to delete unit '%d' from device dictionary.", self->Unit);
-+                                              Py_RETURN_NONE;
-                                       }
-                               }
-                               else
-                               {
--                                      _log.Log(LOG_ERROR, "(%s) Device deletion failed, Hardware/Unit combination (%d:%d) not found in Domoticz.", self->pPlugin->m_Name.c_str(), self->HwdID, self->Unit);
-+                                      self->pPlugin->Log(LOG_ERROR, "Device deletion failed, Hardware/Unit combination (%d:%d) not found in Domoticz.", self->HwdID, self->Unit);
-                               }
-                       }
-                       else
-                       {
--                              _log.Log(LOG_ERROR, "(%s) Device deletion failed, '%s' does not represent a device in Domoticz.", self->pPlugin->m_Name.c_str(), sName.c_str());
-+                              self->pPlugin->Log(LOG_ERROR, "Device deletion failed, '%s' does not represent a device in Domoticz.", sName.c_str());
-                       }
-               }
-               else
-@@ -1155,10 +1155,14 @@ namespace Plugins {
-       void CConnection_dealloc(CConnection * self)
-       {
--              CPlugin *pPlugin = CPlugin::FindPlugin();
-+              CPlugin *pPlugin = self->pPlugin;
-+              if (!pPlugin)
-+              {
-+                      pPlugin = CPlugin::FindPlugin();
-+              }
-               if (pPlugin && (pPlugin->m_bDebug & PDM_CONNECTION))
-               {
--                      _log.Log(LOG_NORM, "(%s) Deallocating connection object '%s' (%s:%s).", pPlugin->m_Name.c_str(), PyUnicode_AsUTF8(self->Name), PyUnicode_AsUTF8(self->Address), PyUnicode_AsUTF8(self->Port));
-+                      pPlugin->Log(LOG_NORM, "Deallocating connection object '%s' (%s:%s).", PyUnicode_AsUTF8(self->Name), PyUnicode_AsUTF8(self->Address), PyUnicode_AsUTF8(self->Port));
-               }
-               Py_XDECREF(self->Target);
-@@ -1180,22 +1184,15 @@ namespace Plugins {
-                       self->pProtocol = nullptr;
-               }
--              Py_TYPE(self)->tp_free((PyObject*)self);
-+              PyNewRef        pType = PyObject_Type((PyObject*)self);
-+              freefunc pFree = (freefunc)PyType_GetSlot(pType, Py_tp_free);
-+              pFree((PyObject*)self);
-       }
-       PyObject * CConnection_new(PyTypeObject * type, PyObject * args, PyObject * kwds)
-       {
--              CConnection *self = nullptr;
--              if ((CConnection *)type->tp_alloc)
--              {
--                      self = (CConnection *)type->tp_alloc(type, 0);
--              }
--              else
--              {
--                      //!Giz: self = NULL here!!
--                      //_log.Log(LOG_ERROR, "(%s) CConnection Type is not ready.", self->pPlugin->m_Name.c_str());
--                      _log.Log(LOG_ERROR, "(Python plugin) CConnection Type is not ready!");
--              }
-+              allocfunc pAlloc = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
-+              CConnection *self = (CConnection*)pAlloc(type, 0);
-               try
-               {
-@@ -1335,19 +1332,19 @@ namespace Plugins {
-               if (pPlugin->IsStopRequested(0))
-               {
-                       pPlugin->Log(LOG_NORM, "%s, connect request from '%s' ignored. Plugin is stopping.", __func__, self->pPlugin->m_Name.c_str());
--                      return Py_None;
-+                      Py_RETURN_NONE;
-               }
-               if (self->pTransport && self->pTransport->IsConnecting())
-               {
-                       pPlugin->Log(LOG_ERROR, "%s, connect request from '%s' ignored. Transport is connecting.", __func__, self->pPlugin->m_Name.c_str());
--                      return Py_None;
-+                      Py_RETURN_NONE;
-               }
-               if (self->pTransport && self->pTransport->IsConnected())
-               {
-                       pPlugin->Log(LOG_ERROR, "%s, connect request from '%s' ignored. Transport is connected.", __func__, self->pPlugin->m_Name.c_str());
--                      return Py_None;
-+                      Py_RETURN_NONE;
-               }
-               PyObject *pTarget = NULL;
-@@ -1457,7 +1454,7 @@ namespace Plugins {
-                       if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &pData, &iDelay))
-                       {
-                               pPlugin->Log(LOG_ERROR, "(%s) failed to parse parameters, Message or Message, Delay expected.", pPlugin->m_Name.c_str());
--                              LogPythonException(pPlugin, std::string(__func__));
-+                              pPlugin->LogPythonException(__func__);
-                       }
-                       else
-                       {
---- a/hardware/plugins/PythonObjects.h
-+++ b/hardware/plugins/PythonObjects.h
-@@ -40,46 +40,6 @@ namespace Plugins {
-               { nullptr } /* Sentinel */
-       };
--      static PyTypeObject CImageType = {
--              PyVarObject_HEAD_INIT(nullptr, 0) "Domoticz.Image", /* tp_name */
--              sizeof(CImage),                                     /* tp_basicsize */
--              0,                                                  /* tp_itemsize */
--              (destructor)CImage_dealloc,                         /* tp_dealloc */
--              0,                                                  /* tp_print */
--              nullptr,                                            /* tp_getattr */
--              nullptr,                                            /* tp_setattr */
--              nullptr,                                            /* tp_reserved */
--              nullptr,                                            /* tp_repr */
--              nullptr,                                            /* tp_as_number */
--              nullptr,                                            /* tp_as_sequence */
--              nullptr,                                            /* tp_as_mapping */
--              nullptr,                                            /* tp_hash  */
--              nullptr,                                            /* tp_call */
--              (reprfunc)CImage_str,                               /* tp_str */
--              nullptr,                                            /* tp_getattro */
--              nullptr,                                            /* tp_setattro */
--              nullptr,                                            /* tp_as_buffer */
--              Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,          /* tp_flags */
--              "Domoticz Image",                                   /* tp_doc */
--              nullptr,                                            /* tp_traverse */
--              nullptr,                                            /* tp_clear */
--              nullptr,                                            /* tp_richcompare */
--              0,                                                  /* tp_weaklistoffset */
--              nullptr,                                            /* tp_iter */
--              nullptr,                                            /* tp_iternext */
--              CImage_methods,                                     /* tp_methods */
--              CImage_members,                                     /* tp_members */
--              nullptr,                                            /* tp_getset */
--              nullptr,                                            /* tp_base */
--              nullptr,                                            /* tp_dict */
--              nullptr,                                            /* tp_descr_get */
--              nullptr,                                            /* tp_descr_set */
--              0,                                                  /* tp_dictoffset */
--              (initproc)CImage_init,                              /* tp_init */
--              nullptr,                                            /* tp_alloc */
--              CImage_new                                          /* tp_new */
--      };
--
-       class CDevice
-       {
-       public:
-@@ -151,46 +111,6 @@ namespace Plugins {
-               { nullptr } /* Sentinel */
-       };
--      static PyTypeObject CDeviceType = {
--              PyVarObject_HEAD_INIT(nullptr, 0) "Domoticz.Device", /* tp_name */
--              sizeof(CDevice),                                     /* tp_basicsize */
--              0,                                                   /* tp_itemsize */
--              (destructor)CDevice_dealloc,                         /* tp_dealloc */
--              0,                                                   /* tp_print */
--              nullptr,                                             /* tp_getattr */
--              nullptr,                                             /* tp_setattr */
--              nullptr,                                             /* tp_reserved */
--              nullptr,                                             /* tp_repr */
--              nullptr,                                             /* tp_as_number */
--              nullptr,                                             /* tp_as_sequence */
--              nullptr,                                             /* tp_as_mapping */
--              nullptr,                                             /* tp_hash  */
--              nullptr,                                             /* tp_call */
--              (reprfunc)CDevice_str,                               /* tp_str */
--              nullptr,                                             /* tp_getattro */
--              nullptr,                                             /* tp_setattro */
--              nullptr,                                             /* tp_as_buffer */
--              Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           /* tp_flags */
--              "Domoticz Device",                                   /* tp_doc */
--              nullptr,                                             /* tp_traverse */
--              nullptr,                                             /* tp_clear */
--              nullptr,                                             /* tp_richcompare */
--              0,                                                   /* tp_weaklistoffset */
--              nullptr,                                             /* tp_iter */
--              nullptr,                                             /* tp_iternext */
--              CDevice_methods,                                     /* tp_methods */
--              CDevice_members,                                     /* tp_members */
--              nullptr,                                             /* tp_getset */
--              nullptr,                                             /* tp_base */
--              nullptr,                                             /* tp_dict */
--              nullptr,                                             /* tp_descr_get */
--              nullptr,                                             /* tp_descr_set */
--              0,                                                   /* tp_dictoffset */
--              (initproc)CDevice_init,                              /* tp_init */
--              nullptr,                                             /* tp_alloc */
--              CDevice_new                                          /* tp_new */
--      };
--
-       class CPluginTransport;
-       class CPluginProtocol;
-@@ -248,43 +168,4 @@ namespace Plugins {
-               { nullptr } /* Sentinel */
-       };
--      static PyTypeObject CConnectionType = {
--              PyVarObject_HEAD_INIT(nullptr, 0) "Domoticz.Connection", /* tp_name */
--              sizeof(CConnection),                                     /* tp_basicsize */
--              0,                                                       /* tp_itemsize */
--              (destructor)CConnection_dealloc,                         /* tp_dealloc */
--              0,                                                       /* tp_print */
--              nullptr,                                                 /* tp_getattr */
--              nullptr,                                                 /* tp_setattr */
--              nullptr,                                                 /* tp_reserved */
--              nullptr,                                                 /* tp_repr */
--              nullptr,                                                 /* tp_as_number */
--              nullptr,                                                 /* tp_as_sequence */
--              nullptr,                                                 /* tp_as_mapping */
--              nullptr,                                                 /* tp_hash  */
--              nullptr,                                                 /* tp_call */
--              (reprfunc)CConnection_str,                               /* tp_str */
--              nullptr,                                                 /* tp_getattro */
--              nullptr,                                                 /* tp_setattro */
--              nullptr,                                                 /* tp_as_buffer */
--              Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,                /* tp_flags */
--              "Domoticz Connection",                                   /* tp_doc */
--              nullptr,                                                 /* tp_traverse */
--              nullptr,                                                 /* tp_clear */
--              nullptr,                                                 /* tp_richcompare */
--              0,                                                       /* tp_weaklistoffset */
--              nullptr,                                                 /* tp_iter */
--              nullptr,                                                 /* tp_iternext */
--              CConnection_methods,                                     /* tp_methods */
--              CConnection_members,                                     /* tp_members */
--              nullptr,                                                 /* tp_getset */
--              nullptr,                                                 /* tp_base */
--              nullptr,                                                 /* tp_dict */
--              nullptr,                                                 /* tp_descr_get */
--              nullptr,                                                 /* tp_descr_set */
--              0,                                                       /* tp_dictoffset */
--              (initproc)CConnection_init,                              /* tp_init */
--              nullptr,                                                 /* tp_alloc */
--              CConnection_new                                          /* tp_new */
--      };
- } // namespace Plugins
---- a/main/EventSystem.cpp
-+++ b/main/EventSystem.cpp
-@@ -42,7 +42,6 @@ extern http::server::CWebServerHelper m_
- #include "../hardware/plugins/PluginMessages.h"
- #include "EventsPythonModule.h"
- #include "EventsPythonDevice.h"
--extern PyObject * PDevice_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
- #endif
- // Helper table for Blockly and SQL name mapping
-@@ -275,7 +274,7 @@ void CEventSystem::LoadEvents()
-                       {
-                               s = dzv_Dir + eitem.Name + ".lua";
-                               _log.Log(LOG_STATUS, "dzVents: Write file: %s", s.c_str());
--                              FILE *fOut = fopen(s.c_str(), "wb+");
-+                              FILE* fOut = fopen(s.c_str(), "wb+");
-                               if (fOut)
-                               {
-                                       fwrite(eitem.Actions.c_str(), 1, eitem.Actions.size(), fOut);
---- a/main/EventsPythonDevice.cpp
-+++ b/main/EventsPythonDevice.cpp
-@@ -14,15 +14,21 @@
-           Py_XDECREF(self->n_value_string);
-           Py_XDECREF(self->s_value);
-           Py_XDECREF(self->last_update_string);
--          Py_TYPE(self)->tp_free((PyObject*)self);
--      }
-+
-+                PyTypeObject* pType = (PyTypeObject*)PyObject_Type((PyObject*)self);
-+                freefunc pFree = (freefunc)PyType_GetSlot(pType, Py_tp_free);
-+                pFree((PyObject*)self);
-+                Py_XDECREF(pType);
-+        }
-       PyObject *
-       PDevice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-       {
-           PDevice *self;
--          self = (PDevice *)type->tp_alloc(type, 0);
-+                allocfunc pAlloc = (allocfunc)PyType_GetSlot(type, Py_tp_alloc);
-+                self = (PDevice*)pAlloc(type, 0);
-+
-         if (self != nullptr)
-         {
-                 self->name = PyUnicode_FromString("");
---- a/main/EventsPythonDevice.h
-+++ b/main/EventsPythonDevice.h
-@@ -47,7 +47,7 @@
-       static PyModuleDef PDevicemodule = { PyModuleDef_HEAD_INIT,
-                                          "DomoticzEvents",
--                                         "Example module that creates an extension type.",
-+                                         "DomoticzEvents module type.",
-                                          -1,
-                                          nullptr,
-                                          nullptr,
-@@ -55,44 +55,6 @@
-                                          nullptr,
-                                          nullptr };
--      static PyTypeObject PDeviceType = {
--            PyVarObject_HEAD_INIT(nullptr, 0) "DomoticzEvents.PDevice", /* tp_name */
--            sizeof(PDevice),                                            /* tp_basicsize */
--            0,                                                          /* tp_itemsize */
--            (destructor)PDevice_dealloc,                                /* tp_dealloc */
--            0,                                                          /* tp_print */
--            0,                                                          /* tp_getattr */
--            0,                                                          /* tp_setattr */
--            0,                                                          /* tp_reserved */
--            0,                                                          /* tp_repr */
--            0,                                                          /* tp_as_number */
--            0,                                                          /* tp_as_sequence */
--            0,                                                          /* tp_as_mapping */
--            0,                                                          /* tp_hash  */
--            0,                                                          /* tp_call */
--            0,                                                          /* tp_str */
--            0,                                                          /* tp_getattro */
--            0,                                                          /* tp_setattro */
--            0,                                                          /* tp_as_buffer */
--            Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,                   /* tp_flags */
--            "PDevice objects",                                          /* tp_doc */
--            0,                                                          /* tp_traverse */
--            0,                                                          /* tp_clear */
--            0,                                                          /* tp_richcompare */
--            0,                                                          /* tp_weaklistoffset */
--            0,                                                          /* tp_iter */
--            0,                                                          /* tp_iternext */
--            PDevice_methods,                                            /* tp_methods */
--            PDevice_members,                                            /* tp_members */
--            0,                                                          /* tp_getset */
--            0,                                                          /* tp_base */
--            0,                                                          /* tp_dict */
--            0,                                                          /* tp_descr_get */
--            0,                                                          /* tp_descr_set */
--            0,                                                          /* tp_dictoffset */
--            (initproc)PDevice_init,                                     /* tp_init */
--            0,                                                          /* tp_alloc */
--            PDevice_new,                                                /* tp_new */
--      };
-+        static PyObject* PDeviceType;
-     }
- #endif
---- a/main/EventsPythonModule.cpp
-+++ b/main/EventsPythonModule.cpp
-@@ -6,22 +6,27 @@
- #include "EventSystem.h"
- #include "mainworker.h"
- #include "localtime_r.h"
-+#include "../hardware/plugins/Plugins.h"
--#ifdef ENABLE_PYTHON
--
--    namespace Plugins {
--        #define GETSTATE(m) ((struct eventModule_state*)PyModule_GetState(m))
-+#include <fstream>
--              void*   m_PyInterpreter;
--        bool ModuleInitialized = false;
-+#ifdef ENABLE_PYTHON
--        struct eventModule_state {
--            PyObject* error;
--        };
--
--      static PyMethodDef DomoticzEventsMethods[] = { { "Log", PyDomoticz_EventsLog, METH_VARARGS, "Write message to Domoticz log." },
--                                                     { "Command", PyDomoticz_EventsCommand, METH_VARARGS, "Schedule a command." },
--                                                     { nullptr, nullptr, 0, nullptr } };
-+namespace Plugins 
-+{
-+#define GETSTATE(m) ((struct eventModule_state*)PyModule_GetState(m))
-+
-+      void*   m_PyInterpreter;
-+    bool      ModuleInitialized = false;
-+
-+    struct eventModule_state {
-+        PyObject*     error;
-+    };
-+
-+      static PyMethodDef DomoticzEventsMethods[] = { 
-+                                                              { "Log", PyDomoticz_EventsLog, METH_VARARGS, "Write message to Domoticz log." },
-+                                                              { "Command", PyDomoticz_EventsCommand, METH_VARARGS, "Schedule a command." },
-+                                                              { nullptr, nullptr, 0, nullptr } };
-       static int DomoticzEventsTraverse(PyObject *m, visitproc visit, void *arg)
-       {
-@@ -44,7 +49,6 @@
-               if (!PyArg_ParseTuple(args, "s", &msg))
-               {
-                       _log.Log(LOG_ERROR, "Pyhton Event System: Failed to parse parameters: string expected.");
--                      // LogPythonException(pModState->pPlugin, std::string(__func__));
-               }
-               else
-               {
-@@ -52,8 +56,7 @@
-                       _log.Log((_eLogLevel)LOG_NORM, message);
-               }
--              Py_INCREF(Py_None);
--              return Py_None;
-+              Py_RETURN_NONE;
-       }
-       static PyObject *PyDomoticz_EventsCommand(PyObject *self, PyObject *args)
-@@ -68,7 +71,6 @@
-               if (!PyArg_ParseTuple(args, "ss", &device, &action))
-               {
-                       _log.Log(LOG_ERROR, "Pyhton EventSystem: Failed to parse parameters: Two strings expected.");
--                      // LogPythonException(pModState->pPlugin, std::string(__func__));
-               }
-               else
-               {
-@@ -78,13 +80,20 @@
-                       m_mainworker.m_eventsystem.PythonScheduleEvent(device, action, "Test");
-               }
--              Py_INCREF(Py_None);
--              return Py_None;
-+              Py_RETURN_NONE;
-       }
--      struct PyModuleDef DomoticzEventsModuleDef
--              = { PyModuleDef_HEAD_INIT,  "DomoticzEvents",    nullptr, sizeof(struct eventModule_state), DomoticzEventsMethods, nullptr,
--                  DomoticzEventsTraverse, DomoticzEventsClear, nullptr };
-+      struct PyModuleDef DomoticzEventsModuleDef = {
-+              PyModuleDef_HEAD_INIT,  
-+              "DomoticzEvents",        
-+              nullptr, 
-+              sizeof(struct eventModule_state), 
-+              DomoticzEventsMethods, 
-+              nullptr,
-+              DomoticzEventsTraverse, 
-+              DomoticzEventsClear, 
-+              nullptr
-+      };
-       PyMODINIT_FUNC PyInit_DomoticzEvents(void)
-       {
-@@ -94,6 +103,22 @@
-               _log.Log(LOG_STATUS, "Python EventSystem: Initializing event module.");
-               PyObject *pModule = PyModule_Create2(&DomoticzEventsModuleDef, PYTHON_API_VERSION);
-+
-+              PyType_Slot PDeviceSlots[] = {
-+                      { Py_tp_doc, (void*)"PDevice objects" },
-+                      { Py_tp_new, (void*)PDevice_new },
-+                      { Py_tp_init, (void*)PDevice_init },
-+                      { Py_tp_dealloc, (void*)PDevice_dealloc },
-+                      { Py_tp_members, PDevice_members },
-+                      { Py_tp_methods, PDevice_methods },
-+                      { 0, nullptr },
-+              };
-+              PyType_Spec PDeviceSpec = { "DomoticzEvents.PDevice", sizeof(PDevice), 0,
-+                                                        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, PDeviceSlots };
-+
-+              PDeviceType = PyType_FromSpec(&PDeviceSpec);
-+              PyModule_AddObject(pModule, "PDevice", (PyObject*)PDeviceType);
-+
-               return pModule;
-       }
-@@ -166,22 +191,21 @@
-       PyObject *PythonEventsGetModule()
-       {
--              PyObject *pModule = PyState_FindModule(&DomoticzEventsModuleDef);
-+              PyBorrowedRef   pModule = PyState_FindModule(&DomoticzEventsModuleDef);
-               if (pModule)
-               {
-                       // _log.Log(LOG_STATUS, "Python Event System: Module found");
-                       return pModule;
-               }
--              Plugins::PyRun_SimpleStringFlags("import DomoticzEvents", nullptr);
-+              PyImport_ImportModule("DomoticzEvents");
-               pModule = PyState_FindModule(&DomoticzEventsModuleDef);
-               if (pModule)
-               {
-                       return pModule;
-               }
--              // Py_INCREF(Py_None);
--              // return Py_None;
-+
-               return nullptr;
-       }
-@@ -189,7 +213,70 @@
-       PyObject *mapToPythonDict(const std::map<std::string, float> &floatMap)
-       {
--              return Py_None;
-+              Py_RETURN_NONE;
-+      }
-+
-+      void LogPythonException()
-+      {
-+              PyNewRef        pTraceback;
-+              PyNewRef        pExcept;
-+              PyNewRef        pValue;
-+
-+              PyErr_Fetch(&pExcept, &pValue, &pTraceback);
-+              PyErr_NormalizeException(&pExcept, &pValue, &pTraceback);
-+
-+              if (!pExcept && !pValue && !pTraceback)
-+              {
-+                      _log.Log(LOG_ERROR, "Unable to decode exception.");
-+              }
-+              else
-+              {
-+                      std::string     sTypeText("Unknown");
-+                      if (pExcept)
-+                      {
-+                              PyTypeObject* TypeName = (PyTypeObject*)pExcept;
-+                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)TypeName, "__name__");
-+                              sTypeText = (std::string)pName;
-+                      }
-+
-+                      /* See if we can get a full traceback */
-+                      PyNewRef        pModule = PyImport_ImportModule("traceback");
-+                      if (pModule)
-+                      {
-+                              PyNewRef        pFunc = PyObject_GetAttrString(pModule, "format_exception");
-+                              if (pFunc && PyCallable_Check(pFunc)) {
-+                                      PyNewRef        pList = PyObject_CallFunctionObjArgs(pFunc, pExcept, pValue, pTraceback, NULL);
-+                                      if (pList)
-+                                      {
-+                                              for (Py_ssize_t i = 0; i < PyList_Size(pList); i++)
-+                                              {
-+                                                      PyBorrowedRef   pPyStr = PyList_GetItem(pList, i);
-+                                                      std::string             pStr(pPyStr);
-+                                                      size_t pos = 0;
-+                                                      std::string token;
-+                                                      while ((pos = pStr.find('\n')) != std::string::npos) {
-+                                                              token = pStr.substr(0, pos);
-+                                                              _log.Log(LOG_ERROR, "%s", token.c_str());
-+                                                              pStr.erase(0, pos + 1);
-+                                                      }
-+                                              }
-+                                      }
-+                                      else
-+                                      {
-+                                              _log.Log(LOG_ERROR, "Exception: '%s'.  No traceback available.", sTypeText.c_str());
-+                                      }
-+                              }
-+                              else
-+                              {
-+                                      _log.Log(LOG_ERROR, "'format_exception' lookup failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-+                              }
-+                      }
-+                      else
-+                      {
-+                              _log.Log(LOG_ERROR, "'Traceback' module import failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-+                      }
-+              }
-+              PyErr_Clear();
-       }
-       void PythonEventsProcessPython(const std::string &reason, const std::string &filename, const std::string &PyString,
-@@ -202,22 +289,15 @@
-                       return;
-               }
--              if (Plugins::Py_IsInitialized())
-+              if (Py_IsInitialized())
-               {
--
-                       if (m_PyInterpreter)
-                               PyEval_RestoreThread((PyThreadState *)m_PyInterpreter);
--                      /*{
--                          _log.Log(LOG_ERROR, "EventSystem - Python: Failed to attach to interpreter");
--                      }*/
--
--                      PyObject *pModule = Plugins::PythonEventsGetModule();
-+                      PyBorrowedRef   pModule = PythonEventsGetModule();
-                       if (pModule)
-                       {
--
--                              PyObject *pModuleDict = Plugins::PyModule_GetDict((PyObject *)pModule); // borrowed referece
--
-+                              PyBorrowedRef   pModuleDict = Plugins::PyModule_GetDict(pModule);
-                               if (!pModuleDict)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to open module dictionary.");
-@@ -225,26 +305,22 @@
-                                       return;
-                               }
--                              if (Plugins::PyDict_SetItemString(
--                                          pModuleDict, "changed_device_name",
--                                          Plugins::PyUnicode_FromString(m_devicestates[DeviceID].deviceName.c_str()))
--                                  == -1)
-+                              PyNewRef        pStrVal = PyUnicode_FromString(m_devicestates[DeviceID].deviceName.c_str());
-+                              if (PyDict_SetItemString(pModuleDict, "changed_device_name", pStrVal) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to set changed_device_name.");
-                                       return;
-                               }
--                              PyObject *m_DeviceDict = Plugins::PyDict_New();
--
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "Devices", (PyObject *)m_DeviceDict) == -1)
-+                              PyNewRef        pDeviceDict = Plugins::PyDict_New();
-+                              if (PyDict_SetItemString(pModuleDict, "Devices", pDeviceDict) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add Device dictionary.");
-                                       PyEval_SaveThread();
-                                       return;
-                               }
--                              Py_DECREF(m_DeviceDict);
--                              if (Plugins::PyType_Ready(&Plugins::PDeviceType) < 0)
-+                              if (PyType_Ready((PyTypeObject*)Plugins::PDeviceType) < 0)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Unable to ready DeviceType Object.");
-                                       PyEval_SaveThread();
-@@ -261,13 +337,12 @@
-                                       // sitem.subType, sitem.switchtype, sitem.nValue, sitem.nValueWording, sitem.sValue,
-                                       // sitem.lastUpdate); devices[sitem.deviceName] = deviceStatus;
--                                      Plugins::PDevice *aDevice = (Plugins::PDevice *)Plugins::PDevice_new(
--                                              &Plugins::PDeviceType, (PyObject *)nullptr, (PyObject *)nullptr);
--                                      PyObject *pKey = Plugins::PyUnicode_FromString(sitem.deviceName.c_str());
-+                                      PDevice *aDevice = (PDevice *)PDevice_new((PyTypeObject*)PDeviceType, (PyObject *)nullptr, (PyObject *)nullptr);
-+                                      PyNewRef        pKey = PyUnicode_FromString(sitem.deviceName.c_str());
-                                       if (sitem.ID == DeviceID)
-                                       {
--                                              if (Plugins::PyDict_SetItemString(pModuleDict, "changed_device", (PyObject *)aDevice) == -1)
-+                                              if (PyDict_SetItemString(pModuleDict, "changed_device", (PyObject *)aDevice) == -1)
-                                               {
-                                                       _log.Log(LOG_ERROR,
-                                                                "Python EventSystem: Failed to add device '%s' as changed_device.",
-@@ -275,7 +350,7 @@
-                                               }
-                                       }
--                                      if (Plugins::PyDict_SetItem((PyObject *)m_DeviceDict, pKey, (PyObject *)aDevice) == -1)
-+                                      if (PyDict_SetItem(pDeviceDict, pKey, (PyObject *)aDevice) == -1)
-                                       {
-                                               _log.Log(LOG_ERROR, "Python EventSystem: Failed to add device '%s' to device dictionary.",
-                                                        sitem.deviceName.c_str());
-@@ -291,19 +366,18 @@
-                                               // If nValueWording contains %, unicode fails?
-                                               aDevice->id = static_cast<int>(sitem.ID);
--                                              aDevice->name = Plugins::PyUnicode_FromString(sitem.deviceName.c_str());
-+                                              aDevice->name = PyUnicode_FromString(sitem.deviceName.c_str());
-                                               aDevice->type = sitem.devType;
-                                               aDevice->sub_type = sitem.subType;
-                                               aDevice->switch_type = sitem.switchtype;
-                                               aDevice->n_value = sitem.nValue;
--                                              aDevice->n_value_string = Plugins::PyUnicode_FromString(temp_n_value_string.c_str());
-+                                              aDevice->n_value_string = PyUnicode_FromString(temp_n_value_string.c_str());
-                                               aDevice->s_value = Plugins::PyUnicode_FromString(sitem.sValue.c_str());
--                                              aDevice->last_update_string = Plugins::PyUnicode_FromString(sitem.lastUpdate.c_str());
-+                                              aDevice->last_update_string = PyUnicode_FromString(sitem.lastUpdate.c_str());
-                                               // _log.Log(LOG_STATUS, "Python EventSystem: deviceName %s added to device dictionary",
-                                               // sitem.deviceName.c_str());
-                                       }
-                                       Py_DECREF(aDevice);
--                                      Py_DECREF(pKey);
-                               }
-                               // devicestatesMutexLock1.unlock();
-@@ -315,28 +389,24 @@
-                               localtime_r(&now, &ltime);
-                               int minutesSinceMidnight = (ltime.tm_hour * 60) + ltime.tm_min;
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "minutes_since_midnight",
--                                                                Plugins::PyLong_FromLong(minutesSinceMidnight))
--                                  == -1)
-+                              PyNewRef        pPyLong = PyLong_FromLong(minutesSinceMidnight);
-+                              if (PyDict_SetItemString(pModuleDict, "minutes_since_midnight", pPyLong) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add 'minutesSinceMidnight' to module_dict");
-                               }
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "sunrise_in_minutes", Plugins::PyLong_FromLong(intSunRise))
--                                  == -1)
-+                              pPyLong = PyLong_FromLong(intSunRise);
-+                              if (PyDict_SetItemString(pModuleDict, "sunrise_in_minutes", pPyLong) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add 'sunrise_in_minutes' to module_dict");
-                               }
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "sunset_in_minutes", Plugins::PyLong_FromLong(intSunSet))
--                                  == -1)
-+                              pPyLong = PyLong_FromLong(intSunSet);
-+                              if (PyDict_SetItemString(pModuleDict, "sunset_in_minutes", pPyLong) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add 'sunset_in_minutes' to module_dict");
-                               }
--
--                              // PyObject* dayTimeBool = Py_False;
--                              // PyObject* nightTimeBool = Py_False;
--
-+                              
-                               bool isDaytime = false;
-                               bool isNightime = false;
-@@ -349,75 +419,121 @@
-                                       isNightime = true;
-                               }
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "is_daytime", Plugins::PyBool_FromLong(isDaytime)) == -1)
-+                              PyNewRef        pPyBool = PyBool_FromLong(isDaytime);
-+                              if (PyDict_SetItemString(pModuleDict, "is_daytime", pPyBool) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add 'is_daytime' to module_dict");
-                               }
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "is_nighttime", Plugins::PyBool_FromLong(isNightime)) == -1)
-+                              pPyBool = PyBool_FromLong(isNightime);
-+                              if (PyDict_SetItemString(pModuleDict, "is_nighttime", pPyBool) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add 'is_daytime' to module_dict");
-                               }
-                               // UserVariables
--                              PyObject *m_uservariablesDict = Plugins::PyDict_New();
--
--                              if (Plugins::PyDict_SetItemString(pModuleDict, "user_variables", (PyObject *)m_uservariablesDict) == -1)
-+                              PyNewRef        userVariablesDict = PyDict_New();
-+                              if (PyDict_SetItemString(pModuleDict, "user_variables", userVariablesDict) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add uservariables dictionary.");
-                                       PyEval_SaveThread();
-                                       return;
-                               }
--                              Py_DECREF(m_uservariablesDict);
--
--                              // This doesn't work
--                              // boost::unique_lock<boost::shared_mutex> uservariablesMutexLock2 (m_uservariablesMutex);
-                               for (auto it_var = m_uservariables.begin(); it_var != m_uservariables.end(); ++it_var)
-                               {
-                                       CEventSystem::_tUserVariable uvitem = it_var->second;
--                                      Plugins::PyDict_SetItemString(m_uservariablesDict, uvitem.variableName.c_str(),
--                                                                    Plugins::PyUnicode_FromString(uvitem.variableValue.c_str()));
-+                                      PyDict_SetItemString(userVariablesDict, uvitem.variableName.c_str(),
-+                                                                    PyUnicode_FromString(uvitem.variableValue.c_str()));
-                               }
--                              // uservariablesMutexLock2.unlock();
--
-                               // Add __main__ module
--                              PyObject *pModule = Plugins::PyImport_AddModule("__main__");
--                              Py_INCREF(pModule);
-+                              PyBorrowedRef   pMainModule = PyImport_AddModule("__main__");
-+                              PyBorrowedRef   global_dict = PyModule_GetDict(pMainModule);
-+                              PyNewRef                local_dict = PyDict_New();
-                               // Override sys.stderr
--                              Plugins::PyRun_SimpleStringFlags("import sys\nclass StdErrRedirect:\n    def __init__(self):\n        "
--                                                               "self.buffer = ''\n    def write(self, "
--                                                               "msg):\n        self.buffer += msg\nstdErrRedirect = "
--                                                               "StdErrRedirect()\nsys.stderr = stdErrRedirect\n",
--                                                               nullptr);
-+                              {
-+                                      PyNewRef        pCode = Py_CompileString("import sys\nclass StdErrRedirect:\n    def __init__(self):\n        "
-+                                                                      "self.buffer = ''\n    def write(self, "
-+                                                                      "msg):\n        self.buffer += msg\nstdErrRedirect = "
-+                                                                      "StdErrRedirect()\nsys.stderr = stdErrRedirect\n",
-+                                                                      filename.c_str(), Py_file_input);
-+                                      if (pCode)
-+                                      {
-+                                              PyNewRef        pEval = PyEval_EvalCode(pCode, global_dict, local_dict);
-+                                      }
-+                                      else
-+                                      {
-+                                              _log.Log(LOG_ERROR, "EventSystem: Failed to compile stderror redirection for event script '%s'", reason.c_str());
-+                                      }
-+                              }
--                              if (PyString.length() > 0)
-+                              if (!PyErr_Occurred() && (PyString.length() > 0))
-                               {
-                                       // Python-string from WebEditor
--                                      Plugins::PyRun_SimpleStringFlags(PyString.c_str(), nullptr);
-+                                      PyNewRef        pCode = Py_CompileString(PyString.c_str(), filename.c_str(), Py_file_input);
-+                                      if (pCode)
-+                                      {
-+                                              PyNewRef        pEval = PyEval_EvalCode(pCode, global_dict, local_dict);
-+                                      }
-+                                      else
-+                                      {
-+                                              _log.Log(LOG_ERROR, "EventSystem: Failed to compile python '%s' event script '%s'", reason.c_str(), filename.c_str());
-+                                      }
-                               }
-                               else
-                               {
-                                       // Script-file
--                                      FILE *PythonScriptFile = fopen(filename.c_str(), "r");
--                                      Plugins::PyRun_SimpleFileExFlags(PythonScriptFile, filename.c_str(), 0, nullptr);
-+                                      std::ifstream PythonScriptFile(filename.c_str());
-+                                      if (PythonScriptFile.is_open())
-+                                      {
-+                                              char    PyLine[256];
-+                                              std::string     PyString;
-+                                              while (PythonScriptFile.getline(PyLine, sizeof(PyLine), '\n'))
-+                                              {
-+                                                      PyString.append(PyLine);
-+                                                      PyString += '\n';
-+                                              }
-+                                              PythonScriptFile.close();
-+
-+                                              PyNewRef        pCode = Py_CompileString(PyString.c_str(), filename.c_str(), Py_file_input);
-+                                              if (pCode)
-+                                              {
-+                                                      PyNewRef        pEval = PyEval_EvalCode(pCode, global_dict, local_dict);
-+                                              }
-+                                              else
-+                                              {
-+                                                      _log.Log(LOG_ERROR, "EventSystem: Failed to compile python '%s' event script file '%s'", reason.c_str(), filename.c_str());
-+                                              }
-+                                      }
-+                                      else
-+                                      {
-+                                              _log.Log(LOG_ERROR, "EventSystem: Failed to open python script file '%s'", filename.c_str());
-+                                      }
-+                              }
--                                      if (PythonScriptFile != nullptr)
--                                              fclose(PythonScriptFile);
-+                              // Log any exceptions
-+                              if (PyErr_Occurred())
-+                              {
-+                                      LogPythonException();
-                               }
-                               // Get message from stderr redirect
--                              PyObject *stdErrRedirect = nullptr, *logBuffer = nullptr, *logBytes = nullptr;
-                               std::string logString;
--                              if ((stdErrRedirect = Plugins::PyObject_GetAttrString(pModule, "stdErrRedirect")) == nullptr)
--                                      goto free_module;
--                              if ((logBuffer = Plugins::PyObject_GetAttrString(stdErrRedirect, "buffer")) == nullptr)
--                                      goto free_stderrredirect;
--                              if ((logBytes = PyUnicode_AsUTF8String(logBuffer)) == nullptr)
--                                      goto free_logbuffer;
--                              logString.append(PyBytes_AsString(logBytes));
-+                              if (PyObject_HasAttrString(pModule, "stdErrRedirect"))
-+                              {
-+                                      PyNewRef        stdErrRedirect = PyObject_GetAttrString(pModule, "stdErrRedirect");
-+                                      if (PyObject_HasAttrString(stdErrRedirect, "buffer"))
-+                                      {
-+                                              PyNewRef        logBuffer = PyObject_GetAttrString(stdErrRedirect, "buffer");
-+                                              PyNewRef        logBytes = PyUnicode_AsUTF8String(logBuffer);
-+                                              if (logBytes)
-+                                              {
-+                                                      logString.append(PyBytes_AsString(logBytes));
-+                                              }
-+                                      }
-+                              }
-                               // Check if there were some errors written to stderr
-                               if (logString.length() > 0)
-@@ -436,15 +552,6 @@
-                                               logString = logString.substr(lineBreakPos + 1);
-                                       }
-                               }
--
--                              // Cleanup
--                              Py_DECREF(logBytes);
--                      free_logbuffer:
--                              Py_DECREF(logBuffer);
--                      free_stderrredirect:
--                              Py_DECREF(stdErrRedirect);
--                      free_module:
--                              Py_DECREF(pModule);
-                       }
-                       else
-                       {
-@@ -458,5 +565,5 @@
-                       _log.Log(LOG_ERROR, "EventSystem: Python not Initialized");
-               }
-       }
--    } // namespace Plugins
-+} // namespace Plugins
- #endif
---- a/main/SQLHelper.cpp
-+++ b/main/SQLHelper.cpp
-@@ -5226,7 +5226,7 @@ uint64_t CSQLHelper::UpdateValueInt(
-                               )
-                       {
-                               if (
--                                      (pHardware->HwdType != HTYPE_MQTTAutoDiscovery)
-+                                      (HWtype != HTYPE_MQTTAutoDiscovery)
-                                       &&
-                                       (switchtype == STYPE_BlindsPercentage
-                                       || switchtype == STYPE_BlindsPercentageWithStop
diff --git a/utils/domoticz/patches/991-linux_crash_when_formating_py.patch b/utils/domoticz/patches/991-linux_crash_when_formating_py.patch
deleted file mode 100644 (file)
index 1955b25..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-From a9df45497dc79023ed1864dd9b8e435935220171 Mon Sep 17 00:00:00 2001
-From: dnpwwo <kendel.boul@gmail.com>
-Date: Tue, 1 Mar 2022 13:09:01 +1100
-Subject: [PATCH] BugFix: Linux crash when formating Python exceptions Other: 
- Continue code cleanup
-
----
- hardware/plugins/Plugins.cpp | 45 +++++++++++-------------------------
- hardware/plugins/Plugins.h   |  3 ++-
- main/EventsPythonModule.cpp  |  6 ++---
- 3 files changed, 18 insertions(+), 36 deletions(-)
-
---- a/hardware/plugins/Plugins.cpp
-+++ b/hardware/plugins/Plugins.cpp
-@@ -724,13 +724,7 @@ namespace Plugins
-               }
-               else
-               {
--                      std::string     sTypeText("Unknown");
--                      if (pExcept)
--                      {
--                              PyTypeObject* TypeName = (PyTypeObject*)pExcept;
--                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)TypeName, "__name__");
--                              sTypeText = (std::string)pName;
--                      }
-+                      std::string     sTypeText("Unknown Error");
-                       /* See if we can get a full traceback */
-                       PyNewRef        pModule = PyImport_ImportModule("traceback");
-@@ -738,7 +732,7 @@ namespace Plugins
-                       {
-                               PyNewRef        pFunc = PyObject_GetAttrString(pModule, "format_exception");
-                               if (pFunc && PyCallable_Check(pFunc)) {
--                                      PyNewRef        pList = PyObject_CallFunctionObjArgs(pFunc, pExcept, pValue, pTraceback, NULL);
-+                                      PyNewRef        pList = PyObject_CallFunctionObjArgs(pFunc, (PyObject*)pExcept, (PyObject*)pValue, (PyObject*)pTraceback, NULL);
-                                       if (pList)
-                                       {
-                                               for (Py_ssize_t i = 0; i < PyList_Size(pList); i++)
-@@ -756,16 +750,19 @@ namespace Plugins
-                                       }
-                                       else
-                                       {
-+                                              if (pExcept) sTypeText = pExcept.Attribute("__name__");
-                                               Log(LOG_ERROR, "Exception: '%s'.  No traceback available.", sTypeText.c_str());
-                                       }
-                               }
-                               else
-                               {
-+                                      if (pExcept) sTypeText = pExcept.Attribute("__name__");
-                                       Log(LOG_ERROR, "'format_exception' lookup failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-                               }
-                       }
-                       else
-                       {
-+                              if (pExcept) sTypeText = pExcept.Attribute("__name__");
-                               Log(LOG_ERROR, "'Traceback' module import failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-                       }
-               }
-@@ -1950,7 +1947,7 @@ namespace Plugins
-               }
-       }
--      void CPlugin::Callback(PyObject *pTarget, const std::string &sHandler, PyObject *pParams)
-+      void CPlugin::Callback(PyBorrowedRef& pTarget, const std::string &sHandler, PyObject *pParams)
-       {
-               try
-               {
-@@ -1966,19 +1963,8 @@ namespace Plugins
-                               PyNewRef pFunc = PyObject_GetAttrString(pTarget, sHandler.c_str());
-                               if (pFunc && PyCallable_Check(pFunc))
-                               {
--                                      module_state *pModState = nullptr;
--                                      PyBorrowedRef brModule = PyState_FindModule(&DomoticzModuleDef);
--                                      if (!brModule)
--                                      {
--                                              brModule = PyState_FindModule(&DomoticzExModuleDef);
--                                      }
--
--                                      if (brModule)
--                                      {
--                                              pModState = ((struct module_state *)PyModule_GetState(brModule));
--                                      }
--
-                                       // Store the callback object so the Dump function has context if invoked
-+                                      module_state* pModState = FindModule();
-                                       if (pModState)
-                                       {
-                                               pModState->lastCallback = pTarget;
-@@ -1986,14 +1972,12 @@ namespace Plugins
-                                       if (m_bDebug & PDM_QUEUE)
-                                       {
--                                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)(pTarget->ob_type), "__name__");
--                                              if (pName)
--                                                      Log(LOG_NORM, "Calling message handler '%s' on '%s' type object.", sHandler.c_str(), (std::string(pName).c_str()));
-+                                              Log(LOG_NORM, "Calling message handler '%s' on '%s' type object.", sHandler.c_str(), pTarget.Type().c_str());
-                                       }
-                                       PyErr_Clear();
--                                      // Invokde the callback function
-+                                      // Invoke the callback function
-                                       PyNewRef        pReturnValue = PyObject_CallObject(pFunc, pParams);
-                                       if (pModState)
-@@ -2020,17 +2004,14 @@ namespace Plugins
-                                                                       std::string sAttrName = pItem;
-                                                                       if (sAttrName.substr(0, 2) != "__") // ignore system stuff
-                                                                       {
--                                                                              if (PyObject_HasAttrString(pTarget, sAttrName.c_str()))
-+                                                                              std::string     strValue = pTarget.Attribute(sAttrName);
-+                                                                              if (strValue.length())
-                                                                               {
-                                                                                       PyNewRef pValue = PyObject_GetAttrString(pTarget, sAttrName.c_str());
-                                                                                       if (!PyCallable_Check(pValue)) // Filter out methods
-                                                                                       {
--                                                                                              std::string     strValue = pValue;
--                                                                                              if (strValue.length())
--                                                                                              {
--                                                                                                      std::string sBlank((sAttrName.length() < 20) ? 20 - sAttrName.length() : 0, ' ');
--                                                                                                      Log(LOG_NORM, " ----> '%s'%s '%s'", sAttrName.c_str(), sBlank.c_str(), strValue.c_str());
--                                                                                              }
-+                                                                                              std::string sBlank((sAttrName.length() < 20) ? 20 - sAttrName.length() : 0, ' ');
-+                                                                                              Log(LOG_NORM, " ----> '%s'%s '%s'", sAttrName.c_str(), sBlank.c_str(), strValue.c_str());
-                                                                                       }
-                                                                               }
-                                                                       }
---- a/hardware/plugins/Plugins.h
-+++ b/hardware/plugins/Plugins.h
-@@ -92,7 +92,7 @@ namespace Plugins {
-         void ConnectionWrite(CDirectiveBase *);
-         void ConnectionDisconnect(CDirectiveBase *);
-         void DisconnectEvent(CEventBase *);
--        void Callback(PyObject* pTarget, const std::string &sHandler, PyObject *pParams);
-+        void Callback(PyBorrowedRef& pTarget, const std::string &sHandler, PyObject *pParams);
-         void RestoreThread();
-         void ReleaseThread();
-         void Stop();
-@@ -157,6 +157,7 @@ namespace Plugins {
-                       m_pObject = pObject;
-               };
-               std::string     Attribute(const char* name);
-+              std::string     Attribute(std::string& name) { return Attribute(name.c_str()); };
-               std::string     Type();
-               bool            IsDict() { return TypeCheck(Py_TPFLAGS_DICT_SUBCLASS); };
-               bool            IsList() { return TypeCheck(Py_TPFLAGS_LIST_SUBCLASS); };
---- a/main/EventsPythonModule.cpp
-+++ b/main/EventsPythonModule.cpp
-@@ -297,7 +297,7 @@ namespace Plugins
-                       PyBorrowedRef   pModule = PythonEventsGetModule();
-                       if (pModule)
-                       {
--                              PyBorrowedRef   pModuleDict = Plugins::PyModule_GetDict(pModule);
-+                              PyBorrowedRef   pModuleDict = PyModule_GetDict(pModule);
-                               if (!pModuleDict)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to open module dictionary.");
-@@ -312,7 +312,7 @@ namespace Plugins
-                                       return;
-                               }
--                              PyNewRef        pDeviceDict = Plugins::PyDict_New();
-+                              PyNewRef        pDeviceDict = PyDict_New();
-                               if (PyDict_SetItemString(pModuleDict, "Devices", pDeviceDict) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to add Device dictionary.");
-@@ -320,7 +320,7 @@ namespace Plugins
-                                       return;
-                               }
--                              if (PyType_Ready((PyTypeObject*)Plugins::PDeviceType) < 0)
-+                              if (PyType_Ready((PyTypeObject*)PDeviceType) < 0)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Unable to ready DeviceType Object.");
-                                       PyEval_SaveThread();
diff --git a/utils/domoticz/patches/992-prevent_crash_processing_py.patch b/utils/domoticz/patches/992-prevent_crash_processing_py.patch
deleted file mode 100644 (file)
index 32b7653..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-From 90e683a16ec1f267d3efd1b3fd1bff0b9ac9691e Mon Sep 17 00:00:00 2001
-From: dnpwwo <kendel.boul@gmail.com>
-Date: Tue, 1 Mar 2022 22:01:14 +1100
-Subject: [PATCH] BugFix: Prevent crash processing Python exceptions on Linux.
- Uplift: Create Device objects using Python rather than C++
-
----
- main/EventsPythonDevice.h   |  2 +-
- main/EventsPythonModule.cpp | 92 ++++++++++++++++---------------------
- 2 files changed, 40 insertions(+), 54 deletions(-)
-
---- a/main/EventsPythonDevice.h
-+++ b/main/EventsPythonDevice.h
-@@ -55,6 +55,6 @@
-                                          nullptr,
-                                          nullptr };
--        static PyObject* PDeviceType;
-+        static PyTypeObject* PDeviceType;
-     }
- #endif
---- a/main/EventsPythonModule.cpp
-+++ b/main/EventsPythonModule.cpp
-@@ -16,11 +16,11 @@ namespace Plugins
- {
- #define GETSTATE(m) ((struct eventModule_state*)PyModule_GetState(m))
--      void*   m_PyInterpreter;
--    bool      ModuleInitialized = false;
-+      PyThreadState*  m_PyInterpreter;
-+    bool                      m_ModuleInitialized = false;
-     struct eventModule_state {
--        PyObject*     error;
-+              PyObject*       error;
-     };
-       static PyMethodDef DomoticzEventsMethods[] = { 
-@@ -116,7 +116,7 @@ namespace Plugins
-               PyType_Spec PDeviceSpec = { "DomoticzEvents.PDevice", sizeof(PDevice), 0,
-                                                         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, PDeviceSlots };
--              PDeviceType = PyType_FromSpec(&PDeviceSpec);
-+              PDeviceType = (PyTypeObject*)PyType_FromSpec(&PDeviceSpec);
-               PyModule_AddObject(pModule, "PDevice", (PyObject*)PDeviceType);
-               return pModule;
-@@ -169,7 +169,7 @@ namespace Plugins
-                 _log.Log(LOG_ERROR, "EventSystem - Python: Failed to initialize module.");
-                 return false;
-             }
--            ModuleInitialized = true;
-+            m_ModuleInitialized = true;
-             return true;
-       }
-@@ -232,12 +232,6 @@ namespace Plugins
-               else
-               {
-                       std::string     sTypeText("Unknown");
--                      if (pExcept)
--                      {
--                              PyTypeObject* TypeName = (PyTypeObject*)pExcept;
--                              PyNewRef        pName = PyObject_GetAttrString((PyObject*)TypeName, "__name__");
--                              sTypeText = (std::string)pName;
--                      }
-                       /* See if we can get a full traceback */
-                       PyNewRef        pModule = PyImport_ImportModule("traceback");
-@@ -245,7 +239,7 @@ namespace Plugins
-                       {
-                               PyNewRef        pFunc = PyObject_GetAttrString(pModule, "format_exception");
-                               if (pFunc && PyCallable_Check(pFunc)) {
--                                      PyNewRef        pList = PyObject_CallFunctionObjArgs(pFunc, pExcept, pValue, pTraceback, NULL);
-+                                      PyNewRef        pList = PyObject_CallFunctionObjArgs(pFunc, (PyObject*)pExcept, (PyObject*)pValue, (PyObject*)pTraceback, NULL);
-                                       if (pList)
-                                       {
-                                               for (Py_ssize_t i = 0; i < PyList_Size(pList); i++)
-@@ -263,16 +257,19 @@ namespace Plugins
-                                       }
-                                       else
-                                       {
-+                                              if (pExcept) sTypeText = pExcept.Attribute("__name__");
-                                               _log.Log(LOG_ERROR, "Exception: '%s'.  No traceback available.", sTypeText.c_str());
-                                       }
-                               }
-                               else
-                               {
-+                                      if (pExcept) sTypeText = pExcept.Attribute("__name__");
-                                       _log.Log(LOG_ERROR, "'format_exception' lookup failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-                               }
-                       }
-                       else
-                       {
-+                              if (pExcept) sTypeText = pExcept.Attribute("__name__");
-                               _log.Log(LOG_ERROR, "'Traceback' module import failed, exception: '%s'.  No traceback available.", sTypeText.c_str());
-                       }
-               }
-@@ -280,11 +277,11 @@ namespace Plugins
-       }
-       void PythonEventsProcessPython(const std::string &reason, const std::string &filename, const std::string &PyString,
--                                     const uint64_t DeviceID, std::map<uint64_t, CEventSystem::_tDeviceStatus> m_devicestates,
--                                     std::map<uint64_t, CEventSystem::_tUserVariable> m_uservariables, int intSunRise, int intSunSet)
-+                                     const uint64_t DeviceID, std::map<uint64_t, CEventSystem::_tDeviceStatus> deviceStates,
-+                                     std::map<uint64_t, CEventSystem::_tUserVariable> userVariables, int intSunRise, int intSunSet)
-       {
--              if (!ModuleInitialized)
-+              if (!m_ModuleInitialized)
-               {
-                       return;
-               }
-@@ -292,7 +289,7 @@ namespace Plugins
-               if (Py_IsInitialized())
-               {
-                       if (m_PyInterpreter)
--                              PyEval_RestoreThread((PyThreadState *)m_PyInterpreter);
-+                              PyEval_RestoreThread(m_PyInterpreter);
-                       PyBorrowedRef   pModule = PythonEventsGetModule();
-                       if (pModule)
-@@ -305,7 +302,7 @@ namespace Plugins
-                                       return;
-                               }
--                              PyNewRef        pStrVal = PyUnicode_FromString(m_devicestates[DeviceID].deviceName.c_str());
-+                              PyNewRef        pStrVal = PyUnicode_FromString(deviceStates[DeviceID].deviceName.c_str());
-                               if (PyDict_SetItemString(pModuleDict, "changed_device_name", pStrVal) == -1)
-                               {
-                                       _log.Log(LOG_ERROR, "Python EventSystem: Failed to set changed_device_name.");
-@@ -327,22 +324,34 @@ namespace Plugins
-                                       return;
-                               }
--                              // Mutex
--                              // boost::shared_lock<boost::shared_mutex> devicestatesMutexLock1(m_devicestatesMutex);
--
--                              for (auto it_type = m_devicestates.begin(); it_type != m_devicestates.end(); ++it_type)
-+                              for (auto it_type = deviceStates.begin(); it_type != deviceStates.end(); ++it_type)
-                               {
-                                       CEventSystem::_tDeviceStatus sitem = it_type->second;
--                                      // object deviceStatus = domoticz_module.attr("Device")(sitem.ID, sitem.deviceName, sitem.devType,
--                                      // sitem.subType, sitem.switchtype, sitem.nValue, sitem.nValueWording, sitem.sValue,
--                                      // sitem.lastUpdate); devices[sitem.deviceName] = deviceStatus;
--                                      PDevice *aDevice = (PDevice *)PDevice_new((PyTypeObject*)PDeviceType, (PyObject *)nullptr, (PyObject *)nullptr);
--                                      PyNewRef        pKey = PyUnicode_FromString(sitem.deviceName.c_str());
-+                                      PyNewRef nrArgList = Py_BuildValue("(iOiiiOiOO)",       static_cast<int>(sitem.ID),
-+                                                                                                                                              PyUnicode_FromString(sitem.deviceName.c_str()),
-+                                                                                                                                              sitem.devType,
-+                                                                                                                                              sitem.subType,
-+                                                                                                                                              sitem.switchtype,
-+                                                                                                                                              PyUnicode_FromString(sitem.sValue.c_str()),
-+                                                                                                                                              sitem.nValue,
-+                                                                                                                                              PyUnicode_FromString(sitem.nValueWording.c_str()),
-+                                                                                                                                              PyUnicode_FromString(sitem.lastUpdate.c_str()));
-+                                      if (!nrArgList)
-+                                      {
-+                                              _log.Log(LOG_ERROR, "Python EventSystem: Building device argument list failed for key %s.", sitem.deviceName.c_str());
-+                                              continue;
-+                                      }
-+                                      PyNewRef pDevice = PyObject_CallObject((PyObject*)PDeviceType, nrArgList);
-+                                      if (!pDevice)
-+                                      {
-+                                              _log.Log(LOG_ERROR, "Python EventSystem: Event Device object creation failed for key %s.", sitem.deviceName.c_str());
-+                                              continue;
-+                                      }
-                                       if (sitem.ID == DeviceID)
-                                       {
--                                              if (PyDict_SetItemString(pModuleDict, "changed_device", (PyObject *)aDevice) == -1)
-+                                              if (PyDict_SetItemString(pModuleDict, "changed_device", (PyObject *)pDevice) == -1)
-                                               {
-                                                       _log.Log(LOG_ERROR,
-                                                                "Python EventSystem: Failed to add device '%s' as changed_device.",
-@@ -350,36 +359,13 @@ namespace Plugins
-                                               }
-                                       }
--                                      if (PyDict_SetItem(pDeviceDict, pKey, (PyObject *)aDevice) == -1)
-+                                      PyNewRef        pKey = PyUnicode_FromString(sitem.deviceName.c_str());
-+                                      if (PyDict_SetItem(pDeviceDict, pKey, (PyObject *)pDevice) == -1)
-                                       {
-                                               _log.Log(LOG_ERROR, "Python EventSystem: Failed to add device '%s' to device dictionary.",
-                                                        sitem.deviceName.c_str());
-                                       }
--                                      else
--                                      {
--
--                                              // _log.Log(LOG_ERROR, "Python EventSystem: nValueWording '%s' - done. ",
--                                              // sitem.nValueWording.c_str());
--
--                                              std::string temp_n_value_string = sitem.nValueWording;
--
--                                              // If nValueWording contains %, unicode fails?
--
--                                              aDevice->id = static_cast<int>(sitem.ID);
--                                              aDevice->name = PyUnicode_FromString(sitem.deviceName.c_str());
--                                              aDevice->type = sitem.devType;
--                                              aDevice->sub_type = sitem.subType;
--                                              aDevice->switch_type = sitem.switchtype;
--                                              aDevice->n_value = sitem.nValue;
--                                              aDevice->n_value_string = PyUnicode_FromString(temp_n_value_string.c_str());
--                                              aDevice->s_value = Plugins::PyUnicode_FromString(sitem.sValue.c_str());
--                                              aDevice->last_update_string = PyUnicode_FromString(sitem.lastUpdate.c_str());
--                                              // _log.Log(LOG_STATUS, "Python EventSystem: deviceName %s added to device dictionary",
--                                              // sitem.deviceName.c_str());
--                                      }
--                                      Py_DECREF(aDevice);
-                               }
--                              // devicestatesMutexLock1.unlock();
-                               // Time related
-@@ -440,7 +426,7 @@ namespace Plugins
-                                       return;
-                               }
--                              for (auto it_var = m_uservariables.begin(); it_var != m_uservariables.end(); ++it_var)
-+                              for (auto it_var = userVariables.begin(); it_var != userVariables.end(); ++it_var)
-                               {
-                                       CEventSystem::_tUserVariable uvitem = it_var->second;
-                                       PyDict_SetItemString(userVariablesDict, uvitem.variableName.c_str(),
diff --git a/utils/domoticz/patches/994-compile_err_whitout_py.patch b/utils/domoticz/patches/994-compile_err_whitout_py.patch
deleted file mode 100644 (file)
index d8bbfa6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-From fff4bef553cfd75030d473b3296ade88b3150909 Mon Sep 17 00:00:00 2001
-From: Rob Peters <Info@Domoticz.com>
-Date: Thu, 10 Mar 2022 07:09:18 +0100
-Subject: [PATCH] Fixed compile error when PYTHON was disabled (Fixes #5187)
-
----
- hardware/plugins/DelayedLink.h | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/hardware/plugins/DelayedLink.h
-+++ b/hardware/plugins/DelayedLink.h
-@@ -1,5 +1,5 @@
- #pragma once
--
-+#ifdef ENABLE_PYTHON
- #ifdef WIN32
- #     define MS_NO_COREDLL 1
- #else
-@@ -574,3 +574,4 @@ static inline void py3__Py_XDECREF(PyObj
- #endif
- #pragma pop_macro("_DEBUG")
- } // namespace Plugins
-+#endif //#ifdef ENABLE_PYTHON
diff --git a/utils/domoticz/patches/995-make_sure_compile_works_without_py.patch b/utils/domoticz/patches/995-make_sure_compile_works_without_py.patch
deleted file mode 100644 (file)
index a55bafc..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From ca4578980e373543d0561564863718c879fa7743 Mon Sep 17 00:00:00 2001
-From: Rob Peters <Info@Domoticz.com>
-Date: Thu, 10 Mar 2022 12:32:29 +0100
-Subject: [PATCH] Making sure code can be compiled without Python
-
----
- hardware/plugins/Plugins.h       | 4 ++++
- hardware/plugins/PythonObjects.h | 1 +
- 2 files changed, 5 insertions(+)
-
---- a/hardware/plugins/Plugins.h
-+++ b/hardware/plugins/Plugins.h
-@@ -1,5 +1,7 @@
- #pragma once
-+#ifdef ENABLE_PYTHON
-+
- #include "../DomoticzHardware.h"
- #include "../hardwaretypes.h"
- #include "../../notifications/NotificationBase.h"
-@@ -300,3 +302,5 @@ namespace Plugins {
-       };
- } // namespace Plugins
-+
-+#endif //#ifdef ENABLE_PYTHON
---- a/hardware/plugins/PythonObjects.h
-+++ b/hardware/plugins/PythonObjects.h
-@@ -169,3 +169,4 @@ namespace Plugins {
-       };
- } // namespace Plugins
-+
diff --git a/utils/dysk/Makefile b/utils/dysk/Makefile
new file mode 100644 (file)
index 0000000..cc559b0
--- /dev/null
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-3.0-only
+#
+# Copyright (C) 2023 Facundo Acevedo
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=dysk
+PKG_VERSION:=2.8.2
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://codeload.github.com/Canop/dysk/tar.gz/v$(PKG_VERSION)?
+PKG_HASH:=3e0f3a470539721748d7bc1acc867bdddcb824695b2f766e3a1f230ebac28c2c
+
+PKG_MAINTAINER:=Facundo Acevedo <facevedo@disroot.org>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENCE
+
+PKG_BUILD_DEPENDS:=rust/host
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+include ../../lang/rust/rust-package.mk
+
+define Package/dysk
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Utility for efficient file and directory management
+  DEPENDS:=$(RUST_ARCH_DEPENDS) 
+  URL:=https://dystroy.org/dysk
+endef
+
+define Package/dysk/description
+  Dysk is a command-line tool designed for efficient file and
+  directory management in Unix-like environments. It offers a
+  streamlined approach to organizing and manipulating files,
+  potentially simplifying various file-related tasks.
+endef
+
+$(eval $(call RustBinPackage,dysk))
+$(eval $(call BuildPackage,dysk))
index 3a47a8a766c57cf519089b4d923be42741aefc4d..81541493d181e91f7b10170a7557a2a5c71e82db 100644 (file)
@@ -9,17 +9,19 @@ include $(TOPDIR)/rules.mk
 include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=fuse3
-PKG_VERSION:=3.10.5
-PKG_RELEASE:=2
+PKG_VERSION:=3.16.2
+PKG_RELEASE:=1
 
-PKG_SOURCE:=fuse-$(PKG_VERSION).tar.xz
+PKG_SOURCE:=fuse-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://github.com/libfuse/libfuse/releases/download/fuse-$(PKG_VERSION)
-PKG_HASH:=b2e283485d47404ac896dd0bb7f7ba81e1470838e677e45f659804c3a3b69666
+PKG_HASH:=f797055d9296b275e981f5f62d4e32e089614fc253d1ef2985851025b8a0ce87
 PKG_BUILD_DIR:=$(BUILD_DIR)/fuse-$(PKG_VERSION)
 
 PKG_MAINTAINER:=
 PKG_CPE_ID:=cpe:/a:fuse_project:fuse
 
+PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_fuse3-utils
+
 include $(INCLUDE_DIR)/package.mk
 include $(INCLUDE_DIR)/meson.mk
 
diff --git a/utils/fx/Makefile b/utils/fx/Makefile
new file mode 100644 (file)
index 0000000..9642d60
--- /dev/null
@@ -0,0 +1,38 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fx
+PKG_VERSION:=31.0.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://codeload.github.com/antonmedv/fx/tar.gz/$(PKG_VERSION)?
+PKG_HASH:=8408047ef42506aac44aa805de209dd64ae4fc084e76bee8e24112ffbdc2d5dc
+
+PKG_MAINTAINER:=Fabian Lipken <dynasticorpheus@gmail.com>
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=LICENSE
+
+PKG_BUILD_DEPENDS:=golang/host
+PKG_BUILD_PARALLEL:=1
+PKG_BUILD_FLAGS:=no-mips16
+
+GO_PKG:=github.com/antonmedv/fx
+
+include $(INCLUDE_DIR)/package.mk
+include ../../lang/golang/golang-package.mk
+
+define Package/fx
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Terminal JSON viewer & processor
+  URL:=https://github.com/antonmedv/fx/
+  DEPENDS:=$(GO_ARCH_DEPENDS)
+endef
+
+define Package/fx/description
+  Fx is a dual-purpose command-line tool tailored for JSON, providing
+  both a terminal-based JSON viewer and a JSON processing utility.
+endef
+
+$(eval $(call GoBinPackage,fx))
+$(eval $(call BuildPackage,fx))
diff --git a/utils/gl-puli-mcu/Config.in b/utils/gl-puli-mcu/Config.in
new file mode 100644 (file)
index 0000000..315526c
--- /dev/null
@@ -0,0 +1,12 @@
+choice
+    depends on PACKAGE_gl-puli-mcu
+
+    prompt "GL.iNet target"
+    default GL_PULI_MCU_XE300
+
+    config GL_PULI_MCU_XE300
+            bool "GL.iNet XE300 (Puli)"
+
+    config GL_PULI_MCU_XE3000
+            bool "GL.iNet XE3000 (Puli AX)"
+endchoice
index d33e9288f3062dc2360994eac8c2ac136f8b15cd..b1da42c77748ae49943db705e4f3d35db80e9506 100644 (file)
@@ -1,24 +1,40 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=gl-puli-mcu
-PKG_VERSION:=1
+PKG_VERSION:=2
 PKG_RELEASE:=1
 
 PKG_MAINTAINER:=Nuno Goncalves <nunojpg@gmail.com>
 PKG_LICENSE:=GPL-3.0-or-later
 
+PKG_CONFIG_DEPENDS:= \
+  CONFIG_GL_PULI_MCU_XE300 \
+  CONFIG_GL_PULI_MCU_XE3000
+
 include $(INCLUDE_DIR)/package.mk
 include $(INCLUDE_DIR)/cmake.mk
 
+define Package/gl-puli-mcu/config
+  source "$(SOURCE)/Config.in"
+endef
+
 define Package/gl-puli-mcu
   SECTION:=utils
   CATEGORY:=Utilities
-  TITLE:=GL.iNet GL-XE300 (Puli) power monitoring support
-  DEPENDS:=+kmod-usb-serial-ch341 +libubus +libubox
+  TITLE:=GL.iNet power monitoring support
+  DEPENDS:=+CONFIG_GL_PULI_MCU_XE300:kmod-usb-serial-ch341 +libubus +libubox
+  MENU:=1
 endef
 
+ifeq ($(CONFIG_GL_PULI_MCU_XE300),y)
+  TARGET_CFLAGS+=-DGL_TARGET=1
+endif
+ifeq ($(CONFIG_GL_PULI_MCU_XE3000),y)
+  TARGET_CFLAGS+=-DGL_TARGET=2
+endif
+
 define Package/gl-puli-mcu/description
-  Interfaces with GL-XE300 (Puli) power monitoring MCU over
+  Interfaces with GL.iNet Puli family power monitoring MCU over
   a USB to UART adapter present on the device and provides
   battery SOC, temperature, charging state and cycle count at
   ubus battery/info.
index fe55cc42d3003135fb6f75da4ad0949ef6b48c04..da7d7db8391477cca0cedf71ee4d996b3894465b 100644 (file)
 #include <libubox/uloop.h>
 #include <libubus.h>
 
+#define GL_TARGET_XE300  1
+#define GL_TARGET_XE3000 2
+
+#if GL_TARGET == GL_TARGET_XE300
+#define MCU_PORT "/dev/ttyUSB0"
+#elif GL_TARGET ==  GL_TARGET_XE3000
+#define MCU_PORT "/dev/ttyS1"
+#else
+#error Please define GL_TARGET!
+#endif /* GL_TARGET */
+
 static struct ustream_fd stream;
 static struct ubus_auto_conn conn;
 static struct blob_buf b;
@@ -39,6 +50,9 @@ struct Battery
        bool set;
 } battery;
 
+#if GL_TARGET == GL_TARGET_XE300
+// MCU status returns something like:
+// {OK},100,275,1,0
 static bool
 process(char *read)
 {
@@ -66,6 +80,65 @@ process(char *read)
                return false;
        return true;
 }
+#elif GL_TARGET == GL_TARGET_XE3000
+static bool
+get_int_value(const char *read, const char *key, int *int_value, char **new_end)
+{
+       char *from = NULL;
+
+       from = strstr(read, key);
+       if ((!from) || (from != read))
+       {
+               return false;
+       }
+       from = (char *)read + strlen(key);
+       *int_value = strtol(from, new_end, 10);
+       if (from == *new_end)
+       {
+               return false;
+       }
+
+       return true;
+}
+
+// MCU status returns something like:
+// {"code":0,"capacity":100,"temp":28,"chg_state":1,"charge_cycle":0}
+static bool
+process(char *read)
+{
+       int int_value = 0;
+       char *to = NULL;
+
+       if ((read[0] != '{') ||
+               (!get_int_value(&read[1], "\"code\":", &int_value, &to)) ||
+               (int_value != 0))
+       {
+               return false;
+       }
+       if (!get_int_value(to + 1, "\"capacity\":", &int_value, &to))
+       {
+               return false;
+       }
+       battery.soc = int_value;
+       if (!get_int_value(to + 1, "\"temp\":", &int_value, &to))
+       {
+               return false;
+       }
+       battery.temperature = (float) int_value;
+       if (!get_int_value(to + 1, "\"chg_state\":", &int_value, &to))
+       {
+               return false;
+       }
+       battery.charging = (bool) int_value;
+       if (!get_int_value(to + 1, "\"charge_cycle\":", &int_value, &to))
+       {
+               return false;
+       }
+       battery.cycles = (uint16_t) int_value;
+
+       return true;
+}
+#endif /* GL_TARGET */
 
 static int
 consume(struct ustream *s, char **a)
@@ -79,7 +152,7 @@ consume(struct ustream *s, char **a)
 
        battery.set = process(*a);
        if (!battery.set)
-               ULOG_ERR("failed to parse message from serial: %s", a);
+               ULOG_ERR("failed to parse message from serial: %s", *a);
 
        ustream_consume(s, eol - *a);
        *a = eol;
@@ -202,7 +275,7 @@ main(int argc, char **argv)
        conn.cb = ubus_connect_handler;
        ubus_auto_connect(&conn);
 
-       if (serial_open("/dev/ttyUSB0") < 0)
+       if (serial_open(MCU_PORT) < 0)
                return -1;
 
        serial_query_timer.cb = serial_query_handler;
index b1e6d052ecb4b0b4d07c94b90e609836eb0a885a..688764e43ccda647dece2c0862e8f5e24082b4f2 100644 (file)
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=gummiboot
 PKG_VERSION:=48.1
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://dev.alpinelinux.org/archive/gummiboot/
diff --git a/utils/gummiboot/patches/030-fix-efi-conflicts.patch b/utils/gummiboot/patches/030-fix-efi-conflicts.patch
new file mode 100644 (file)
index 0000000..51b28d4
--- /dev/null
@@ -0,0 +1,66 @@
+--- a/src/efi/console.c
++++ b/src/efi/console.c
+@@ -21,63 +21,10 @@
+ #include "util.h"
+ #include "console.h"
+-#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
+-        { 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }
+-
+ struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
+-typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)(
+-        struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
+-        BOOLEAN ExtendedVerification;
+-);
+-
+ typedef UINT8 EFI_KEY_TOGGLE_STATE;
+-typedef struct {
+-        UINT32 KeyShiftState;
+-        EFI_KEY_TOGGLE_STATE KeyToggleState;
+-} EFI_KEY_STATE;
+-
+-typedef struct {
+-        EFI_INPUT_KEY Key;
+-        EFI_KEY_STATE KeyState;
+-} EFI_KEY_DATA;
+-
+-typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)(
+-        struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
+-        EFI_KEY_DATA *KeyData;
+-);
+-
+-typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)(
+-        struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
+-        EFI_KEY_TOGGLE_STATE *KeyToggleState;
+-);
+-
+-typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)(
+-        EFI_KEY_DATA *KeyData;
+-);
+-
+-typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)(
+-        struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
+-        EFI_KEY_DATA KeyData;
+-        EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction;
+-        VOID **NotifyHandle;
+-);
+-
+-typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)(
+-        struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
+-        VOID *NotificationHandle;
+-);
+-
+-typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
+-        EFI_INPUT_RESET_EX Reset;
+-        EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
+-        EFI_EVENT WaitForKeyEx;
+-        EFI_SET_STATE SetState;
+-        EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
+-        EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
+-} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
+-
+ EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
+         EFI_GUID EfiSimpleTextInputExProtocolGuid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+         static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx;
index 6717c352e56d3cb410f21c00348cc24f46cfbf79..23d4b3899ddd77dea38f4410c9784757a8725f0f 100644 (file)
@@ -5,13 +5,13 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=irqbalance
-PKG_VERSION:=1.9.2
-PKG_RELEASE:=3
+PKG_VERSION:=1.9.3
+PKG_RELEASE:=1
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL:=https://github.com/Irqbalance/irqbalance.git
 PKG_SOURCE_VERSION:=v$(PKG_VERSION)
-PKG_MIRROR_HASH:=e2c81725e7b6d711a47d68755a222236d7081726d567aca1c1295e6fe1caa865
+PKG_MIRROR_HASH:=ff2936e9b7486e802206cbf9e16aa6cb7e1501bdf502441d31f409d104e757b8
 
 PKG_MAINTAINER:=Hannu Nyman <hannu.nyman@iki.fi>
 PKG_LICENSE:=GPL-2.0-or-later
diff --git a/utils/irqbalance/patches/001-upstream-fix-aarch64-irq-parsing.patch b/utils/irqbalance/patches/001-upstream-fix-aarch64-irq-parsing.patch
deleted file mode 100644 (file)
index 33213f0..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-From bbcd9a42c3cec0935b960b7f2046f1fdfab4f7ef Mon Sep 17 00:00:00 2001
-From: Vignesh Raghavendra <vigneshr@ti.com>
-Date: Wed, 7 Dec 2022 19:46:19 +0530
-Subject: [PATCH] procinterrupts: Fix IRQ name parsing on certain arm64 SoC
-
-On arm64 SoCs like TI's K3 SoC and few other SoCs, IRQ names don't get
-parsed correct due to which they end up being classified into wrong
-class. Fix this by considering last token to contain IRQ name always.
-
-Eg.: /proc/interrupt
-
-cat /proc/interrupts
-           CPU0       CPU1       CPU2       CPU3
- 11:       7155       8882       7235       7791     GICv3  30 Level     arch_timer
- 14:          0          0          0          0     GICv3  23 Level     arm-pmu
- 15:          0          0          0          0     GICv3 208 Level     4b00000.spi
- 16:          0          0          0          0     GICv3 209 Level     4b10000.spi
-116:          0          0          0          0  MSI-INTA 1716234 Level     485c0100.dma-controller chan6
-134:        166          0          0          0  MSI-INTA 1970707 Level     8000000.ethernet-tx0
-224:        149          0          0          0  MSI-INTA 1971731 Level     8000000.ethernet
-
-W/o patch irqbalance -d
-IRQ (11) guessed as class 0
-IRQ (14) guessed as class 0
-IRQ (15) guessed as class 0
-IRQ (16) guessed as class 0
-IRQ 485c0100.dma-controller chan6(116) guessed as class 0
-IRQ (134) guessed as class 0
-IRQ (224) guessed as class 0
-
-W/ this patch
-IRQ arch_timer(11) guessed as class 0
-IRQ arm-pmu(14) guessed as class 0
-IRQ 4b00000.spi(15) guessed as class 0
-IRQ 4b10000.spi(16) guessed as class 0
-IRQ 485c0100.dma-controller chan6(116) guessed as class 0
-IRQ 8000000.ethernet-tx0(134) guessed as class 5
-IRQ 8000000.ethernet(224) guessed as class 5
-IRQ 8000000.ethernet(257) guessed as class 5
-IRQ -davinci_gpio  wl18xx(362) guessed as class
-
-Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
----
- procinterrupts.c | 12 +++++++-----
- 1 file changed, 7 insertions(+), 5 deletions(-)
-
---- a/procinterrupts.c
-+++ b/procinterrupts.c
-@@ -178,12 +178,14 @@ void init_irq_class_and_type(char *saved
-       }
- #ifdef AARCH64
--      if (savedptr && strlen(savedptr) > 0) {
-+      if (savedptr && strlen(savedptr) > 0)
-               snprintf(irq_fullname, PATH_MAX, "%s %s", last_token, savedptr);
--              tmp = strchr(irq_fullname, '\n');
--              if (tmp)
--                      *tmp = 0;
--      }
-+      else
-+              snprintf(irq_fullname, PATH_MAX, "%s", last_token);
-+
-+      tmp = strchr(irq_fullname, '\n');
-+      if (tmp)
-+              *tmp = 0;
- #else
-       snprintf(irq_fullname, PATH_MAX, "%s", last_token);
- #endif
index 28dbad66fc6c3a13a7d7a313a68ee817e889e485..8ff5a85df4b81c1565f1f0c27f7d7d1bb262476b 100644 (file)
@@ -6,15 +6,15 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=mc
-PKG_VERSION:=4.8.27
-PKG_RELEASE:=3
+PKG_VERSION:=4.8.30
+PKG_RELEASE:=1
 PKG_MAINTAINER:=
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_CPE_ID:=cpe:/a:midnight_commander:midnight_commander
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=http://ftp.midnight-commander.org/
-PKG_HASH:=31be59225ffa9920816e9a8b3be0ab225a16d19e4faf46890f25bdffa02a4ff4
+PKG_HASH:=5ebc3cb2144b970c5149fda556c4ad50b78780494696cdf2d14a53204c95c7df
 PKG_BUILD_PARALLEL:=1
 PKG_FIXUP:=autoreconf gettext-version
 PKG_BUILD_DEPENDS:=MC_VFS:libtirpc
@@ -57,7 +57,6 @@ CONFIGURE_ARGS += \
        --enable-silent-rules \
        --disable-tests \
        --disable-doxygen-doc \
-       --with-homedir=/etc/mc \
        --with-screen=ncurses \
        --without-x \
 
@@ -99,7 +98,7 @@ define Package/mc/install
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/mc $(1)/usr/bin
        $(INSTALL_DIR) $(1)/etc/mc
        $(INSTALL_DATA) $(PKG_BUILD_DIR)/misc/mc.charsets $(1)/etc/mc
-       $(INSTALL_DATA) $(PKG_BUILD_DIR)/misc/mc.ext $(1)/etc/mc
+       $(INSTALL_DATA) $(PKG_BUILD_DIR)/misc/mc.ext.ini $(1)/etc/mc
        $(INSTALL_DATA) $(PKG_BUILD_DIR)/misc/mc.default.keymap $(1)/etc/mc/mc.keymap
        $(INSTALL_DATA) $(PKG_BUILD_DIR)/misc/filehighlight.ini $(1)/etc/mc
        $(INSTALL_DIR) $(1)/usr/share/mc/help
index bc7ddee5fa6ef4ed412e6411ba666343c4c0a8dd..64f3fdba91eb325e3668552b58ca1e971c62da9d 100644 (file)
@@ -1,6 +1,6 @@
 --- a/src/subshell/common.c
 +++ b/src/subshell/common.c
-@@ -1140,7 +1140,7 @@ init_subshell_precmd (char *precmd, size
+@@ -1143,7 +1143,7 @@ init_subshell_precmd (char *precmd, size
                      "else "
                      "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; "
                      "fi; "
index bf6853a710245088d9e0f861d207c0bb488dff38..1d122f678418f434f6e7bc2f8392559b6f871856 100644 (file)
@@ -1,6 +1,6 @@
 --- a/lib/tty/tty.c
 +++ b/lib/tty/tty.c
-@@ -402,7 +402,7 @@ tty_init_xterm_support (gboolean is_xter
+@@ -407,7 +407,7 @@ tty_init_xterm_support (gboolean is_xter
      if (xmouse_seq != NULL)
      {
          if (strcmp (xmouse_seq, ESC_STR "[<") == 0)
index 0191be0e6825898478dac9c8db418d35f2e05a61..37274c14c10b3313454b32e4709aafbb8e9b73e6 100644 (file)
@@ -1,6 +1,6 @@
 --- a/lib/shell.c
 +++ b/lib/shell.c
-@@ -68,6 +68,8 @@ mc_shell_get_installed_in_system (void)
+@@ -70,6 +70,8 @@ mc_shell_get_installed_in_system (void)
          mc_shell->path = g_strdup ("/bin/bash");
      else if (access ("/bin/ash", X_OK) == 0)
          mc_shell->path = g_strdup ("/bin/ash");
@@ -9,7 +9,7 @@
      else if (access ("/bin/dash", X_OK) == 0)
          mc_shell->path = g_strdup ("/bin/dash");
      else if (access ("/bin/busybox", X_OK) == 0)
-@@ -149,6 +151,12 @@ mc_shell_recognize_real_path (mc_shell_t
+@@ -151,6 +153,12 @@ mc_shell_recognize_real_path (mc_shell_t
          mc_shell->type = SHELL_ZSH;
          mc_shell->name = "zsh";
      }
@@ -34,7 +34,7 @@
      SHELL_FISH
 --- a/src/subshell/common.c
 +++ b/src/subshell/common.c
-@@ -378,6 +378,11 @@ init_subshell_child (const char *pty_nam
+@@ -380,6 +380,11 @@ init_subshell_child (const char *pty_nam
          }
          break;
  
@@ -46,7 +46,7 @@
          /* TODO: Find a way to pass initfile to TCSH and FISH */
      case SHELL_TCSH:
      case SHELL_FISH:
-@@ -427,6 +432,7 @@ init_subshell_child (const char *pty_nam
+@@ -429,6 +434,7 @@ init_subshell_child (const char *pty_nam
  
      case SHELL_ASH_BUSYBOX:
      case SHELL_DASH:
@@ -54,7 +54,7 @@
      case SHELL_TCSH:
      case SHELL_FISH:
          execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL);
-@@ -1091,6 +1097,10 @@ init_subshell_precmd (char *precmd, size
+@@ -1094,6 +1100,10 @@ init_subshell_precmd (char *precmd, size
                      "PS1='\\u@\\h:\\w\\$ '\n", command_buffer_pipe[WRITE],
                      command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
          break;
index e68b289501af04534dfbc5e4d3fdb74d4df9c2b4..4400b780f2d66434cb008f38a6178128f7f0c6e4 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=nano
 PKG_VERSION:=7.2
-PKG_RELEASE:=2
+PKG_RELEASE:=3
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=@GNU/nano
@@ -140,6 +140,7 @@ define Package/nano-full/install
        $(INSTALL_DIR) $(1)/etc $(1)/usr/share/nano
        $(INSTALL_DATA) ./files/nanorc $(1)/etc/nanorc
        $(INSTALL_DATA) ./files/uci.nanorc $(1)/usr/share/nano
+       $(INSTALL_DATA) ./files/ucode.nanorc $(1)/usr/share/nano
        $(CP) $(PKG_INSTALL_DIR)/usr/share/nano/* $(1)/usr/share/nano
 endef
 
diff --git a/utils/nano/files/ucode.nanorc b/utils/nano/files/ucode.nanorc
new file mode 100644 (file)
index 0000000..96c7848
--- /dev/null
@@ -0,0 +1,51 @@
+## Syntax highlighting for OpenWrt ucode scripts.
+
+syntax ucode "/ucode/|\.u[ct]$"
+header "^#!.*\<ucode\>"
+comment "//"
+
+# Declarations
+color green "\<(let|const|function|this)\>"
+
+# Arrow functions
+color green "(\<\w+\>|\([[:alnum:][:space:]_,.]*\))[[:space:]]*=>"
+
+# Flow control and keywords
+color brightyellow "\<(while|if|else|elif|switch|case|default|for|in|endif|endfor|endwhile|endfunction)\>"
+color brightyellow "\<(export|import|try|catch|delete)\>"
+
+# Exit points
+color magenta "\<(break|continue|return)\>"
+
+# Numeric literals
+color cyan "\<([0-9]+\.[0-9]+([eE][+-]?[0-9]+)?|[0-9]+[eE][+-]?[0-9]+)\>"
+color cyan "\<0[xX][[:xdigit:]]+(\.[[:xdigit:]]+)?\>"
+color cyan "\<(0[oO][0-7]+|0[bB][01]+|[0-9]+)\>"
+
+# Special values
+color cyan "\<(true|false|null|NaN|Infinity)\>"
+
+# Strings
+color brightmagenta ""([^"\{%#}]|\\.|\{[^"\{%#]|[%#}][^"\}]|[{%#}]\\.)*[{%#}]?""
+color brightmagenta "'([^'\{%#}]|\\.|\{[^'\{%#]|[%#}][^'\}]|[{%#}]\\.)*[{%#}]?'"
+color brightmagenta "`([^`\{%#}]|\\.|\{[^`\{%#]|[%#}][^`\}]|[{%#}]\\.)*[{%#}]?`"
+
+# Template string expressions
+color normal start="\$\{" end="}"
+
+# Comments
+color brightblue "(^|[[:blank:]])//.*"
+color brightblue start="(^|[[:space:]])/\*" end="\*/"
+color brightblue start="\{#" end="#\}"
+
+# Trailing whitespace.
+color ,green "[[:space:]]+$"
+
+# Text outside template directives
+color slate start="[}%#]\}" end="\{[{%#]"
+color slate start="^#!" end="\{[{%#]"
+color slate "^([^{%#}]|\{[^{%#]|[%#}][^}])+\{[{%#]"
+
+# Template tags
+color white "\{[{%][+-]?|-?[%}]\}"
+color brightblue "\{#[+-]?|-?#\}"
index 5ac3dc5fefbe92a9cc0cada988c2a11abec96166..cbcb82be817adaa1a35d68e3558a1e96eab82e19 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pps-tools
 PKG_VERSION:=1.0.2
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_SOURCE_URL:=https://codeload.github.com/redlab-i/pps-tools/tar.gz/v$(PKG_VERSION)?
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
diff --git a/utils/pps-tools/patches/001-time_t_64bit.patch b/utils/pps-tools/patches/001-time_t_64bit.patch
new file mode 100644 (file)
index 0000000..aacd8be
--- /dev/null
@@ -0,0 +1,31 @@
+--- a/ppstest.c
++++ b/ppstest.c
+@@ -110,13 +110,13 @@ retry:
+       }
+       printf("source %d - "
+-             "assert %ld.%09ld, sequence: %ld - "
+-             "clear  %ld.%09ld, sequence: %ld\n",
++             "assert %lld.%09ld, sequence: %ld - "
++             "clear  %lld.%09ld, sequence: %ld\n",
+              i,
+-             infobuf.assert_timestamp.tv_sec,
++             (long long)infobuf.assert_timestamp.tv_sec,
+              infobuf.assert_timestamp.tv_nsec,
+              infobuf.assert_sequence,
+-             infobuf.clear_timestamp.tv_sec,
++             (long long)infobuf.clear_timestamp.tv_sec,
+              infobuf.clear_timestamp.tv_nsec, infobuf.clear_sequence);
+       fflush(stdout);
+--- a/ppswatch.c
++++ b/ppswatch.c
+@@ -145,7 +145,7 @@ int fetch_source(pps_handle_t handle, in
+       if (max_divergence < div)
+               max_divergence = div;
+       if (div >= margin) {
+-              printf("timestamp: %ld, sequence: %ld, offset: % 6ld\n", ts.tv_sec, seq, ts.tv_nsec);
++              printf("timestamp: %lld, sequence: %ld, offset: % 6ld\n", (long long)ts.tv_sec, seq, ts.tv_nsec);
+               fflush(stdout);
+               overflows++;
+               curr_unsync++;
index 52daf82b1fec096ad22ec9c73dce38ae768c0374..305c56d7888e9d5f8af6a7d87bdea28cc73dacb6 100644 (file)
@@ -4,8 +4,8 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=sockread
-PKG_VERSION:=1.0
-PKG_RELEASE:=2
+PKG_VERSION:=1.1
+PKG_RELEASE:=1
 PKG_LICENSE:=CC0-1.0
 
 include $(INCLUDE_DIR)/package.mk
@@ -13,13 +13,12 @@ include $(INCLUDE_DIR)/package.mk
 define Package/sockread
        SECTION:=utils
        CATEGORY:=Utilities
-       TITLE:=sockread
+       TITLE:=Unix domain sockets utility
        MAINTAINER:=Moritz Warning <moritzwarning@web.de>
 endef
 
 define Package/sockread/description
-       sockread writes and reads data from a Unix domain socket
-       represented as a special file on the file system.
+       Command line utility to read and write to Unix domain sockets.
 endef
 
 define Build/Prepare
index c685bce71b89ce4eb9f9156bca6596f74bb85812..b6d0713a96c9567a54fb5090c03a48f25fe768c0 100644 (file)
@@ -7,57 +7,65 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-int main(int argc, char *argv[]) {
-       char buf[1024];
-       ssize_t r;
-
-       if (argc != 2) {
-               fprintf(stderr, "Write to and read from a Unix domain socket.\n\nUsage: %s <socket>\n", argv[0]);
-               return 1;
-       }
-
-       size_t addrlen = strlen(argv[1]);
-
-       /* Allocate enough space for arbitrary-length paths */
-       char addrbuf[offsetof(struct sockaddr_un, sun_path) + addrlen + 1];
-       memset(addrbuf, 0, sizeof(addrbuf));
-
-       struct sockaddr_un *addr = (struct sockaddr_un *)addrbuf;
-       addr->sun_family = AF_UNIX;
-       memcpy(addr->sun_path, argv[1], addrlen+1);
-
-       int fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd < 0) {
-               fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
-               return 1;
-       }
-
-       if (connect(fd, (struct sockaddr*)addr, sizeof(addrbuf)) < 0) {
-               fprintf(stderr, "Can't connect to `%s': %s\n", argv[1], strerror(errno));
-               return 1;
-       }
-
-       /* Check if stdin refers to a terminal */
-       if (!isatty(fileno(stdin))) {
-               /* Read from stdin and write to socket */
-               while (0 < (r = fread(buf, 1, sizeof(buf), stdin))) {
-                       send(fd, buf, r, 0);
-               }
-       }
-
-       /* Read from socket and write to stdout */
-       while (1) {
-               r = recv(fd, buf, sizeof(buf), 0);
-               if (r < 0) {
-                       fprintf(stderr, "read: %s\n", strerror(errno));
-                       return 1;
-               }
-
-               if (r == 0)
-                       return 0;
-
-               fwrite(buf, r, 1, stdout);
-       }
-
-       return 0;
+const char *usage =
+    "Write to and read from a Unix domain socket.\n"
+    "Add commands to send as arguments or pass by pipe.\n"
+    "\n"
+    "Usage: sockread <path> [<commands>]\n";
+
+int main(int argc, char *argv[])
+{
+    char buffer[1024];
+    ssize_t r;
+
+    if (argc < 2) {
+        fprintf(stderr, "%s", usage);
+        return EXIT_FAILURE;
+    }
+
+    struct sockaddr_un address = {0};
+    address.sun_family = AF_UNIX;
+    strcpy((char*) &address.sun_path, argv[1]);
+
+    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        fprintf(stderr, "socket() %s\n", strerror(errno));
+        return EXIT_FAILURE;
+    }
+
+    if (connect(sock, (struct sockaddr*)&address, sizeof(address)) < 0) {
+        fprintf(stderr, "connect() %s\n", strerror(errno));
+        return EXIT_FAILURE;
+    }
+
+    /* Check if stdin refers to a terminal */
+    if (!isatty(fileno(stdin))) {
+        /* Read from stdin and write to socket */
+        while (0 < (r = fread(buffer, 1, sizeof(buffer), stdin))) {
+            send(sock, buffer, r, 0);
+        }
+    } else {
+        for (size_t i = 2; i < argc; i++) {
+            if (i > 2) {
+                send(sock, " ", 1, 0);
+            }
+            send(sock, argv[i], strlen(argv[i]), 0);
+        }
+    }
+
+    /* Read from socket and write to stdout */
+    while (1) {
+        r = recv(sock, buffer, sizeof(buffer), 0);
+        if (r < 0) {
+            fprintf(stderr, "recv() %s\n", strerror(errno));
+            return EXIT_FAILURE;
+        }
+
+        if (r == 0)
+            break;
+
+        fwrite(buffer, r, 1, stdout);
+    }
+
+    return EXIT_SUCCESS;
 }
index 4660fa78696a7ac80b106f286c9f2a4ace742b4c..89af1cbe65d041b70417e08cbefd32ae741ff58f 100644 (file)
@@ -9,13 +9,13 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=tang
 PKG_VERSION:=14
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://github.com/latchset/$(PKG_NAME)/releases/download/v$(PKG_VERSION)/
 PKG_HASH:=04263ed1cc98d60cab29fe47f908921b7b1aa4d6da5f9de2fcbe543773b75886
 
-PKG_MAINTAINER:=Tibor Dudlák <tibor.dudlak@gmail.com>
+PKG_MAINTAINER:=Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
 PKG_LICENSE:=GPL-3.0-or-later
 PKG_LICENSE_FILES:=COPYING
 
index ea4045f2e1929df2684926cea6a9d0781d5a2ecf..efcd3f2ccf783492126032b3004eff202d5c1485 100644 (file)
@@ -8,6 +8,7 @@ start_service() {
        if [ -z "${KEYS}" ] || [ "${KEYS}" = "0" ]; then # if db is empty generate new key pair
                mkdir -p /usr/share/tang/db
                /usr/sbin/tangd-keygen /usr/share/tang/db
+               chown -R tang /usr/share/tang/db
        fi
 
        config_load "tang"
index 6400b4807a1de13834272ca1b3357fcc3db787cc..ac72cca04c5ace7b4245a102e63b9a067c35a8ed 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=yq
-PKG_VERSION:=4.35.2
+PKG_VERSION:=4.40.3
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/mikefarah/yq/tar.gz/v$(PKG_VERSION)?
-PKG_HASH:=8b17d710c56f764e9beff06d7a7b1c77d87c4ba4219ce4ce67e7ee29670f4f13
+PKG_HASH:=238b695d372753a32bc0b8500a7ca99f98cf98d7855c3e84d6984a2b035b6268
 
 PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
 PKG_LICENSE:=MIT