Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mtxclient for openSUSE:Factory 
checked in at 2025-08-11 13:54:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mtxclient (Old)
 and      /work/SRC/openSUSE:Factory/.mtxclient.new.1085 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mtxclient"

Mon Aug 11 13:54:08 2025 rev:3 rq:1298783 version:0.10.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/mtxclient/mtxclient.changes      2025-03-27 
22:34:11.245290535 +0100
+++ /work/SRC/openSUSE:Factory/.mtxclient.new.1085/mtxclient.changes    
2025-08-11 13:54:32.286170130 +0200
@@ -1,0 +2,13 @@
+Mon Aug  4 05:41:12 UTC 2025 - Dead Mozay <dead_mo...@opensuse.org>
+
+- Update to version 0.10.1:
+  * Fix v12 room ids without server name
+  * Experimental support for invite permissions
+  * Support new style join vias (instead of server_name)
+  * Redirects for media downloads (Karthik)
+  * Location messages (MTRNord)
+  * Build against fmt11 (Kefu Chai)
+  * Fix incompatibility with null aliases
+- Remove patch fix-build-with-fmt11.patch as it is fixed upstream
+
+-------------------------------------------------------------------

Old:
----
  fix-build-with-fmt11.patch
  mtxclient-0.10.0.tar.gz

New:
----
  mtxclient-0.10.1.tar.gz

----------(Old B)----------
  Old:  * Fix incompatibility with null aliases
- Remove patch fix-build-with-fmt11.patch as it is fixed upstream
----------(Old E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mtxclient.spec ++++++
--- /var/tmp/diff_new_pack.muheAE/_old  2025-08-11 13:54:33.458218483 +0200
+++ /var/tmp/diff_new_pack.muheAE/_new  2025-08-11 13:54:33.462218648 +0200
@@ -19,14 +19,13 @@
 %define libname libmatrix_client%(echo %{version} | tr . _)
 %define sover 0
 Name:           mtxclient
-Version:        0.10.0
+Version:        0.10.1
 Release:        0
 Summary:        Client API library for Matrix, built on top of Boost.Asio
 License:        MIT
 Group:          Development/Libraries/C and C++
 URL:            https://github.com/Nheko-Reborn/mtxclient
 Source0:        
%{url}/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
-Patch0:         fix-build-with-fmt11.patch
 BuildRequires:  cmake >= 3.13
 BuildRequires:  fdupes
 %if 0%{?suse_version} < 1600

++++++ mtxclient-0.10.0.tar.gz -> mtxclient-0.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/.ci/adjust-config.sh 
new/mtxclient-0.10.1/.ci/adjust-config.sh
--- old/mtxclient-0.10.0/.ci/adjust-config.sh   2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/.ci/adjust-config.sh   2025-08-02 21:59:13.000000000 
+0200
@@ -6,18 +6,46 @@
     CMD="sudo"
 fi
 
-$CMD perl -pi -w -e \
-    's/rc_messages_per_second.*/rc_messages_per_second: 1000/g;' 
data/homeserver.yaml
-$CMD perl -pi -w -e \
-    's/rc_message_burst_count.*/rc_message_burst_count: 10000/g;' 
data/homeserver.yaml
-
 (
 cat <<HEREDOC
 
+server_name: "localhost"
+pid_file: /data/homeserver.pid
+listeners:
+  - port: 8008
+    tls: true
+    type: http
+    x_forwarded: true
+    resources:
+      - names: [client, federation]
+        compress: false
+  - port: 8009
+    tls: false
+    type: http
+    x_forwarded: true
+    resources:
+      - names: [client, federation]
+        compress: false
+database:
+  name: sqlite3
+  args:
+    database: /data/homeserver.db
+log_config: "/data/localhost.log.config"
+media_store_path: /data/media_store
+registration_shared_secret: 
"&=bz^dG2c34^NHZYMidt7crX~ZheXN0r1dV02uKapb9uxmktR:"
+report_stats: false
+macaroon_secret_key: "Ea#Ny0z,r=kv&2.H47au0QSsL&QDjpZqxYX0NcUe9EKsX~Eyrz"
+form_secret: ";,kjZhkoUnRLbUq@H21PJcX#T+p&MuNi4O9qbH*gZk2+84ree+"
+signing_key_path: "/data/localhost.signing.key"
+trusted_key_servers: []
+
 
 enable_registration: true
 enable_registration_without_verification: true
 
+room_list_publication_rules:
+  - action: allow
+
 tls_certificate_path: "/data/localhost.tls.crt"
 tls_private_key_path: "/data/localhost.tls.key"
 
@@ -52,14 +80,17 @@
     per_second: 10000
     burst_count: 100000
 
+rc_presence:
+  per_user:
+    per_second: 10000
+    burst_count: 100000
+
 experimental_features:
   msc3266_enabled: true
 
-HEREDOC
-) | $CMD tee -a data/homeserver.yaml
 
-$CMD perl -pi -w -e \
-    's/tls: false/tls: true/g;' data/homeserver.yaml
+HEREDOC
+) | $CMD tee data/homeserver.yaml
 
 $CMD openssl req -x509 -newkey rsa:4096 -keyout data/localhost.tls.key -out 
data/localhost.tls.crt -days 365 -subj '/CN=localhost' -nodes
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/.ci/synapse/Dockerfile 
new/mtxclient-0.10.1/.ci/synapse/Dockerfile
--- old/mtxclient-0.10.0/.ci/synapse/Dockerfile 2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/.ci/synapse/Dockerfile 2025-08-02 21:59:13.000000000 
+0200
@@ -1,4 +1,4 @@
-FROM matrixdotorg/synapse:v1.63.1
+FROM matrixdotorg/synapse:v1.135.0
 
 COPY setup-synapse.sh /setup-synapse.sh
 COPY entrypoint.sh /entrypoint.sh
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/.ci/synapse/service/postgresql/run 
new/mtxclient-0.10.1/.ci/synapse/service/postgresql/run
--- old/mtxclient-0.10.0/.ci/synapse/service/postgresql/run     2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/.ci/synapse/service/postgresql/run     2025-08-02 
21:59:13.000000000 +0200
@@ -1,3 +1,3 @@
 #!/bin/sh
 
-exec chpst -u postgres:postgres /usr/lib/postgresql/13/bin/postgres -D 
'/data2/db' 2>&1
+exec chpst -u postgres:postgres /usr/lib/postgresql/15/bin/postgres -D 
'/data2/db' 2>&1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/.ci/synapse/setup-synapse.sh 
new/mtxclient-0.10.1/.ci/synapse/setup-synapse.sh
--- old/mtxclient-0.10.0/.ci/synapse/setup-synapse.sh   2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/.ci/synapse/setup-synapse.sh   2025-08-02 
21:59:13.000000000 +0200
@@ -13,13 +13,12 @@
 chown postgres /data2/db
 
 # Initialise & start the database
-su -c '/usr/lib/postgresql/13/bin/initdb -D /data2/db -E "UTF-8" 
--lc-collate="C" --lc-ctype="C" --username=postgres' postgres
-su -c '/usr/lib/postgresql/13/bin/pg_ctl -w -D /data2/db start' postgres
-su -c '/usr/lib/postgresql/13/bin/createuser synapse_user' postgres
-su -c '/usr/lib/postgresql/13/bin/createdb -O synapse_user synapse' postgres
+su -c '/usr/lib/postgresql/15/bin/initdb -D /data2/db -E "UTF-8" 
--lc-collate="C" --lc-ctype="C" --username=postgres' postgres
+su -c '/usr/lib/postgresql/15/bin/pg_ctl -w -D /data2/db start' postgres
+su -c '/usr/lib/postgresql/15/bin/createuser synapse_user' postgres
+su -c '/usr/lib/postgresql/15/bin/createdb -O synapse_user synapse' postgres
 
 sed -i 's,/data,/data2,g' /start.py
-sed -i 's,/data,/data2,g' /conf/homeserver.yaml
 
 SYNAPSE_SERVER_NAME=synapse SYNAPSE_REPORT_STATS=no /start.py generate
 
@@ -27,18 +26,25 @@
 chmod 0777 data2/synapse.tls.crt
 chmod 0777 data2/synapse.tls.key
 
-sed -i 's/tls: false/tls: true/g;' data2/homeserver.yaml
-
 # yes, the empty line is needed
 cat <<EOF >> /data2/homeserver.yaml
-
-
-enable_registration: true
-enable_registration_without_verification: true
-
-tls_certificate_path: "/data2/synapse.tls.crt"
-tls_private_key_path: "/data2/synapse.tls.key"
-
+server_name: "synapse"
+pid_file: /data2/homeserver.pid
+listeners:
+  - port: 8008
+    tls: true
+    type: http
+    x_forwarded: true
+    resources:
+      - names: [client, federation]
+        compress: false
+  - port: 8009
+    tls: false
+    type: http
+    x_forwarded: true
+    resources:
+      - names: [client, federation]
+        compress: false
 database:
   name: psycopg2
   args:
@@ -47,6 +53,24 @@
     host: localhost
     cp_min: 5
     cp_max: 10
+log_config: "/data2/synapse.log.config"
+media_store_path: /data2/media_store
+registration_shared_secret: 
"&=bz^dG2c34^NHZYMidt7crX~ZheXN0r1dV02uKapb9uxmktR:"
+report_stats: false
+macaroon_secret_key: "Ea#Ny0z,r=kv&2.H47au0QSsL&QDjpZqxYX0NcUe9EKsX~Eyrz"
+form_secret: ";,kjZhkoUnRLbUq@H21PJcX#T+p&MuNi4O9qbH*gZk2+84ree+"
+signing_key_path: "/data2/synapse.signing.key"
+trusted_key_servers: []
+
+
+enable_registration: true
+enable_registration_without_verification: true
+
+room_list_publication_rules:
+  - action: allow
+
+tls_certificate_path: "/data2/synapse.tls.crt"
+tls_private_key_path: "/data2/synapse.tls.key"
 
 rc_message:
   per_second: 10000
@@ -79,6 +103,11 @@
     per_second: 10000
     burst_count: 100000
 
+rc_presence:
+  per_user:
+    per_second: 10000
+    burst_count: 100000
+
 experimental_features:
   msc3266_enabled: true
 EOF
@@ -89,11 +118,15 @@
 echo Waiting for synapse to start...
 until curl -s -f -k https://localhost:8008/_matrix/client/versions; do echo 
"Checking ..."; sleep 2; done
 echo Register alice
-register_new_matrix_user --admin -u alice -p secret -c /data2/homeserver.yaml 
https://localhost:8008
+register_new_matrix_user --admin -u alice -p secret -c /data2/homeserver.yaml 
http://localhost:8009
 echo Register bob
-register_new_matrix_user --admin -u bob -p secret -c /data2/homeserver.yaml 
https://localhost:8008
+register_new_matrix_user --admin -u bob -p secret -c /data2/homeserver.yaml 
http://localhost:8009
 echo Register carl
-register_new_matrix_user --admin -u carl -p secret -c /data2/homeserver.yaml 
https://localhost:8008
+register_new_matrix_user --admin -u carl -p secret -c /data2/homeserver.yaml 
http://localhost:8009
+echo Register presence
+register_new_matrix_user --admin -u presence -p secret -c 
/data2/homeserver.yaml http://localhost:8009
+echo Register presencesync
+register_new_matrix_user --admin -u presencesync -p secret -c 
/data2/homeserver.yaml http://localhost:8009
 
 exit 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/.gitlab-ci.yml 
new/mtxclient-0.10.1/.gitlab-ci.yml
--- old/mtxclient-0.10.0/.gitlab-ci.yml 2024-06-11 00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/.gitlab-ci.yml 2025-08-02 21:59:13.000000000 +0200
@@ -27,17 +27,23 @@
   script:
     - mkdir -p /kaniko/.docker
     - echo 
"{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}"
 > /kaniko/.docker/config.json
-    - /kaniko/executor --whitelist-var-run=false --context 
$CI_PROJECT_DIR/.ci/synapse --dockerfile $CI_PROJECT_DIR/.ci/synapse/Dockerfile 
--destination $CI_REGISTRY_IMAGE/synapse-${M_ARCH}:latest
+    - /kaniko/executor --whitelist-var-run=false --context 
$CI_PROJECT_DIR/.ci/synapse --dockerfile $CI_PROJECT_DIR/.ci/synapse/Dockerfile 
--destination $CI_REGISTRY_IMAGE/synapse-${M_ARCH}:latest --force
 
 build synapse amd64:
   extends: .build-synapse-image
   tags: [docker]
+  image:
+    docker:
+      platform: amd64
   variables:
     M_ARCH: x86_64
 
 build synapse arm64:
   extends: .build-synapse-image
-  tags: [docker-arm64]
+  tags: [docker]
+  image:
+    docker:
+      platform: arm64
   variables:
     M_ARCH: aarch64
 
@@ -50,6 +56,7 @@
       alias: synapse
   variables:
     TRAVIS_OS_NAME: linux
+    RUNNER_AFTER_SCRIPT_TIMEOUT: 10m
   before_script:
     - apt-get update
     - apt-get install -y software-properties-common
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/CHANGELOG.md 
new/mtxclient-0.10.1/CHANGELOG.md
--- old/mtxclient-0.10.0/CHANGELOG.md   2024-06-11 00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/CHANGELOG.md   2025-08-02 21:59:13.000000000 +0200
@@ -1,10 +1,20 @@
 # Changelog
 
+## [0.10.1] -- 2025-08-02
+
+- Fix room ids without server name
+- Experimental support for invite permissions
+- Support new style join vias (instead of server_name)
+- Redirects for media downloads (Karthik)
+- Location messages (MTRNord)
+- Build against fmt11 (Kefu Chai)
+- Fix incompatibility with null avatars
+
 ## [0.10.0] -- 2024-06-11
 
 - Authentication for media (MSC3916, experimental)
 - Intentional mentions and associated push rules (event_property_is and 
event_property_contains)
-- Woraround for Element setting "order" in tags as strings
+- Workaround for Element setting "order" in tags as strings
 - Basic support for url previews (NepNep)
 - Support the "fixed" mac method of interactive verification
 - Various speedups for compilation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/CMakeLists.txt 
new/mtxclient-0.10.1/CMakeLists.txt
--- old/mtxclient-0.10.0/CMakeLists.txt 2024-06-11 00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/CMakeLists.txt 2025-08-02 21:59:13.000000000 +0200
@@ -38,12 +38,12 @@
 
 if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12)
 project(matrix_client
-       VERSION 0.10.0
+       VERSION 0.10.1
        DESCRIPTION "Client API library for Matrix."
        HOMEPAGE_URL https://github.com/Nheko-Reborn/mtxclient)
 else()
 project(matrix_client
-       VERSION 0.10.0
+       VERSION 0.10.1
        DESCRIPTION "Client API library for Matrix.")
 endif()
 
@@ -245,11 +245,13 @@
        lib/structs/events/ephemeral/typing.cpp
        lib/structs/events/nheko_extensions/event_expiry.cpp
        lib/structs/events/nheko_extensions/hidden_events.cpp
+       lib/structs/events/nheko_extensions/invite_permissions.cpp
        lib/structs/events/messages/audio.cpp
        lib/structs/events/messages/elementeffect.cpp
        lib/structs/events/messages/emote.cpp
        lib/structs/events/messages/file.cpp
        lib/structs/events/messages/image.cpp
+       lib/structs/events/messages/location.cpp
        lib/structs/events/messages/notice.cpp
        lib/structs/events/messages/text.cpp
        lib/structs/events/messages/unknown.cpp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/Makefile 
new/mtxclient-0.10.1/Makefile
--- old/mtxclient-0.10.0/Makefile       2024-06-11 00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/Makefile       2025-08-02 21:59:13.000000000 +0200
@@ -1,6 +1,6 @@
 FILES=`find lib include tests examples -type f -type f \( -iname "*.cpp" -o 
-iname "*.hpp" \)`
 
-SYNAPSE_IMAGE="matrixdotorg/synapse:v1.63.1"
+SYNAPSE_IMAGE="matrixdotorg/synapse:v1.135.0"
 
 DEPS_BUILD_DIR=.deps
 DEPS_SOURCE_DIR=deps
@@ -53,15 +53,20 @@
                -p 443:8008 \
                -p 8448:8008 \
                -p 8008:8008 \
+               -p 8009:8009 \
                -v `pwd`/data:/data ${SYNAPSE_IMAGE}
        @echo Waiting for synapse to start...
        @until curl -s -f -k https://localhost:443/_matrix/client/versions; do 
echo "Checking ..."; sleep 2; done
        @echo Register alice
-       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
alice -p secret -c /data/homeserver.yaml https://localhost:8008'
+       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
alice -p secret -c /data/homeserver.yaml http://localhost:8009'
        @echo Register bob
-       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
bob -p secret -c /data/homeserver.yaml https://localhost:8008'
+       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
bob -p secret -c /data/homeserver.yaml http://localhost:8009'
        @echo Register carl
-       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
carl -p secret -c /data/homeserver.yaml https://localhost:8008'
+       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
carl -p secret -c /data/homeserver.yaml http://localhost:8009'
+       @echo Register presence
+       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
presence -p secret -c /data/homeserver.yaml http://localhost:8009'
+       @echo Register presencesync
+       @docker exec synapse /bin/sh -c 'register_new_matrix_user --admin -u 
presencesync -p secret -c /data/homeserver.yaml http://localhost:8009'
 
 stop-synapse: ## Stop any running instance of synapse
        @rm -rf ./data/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtx/events/collections.hpp 
new/mtxclient-0.10.1/include/mtx/events/collections.hpp
--- old/mtxclient-0.10.0/include/mtx/events/collections.hpp     2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/include/mtx/events/collections.hpp     2025-08-02 
21:59:13.000000000 +0200
@@ -25,6 +25,7 @@
 #include "mtx/events/name.hpp"
 #include "mtx/events/nheko_extensions/event_expiry.hpp"
 #include "mtx/events/nheko_extensions/hidden_events.hpp"
+#include "mtx/events/nheko_extensions/invite_permissions.hpp"
 #include "mtx/events/pinned_events.hpp"
 #include "mtx/events/policy_rules.hpp"
 #include "mtx/events/power_levels.hpp"
@@ -45,6 +46,7 @@
 #include "mtx/events/messages/emote.hpp"
 #include "mtx/events/messages/file.hpp"
 #include "mtx/events/messages/image.hpp"
+#include "mtx/events/messages/location.hpp"
 #include "mtx/events/messages/notice.hpp"
 #include "mtx/events/messages/text.hpp"
 #include "mtx/events/messages/unknown.hpp"
@@ -89,6 +91,7 @@
       mtx::events::AccountDataEvent<mtx::pushrules::GlobalRuleset>,
       
mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>,
       
mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::EventExpiry>,
+      
mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::InvitePermissions>,
       mtx::events::AccountDataEvent<mtx::events::msc2545::ImagePack>,
       mtx::events::AccountDataEvent<mtx::events::msc2545::ImagePackRooms>,
       mtx::events::AccountDataEvent<mtx::events::Unknown>>
@@ -191,7 +194,7 @@
                         mtx::events::RoomEvent<mtx::events::msg::Emote>,
                         mtx::events::RoomEvent<mtx::events::msg::File>,
                         mtx::events::RoomEvent<mtx::events::msg::Image>,
-                        // TODO: events::RoomEvent<mtx::events::msg::Location>,
+                        mtx::events::RoomEvent<mtx::events::msg::Location>,
                         mtx::events::RoomEvent<mtx::events::msg::Notice>,
                         mtx::events::RoomEvent<mtx::events::msg::Text>,
                         mtx::events::RoomEvent<mtx::events::msg::Unknown>,
@@ -256,6 +259,9 @@
 constexpr inline EventType message_content_to_type<mtx::events::msg::Image> =
   EventType::RoomMessage;
 template<>
+constexpr inline EventType message_content_to_type<mtx::events::msg::Location> 
=
+  EventType::RoomMessage;
+template<>
 constexpr inline EventType message_content_to_type<mtx::events::msg::Notice> =
   EventType::RoomMessage;
 template<>
@@ -445,6 +451,10 @@
 constexpr inline EventType
   
account_data_content_to_type<mtx::events::account_data::nheko_extensions::EventExpiry>
 =
     EventType::NhekoEventExpiry;
+template<>
+constexpr inline EventType
+  
account_data_content_to_type<mtx::events::account_data::nheko_extensions::InvitePermissions>
 =
+    EventType::NhekoInvitePermissions;
 
 } // namespace events
 } // namespace mtx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtx/events/common.hpp 
new/mtxclient-0.10.1/include/mtx/events/common.hpp
--- old/mtxclient-0.10.0/include/mtx/events/common.hpp  2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/include/mtx/events/common.hpp  2025-08-02 
21:59:13.000000000 +0200
@@ -142,14 +142,12 @@
     ThumbnailInfo thumbnail_info;
     //! Encryption members. If present, they replace thumbnail_url.
     std::optional<crypto::EncryptedFile> thumbnail_file;
-    //! experimental blurhash, see MSC2448
-    std::string blurhash;
 
     //! Deserialization method needed by @p nlohmann::json.
-    friend void from_json(const nlohmann::json &obj, ThumbnailInfo &info);
+    friend void from_json(const nlohmann::json &obj, LocationInfo &info);
 
     //! Serialization method needed by @p nlohmann::json.
-    friend void to_json(nlohmann::json &obj, const ThumbnailInfo &info);
+    friend void to_json(nlohmann::json &obj, const LocationInfo &info);
 };
 
 /// @brief Mentions metadata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtx/events/event_type.hpp 
new/mtxclient-0.10.1/include/mtx/events/event_type.hpp
--- old/mtxclient-0.10.0/include/mtx/events/event_type.hpp      2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/include/mtx/events/event_type.hpp      2025-08-02 
21:59:13.000000000 +0200
@@ -139,6 +139,8 @@
     NhekoHiddenEvents,
     // im.nheko.event_expiry
     NhekoEventExpiry,
+    // im.nheko.invite_permissions
+    NhekoInvitePermissions,
 
     // MSCs
     //! m.image_pack, currently im.ponies.room_emotes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mtxclient-0.10.0/include/mtx/events/nheko_extensions/invite_permissions.hpp 
new/mtxclient-0.10.1/include/mtx/events/nheko_extensions/invite_permissions.hpp
--- 
old/mtxclient-0.10.0/include/mtx/events/nheko_extensions/invite_permissions.hpp 
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/mtxclient-0.10.1/include/mtx/events/nheko_extensions/invite_permissions.hpp 
    2025-08-02 21:59:13.000000000 +0200
@@ -0,0 +1,48 @@
+#pragma once
+
+/// @file
+/// @brief A nheko specific event in account data used to block or allow list 
invites.
+
+#include <map>
+#include <string>
+
+#if __has_include(<nlohmann/json_fwd.hpp>)
+#include <nlohmann/json_fwd.hpp>
+#else
+#include <nlohmann/json.hpp>
+#endif
+
+namespace mtx {
+namespace events {
+namespace account_data {
+namespace nheko_extensions {
+//! Custom event to allow or block invites.
+struct InvitePermissions
+{
+    //! Default permissions
+    std::string default_;
+
+    //! Server allowed to invite
+    std::map<std::string, std::string, std::less<>> server_allow;
+    //! Server denied from inviting
+    std::map<std::string, std::string, std::less<>> server_deny;
+
+    //! Rooms the user accepts invites to
+    std::map<std::string, std::string, std::less<>> room_allow;
+    //! Rooms the user blocks invites to
+    std::map<std::string, std::string, std::less<>> room_deny;
+
+    //! Users the user is accepting invites from
+    std::map<std::string, std::string, std::less<>> user_allow;
+    //! Users the user is blocking invites from
+    std::map<std::string, std::string, std::less<>> user_deny;
+
+    [[nodiscard]] bool invite_allowed(std::string_view room_id, 
std::string_view inviter) const;
+
+    friend void from_json(const nlohmann::json &obj, InvitePermissions 
&content);
+    friend void to_json(nlohmann::json &obj, const InvitePermissions &content);
+};
+}
+} // namespace account_data
+} // namespace events
+} // namespace mtx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtx/identifiers.hpp 
new/mtxclient-0.10.1/include/mtx/identifiers.hpp
--- old/mtxclient-0.10.0/include/mtx/identifiers.hpp    2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/include/mtx/identifiers.hpp    2025-08-02 
21:59:13.000000000 +0200
@@ -109,11 +109,12 @@
         identifier.hostname_  = id.substr(parts + 1);
         identifier.id_        = id;
         return identifier;
-    } else if (Identifier::sigil == "$") {
+    } else if (Identifier::sigil == "$" || Identifier::sigil == "!") {
         // V3 event ids don't use ':' at all, don't parse them the same way.
+        // V12 rooms don't use a server host in the id.
         Identifier identifier{};
-        identifier.localpart_ = id;
-        identifier.hostname_  = id;
+        identifier.localpart_ = id.substr(1);
+        identifier.hostname_  = "";
         identifier.id_        = id;
         return identifier;
     } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtx.hpp 
new/mtxclient-0.10.1/include/mtx.hpp
--- old/mtxclient-0.10.0/include/mtx.hpp        2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/include/mtx.hpp        2025-08-02 21:59:13.000000000 
+0200
@@ -28,6 +28,7 @@
 #include "mtx/events/messages/emote.hpp"
 #include "mtx/events/messages/file.hpp"
 #include "mtx/events/messages/image.hpp"
+#include "mtx/events/messages/location.hpp"
 #include "mtx/events/messages/notice.hpp"
 #include "mtx/events/messages/text.hpp"
 #include "mtx/events/messages/unknown.hpp"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtxclient/http/client.hpp 
new/mtxclient-0.10.1/include/mtxclient/http/client.hpp
--- old/mtxclient-0.10.0/include/mtxclient/http/client.hpp      2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/include/mtxclient/http/client.hpp      2025-08-02 
21:59:13.000000000 +0200
@@ -908,6 +908,7 @@
 MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::Emote)
 MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::File)
 MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::Image)
+MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::Location)
 MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::Notice)
 MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::Text)
 MTXCLIENT_SEND_ROOM_MESSAGE_FWD(mtx::events::msg::Video)
@@ -974,6 +975,7 @@
 MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::msc2545::ImagePack)
 MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::msc2545::ImagePackRooms)
 
MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::account_data::nheko_extensions::HiddenEvents)
+MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::account_data::nheko_extensions::InvitePermissions)
 
MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::account_data::nheko_extensions::EventExpiry)
 MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::account_data::Tags)
 MTXCLIENT_ACCOUNT_DATA_FWD(mtx::events::account_data::Direct)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/include/mtxclient/http/errors.hpp 
new/mtxclient-0.10.1/include/mtxclient/http/errors.hpp
--- old/mtxclient-0.10.0/include/mtxclient/http/errors.hpp      2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/include/mtxclient/http/errors.hpp      2025-08-02 
21:59:13.000000000 +0200
@@ -87,7 +87,7 @@
     // Formats the point p using the parsed format specification (presentation)
     // stored in this formatter.
     template<typename FormatContext>
-    auto format(const mtx::http::ClientError &e, FormatContext &ctx) -> 
decltype(ctx.out())
+    auto format(const mtx::http::ClientError &e, FormatContext &ctx) const -> 
decltype(ctx.out())
     {
         // ctx.out() is an output iterator to write to.
         bool prepend_comma = false;
@@ -132,7 +132,7 @@
 {
     // parse is inherited from formatter<string_view>.
     template<typename FormatContext>
-    auto format(std::optional<mtx::http::ClientError> c, FormatContext &ctx)
+    auto format(std::optional<mtx::http::ClientError> c, FormatContext &ctx) 
const
     {
         if (!c)
             return fmt::format_to(ctx.out(), "(no error)");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/lib/http/client.cpp 
new/mtxclient-0.10.1/lib/http/client.cpp
--- old/mtxclient-0.10.0/lib/http/client.cpp    2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/lib/http/client.cpp    2025-08-02 21:59:13.000000000 
+0200
@@ -542,6 +542,9 @@
         for (size_t i = 1; i < via.size(); i++) {
             query += "&server_name=" + url_encode(via[i]);
         }
+        for (const auto &v : via) {
+            query += "&via=" + url_encode(v);
+        }
     }
     auto api_path = "/client/v3/join/" + url_encode(room) + query;
 
@@ -565,6 +568,9 @@
         for (size_t i = 1; i < via.size(); i++) {
             query += "&server_name=" + url_encode(via[i]);
         }
+        for (const auto &v : via) {
+            query += "&via=" + url_encode(v);
+        }
     }
     auto api_path = "/client/v3/knock/" + url_encode(room) + query;
 
@@ -837,18 +843,21 @@
 
     const auto api_path = "/client/v1/media/download/" + 
client::utils::url_encode(server) + "/" +
                           client::utils::url_encode(media_id);
-    get<std::string>(api_path,
-                     [_this = shared_from_this(), cb = std::move(cb), server, 
media_id](
-                       const std::string &res, HeaderFields fields, RequestErr 
err) {
-                         if (!err || !(err->status_code == 404 || 
err->status_code == 400)) {
-                             cb(res, fields, err);
-                         } else {
-                             const auto api_path = "/media/v3/download/" +
-                                                   
client::utils::url_encode(server) + "/" +
-                                                   
client::utils::url_encode(media_id);
-                             _this->get<std::string>(api_path, std::move(cb));
-                         }
-                     });
+    get<std::string>(
+      api_path,
+      [_this = shared_from_this(), cb = std::move(cb), server, media_id](
+        const std::string &res, HeaderFields fields, RequestErr err) {
+          if (!err || !(err->status_code == 404 || err->status_code == 400)) {
+              cb(res, fields, err);
+          } else {
+              const auto api_path = "/media/v3/download/" + 
client::utils::url_encode(server) +
+                                    "/" + client::utils::url_encode(media_id);
+              _this->get<std::string>(api_path, std::move(cb));
+          }
+      },
+      true,
+      "/_matrix",
+      3);
 }
 
 void
@@ -1804,6 +1813,7 @@
 MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Emote)
 MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::File)
 MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Image)
+MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Location)
 MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Notice)
 MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Text)
 MTXCLIENT_SEND_ROOM_MESSAGE(mtx::events::msg::Unknown)
@@ -1870,6 +1880,7 @@
 MTXCLIENT_ACCOUNT_DATA(mtx::events::msc2545::ImagePack)
 MTXCLIENT_ACCOUNT_DATA(mtx::events::msc2545::ImagePackRooms)
 
MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::nheko_extensions::HiddenEvents)
+MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::nheko_extensions::InvitePermissions)
 
MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::nheko_extensions::EventExpiry)
 MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::Tags)
 MTXCLIENT_ACCOUNT_DATA(mtx::events::account_data::Direct)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mtxclient-0.10.0/lib/structs/events/canonical_alias.cpp 
new/mtxclient-0.10.1/lib/structs/events/canonical_alias.cpp
--- old/mtxclient-0.10.0/lib/structs/events/canonical_alias.cpp 2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/lib/structs/events/canonical_alias.cpp 2025-08-02 
21:59:13.000000000 +0200
@@ -23,6 +23,8 @@
 void
 to_json(json &obj, const CanonicalAlias &canonical_alias)
 {
+    obj = nlohmann::json::object();
+
     if (!canonical_alias.alias.empty())
         obj["alias"] = canonical_alias.alias;
     if (!canonical_alias.alt_aliases.empty())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/lib/structs/events/collections.cpp 
new/mtxclient-0.10.1/lib/structs/events/collections.cpp
--- old/mtxclient-0.10.0/lib/structs/events/collections.cpp     2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/lib/structs/events/collections.cpp     2025-08-02 
21:59:13.000000000 +0200
@@ -47,6 +47,7 @@
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, 
mtx::events::msg::Emote)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, mtx::events::msg::File)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, 
mtx::events::msg::Image)
+MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, 
mtx::events::msg::Location)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, 
mtx::events::msg::Notice)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, mtx::events::msg::Text)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::RoomEvent, 
mtx::events::msg::Unknown)
@@ -128,6 +129,8 @@
                                      
mtx::events::account_data::nheko_extensions::HiddenEvents)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::AccountDataEvent,
                                      
mtx::events::account_data::nheko_extensions::EventExpiry)
+MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::AccountDataEvent,
+                                     
mtx::events::account_data::nheko_extensions::InvitePermissions)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::AccountDataEvent, 
msc2545::ImagePackRooms)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::AccountDataEvent, 
msc2545::ImagePack)
 MTXCLIENT_INSTANTIATE_JSON_FUNCTIONS(events::Event, presence::Presence)
@@ -322,8 +325,7 @@
                 break;
             }
             case MsgType::Location: {
-                /* events::RoomEvent<events::msg::Location> location = e; */
-                /* container.emplace_back(location); */
+                e = events::RoomEvent<events::msg::Location>(obj);
                 break;
             }
             case MsgType::Notice: {
@@ -405,6 +407,7 @@
         case events::EventType::FullyRead:
         case events::EventType::IgnoredUsers:
         case events::EventType::NhekoHiddenEvents:
+        case events::EventType::NhekoInvitePermissions:
         case events::EventType::NhekoEventExpiry:
         case events::EventType::ImagePackInAccountData:
         case events::EventType::ImagePackRooms:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/lib/structs/events/common.cpp 
new/mtxclient-0.10.1/lib/structs/events/common.cpp
--- old/mtxclient-0.10.0/lib/structs/events/common.cpp  2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/lib/structs/events/common.cpp  2025-08-02 
21:59:13.000000000 +0200
@@ -170,6 +170,32 @@
 }
 
 void
+from_json(const json &obj, LocationInfo &info)
+{
+    if (obj.contains("thumbnail_url"))
+        info.thumbnail_url = obj.at("thumbnail_url").get<std::string>();
+
+    if (obj.contains("thumbnail_info"))
+        info.thumbnail_info = obj.at("thumbnail_info").get<ThumbnailInfo>();
+
+    if (obj.contains("thumbnail_file"))
+        info.thumbnail_file = 
obj.at("thumbnail_file").get<crypto::EncryptedFile>();
+}
+
+void
+to_json(json &obj, const LocationInfo &info)
+{
+    if (!info.thumbnail_url.empty()) {
+        obj["thumbnail_url"]  = info.thumbnail_url;
+        obj["thumbnail_info"] = info.thumbnail_info;
+    }
+    if (info.thumbnail_file) {
+        obj["thumbnail_file"] = info.thumbnail_file.value();
+        obj["thumbnail_info"] = info.thumbnail_info;
+    }
+}
+
+void
 from_json(const json &obj, Mentions &info)
 {
     info.room     = obj.value("room", false);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/lib/structs/events/create.cpp 
new/mtxclient-0.10.1/lib/structs/events/create.cpp
--- old/mtxclient-0.10.0/lib/structs/events/create.cpp  2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/lib/structs/events/create.cpp  2025-08-02 
21:59:13.000000000 +0200
@@ -14,13 +14,14 @@
 from_json(const json &obj, PreviousRoom &predecessor)
 {
     predecessor.room_id  = obj.at("room_id").get<std::string>();
-    predecessor.event_id = obj.at("event_id").get<std::string>();
+    predecessor.event_id = obj.value("event_id", "");
 }
 void
 to_json(json &obj, const PreviousRoom &predecessor)
 {
-    obj["room_id"]  = predecessor.room_id;
-    obj["event_id"] = predecessor.event_id;
+    obj["room_id"] = predecessor.room_id;
+    if (!predecessor.event_id.empty())
+        obj["event_id"] = predecessor.event_id;
 }
 
 void
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mtxclient-0.10.0/lib/structs/events/messages/location.cpp 
new/mtxclient-0.10.1/lib/structs/events/messages/location.cpp
--- old/mtxclient-0.10.0/lib/structs/events/messages/location.cpp       
1970-01-01 01:00:00.000000000 +0100
+++ new/mtxclient-0.10.1/lib/structs/events/messages/location.cpp       
2025-08-02 21:59:13.000000000 +0200
@@ -0,0 +1,40 @@
+#include <nlohmann/json.hpp>
+#include <string>
+
+#include "mtx/events/common.hpp"
+#include "mtx/events/messages/location.hpp"
+
+using json = nlohmann::json;
+
+namespace mtx {
+namespace events {
+namespace msg {
+
+void
+from_json(const json &obj, Location &content)
+{
+    content.body    = obj.at("body").get<std::string>();
+    content.msgtype = obj.at("msgtype").get<std::string>();
+    if (obj.find("geo_uri") != obj.end())
+        content.geo_uri = obj.at("geo_uri").get<std::string>();
+
+    if (obj.find("info") != obj.end())
+        content.info = obj.at("info").get<common::LocationInfo>();
+
+    content.relations = common::parse_relations(obj);
+}
+
+void
+to_json(json &obj, const Location &content)
+{
+    obj["msgtype"] = "m.location";
+    obj["body"]    = content.body;
+
+    obj["geo_uri"] = content.geo_uri;
+    obj["info"]    = content.info;
+    common::apply_relations(obj, content.relations);
+}
+
+} // namespace msg
+} // namespace events
+} // namespace mtx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mtxclient-0.10.0/lib/structs/events/nheko_extensions/invite_permissions.cpp 
new/mtxclient-0.10.1/lib/structs/events/nheko_extensions/invite_permissions.cpp
--- 
old/mtxclient-0.10.0/lib/structs/events/nheko_extensions/invite_permissions.cpp 
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/mtxclient-0.10.1/lib/structs/events/nheko_extensions/invite_permissions.cpp 
    2025-08-02 21:59:13.000000000 +0200
@@ -0,0 +1,98 @@
+#include "mtx/events/nheko_extensions/invite_permissions.hpp"
+
+#include <tuple>
+
+#include <nlohmann/json.hpp>
+
+#include <mtx/log.hpp>
+
+static std::tuple<std::map<std::string, std::string, std::less<>>,
+                  std::map<std::string, std::string, std::less<>>>
+parse_subset(const std::string &key, const nlohmann::json &obj)
+{
+    std::map<std::string, std::string, std::less<>> allow, deny;
+
+    if (auto o = obj.find(key); o != obj.end()) {
+        auto a = o->value("allow", std::map<std::string, nlohmann::json>());
+        auto d = o->value("deny", std::map<std::string, nlohmann::json>());
+
+        for (const auto &[k, v] : a) {
+            allow.emplace(k, v.dump());
+        }
+        for (const auto &[k, v] : d) {
+            deny.emplace(k, v.dump());
+        }
+    }
+
+    return {allow, deny};
+}
+
+static void
+emit_subset(nlohmann::json &obj,
+            std::string_view key,
+            const std::map<std::string, std::string, std::less<>> &allow,
+            const std::map<std::string, std::string, std::less<>> &deny)
+{
+    for (const auto &[k, v] : allow) {
+        obj[key]["allow"][k] = nlohmann::json::parse(v);
+    }
+    for (const auto &[k, v] : deny) {
+        obj[key]["deny"][k] = nlohmann::json::parse(v);
+    }
+}
+
+namespace mtx {
+namespace events {
+namespace account_data {
+namespace nheko_extensions {
+
+void
+from_json(const nlohmann::json &obj, InvitePermissions &content)
+{
+    if (obj.contains("default")) {
+        content.default_ = obj.at("default").get<std::string>();
+    } else {
+        content.default_ = "allow";
+    }
+
+    std::tie(content.server_allow, content.server_deny) = 
parse_subset("server", obj);
+    std::tie(content.room_allow, content.room_deny)     = parse_subset("room", 
obj);
+    std::tie(content.user_allow, content.user_deny)     = parse_subset("user", 
obj);
+}
+
+void
+to_json(nlohmann::json &obj, const InvitePermissions &content)
+{
+    obj["default"] = content.default_;
+
+    emit_subset(obj, "server", content.server_allow, content.server_deny);
+    emit_subset(obj, "room", content.room_allow, content.room_deny);
+    emit_subset(obj, "user", content.user_allow, content.user_deny);
+}
+
+bool
+InvitePermissions::invite_allowed(std::string_view room_id, std::string_view 
inviter) const
+{
+    if (this->user_deny.contains(inviter))
+        return false;
+    if (this->user_allow.contains(inviter))
+        return true;
+    if (this->room_deny.contains(room_id))
+        return false;
+    if (this->room_allow.contains(room_id))
+        return true;
+
+    if (auto pos = inviter.find_first_of(':'); pos != std::string_view::npos) {
+        auto server = inviter.substr(pos + 1);
+        if (this->server_deny.contains(server))
+            return false;
+        if (this->server_allow.contains(server))
+            return false;
+    }
+
+    return this->default_ != "deny";
+}
+}
+} // namespace account_data
+} // namespace events
+} // namespace mtx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/lib/structs/events.cpp 
new/mtxclient-0.10.1/lib/structs/events.cpp
--- old/mtxclient-0.10.0/lib/structs/events.cpp 2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/lib/structs/events.cpp 2025-08-02 21:59:13.000000000 
+0200
@@ -129,6 +129,8 @@
         return EventType::NhekoHiddenEvents;
     else if (type == "im.nheko.event_expiry")
         return EventType::NhekoEventExpiry;
+    else if (type == "im.nheko.invite_permissions")
+        return EventType::NhekoInvitePermissions;
     else if (type == "im.ponies.room_emotes")
         return EventType::ImagePackInRoom;
     else if (type == "im.ponies.user_emotes")
@@ -264,6 +266,8 @@
         return "im.nheko.hidden_events";
     case EventType::NhekoEventExpiry:
         return "im.nheko.event_expiry";
+    case EventType::NhekoInvitePermissions:
+        return "im.nheko.invite_permissions";
     case EventType::ImagePackInRoom:
         return "im.ponies.room_emotes";
     case EventType::ImagePackInAccountData:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/lib/structs/responses/common.cpp 
new/mtxclient-0.10.1/lib/structs/responses/common.cpp
--- old/mtxclient-0.10.0/lib/structs/responses/common.cpp       2024-06-11 
00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/lib/structs/responses/common.cpp       2025-08-02 
21:59:13.000000000 +0200
@@ -140,6 +140,11 @@
                 
container.emplace_back(events::AccountDataEvent<nheko_extensions::EventExpiry>(e));
                 break;
             }
+            case events::EventType::NhekoInvitePermissions: {
+                container.emplace_back(
+                  
events::AccountDataEvent<nheko_extensions::InvitePermissions>(e));
+                break;
+            }
             case events::EventType::ImagePackRooms: {
                 container.emplace_back(
                   
events::AccountDataEvent<events::msc2545::ImagePackRooms>(e));
@@ -424,8 +429,7 @@
                     break;
                 }
                 case MsgType::Location: {
-                    /* events::RoomEvent<events::msg::Location> location = e; 
*/
-                    /* container.emplace_back(location); */
+                    
container.emplace_back(events::RoomEvent<events::msg::Location>(e));
                     break;
                 }
                 case MsgType::Notice: {
@@ -528,6 +532,7 @@
             case events::EventType::IgnoredUsers:
             case events::EventType::NhekoHiddenEvents:
             case events::EventType::NhekoEventExpiry:
+            case events::EventType::NhekoInvitePermissions:
             case events::EventType::ImagePackRooms:
             case events::EventType::ImagePackInAccountData:
             case events::EventType::Dummy:
@@ -808,6 +813,7 @@
             case events::EventType::IgnoredUsers:
             case events::EventType::NhekoHiddenEvents:
             case events::EventType::NhekoEventExpiry:
+            case events::EventType::NhekoInvitePermissions:
             case events::EventType::ImagePackRooms:
             case events::EventType::ImagePackInAccountData:
             case events::EventType::Dummy:
@@ -977,6 +983,7 @@
             case events::EventType::IgnoredUsers:
             case events::EventType::NhekoHiddenEvents:
             case events::EventType::NhekoEventExpiry:
+            case events::EventType::NhekoInvitePermissions:
             case events::EventType::ImagePackInAccountData:
             case events::EventType::ImagePackInRoom:
             case events::EventType::ImagePackRooms:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/meson.build 
new/mtxclient-0.10.1/meson.build
--- old/mtxclient-0.10.0/meson.build    2024-06-11 00:15:15.000000000 +0200
+++ new/mtxclient-0.10.1/meson.build    2025-08-02 21:59:13.000000000 +0200
@@ -1,7 +1,7 @@
 project(
   'mtxclient',
   'cpp',
-version : '0.10.0',
+version : '0.10.1',
 meson_version : '>=0.57.0',
 license : 'MIT',
 default_options : 'cpp_std=c++20'
@@ -86,14 +86,16 @@
        'lib/structs/events/messages/emote.cpp',
        'lib/structs/events/messages/file.cpp',
        'lib/structs/events/messages/image.cpp',
+       'lib/structs/events/messages/location.cpp',
        'lib/structs/events/messages/notice.cpp',
        'lib/structs/events/messages/text.cpp',
        'lib/structs/events/messages/unknown.cpp',
        'lib/structs/events/messages/video.cpp',
        'lib/structs/events/mscs/image_packs.cpp',
        'lib/structs/events/name.cpp',
-       'lib/structs/events/nheko_extensions/hidden_events.cpp',
        'lib/structs/events/nheko_extensions/event_expiry.cpp',
+       'lib/structs/events/nheko_extensions/hidden_events.cpp',
+       'lib/structs/events/nheko_extensions/invite_permissions.cpp',
        'lib/structs/events/pinned_events.cpp',
        'lib/structs/events/policy_rules.cpp',
        'lib/structs/events/power_levels.cpp',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/tests/client_api.cpp 
new/mtxclient-0.10.1/tests/client_api.cpp
--- old/mtxclient-0.10.0/tests/client_api.cpp   2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/tests/client_api.cpp   2025-08-02 21:59:13.000000000 
+0200
@@ -968,7 +968,7 @@
     mtx_client->versions([](const mtx::responses::Versions &res, RequestErr 
err) {
         check_error(err);
 
-        EXPECT_EQ(res.versions.size(), 10);
+        EXPECT_EQ(res.versions.size(), 20);
         EXPECT_EQ(res.versions.at(0), "r0.0.1");
         EXPECT_EQ(res.versions.at(1), "r0.1.0");
         EXPECT_EQ(res.versions.at(2), "r0.2.0");
@@ -1070,11 +1070,13 @@
 {
     auto alice = make_test_client();
 
-    alice->login(
-      "alice", "secret", [](const mtx::responses::Login &, RequestErr err) { 
check_error(err); });
+    // special user just for presence
+    alice->login("presence", "secret", [](const mtx::responses::Login &, 
RequestErr err) {
+        check_error(err);
+    });
 
     while (alice->access_token().empty())
-        sleep();
+        std::this_thread::yield();
 
     alice->put_presence_status(
       mtx::presence::unavailable, "Is this thing on?", [alice](RequestErr err) 
{
@@ -1112,8 +1114,9 @@
     auto alice = make_test_client();
     auto bob   = make_test_client();
 
-    alice->login(
-      "alice", "secret", [](const mtx::responses::Login &, RequestErr err) { 
check_error(err); });
+    alice->login("presencesync", "secret", [](const mtx::responses::Login &, 
RequestErr err) {
+        check_error(err);
+    });
     bob->login(
       "bob", "secret", [](const mtx::responses::Login &, RequestErr err) { 
check_error(err); });
 
@@ -1158,7 +1161,7 @@
 
                                   bool found = false;
                                   for (const auto &p : s.presence) {
-                                      if (p.sender == "@alice:" + 
server_name()) {
+                                      if (p.sender == "@presencesync:" + 
server_name()) {
                                           found = true;
                                           EXPECT_EQ(p.content.presence, 
mtx::presence::online);
                                           EXPECT_EQ(p.content.status_msg,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/tests/events.cpp 
new/mtxclient-0.10.1/tests/events.cpp
--- old/mtxclient-0.10.0/tests/events.cpp       2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/tests/events.cpp       2025-08-02 21:59:13.000000000 
+0200
@@ -2067,6 +2067,59 @@
     ASSERT_EQ(event.content.keep_only_latest, 100);
 }
 
+TEST(RoomAccountData, NhekoInvitePermissions)
+{
+    json data = R"({
+          "content": {
+            "default": "allow",
+            "room": {
+              "allow": {
+                "!abc:example.net": {}
+              },
+              "deny": {
+                "!def:example.net": {}
+              }
+            },
+            "user": {
+              "allow": {
+                "@abc:example.net": {}
+              },
+              "deny": {
+                "@def:example.net": {}
+              }
+            },
+            "server": {
+              "allow": {
+                "example.com": {},
+                "nheko.im": {}
+              },
+              "deny": {
+                "example.org": {}
+              }
+            }
+          },
+          "type": "im.nheko.invite_permissions"
+        })"_json;
+
+    
ns::AccountDataEvent<ns::account_data::nheko_extensions::InvitePermissions> 
event =
+      
data.get<ns::AccountDataEvent<ns::account_data::nheko_extensions::InvitePermissions>>();
+
+    EXPECT_EQ(data, json(event));
+
+    EXPECT_EQ(event.content.default_, "allow");
+    EXPECT_TRUE(event.content.server_allow.contains("nheko.im"));
+    EXPECT_TRUE(event.content.server_deny.contains("example.org"));
+    EXPECT_TRUE(event.content.user_allow.contains("@abc:example.net"));
+    EXPECT_TRUE(event.content.user_deny.contains("@def:example.net"));
+    EXPECT_TRUE(event.content.room_allow.contains("!abc:example.net"));
+    EXPECT_TRUE(event.content.room_deny.contains("!def:example.net"));
+
+    EXPECT_TRUE(event.content.invite_allowed("!abc:example.net", 
"@test:example.org"));
+    EXPECT_TRUE(event.content.invite_allowed("!def:example.net", 
"@abc:example.net"));
+    EXPECT_FALSE(event.content.invite_allowed("!random:example.net", 
"@abc:example.org"));
+    EXPECT_FALSE(event.content.invite_allowed("!def:example.net", 
"@abc:example.com"));
+}
+
 TEST(RoomAccountData, ImagePack)
 {
     json data = R"({
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/tests/identifiers.cpp 
new/mtxclient-0.10.1/tests/identifiers.cpp
--- old/mtxclient-0.10.0/tests/identifiers.cpp  2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/tests/identifiers.cpp  2025-08-02 21:59:13.000000000 
+0200
@@ -47,6 +47,11 @@
     EXPECT_EQ(room2.to_string(), "!39fasdsdfsdf:example.com");
     EXPECT_EQ(room2.localpart(), "39fasdsdfsdf");
     EXPECT_EQ(room2.hostname(), "example.com");
+
+    Room room3 = parse<Room>("!39fasdsdfsdf");
+    EXPECT_EQ(room3.to_string(), "!39fasdsdfsdf");
+    EXPECT_EQ(room3.localpart(), "39fasdsdfsdf");
+    EXPECT_EQ(room3.hostname(), "");
 }
 
 TEST(MatrixIdentifiers, IdentifierInvalid)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mtxclient-0.10.0/tests/messages.cpp 
new/mtxclient-0.10.1/tests/messages.cpp
--- old/mtxclient-0.10.0/tests/messages.cpp     2024-06-11 00:15:15.000000000 
+0200
+++ new/mtxclient-0.10.1/tests/messages.cpp     2025-08-02 21:59:13.000000000 
+0200
@@ -503,7 +503,53 @@
               mtx::common::RelationType::InReplyTo);
 }
 
-TEST(RoomEvents, LocationMessage) {}
+TEST(RoomEvents, LocationMessage)
+{
+    json data                      = R"({
+            "content": {
+              "body": "Big Ben, London, UK",
+              "geo_uri": "geo:51.5008,0.1247",
+              "info": {
+                "thumbnail_info": {
+                  "h": 300,
+                  "mimetype": "image/jpeg",
+                  "size": 46144,
+                  "w": 300
+                },
+                "thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe"
+              },
+              "msgtype": "m.location",
+              "m.relates_to": {
+                    "m.in_reply_to": {
+                                    "event_id": 
"$6GKhAfJOcwNd69lgSizdcTob8z2pWQgBOZPrnsWMA1E"
+                                }
+                            }
+            },
+            "event_id": "$143273582443PhrSn:example.org",
+            "origin_server_ts": 1432735824653,
+            "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
+            "sender": "@example:example.org",
+            "type": "m.room.message",
+            "unsigned": {
+              "age": 69168455
+            }
+          }
+        )"_json;
+    RoomEvent<msg::Location> event = data.get<RoomEvent<msg::Location>>();
+
+    EXPECT_EQ(event.type, EventType::RoomMessage);
+    EXPECT_EQ(event.event_id, "$143273582443PhrSn:example.org");
+    EXPECT_EQ(event.room_id, "!jEsUZKDJdhlrceRyVU:example.org");
+    EXPECT_EQ(event.sender, "@example:example.org");
+    EXPECT_EQ(event.origin_server_ts, 1432735824653);
+    EXPECT_EQ(event.unsigned_data.age, 69168455);
+    EXPECT_EQ(event.content.body, "Big Ben, London, UK");
+    EXPECT_EQ(event.content.msgtype, "m.location");
+    EXPECT_EQ(event.content.relations.relations.at(0).event_id,
+              "$6GKhAfJOcwNd69lgSizdcTob8z2pWQgBOZPrnsWMA1E");
+    EXPECT_EQ(event.content.relations.relations.at(0).rel_type,
+              mtx::common::RelationType::InReplyTo);
+}
 
 TEST(RoomEvents, NoticeMessage)
 {

Reply via email to