From 73f5d950e55170fb9a12e5febb6a689c65e1a28b Mon Sep 17 00:00:00 2001 From: Linus Jahn Date: Sat, 26 Oct 2024 12:52:39 +0200 Subject: [PATCH 001/170] mix_pam: Remove 'Channels' roster group of mix channels This isn't specified and was probably only meant for debugging. In real clients having this (forced) 'Channels' group is undesireable in most cases. --- src/mod_mix_pam.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_mix_pam.erl b/src/mod_mix_pam.erl index eb94877d288..7f6c768e87e 100644 --- a/src/mod_mix_pam.erl +++ b/src/mod_mix_pam.erl @@ -227,7 +227,7 @@ get_mix_roster_items(Acc, {LUser, LServer}) -> name = <<>>, subscription = both, ask = undefined, - groups = [<<"Channels">>], + groups = [], mix_channel = #mix_roster_channel{participant_id = Id} } end, Channels); From f38f81159d1a46c9de817b67d3ea548d694901fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 19 Dec 2024 14:04:38 +0100 Subject: [PATCH 002/170] Fix issue with wrong namespace in mod_s2s_bidi --- mix.exs | 2 +- mix.lock | 2 +- rebar.config | 4 ++-- rebar.lock | 7 ++++--- src/mod_s2s_bidi.erl | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mix.exs b/mix.exs index 9a48e3c3650..45f2479b964 100644 --- a/mix.exs +++ b/mix.exs @@ -144,7 +144,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, "~> 1.9.1"}, + {:xmpp, "~> 1.9.2"}, {:yconf, "~> 1.0.17"}] ++ cond_deps() end diff --git a/mix.lock b/mix.lock index 9627ce0a34d..38c7d2aa5bd 100644 --- a/mix.lock +++ b/mix.lock @@ -34,6 +34,6 @@ "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:hex, :xmpp, "1.9.1", "a1642d93cdbdf947f32344b0e05fcc8efcfb9f11c32832acc9bd826b52adbe48", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "d2b1431af6e4c1a4c8bf90caf0cc11cdeb047b8323b87e9d7e4826d4913275dc"}, + "xmpp": {:hex, :xmpp, "1.9.2", "e0f5f8543d8bb92d433ab75a962bc53dba4601ea3606dac67a50e754e86d43ab", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "4fa1624666d695149d651ce5c104ca669c233f91db81d38b2d31ccf97fd0454e"}, "yconf": {:hex, :yconf, "1.0.17", "dcf242e27f3fc5d0743d6b8175dd39bc14a1f4ed7e6ea986366a44a6ff3b2a3a", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "dd2892923241449a46cc8457b9ec0fb14030700735a5885955677c735c341a25"}, } diff --git a/rebar.config b/rebar.config index 939c7399a79..219e62f7307 100644 --- a/rebar.config +++ b/rebar.config @@ -69,7 +69,7 @@ {p1_mysql, "~> 1.0.24", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.25"}}}}, {p1_oauth2, "~> 0.6.14", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.14"}}}, {if_var_true, pgsql, - {p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.29"}}}}, + {p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.30"}}}}, {p1_utils, "~> 1.0.25", {git, "https://github.com/processone/p1_utils", {tag, "1.0.26"}}}, {pkix, "~> 1.0.10", {git, "https://github.com/processone/pkix", {tag, "1.0.10"}}}, {if_var_true, sqlite, @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.1", {git, "https://github.com/processone/xmpp", {tag, "1.9.1"}}}, + {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", {tag, "1.9.2"}}}, {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", {tag, "1.0.17"}}} ]}. diff --git a/rebar.lock b/rebar.lock index 9a4b76f03ff..5a7445546eb 100644 --- a/rebar.lock +++ b/rebar.lock @@ -24,7 +24,10 @@ {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.30">>},0}, {<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, - {<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.1">>},0}, + {<<"xmpp">>, + {git,"https://github.com/processone/xmpp", + {ref,"a1dd8d3ab94fd251f20598e6f002eba38905e218"}}, + 0}, {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.17">>},0}]}. [ {pkg_hash,[ @@ -53,7 +56,6 @@ {<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>}, {<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>}, {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, - {<<"xmpp">>, <<"A1642D93CDBDF947F32344B0E05FCC8EFCFB9F11C32832ACC9BD826B52ADBE48">>}, {<<"yconf">>, <<"DCF242E27F3FC5D0743D6B8175DD39BC14A1F4ED7E6EA986366A44A6FF3B2A3A">>}]}, {pkg_hash_ext,[ {<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>}, @@ -81,6 +83,5 @@ {<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>}, {<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>}, {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, - {<<"xmpp">>, <<"D2B1431AF6E4C1A4C8BF90CAF0CC11CDEB047B8323B87E9D7E4826D4913275DC">>}, {<<"yconf">>, <<"DD2892923241449A46CC8457B9EC0FB14030700735A5885955677C735C341A25">>}]} ]. diff --git a/src/mod_s2s_bidi.erl b/src/mod_s2s_bidi.erl index 10cc0e773c4..5d0ba699dc0 100644 --- a/src/mod_s2s_bidi.erl +++ b/src/mod_s2s_bidi.erl @@ -72,7 +72,7 @@ mod_doc() -> " mod_s2s_bidi: {}"]}. s2s_in_features(Acc, _) -> - [#s2s_bidi{}|Acc]. + [#s2s_bidi_feature{}|Acc]. s2s_in_packet(State, #s2s_bidi{}) -> {stop, State#{bidi_enabled => true}}; @@ -115,8 +115,8 @@ s2s_out_packet(#{bidi_enabled := true, ip := {IP, _}} = State, Pkt0) s2s_out_packet(#{db_verify := _} = State, #stream_features{}) -> State; s2s_out_packet(State, #stream_features{} = Pkt) -> - try xmpp:try_subtag(Pkt, #s2s_bidi{}) of - #s2s_bidi{} -> + try xmpp:try_subtag(Pkt, #s2s_bidi_feature{}) of + #s2s_bidi_feature{} -> ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{}) catch _:{xmpp_codec, _Why} -> State From 5b3b29565ca46115042ab0c65cf399bdcf1e2839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 19 Dec 2024 16:27:16 +0100 Subject: [PATCH 003/170] Remove overide on fast_xml --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 45f2479b964..7671c3ffbb9 100644 --- a/mix.exs +++ b/mix.exs @@ -135,7 +135,7 @@ defmodule Ejabberd.MixProject do {:eimp, "~> 1.0"}, {:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false}, {:fast_tls, "~> 1.1.22"}, - {:fast_xml, "~> 1.1.53", override: true}, + {:fast_xml, "~> 1.1.53"}, {:fast_yaml, "~> 1.0"}, {:idna, "~> 6.0"}, {:mqtree, "~> 1.0"}, From aa65e626f4c9a2093043b97e6a76480cfa644b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 20 Dec 2024 09:38:03 +0100 Subject: [PATCH 004/170] Fix values allowed in db_type of mod_auth_fast documentation --- src/mod_auth_fast.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_auth_fast.erl b/src/mod_auth_fast.erl index 6ada831c27f..c6a79167cef 100644 --- a/src/mod_auth_fast.erl +++ b/src/mod_auth_fast.erl @@ -98,7 +98,7 @@ mod_doc() -> note => "added in 24.12", opts => [{db_type, - #{value => "mnesia | sql", + #{value => "mnesia", desc => ?T("Same as top-level _`default_db`_ option, but applied to this module only.")}}, {token_lifetime, From 213a513f54f0dec816082e3b9eccb5ebeff2d8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 20 Dec 2024 10:32:21 +0100 Subject: [PATCH 005/170] Fix name option in documentation --- src/mod_auth_fast.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_auth_fast.erl b/src/mod_auth_fast.erl index c6a79167cef..8ccf00e914f 100644 --- a/src/mod_auth_fast.erl +++ b/src/mod_auth_fast.erl @@ -112,7 +112,7 @@ mod_doc() -> example => ["modules:", " mod_auth_fast:", - " token_timeout: 14days"]}. + " token_lifetime: 14days"]}. get_mechanisms(_LServer) -> [<<"HT-SHA-256-NONE">>, <<"HT-SHA-256-UNIQ">>, <<"HT-SHA-256-EXPR">>, <<"HT-SHA-256-ENDP">>]. From 364ee0f8edcb2a6b62d9b44a0f55f40ee47e5421 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Sat, 21 Dec 2024 11:04:08 +0100 Subject: [PATCH 006/170] ejabberd.yml.example: Enable mod_muc_occupantid Add mod_muc_occupantid to the list of modules enabled in the sample configuration. It's not necessarily obvious that it's required for using certain modern features in group chat, and there's no downside in activating this module. --- ejabberd.yml.example | 1 + 1 file changed, 1 insertion(+) diff --git a/ejabberd.yml.example b/ejabberd.yml.example index 39e423a6449..0964afa0632 100644 --- a/ejabberd.yml.example +++ b/ejabberd.yml.example @@ -199,6 +199,7 @@ modules: default_room_options: mam: true mod_muc_admin: {} + mod_muc_occupantid: {} mod_offline: access_max_user_messages: max_user_offline_messages mod_ping: {} From 7d5413ce95f3e9395f8d584469c5e016ebaaa689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Sat, 21 Dec 2024 20:03:18 +0100 Subject: [PATCH 007/170] Update xmpp to bring fix for ssdp hash calculation --- mix.exs | 2 +- mix.lock | 2 +- rebar.config | 4 ++-- rebar.lock | 13 ++++++------- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/mix.exs b/mix.exs index 7671c3ffbb9..4f46caf86d1 100644 --- a/mix.exs +++ b/mix.exs @@ -144,7 +144,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, "~> 1.9.2"}, + {:xmpp, "~> 1.9.3"}, {:yconf, "~> 1.0.17"}] ++ cond_deps() end diff --git a/mix.lock b/mix.lock index 38c7d2aa5bd..eeceba2ab8f 100644 --- a/mix.lock +++ b/mix.lock @@ -34,6 +34,6 @@ "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:hex, :xmpp, "1.9.2", "e0f5f8543d8bb92d433ab75a962bc53dba4601ea3606dac67a50e754e86d43ab", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "4fa1624666d695149d651ce5c104ca669c233f91db81d38b2d31ccf97fd0454e"}, + "xmpp": {:hex, :xmpp, "1.9.3", "fa4f9eda52d789f4b9f5ff11fed17da2c43fa8d01ed7c4fadcb09ab602be9c18", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "d5c96fcb2cf8a8da43a5f81935b2e43fa9b959e1626fcecf082f4af9139bdbd2"}, "yconf": {:hex, :yconf, "1.0.17", "dcf242e27f3fc5d0743d6b8175dd39bc14a1f4ed7e6ea986366a44a6ff3b2a3a", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "dd2892923241449a46cc8457b9ec0fb14030700735a5885955677c735c341a25"}, } diff --git a/rebar.config b/rebar.config index 219e62f7307..dbaf948e1c3 100644 --- a/rebar.config +++ b/rebar.config @@ -69,7 +69,7 @@ {p1_mysql, "~> 1.0.24", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.25"}}}}, {p1_oauth2, "~> 0.6.14", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.14"}}}, {if_var_true, pgsql, - {p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.30"}}}}, + {p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.31"}}}}, {p1_utils, "~> 1.0.25", {git, "https://github.com/processone/p1_utils", {tag, "1.0.26"}}}, {pkix, "~> 1.0.10", {git, "https://github.com/processone/pkix", {tag, "1.0.10"}}}, {if_var_true, sqlite, @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", {tag, "1.9.2"}}}, + {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", {tag, "1.9.3"}}}, {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", {tag, "1.0.17"}}} ]}. diff --git a/rebar.lock b/rebar.lock index 5a7445546eb..7a9e810bfbd 100644 --- a/rebar.lock +++ b/rebar.lock @@ -17,17 +17,14 @@ {<<"p1_acme">>,{pkg,<<"p1_acme">>,<<"1.0.25">>},0}, {<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.25">>},0}, {<<"p1_oauth2">>,{pkg,<<"p1_oauth2">>,<<"0.6.14">>},0}, - {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.29">>},0}, + {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.31">>},0}, {<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.26">>},0}, {<<"pkix">>,{pkg,<<"pkix">>,<<"1.0.10">>},0}, {<<"sqlite3">>,{pkg,<<"sqlite3">>,<<"1.1.15">>},0}, {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.30">>},0}, {<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, - {<<"xmpp">>, - {git,"https://github.com/processone/xmpp", - {ref,"a1dd8d3ab94fd251f20598e6f002eba38905e218"}}, - 0}, + {<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.3">>},0}, {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.17">>},0}]}. [ {pkg_hash,[ @@ -49,13 +46,14 @@ {<<"p1_acme">>, <<"DB91F0D6C193CD1D5C0B0FA3939A898DBF56A6075DB4347CDE26E802715DE50C">>}, {<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>}, {<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>}, - {<<"p1_pgsql">>, <<"FAE0C90CBC5931865958150F1B667FB0D20B063F6A46A17770A4E5232DED632C">>}, + {<<"p1_pgsql">>, <<"8339BEAC1F0F4A45F476FF5306BE5135020F02979A61DF0D8CF7B1C67E85E2FD">>}, {<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>}, {<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>}, {<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>}, {<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>}, {<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>}, {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, + {<<"xmpp">>, <<"FA4F9EDA52D789F4B9F5FF11FED17DA2C43FA8D01ED7C4FADCB09AB602BE9C18">>}, {<<"yconf">>, <<"DCF242E27F3FC5D0743D6B8175DD39BC14A1F4ED7E6EA986366A44A6FF3B2A3A">>}]}, {pkg_hash_ext,[ {<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>}, @@ -76,12 +74,13 @@ {<<"p1_acme">>, <<"A7B55B47495DDB4F98A15E65451EC3AD43F4637B955C74CD695D98E6A645D08C">>}, {<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>}, {<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>}, - {<<"p1_pgsql">>, <<"A6FF58E8B174993F3895DA3EA6211A9F9D0C54D1A6E28BB321DA3B3CD68B38C1">>}, + {<<"p1_pgsql">>, <<"B7FC45DFB2549187347871B7FD0573638AD5EA337F6263FBA1B3840EFAB2FF49">>}, {<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>}, {<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>}, {<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>}, {<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>}, {<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>}, {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, + {<<"xmpp">>, <<"D5C96FCB2CF8A8DA43A5F81935B2E43FA9B959E1626FCECF082F4AF9139BDBD2">>}, {<<"yconf">>, <<"DD2892923241449A46CC8457B9EC0FB14030700735A5885955677C735C341A25">>}]} ]. From 5945dba412927acb10b364ab4c5131146aa2030f Mon Sep 17 00:00:00 2001 From: Dmitriy Bogdanov Date: Thu, 26 Dec 2024 14:55:31 +0100 Subject: [PATCH 008/170] Fix a couple of typos in documentation --- src/mod_auth_fast.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_auth_fast.erl b/src/mod_auth_fast.erl index 8ccf00e914f..aa40e8f1ac8 100644 --- a/src/mod_auth_fast.erl +++ b/src/mod_auth_fast.erl @@ -93,8 +93,8 @@ mod_doc() -> #{desc => [?T("The module adds support for " "https://xmpp.org/extensions/xep-0484.html" - "[XEP-0480: Fast Authentication Streamlining Tokens] that allows users to authenticate " - "using self managed tokens.")], + "[XEP-0484: Fast Authentication Streamlining Tokens] that allows users to authenticate " + "using self-managed tokens.")], note => "added in 24.12", opts => [{db_type, @@ -103,7 +103,7 @@ mod_doc() -> ?T("Same as top-level _`default_db`_ option, but applied to this module only.")}}, {token_lifetime, #{value => "timeout()", - desc => ?T("Time that tokens will be keept, measured from it's creation time. " + desc => ?T("Time that tokens will be kept, measured from it's creation time. " "Default value set to 30 days")}}, {token_refresh_age, #{value => "timeout()", From aa8957f1373a602b389584484267f6511efd553e Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 2 Jan 2025 18:24:30 +0100 Subject: [PATCH 009/170] make-binaries: Bump dependency versions --- .github/workflows/runtime.yml | 4 ++-- tools/make-binaries | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/runtime.yml b/.github/workflows/runtime.yml index 7e0b6351868..076798aba96 100644 --- a/.github/workflows/runtime.yml +++ b/.github/workflows/runtime.yml @@ -164,7 +164,7 @@ jobs: strategy: fail-fast: false matrix: - elixir: ['1.13', '1.14', '1.15', '1.16', '1.17'] + elixir: ['1.13', '1.14', '1.15', '1.16', '1.17', '1.18'] runs-on: ubuntu-24.04 container: image: elixir:${{ matrix.elixir }} @@ -287,7 +287,7 @@ jobs: strategy: fail-fast: false matrix: - elixir: ['1.13', '1.14', '1.15', '1.16', '1.17'] + elixir: ['1.13', '1.14', '1.15', '1.16', '1.17', '1.18'] runs-on: ubuntu-24.04 container: image: elixir:${{ matrix.elixir }} diff --git a/tools/make-binaries b/tools/make-binaries index 98cd0121347..36b29d3643f 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -70,16 +70,16 @@ termcap_vsn='1.3.1' expat_vsn='2.6.4' zlib_vsn='1.3.1' yaml_vsn='0.2.5' -ssl_vsn='3.3.2' +ssl_vsn='3.4.0' otp_vsn='26.2.5.4' -elixir_vsn='1.17.2' +elixir_vsn='1.18.1' pam_vsn='1.6.1' -png_vsn='1.6.43' +png_vsn='1.6.44' jpeg_vsn='9f' -webp_vsn='1.4.0' +webp_vsn='1.5.0' gd_vsn='2.3.3' odbc_vsn='2.3.12' -sqlite_vsn='3460100' +sqlite_vsn='3470200' root_dir="${BUILD_DIR:-$HOME/build}" bootstrap_dir="$root_dir/bootstrap" ct_prefix_dir="$root_dir/x-tools" From 2b2551bc5070f01a99fc88cfa2bc24b474285ea1 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Thu, 2 Jan 2025 18:25:24 +0100 Subject: [PATCH 010/170] make-binaries: Bump Erlang/OTP version to 27.2 --- .github/workflows/ci.yml | 6 +++--- tools/make-binaries | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6cfb4b6bce..d95bcc15563 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v4 - name: Test shell scripts - if: matrix.otp == '26' + if: matrix.otp == '27' run: | shellcheck test/ejabberd_SUITE_data/gencerts.sh shellcheck tools/captcha.sh @@ -153,7 +153,7 @@ jobs: grep -q "is started in" $RE/logs/ejabberd.log - name: Run XMPP Interoperability Tests against CI server. - if: matrix.otp == '26' + if: matrix.otp == '27' continue-on-error: true uses: XMPP-Interop-Testing/xmpp-interop-tests-action@v1.4.0 with: @@ -203,7 +203,7 @@ jobs: find logs/ -name exunit.log -exec cat '{}' ';' - name: Send to coveralls - if: matrix.otp == '26' + if: matrix.otp == '27' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/tools/make-binaries b/tools/make-binaries index 36b29d3643f..5c92b241bb8 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -71,7 +71,7 @@ expat_vsn='2.6.4' zlib_vsn='1.3.1' yaml_vsn='0.2.5' ssl_vsn='3.4.0' -otp_vsn='26.2.5.4' +otp_vsn='27.2' elixir_vsn='1.18.1' pam_vsn='1.6.1' png_vsn='1.6.44' From 172847bc761facc440e71b958406d251a6a2f6b0 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 30 Dec 2024 23:22:14 +0100 Subject: [PATCH 011/170] Update path to ejabberd-contrib section in Docs site --- src/ejabberd_options_doc.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 181599afa51..a3d081d4925 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -307,7 +307,7 @@ doc() -> #{value => "true | false", desc => ?T("Whether to allow installation of third-party modules or not. " - "See _`../../developer/extending-ejabberd/modules.md#ejabberd-contrib|ejabberd-contrib`_ " + "See _`../../admin/guide/modules.md#ejabberd-contrib|ejabberd-contrib`_ " "documentation section. " "The default value is 'true'.")}}, {allow_multiple_connections, @@ -368,7 +368,7 @@ doc() -> desc => ?T("This is used by the contributed module " "'ejabberd_auth_http' that can be installed from the " - "https://github.com/processone/ejabberd-contrib[ejabberd-contrib]" + "_`../../admin/guide/modules.md#ejabberd-contrib|ejabberd-contrib`_ " "Git repository. Please refer to that " "module's README file for details.")}}, {auth_password_format, @@ -719,7 +719,7 @@ doc() -> note => "added in 23.10", desc => ?T("Modules to install from " - "_`../../developer/extending-ejabberd/modules.md#ejabberd-contrib|ejabberd-contrib`_ " + "_`../../admin/guide/modules.md#ejabberd-contrib|ejabberd-contrib`_ " "at start time. " "The default value is an empty list of modules: '[]'.")}}, {jwt_auth_only_rule, From 13dae75d01be002d2890d398480f7b3f4d328371 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 3 Jan 2025 11:24:51 +0100 Subject: [PATCH 012/170] Partially revert "Workflows: Bump ubuntu from 22.04 to 24.04 when possible (#4281)" ubuntu-24.04 includes texinfo 7.1, which has a problematic bug. Let's revert to ubuntu-22.04 until 24.04 includes a fixed texinfo. URL to keep an eye: https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md This partially reverts commit d3baacd78eea597713e3a960537dc919dc085b04. --- .github/workflows/container.yml | 2 +- .github/workflows/installers.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 40873eb60d9..33ae16960a6 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -19,7 +19,7 @@ env: jobs: container: name: Container - runs-on: ubuntu-24.04 + runs-on: ubuntu-22.04 permissions: packages: write steps: diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index 59db4a81e4c..b820dd6d9e4 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -21,7 +21,7 @@ on: jobs: binaries: name: Binaries - runs-on: ubuntu-24.04 + runs-on: ubuntu-22.04 steps: - name: Cache build directory uses: actions/cache@v4 @@ -70,7 +70,7 @@ jobs: release: name: Release needs: [binaries] - runs-on: ubuntu-24.04 + runs-on: ubuntu-22.04 if: github.ref_type == 'tag' steps: - name: Download packages From 8ebbb45a19d3ab9f194e3a805af2114238828f3c Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 3 Jan 2025 11:40:17 +0100 Subject: [PATCH 013/170] Update copyright year to 2025 (#4139) --- include/bosh.hrl | 2 +- include/ejabberd_auth.hrl | 2 +- include/ejabberd_commands.hrl | 2 +- include/ejabberd_ctl.hrl | 2 +- include/ejabberd_http.hrl | 2 +- include/ejabberd_oauth.hrl | 2 +- include/ejabberd_sm.hrl | 2 +- include/ejabberd_sql.hrl | 2 +- include/ejabberd_sql_pt.hrl | 2 +- include/ejabberd_stacktrace.hrl | 2 +- include/ejabberd_web_admin.hrl | 2 +- include/eldap.hrl | 2 +- include/http_bind.hrl | 2 +- include/logger.hrl | 2 +- include/mod_announce.hrl | 2 +- include/mod_caps.hrl | 2 +- include/mod_last.hrl | 2 +- include/mod_mam.hrl | 2 +- include/mod_matrix_gw.hrl | 2 +- include/mod_muc.hrl | 2 +- include/mod_muc_room.hrl | 2 +- include/mod_offline.hrl | 2 +- include/mod_privacy.hrl | 2 +- include/mod_private.hrl | 2 +- include/mod_proxy65.hrl | 2 +- include/mod_push.hrl | 2 +- include/mod_roster.hrl | 2 +- include/mod_shared_roster.hrl | 2 +- include/mod_vcard.hrl | 2 +- include/mqtt.hrl | 2 +- include/pubsub.hrl | 2 +- man/ejabberd.yml.5 | 2 +- rebar.config | 2 +- rebar.config.script | 2 +- rel/reltool.config.script | 2 +- sql/lite.new.sql | 2 +- sql/lite.sql | 2 +- sql/mssql.new.sql | 2 +- sql/mssql.sql | 2 +- sql/mysql.new.sql | 2 +- sql/mysql.sql | 2 +- sql/pg.new.sql | 2 +- sql/pg.sql | 2 +- src/acl.erl | 2 +- src/econf.erl | 2 +- src/ejabberd.erl | 2 +- src/ejabberd_access_permissions.erl | 2 +- src/ejabberd_acme.erl | 2 +- src/ejabberd_admin.erl | 2 +- src/ejabberd_app.erl | 2 +- src/ejabberd_auth.erl | 2 +- src/ejabberd_auth_anonymous.erl | 2 +- src/ejabberd_auth_external.erl | 2 +- src/ejabberd_auth_jwt.erl | 2 +- src/ejabberd_auth_ldap.erl | 2 +- src/ejabberd_auth_mnesia.erl | 2 +- src/ejabberd_auth_pam.erl | 2 +- src/ejabberd_auth_sql.erl | 2 +- src/ejabberd_backend_sup.erl | 2 +- src/ejabberd_batch.erl | 2 +- src/ejabberd_bosh.erl | 2 +- src/ejabberd_c2s.erl | 2 +- src/ejabberd_c2s_config.erl | 2 +- src/ejabberd_captcha.erl | 2 +- src/ejabberd_cluster.erl | 2 +- src/ejabberd_cluster_mnesia.erl | 2 +- src/ejabberd_commands.erl | 2 +- src/ejabberd_commands_doc.erl | 2 +- src/ejabberd_config.erl | 2 +- src/ejabberd_config_transformer.erl | 2 +- src/ejabberd_ctl.erl | 2 +- src/ejabberd_db_sup.erl | 2 +- src/ejabberd_doc.erl | 2 +- src/ejabberd_hooks.erl | 2 +- src/ejabberd_http.erl | 2 +- src/ejabberd_http_ws.erl | 2 +- src/ejabberd_iq.erl | 2 +- src/ejabberd_listener.erl | 2 +- src/ejabberd_local.erl | 2 +- src/ejabberd_logger.erl | 2 +- src/ejabberd_mnesia.erl | 2 +- src/ejabberd_oauth.erl | 2 +- src/ejabberd_oauth_mnesia.erl | 2 +- src/ejabberd_oauth_rest.erl | 2 +- src/ejabberd_oauth_sql.erl | 2 +- src/ejabberd_old_config.erl | 2 +- src/ejabberd_options.erl | 2 +- src/ejabberd_options_doc.erl | 2 +- src/ejabberd_piefxis.erl | 2 +- src/ejabberd_pkix.erl | 2 +- src/ejabberd_redis.erl | 2 +- src/ejabberd_redis_sup.erl | 2 +- src/ejabberd_regexp.erl | 2 +- src/ejabberd_router.erl | 2 +- src/ejabberd_router_mnesia.erl | 2 +- src/ejabberd_router_multicast.erl | 2 +- src/ejabberd_router_redis.erl | 2 +- src/ejabberd_router_sql.erl | 2 +- src/ejabberd_s2s.erl | 2 +- src/ejabberd_s2s_in.erl | 2 +- src/ejabberd_s2s_out.erl | 2 +- src/ejabberd_service.erl | 2 +- src/ejabberd_shaper.erl | 2 +- src/ejabberd_sip.erl | 2 +- src/ejabberd_sm.erl | 2 +- src/ejabberd_sm_mnesia.erl | 2 +- src/ejabberd_sm_redis.erl | 2 +- src/ejabberd_sm_sql.erl | 2 +- src/ejabberd_sql.erl | 2 +- src/ejabberd_sql_pt.erl | 2 +- src/ejabberd_sql_schema.erl | 2 +- src/ejabberd_sql_sup.erl | 2 +- src/ejabberd_stun.erl | 2 +- src/ejabberd_sup.erl | 2 +- src/ejabberd_system_monitor.erl | 2 +- src/ejabberd_tmp_sup.erl | 2 +- src/ejabberd_update.erl | 2 +- src/ejabberd_web.erl | 2 +- src/ejabberd_web_admin.erl | 4 ++-- src/ejabberd_websocket.erl | 2 +- src/ejabberd_websocket_codec.erl | 2 +- src/ejabberd_xmlrpc.erl | 2 +- src/ejd2sql.erl | 2 +- src/eldap_filter.erl | 2 +- src/eldap_pool.erl | 2 +- src/eldap_utils.erl | 2 +- src/elixir_logger_backend.erl | 2 +- src/ext_mod.erl | 2 +- src/extauth.erl | 2 +- src/extauth_sup.erl | 2 +- src/gen_iq_handler.erl | 2 +- src/gen_mod.erl | 2 +- src/gen_pubsub_node.erl | 2 +- src/gen_pubsub_nodetree.erl | 2 +- src/jd2ejd.erl | 2 +- src/misc.erl | 2 +- src/mod_adhoc.erl | 2 +- src/mod_admin_extra.erl | 2 +- src/mod_admin_update_sql.erl | 2 +- src/mod_announce.erl | 2 +- src/mod_announce_mnesia.erl | 2 +- src/mod_announce_sql.erl | 2 +- src/mod_auth_fast.erl | 2 +- src/mod_auth_fast_mnesia.erl | 2 +- src/mod_avatar.erl | 2 +- src/mod_block_strangers.erl | 2 +- src/mod_blocking.erl | 2 +- src/mod_bosh.erl | 2 +- src/mod_bosh_mnesia.erl | 2 +- src/mod_bosh_redis.erl | 2 +- src/mod_bosh_sql.erl | 2 +- src/mod_caps.erl | 2 +- src/mod_caps_mnesia.erl | 2 +- src/mod_caps_sql.erl | 2 +- src/mod_carboncopy.erl | 2 +- src/mod_client_state.erl | 2 +- src/mod_configure.erl | 2 +- src/mod_conversejs.erl | 2 +- src/mod_delegation.erl | 2 +- src/mod_disco.erl | 2 +- src/mod_fail2ban.erl | 2 +- src/mod_http_api.erl | 2 +- src/mod_http_fileserver.erl | 2 +- src/mod_http_upload.erl | 2 +- src/mod_http_upload_quota.erl | 2 +- src/mod_jidprep.erl | 2 +- src/mod_last.erl | 2 +- src/mod_last_mnesia.erl | 2 +- src/mod_last_sql.erl | 2 +- src/mod_legacy_auth.erl | 2 +- src/mod_mam.erl | 2 +- src/mod_mam_mnesia.erl | 2 +- src/mod_mam_sql.erl | 2 +- src/mod_matrix_gw.erl | 2 +- src/mod_matrix_gw_room.erl | 2 +- src/mod_matrix_gw_s2s.erl | 2 +- src/mod_matrix_gw_sup.erl | 2 +- src/mod_metrics.erl | 2 +- src/mod_mqtt.erl | 2 +- src/mod_mqtt_bridge.erl | 2 +- src/mod_mqtt_bridge_session.erl | 2 +- src/mod_mqtt_mnesia.erl | 2 +- src/mod_mqtt_session.erl | 2 +- src/mod_mqtt_sql.erl | 2 +- src/mod_mqtt_ws.erl | 2 +- src/mod_muc.erl | 2 +- src/mod_muc_admin.erl | 2 +- src/mod_muc_log.erl | 2 +- src/mod_muc_mnesia.erl | 2 +- src/mod_muc_occupantid.erl | 2 +- src/mod_muc_room.erl | 2 +- src/mod_muc_rtbl.erl | 2 +- src/mod_muc_sql.erl | 2 +- src/mod_muc_sup.erl | 2 +- src/mod_multicast.erl | 2 +- src/mod_offline.erl | 2 +- src/mod_offline_mnesia.erl | 2 +- src/mod_offline_sql.erl | 2 +- src/mod_ping.erl | 2 +- src/mod_pres_counter.erl | 2 +- src/mod_privacy.erl | 2 +- src/mod_privacy_mnesia.erl | 2 +- src/mod_privacy_sql.erl | 2 +- src/mod_private.erl | 2 +- src/mod_private_mnesia.erl | 2 +- src/mod_private_sql.erl | 2 +- src/mod_privilege.erl | 2 +- src/mod_proxy65.erl | 2 +- src/mod_proxy65_lib.erl | 2 +- src/mod_proxy65_mnesia.erl | 2 +- src/mod_proxy65_redis.erl | 2 +- src/mod_proxy65_service.erl | 2 +- src/mod_proxy65_sql.erl | 2 +- src/mod_proxy65_stream.erl | 2 +- src/mod_pubsub.erl | 2 +- src/mod_pubsub_mnesia.erl | 2 +- src/mod_pubsub_sql.erl | 2 +- src/mod_push.erl | 2 +- src/mod_push_keepalive.erl | 2 +- src/mod_push_mnesia.erl | 2 +- src/mod_push_sql.erl | 2 +- src/mod_register.erl | 2 +- src/mod_register_web.erl | 2 +- src/mod_roster.erl | 2 +- src/mod_roster_mnesia.erl | 2 +- src/mod_roster_sql.erl | 2 +- src/mod_s2s_bidi.erl | 2 +- src/mod_s2s_dialback.erl | 2 +- src/mod_scram_upgrade.erl | 2 +- src/mod_service_log.erl | 2 +- src/mod_shared_roster.erl | 2 +- src/mod_shared_roster_ldap.erl | 2 +- src/mod_shared_roster_mnesia.erl | 2 +- src/mod_shared_roster_sql.erl | 2 +- src/mod_sic.erl | 2 +- src/mod_sip.erl | 2 +- src/mod_sip_proxy.erl | 2 +- src/mod_sip_registrar.erl | 2 +- src/mod_stats.erl | 2 +- src/mod_stream_mgmt.erl | 2 +- src/mod_stun_disco.erl | 2 +- src/mod_time.erl | 2 +- src/mod_vcard.erl | 2 +- src/mod_vcard_ldap.erl | 2 +- src/mod_vcard_mnesia.erl | 2 +- src/mod_vcard_sql.erl | 2 +- src/mod_vcard_xupdate.erl | 2 +- src/mod_version.erl | 2 +- src/mqtt_codec.erl | 2 +- src/node_flat.erl | 2 +- src/node_flat_sql.erl | 2 +- src/node_pep.erl | 2 +- src/node_pep_sql.erl | 2 +- src/nodetree_tree.erl | 2 +- src/nodetree_tree_sql.erl | 2 +- src/nodetree_virtual.erl | 2 +- src/prosody2ejabberd.erl | 2 +- src/proxy_protocol.erl | 2 +- src/pubsub_db_sql.erl | 2 +- src/pubsub_index.erl | 2 +- src/pubsub_migrate.erl | 2 +- src/pubsub_subscription.erl | 2 +- src/pubsub_subscription_sql.erl | 2 +- src/rest.erl | 2 +- src/str.erl | 2 +- src/translate.erl | 2 +- src/win32_dns.erl | 2 +- test/announce_tests.erl | 2 +- test/carbons_tests.erl | 2 +- test/commands_tests.erl | 2 +- test/csi_tests.erl | 2 +- test/ejabberd_SUITE.erl | 2 +- test/example_tests.erl | 2 +- test/jidprep_tests.erl | 2 +- test/ldap_srv.erl | 2 +- test/mam_tests.erl | 2 +- test/muc_tests.erl | 2 +- test/offline_tests.erl | 2 +- test/privacy_tests.erl | 2 +- test/private_tests.erl | 2 +- test/proxy65_tests.erl | 2 +- test/pubsub_tests.erl | 2 +- test/push_tests.erl | 2 +- test/replaced_tests.erl | 2 +- test/roster_tests.erl | 2 +- test/sm_tests.erl | 2 +- test/stundisco_tests.erl | 2 +- test/suite.erl | 2 +- test/upload_tests.erl | 2 +- test/vcard_tests.erl | 2 +- test/webadmin_tests.erl | 2 +- tools/xml_compress_gen.erl | 2 +- vars.config.in | 2 +- 293 files changed, 294 insertions(+), 294 deletions(-) diff --git a/include/bosh.hrl b/include/bosh.hrl index dd853e6b236..dd9f1b6a1dc 100644 --- a/include/bosh.hrl +++ b/include/bosh.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_auth.hrl b/include/ejabberd_auth.hrl index 443cc322896..1f9117efbfd 100644 --- a/include/ejabberd_auth.hrl +++ b/include/ejabberd_auth.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_commands.hrl b/include/ejabberd_commands.hrl index a6a960d8c78..14d19d2e1fd 100644 --- a/include/ejabberd_commands.hrl +++ b/include/ejabberd_commands.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_ctl.hrl b/include/ejabberd_ctl.hrl index a93544b5c56..cad82da8968 100644 --- a/include/ejabberd_ctl.hrl +++ b/include/ejabberd_ctl.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_http.hrl b/include/ejabberd_http.hrl index 77ef5edb1a4..9e1373ce6bb 100644 --- a/include/ejabberd_http.hrl +++ b/include/ejabberd_http.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_oauth.hrl b/include/ejabberd_oauth.hrl index 7cb712a4946..4798d9070a0 100644 --- a/include/ejabberd_oauth.hrl +++ b/include/ejabberd_oauth.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_sm.hrl b/include/ejabberd_sm.hrl index cb9e9ae1955..54a828e1a7a 100644 --- a/include/ejabberd_sm.hrl +++ b/include/ejabberd_sm.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_sql.hrl b/include/ejabberd_sql.hrl index b5a4933fc78..d0ab55cba5f 100644 --- a/include/ejabberd_sql.hrl +++ b/include/ejabberd_sql.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_sql_pt.hrl b/include/ejabberd_sql_pt.hrl index 36ce4022552..f89f5c96950 100644 --- a/include/ejabberd_sql_pt.hrl +++ b/include/ejabberd_sql_pt.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_stacktrace.hrl b/include/ejabberd_stacktrace.hrl index 03cd78f6a9d..e65c5264f86 100644 --- a/include/ejabberd_stacktrace.hrl +++ b/include/ejabberd_stacktrace.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/ejabberd_web_admin.hrl b/include/ejabberd_web_admin.hrl index f2e5e582eec..45e4beadaf5 100644 --- a/include/ejabberd_web_admin.hrl +++ b/include/ejabberd_web_admin.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/eldap.hrl b/include/eldap.hrl index 3ae1047d05e..0b6dc97e5ba 100644 --- a/include/eldap.hrl +++ b/include/eldap.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/http_bind.hrl b/include/http_bind.hrl index d55e7bcca4b..ab1294e7dcc 100644 --- a/include/http_bind.hrl +++ b/include/http_bind.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/logger.hrl b/include/logger.hrl index 5518f5a1a2b..27c5ffdc8f8 100644 --- a/include/logger.hrl +++ b/include/logger.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_announce.hrl b/include/mod_announce.hrl index 7d680514e42..77badf90e01 100644 --- a/include/mod_announce.hrl +++ b/include/mod_announce.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_caps.hrl b/include/mod_caps.hrl index 29c1528feb3..ee1bbe44eac 100644 --- a/include/mod_caps.hrl +++ b/include/mod_caps.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_last.hrl b/include/mod_last.hrl index b0da17ce01b..b1c13621aa4 100644 --- a/include/mod_last.hrl +++ b/include/mod_last.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_mam.hrl b/include/mod_mam.hrl index bca473c6222..77ea54a5e88 100644 --- a/include/mod_mam.hrl +++ b/include/mod_mam.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_matrix_gw.hrl b/include/mod_matrix_gw.hrl index 7ebaa085437..18efbf25213 100644 --- a/include/mod_matrix_gw.hrl +++ b/include/mod_matrix_gw.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_muc.hrl b/include/mod_muc.hrl index 127b71579f3..f801b29e16c 100644 --- a/include/mod_muc.hrl +++ b/include/mod_muc.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_muc_room.hrl b/include/mod_muc_room.hrl index 1d0ca444279..1e90a7912a7 100644 --- a/include/mod_muc_room.hrl +++ b/include/mod_muc_room.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_offline.hrl b/include/mod_offline.hrl index 58e52aef2ed..e1bb236f631 100644 --- a/include/mod_offline.hrl +++ b/include/mod_offline.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_privacy.hrl b/include/mod_privacy.hrl index d6a1286e25a..8118a6de688 100644 --- a/include/mod_privacy.hrl +++ b/include/mod_privacy.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_private.hrl b/include/mod_private.hrl index 412ca8f2943..05adc7d8bab 100644 --- a/include/mod_private.hrl +++ b/include/mod_private.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_proxy65.hrl b/include/mod_proxy65.hrl index 1a309a6632a..4f017124adf 100644 --- a/include/mod_proxy65.hrl +++ b/include/mod_proxy65.hrl @@ -2,7 +2,7 @@ %%% RFC 1928 constants. %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_push.hrl b/include/mod_push.hrl index 5b6ea40c5f1..8a9de102bd6 100644 --- a/include/mod_push.hrl +++ b/include/mod_push.hrl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_roster.hrl b/include/mod_roster.hrl index 7e213fe69d6..a056dd22c9b 100644 --- a/include/mod_roster.hrl +++ b/include/mod_roster.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_shared_roster.hrl b/include/mod_shared_roster.hrl index 5fc9fd3c5f9..4c35878e8d5 100644 --- a/include/mod_shared_roster.hrl +++ b/include/mod_shared_roster.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mod_vcard.hrl b/include/mod_vcard.hrl index 56506f207fe..d97e5c9008f 100644 --- a/include/mod_vcard.hrl +++ b/include/mod_vcard.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/include/mqtt.hrl b/include/mqtt.hrl index e618914a624..bf910368f38 100644 --- a/include/mqtt.hrl +++ b/include/mqtt.hrl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/include/pubsub.hrl b/include/pubsub.hrl index e625e7f23aa..316be342a72 100644 --- a/include/pubsub.hrl +++ b/include/pubsub.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/man/ejabberd.yml.5 b/man/ejabberd.yml.5 index 52c726a7429..493aaee19b0 100644 --- a/man/ejabberd.yml.5 +++ b/man/ejabberd.yml.5 @@ -8110,4 +8110,4 @@ Configuration Guide: https://docs\&.ejabberd\&.im/admin/configuration Source code: https://github\&.com/processone/ejabberd .SH "COPYING" .sp -Copyright (c) 2002\-2024 ProcessOne\&. +Copyright (c) 2002\-2025 ProcessOne\&. diff --git a/rebar.config b/rebar.config index dbaf948e1c3..f367477cf48 100644 --- a/rebar.config +++ b/rebar.config @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/rebar.config.script b/rebar.config.script index 0b5c75d1533..e476df44885 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/rel/reltool.config.script b/rel/reltool.config.script index f1f0852d2f8..0a87ce73540 100644 --- a/rel/reltool.config.script +++ b/rel/reltool.config.script @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeniy Khramtsov -%%% @copyright (C) 2013-2024, Evgeniy Khramtsov +%%% @copyright (C) 2013-2025, Evgeniy Khramtsov %%% @doc %%% %%% @end diff --git a/sql/lite.new.sql b/sql/lite.new.sql index 34d3953a195..7248d080b40 100644 --- a/sql/lite.new.sql +++ b/sql/lite.new.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/lite.sql b/sql/lite.sql index 8ef925eae09..2958a96289f 100644 --- a/sql/lite.sql +++ b/sql/lite.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/mssql.new.sql b/sql/mssql.new.sql index d4220aabf6b..3e6817012fd 100644 --- a/sql/mssql.new.sql +++ b/sql/mssql.new.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/mssql.sql b/sql/mssql.sql index dc8e8cc1255..5ee11d880f8 100644 --- a/sql/mssql.sql +++ b/sql/mssql.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/mysql.new.sql b/sql/mysql.new.sql index afd9c6a075b..c5a4675b0ae 100644 --- a/sql/mysql.new.sql +++ b/sql/mysql.new.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/mysql.sql b/sql/mysql.sql index d013d782c58..479ccb435f3 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/pg.new.sql b/sql/pg.new.sql index ffc88368dcb..a7e79fee3b1 100644 --- a/sql/pg.new.sql +++ b/sql/pg.new.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/sql/pg.sql b/sql/pg.sql index ee559056446..2cc8d4c951b 100644 --- a/sql/pg.sql +++ b/sql/pg.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2024 ProcessOne +-- ejabberd, Copyright (C) 2002-2025 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/src/acl.erl b/src/acl.erl index 88ea0119e81..9daa373b391 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/econf.erl b/src/econf.erl index 0ffd05e4ef3..a2a884e76b6 100644 --- a/src/econf.erl +++ b/src/econf.erl @@ -3,7 +3,7 @@ %%% Purpose : Validator for ejabberd configuration options %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd.erl b/src/ejabberd.erl index a251003b3f1..579c9c628aa 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_access_permissions.erl b/src/ejabberd_access_permissions.erl index b4962488ba2..1889ca8dfa8 100644 --- a/src/ejabberd_access_permissions.erl +++ b/src/ejabberd_access_permissions.erl @@ -5,7 +5,7 @@ %%% Created : 7 Sep 2016 by Paweł Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_acme.erl b/src/ejabberd_acme.erl index dcd2bb428f1..8b16fc727c5 100644 --- a/src/ejabberd_acme.erl +++ b/src/ejabberd_acme.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 1c53872235a..2452e86b761 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -5,7 +5,7 @@ %%% Created : 7 May 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index fc9830fe976..9f93244941f 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 998dbe10f44..4ead00f487b 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -5,7 +5,7 @@ %%% Created : 23 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 7c1156ff6dd..8f67b695bec 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -5,7 +5,7 @@ %%% Created : 17 Feb 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index 33a58e83365..1b69a9a10ce 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_jwt.erl b/src/ejabberd_auth_jwt.erl index 6f8c16727c2..7fac3e4f76d 100644 --- a/src/ejabberd_auth_jwt.erl +++ b/src/ejabberd_auth_jwt.erl @@ -5,7 +5,7 @@ %%% Created : 16 Mar 2019 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index 096b56fc693..091e567a865 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl index 81faab2d2a1..6ed303fae69 100644 --- a/src/ejabberd_auth_mnesia.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index 17940640d1c..d795b0d6f27 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jul 2007 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_sql.erl b/src/ejabberd_auth_sql.erl index 49da353f7c0..fefabdf76d1 100644 --- a/src/ejabberd_auth_sql.erl +++ b/src/ejabberd_auth_sql.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_backend_sup.erl b/src/ejabberd_backend_sup.erl index 8a724955c1c..1b3495e3674 100644 --- a/src/ejabberd_backend_sup.erl +++ b/src/ejabberd_backend_sup.erl @@ -2,7 +2,7 @@ %%% Created : 24 Feb 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_batch.erl b/src/ejabberd_batch.erl index 750c5978fb2..5a907c74bd0 100644 --- a/src/ejabberd_batch.erl +++ b/src/ejabberd_batch.erl @@ -5,7 +5,7 @@ %%% Created : 8 mar 2022 by Paweł Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_bosh.erl b/src/ejabberd_bosh.erl index 0805f185736..8d1dbd5959c 100644 --- a/src/ejabberd_bosh.erl +++ b/src/ejabberd_bosh.erl @@ -5,7 +5,7 @@ %%% Created : 20 Jul 2011 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 06ba6fb02d5..c68e6ad30e7 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -2,7 +2,7 @@ %%% Created : 8 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_c2s_config.erl b/src/ejabberd_c2s_config.erl index 2abbbebd319..0c80ebec942 100644 --- a/src/ejabberd_c2s_config.erl +++ b/src/ejabberd_c2s_config.erl @@ -6,7 +6,7 @@ %%% Created : 2 Nov 2007 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index ed7408699e7..794041a1993 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -5,7 +5,7 @@ %%% Created : 26 Apr 2008 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_cluster.erl b/src/ejabberd_cluster.erl index ff85de059be..38a378d30b4 100644 --- a/src/ejabberd_cluster.erl +++ b/src/ejabberd_cluster.erl @@ -3,7 +3,7 @@ %%% Created : 5 Jul 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_cluster_mnesia.erl b/src/ejabberd_cluster_mnesia.erl index 91910ad6751..ada0703be4c 100644 --- a/src/ejabberd_cluster_mnesia.erl +++ b/src/ejabberd_cluster_mnesia.erl @@ -5,7 +5,7 @@ %%% Created : 7 Oct 2015 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index a2d4bf525b5..5028f05fc4c 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -5,7 +5,7 @@ %%% Created : 20 May 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_commands_doc.erl b/src/ejabberd_commands_doc.erl index 7b0b462461f..b4780fee93e 100644 --- a/src/ejabberd_commands_doc.erl +++ b/src/ejabberd_commands_doc.erl @@ -5,7 +5,7 @@ %%% Created : 20 May 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 8b63cc7bba1..8b55be2db36 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -5,7 +5,7 @@ %%% Created : 14 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_config_transformer.erl b/src/ejabberd_config_transformer.erl index 87a87a824c4..a04e8771f9a 100644 --- a/src/ejabberd_config_transformer.erl +++ b/src/ejabberd_config_transformer.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 14780278af4..6fcd46e1ca1 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jan 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_db_sup.erl b/src/ejabberd_db_sup.erl index 9f9ce11df17..192c355c383 100644 --- a/src/ejabberd_db_sup.erl +++ b/src/ejabberd_db_sup.erl @@ -2,7 +2,7 @@ %%% Created : 13 June 2019 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_doc.erl b/src/ejabberd_doc.erl index 053e5826cf9..ce030c22183 100644 --- a/src/ejabberd_doc.erl +++ b/src/ejabberd_doc.erl @@ -2,7 +2,7 @@ %%% File : ejabberd_doc.erl %%% Purpose : Options documentation generator %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 4ef95d0ff1d..39a8c812cf6 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -5,7 +5,7 @@ %%% Created : 8 Aug 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index 912b25b427d..76fd80c4007 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -5,7 +5,7 @@ %%% Created : 27 Feb 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_http_ws.erl b/src/ejabberd_http_ws.erl index 60daea68576..c14ed2d587f 100644 --- a/src/ejabberd_http_ws.erl +++ b/src/ejabberd_http_ws.erl @@ -5,7 +5,7 @@ %%% Created : 09-10-2010 by Eric Cestari %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_iq.erl b/src/ejabberd_iq.erl index bddfb51985a..507820b20bc 100644 --- a/src/ejabberd_iq.erl +++ b/src/ejabberd_iq.erl @@ -5,7 +5,7 @@ %%% Created : 10 Nov 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index e749d23e9ee..2412eb54542 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 6c9ca918dff..34735cd2cd2 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -5,7 +5,7 @@ %%% Created : 30 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_logger.erl b/src/ejabberd_logger.erl index ced5378fc22..746925b2997 100644 --- a/src/ejabberd_logger.erl +++ b/src/ejabberd_logger.erl @@ -5,7 +5,7 @@ %%% Created : 12 May 2013 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2013-2024 ProcessOne +%%% ejabberd, Copyright (C) 2013-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_mnesia.erl b/src/ejabberd_mnesia.erl index da817f27fa0..f3191b9108b 100644 --- a/src/ejabberd_mnesia.erl +++ b/src/ejabberd_mnesia.erl @@ -5,7 +5,7 @@ %%% Created : 17 Nov 2016 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 8c42dbe775e..5275673fef8 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -5,7 +5,7 @@ %%% Created : 20 Mar 2015 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_oauth_mnesia.erl b/src/ejabberd_oauth_mnesia.erl index 649fdb87c3c..37fa3285c8c 100644 --- a/src/ejabberd_oauth_mnesia.erl +++ b/src/ejabberd_oauth_mnesia.erl @@ -5,7 +5,7 @@ %%% Created : 20 Jul 2016 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_oauth_rest.erl b/src/ejabberd_oauth_rest.erl index e38dceffe64..b7200872add 100644 --- a/src/ejabberd_oauth_rest.erl +++ b/src/ejabberd_oauth_rest.erl @@ -5,7 +5,7 @@ %%% Created : 26 Jul 2016 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_oauth_sql.erl b/src/ejabberd_oauth_sql.erl index 17c38f20c8f..fe0a159ad1a 100644 --- a/src/ejabberd_oauth_sql.erl +++ b/src/ejabberd_oauth_sql.erl @@ -5,7 +5,7 @@ %%% Created : 27 Jul 2016 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_old_config.erl b/src/ejabberd_old_config.erl index cee8f61941c..670dd715835 100644 --- a/src/ejabberd_old_config.erl +++ b/src/ejabberd_old_config.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% Purpose: Transform old-style Erlang config to YAML config %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index 66633d10759..673de29d7e9 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index a3d081d4925..380b2b6054f 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl index 4cf39328a27..789be7359d1 100644 --- a/src/ejabberd_piefxis.erl +++ b/src/ejabberd_piefxis.erl @@ -5,7 +5,7 @@ %%% Created : 17 Jul 2008 by Pablo Polvorin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_pkix.erl b/src/ejabberd_pkix.erl index 6a9f08e8a49..b699454ddc8 100644 --- a/src/ejabberd_pkix.erl +++ b/src/ejabberd_pkix.erl @@ -3,7 +3,7 @@ %%% Created : 4 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_redis.erl b/src/ejabberd_redis.erl index 46fe8ce9055..27e8775e1b8 100644 --- a/src/ejabberd_redis.erl +++ b/src/ejabberd_redis.erl @@ -4,7 +4,7 @@ %%% Created : 8 May 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_redis_sup.erl b/src/ejabberd_redis_sup.erl index 350f1292d74..8d49f4632b1 100644 --- a/src/ejabberd_redis_sup.erl +++ b/src/ejabberd_redis_sup.erl @@ -3,7 +3,7 @@ %%% Created : 6 Apr 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_regexp.erl b/src/ejabberd_regexp.erl index d474f112751..7644810cda1 100644 --- a/src/ejabberd_regexp.erl +++ b/src/ejabberd_regexp.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2011 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 8f877dfaf95..2d80314c7c4 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -5,7 +5,7 @@ %%% Created : 27 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_router_mnesia.erl b/src/ejabberd_router_mnesia.erl index f53ee679f81..66ae0220831 100644 --- a/src/ejabberd_router_mnesia.erl +++ b/src/ejabberd_router_mnesia.erl @@ -2,7 +2,7 @@ %%% Created : 11 Jan 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_router_multicast.erl b/src/ejabberd_router_multicast.erl index 312718fd781..df8473c2bca 100644 --- a/src/ejabberd_router_multicast.erl +++ b/src/ejabberd_router_multicast.erl @@ -5,7 +5,7 @@ %%% Created : 11 Aug 2007 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_router_redis.erl b/src/ejabberd_router_redis.erl index 8ffde1f6ae8..0ddd63aa728 100644 --- a/src/ejabberd_router_redis.erl +++ b/src/ejabberd_router_redis.erl @@ -3,7 +3,7 @@ %%% Created : 28 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_router_sql.erl b/src/ejabberd_router_sql.erl index 03e617654ac..ad120d82fb5 100644 --- a/src/ejabberd_router_sql.erl +++ b/src/ejabberd_router_sql.erl @@ -3,7 +3,7 @@ %%% Created : 28 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 7c9a041fa24..44877361224 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -5,7 +5,7 @@ %%% Created : 7 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 1af45a161a7..e065f8418fd 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -2,7 +2,7 @@ %%% Created : 12 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 55903a519f1..0bb384732ff 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -2,7 +2,7 @@ %%% Created : 16 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 5bc92a0a239..5947fea2bb4 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -2,7 +2,7 @@ %%% Created : 11 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_shaper.erl b/src/ejabberd_shaper.erl index 930f8674b9e..c47d72dbd37 100644 --- a/src/ejabberd_shaper.erl +++ b/src/ejabberd_shaper.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sip.erl b/src/ejabberd_sip.erl index 4991629662e..d39aa5d30ce 100644 --- a/src/ejabberd_sip.erl +++ b/src/ejabberd_sip.erl @@ -5,7 +5,7 @@ %%% Created : 30 Apr 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2013-2024 ProcessOne +%%% ejabberd, Copyright (C) 2013-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 4745c57d93a..c1d970d845a 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -5,7 +5,7 @@ %%% Created : 24 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sm_mnesia.erl b/src/ejabberd_sm_mnesia.erl index 26b4c6806f3..a826879633a 100644 --- a/src/ejabberd_sm_mnesia.erl +++ b/src/ejabberd_sm_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 9 Mar 2015 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sm_redis.erl b/src/ejabberd_sm_redis.erl index 3a7a0f99a95..8e63cdcec40 100644 --- a/src/ejabberd_sm_redis.erl +++ b/src/ejabberd_sm_redis.erl @@ -4,7 +4,7 @@ %%% Created : 11 Mar 2015 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sm_sql.erl b/src/ejabberd_sm_sql.erl index df8e0970d57..bef3774e150 100644 --- a/src/ejabberd_sm_sql.erl +++ b/src/ejabberd_sm_sql.erl @@ -4,7 +4,7 @@ %%% Created : 9 Mar 2015 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sql.erl b/src/ejabberd_sql.erl index 117609182d7..e6e06bc402b 100644 --- a/src/ejabberd_sql.erl +++ b/src/ejabberd_sql.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sql_pt.erl b/src/ejabberd_sql_pt.erl index 8484183d96d..365cc2b472b 100644 --- a/src/ejabberd_sql_pt.erl +++ b/src/ejabberd_sql_pt.erl @@ -5,7 +5,7 @@ %%% Created : 20 Jan 2016 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sql_schema.erl b/src/ejabberd_sql_schema.erl index 644844714f7..f798af5b832 100644 --- a/src/ejabberd_sql_schema.erl +++ b/src/ejabberd_sql_schema.erl @@ -5,7 +5,7 @@ %%% Created : 15 Aug 2023 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sql_sup.erl b/src/ejabberd_sql_sup.erl index 984f59f62ef..41482835833 100644 --- a/src/ejabberd_sql_sup.erl +++ b/src/ejabberd_sql_sup.erl @@ -5,7 +5,7 @@ %%% Created : 22 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_stun.erl b/src/ejabberd_stun.erl index ba99712e389..cc7bb472f6a 100644 --- a/src/ejabberd_stun.erl +++ b/src/ejabberd_stun.erl @@ -5,7 +5,7 @@ %%% Created : 8 May 2014 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2013-2024 ProcessOne +%%% ejabberd, Copyright (C) 2013-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 0977265a68b..3fa0fee0fbf 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 4e24f4e8c50..35a1f037097 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -5,7 +5,7 @@ %%% Created : 21 Mar 2007 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_tmp_sup.erl b/src/ejabberd_tmp_sup.erl index 70d01a2362a..7d26e615469 100644 --- a/src/ejabberd_tmp_sup.erl +++ b/src/ejabberd_tmp_sup.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jul 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_update.erl b/src/ejabberd_update.erl index 17f4717dc89..6c80fe8e771 100644 --- a/src/ejabberd_update.erl +++ b/src/ejabberd_update.erl @@ -5,7 +5,7 @@ %%% Created : 27 Jan 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_web.erl b/src/ejabberd_web.erl index b9dcd7943f1..e6090f2d810 100644 --- a/src/ejabberd_web.erl +++ b/src/ejabberd_web.erl @@ -5,7 +5,7 @@ %%% Created : 28 Feb 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl index 1b945c79497..02cd3c13d9a 100644 --- a/src/ejabberd_web_admin.erl +++ b/src/ejabberd_web_admin.erl @@ -5,7 +5,7 @@ %%% Created : 9 Apr 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -369,7 +369,7 @@ make_xhtml(Els, Host, Node, Username, #request{lang = Lang} = R, JID, Level) -> [?XE(<<"p">>, [?AC(<<"https://www.ejabberd.im/">>, <<"ejabberd">>), ?C(<<" ">>), ?C(ejabberd_option:version()), - ?C(<<" (c) 2002-2024 ">>), + ?C(<<" (c) 2002-2025 ">>), ?AC(<<"https://www.process-one.net/">>, <<"ProcessOne, leader in messaging and push solutions">>)] )])])])]}}. diff --git a/src/ejabberd_websocket.erl b/src/ejabberd_websocket.erl index 474a64c51a9..43b6673d48d 100644 --- a/src/ejabberd_websocket.erl +++ b/src/ejabberd_websocket.erl @@ -33,7 +33,7 @@ %%% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %%% POSSIBILITY OF SUCH DAMAGE. %%% ========================================================================================================== -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%%---------------------------------------------------------------------- -module(ejabberd_websocket). diff --git a/src/ejabberd_websocket_codec.erl b/src/ejabberd_websocket_codec.erl index fb8c5586ddb..8dde29f5385 100644 --- a/src/ejabberd_websocket_codec.erl +++ b/src/ejabberd_websocket_codec.erl @@ -5,7 +5,7 @@ % Created : 9 sty 2023 by Paweł Chmielowski % % -% ejabberd, Copyright (C) 2002-2024 ProcessOne +% ejabberd, Copyright (C) 2002-2025 ProcessOne % % This program is free software; you can redistribute it and/or % modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_xmlrpc.erl b/src/ejabberd_xmlrpc.erl index e0e92216675..d257fea02a7 100644 --- a/src/ejabberd_xmlrpc.erl +++ b/src/ejabberd_xmlrpc.erl @@ -5,7 +5,7 @@ %%% Created : 21 Aug 2007 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejd2sql.erl b/src/ejd2sql.erl index 090bb32f066..263e98f1aa5 100644 --- a/src/ejd2sql.erl +++ b/src/ejd2sql.erl @@ -5,7 +5,7 @@ %%% Created : 22 Aug 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap_filter.erl b/src/eldap_filter.erl index be266954f07..3483e8b0271 100644 --- a/src/eldap_filter.erl +++ b/src/eldap_filter.erl @@ -6,7 +6,7 @@ %%% Author: Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap_pool.erl b/src/eldap_pool.erl index d35edbd7a75..78391eb1d16 100644 --- a/src/eldap_pool.erl +++ b/src/eldap_pool.erl @@ -5,7 +5,7 @@ %%% Created : 12 Nov 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap_utils.erl b/src/eldap_utils.erl index ddf9b8d559f..6225c5ccef2 100644 --- a/src/eldap_utils.erl +++ b/src/eldap_utils.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/elixir_logger_backend.erl b/src/elixir_logger_backend.erl index 0579528b727..e431dcef366 100644 --- a/src/elixir_logger_backend.erl +++ b/src/elixir_logger_backend.erl @@ -5,7 +5,7 @@ %%% Created : 9 March 2016 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 7416848da32..451467c6670 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -5,7 +5,7 @@ %%% Created : 19 Feb 2015 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2006-2024 ProcessOne +%%% ejabberd, Copyright (C) 2006-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/extauth.erl b/src/extauth.erl index 85bf4e6a792..b1acd4a7e04 100644 --- a/src/extauth.erl +++ b/src/extauth.erl @@ -2,7 +2,7 @@ %%% Created : 7 May 2018 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/extauth_sup.erl b/src/extauth_sup.erl index 723d73f74e3..40769cbc958 100644 --- a/src/extauth_sup.erl +++ b/src/extauth_sup.erl @@ -2,7 +2,7 @@ %%% Created : 7 May 2018 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index f4d6babbe33..a02e9178abd 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -5,7 +5,7 @@ %%% Created : 22 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 58d855938e5..9d40e0c1795 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -5,7 +5,7 @@ %%% Created : 24 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/gen_pubsub_node.erl b/src/gen_pubsub_node.erl index 82e308bc869..48b43a05bcd 100644 --- a/src/gen_pubsub_node.erl +++ b/src/gen_pubsub_node.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/gen_pubsub_nodetree.erl b/src/gen_pubsub_nodetree.erl index cd4be7f4740..6d958ae6254 100644 --- a/src/gen_pubsub_nodetree.erl +++ b/src/gen_pubsub_nodetree.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index f6bba4b8fdd..cf17acdd5e7 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -5,7 +5,7 @@ %%% Created : 2 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/misc.erl b/src/misc.erl index 233a03f1fb5..2bfb6ded855 100644 --- a/src/misc.erl +++ b/src/misc.erl @@ -8,7 +8,7 @@ %%% Created : 30 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index 7baf6bf0731..39f03ba535e 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Nov 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 79b523c9b33..d5149708faa 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -5,7 +5,7 @@ %%% Created : 10 Aug 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_admin_update_sql.erl b/src/mod_admin_update_sql.erl index 85d039495a5..917c8d2bca4 100644 --- a/src/mod_admin_update_sql.erl +++ b/src/mod_admin_update_sql.erl @@ -5,7 +5,7 @@ %%% Created : 9 Aug 2017 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_announce.erl b/src/mod_announce.erl index d7f98371663..366a81e428a 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -5,7 +5,7 @@ %%% Created : 11 Aug 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_announce_mnesia.erl b/src/mod_announce_mnesia.erl index e004d151c67..6e578e0010e 100644 --- a/src/mod_announce_mnesia.erl +++ b/src/mod_announce_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_announce_sql.erl b/src/mod_announce_sql.erl index 7b1f9bbc9af..2a2692d375c 100644 --- a/src/mod_announce_sql.erl +++ b/src/mod_announce_sql.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_auth_fast.erl b/src/mod_auth_fast.erl index aa40e8f1ac8..0cad39b85a1 100644 --- a/src/mod_auth_fast.erl +++ b/src/mod_auth_fast.erl @@ -4,7 +4,7 @@ %%% Created : 1 Dec 2024 by Pawel Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_auth_fast_mnesia.erl b/src/mod_auth_fast_mnesia.erl index 4e70bc0fae2..53337b39029 100644 --- a/src/mod_auth_fast_mnesia.erl +++ b/src/mod_auth_fast_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 1 Dec 2024 by Pawel Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_avatar.erl b/src/mod_avatar.erl index e404d7d2051..e5fc3503b06 100644 --- a/src/mod_avatar.erl +++ b/src/mod_avatar.erl @@ -3,7 +3,7 @@ %%% Created : 13 Sep 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_block_strangers.erl b/src/mod_block_strangers.erl index 26b8e73d0e3..c0a85faf10a 100644 --- a/src/mod_block_strangers.erl +++ b/src/mod_block_strangers.erl @@ -5,7 +5,7 @@ %%% Created : 25 Dec 2016 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_blocking.erl b/src/mod_blocking.erl index da0913e9344..562899c3b6a 100644 --- a/src/mod_blocking.erl +++ b/src/mod_blocking.erl @@ -5,7 +5,7 @@ %%% Created : 24 Aug 2008 by Stephan Maka %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_bosh.erl b/src/mod_bosh.erl index cd2fea99b7f..5f70a4ea9b8 100644 --- a/src/mod_bosh.erl +++ b/src/mod_bosh.erl @@ -7,7 +7,7 @@ %%% Created : 20 Jul 2011 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_bosh_mnesia.erl b/src/mod_bosh_mnesia.erl index e396dbbd983..7ac19df01d4 100644 --- a/src/mod_bosh_mnesia.erl +++ b/src/mod_bosh_mnesia.erl @@ -2,7 +2,7 @@ %%% Created : 12 Jan 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_bosh_redis.erl b/src/mod_bosh_redis.erl index 6337540c058..efd05a7bae8 100644 --- a/src/mod_bosh_redis.erl +++ b/src/mod_bosh_redis.erl @@ -5,7 +5,7 @@ %%% Created : 28 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_bosh_sql.erl b/src/mod_bosh_sql.erl index 643928fe1f8..29549ed49bf 100644 --- a/src/mod_bosh_sql.erl +++ b/src/mod_bosh_sql.erl @@ -5,7 +5,7 @@ %%% Created : 28 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 5468f8fee20..79ae36edced 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -5,7 +5,7 @@ %%% Created : 7 Oct 2006 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_caps_mnesia.erl b/src/mod_caps_mnesia.erl index 1b83705eb7a..a0dc48c4f5b 100644 --- a/src/mod_caps_mnesia.erl +++ b/src/mod_caps_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_caps_sql.erl b/src/mod_caps_sql.erl index 06449175a4a..9d96697e760 100644 --- a/src/mod_caps_sql.erl +++ b/src/mod_caps_sql.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index ef1aa97caa4..dfd723c9920 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -7,7 +7,7 @@ %%% {mod_carboncopy, []} %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl index c56207464ac..67f9737842f 100644 --- a/src/mod_client_state.erl +++ b/src/mod_client_state.erl @@ -5,7 +5,7 @@ %%% Created : 11 Sep 2014 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2014-2024 ProcessOne +%%% ejabberd, Copyright (C) 2014-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 947333f84ad..d213ae9d957 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -5,7 +5,7 @@ %%% Created : 19 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_conversejs.erl b/src/mod_conversejs.erl index b932d862eae..3673f345fc8 100644 --- a/src/mod_conversejs.erl +++ b/src/mod_conversejs.erl @@ -5,7 +5,7 @@ %%% Created : 8 Nov 2021 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_delegation.erl b/src/mod_delegation.erl index 12e2fcd5099..f6879ea7ffe 100644 --- a/src/mod_delegation.erl +++ b/src/mod_delegation.erl @@ -4,7 +4,7 @@ %%% Purpose : XEP-0355: Namespace Delegation %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 34d6689750d..3dbecf6a90b 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -5,7 +5,7 @@ %%% Created : 1 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_fail2ban.erl b/src/mod_fail2ban.erl index 3ed3a981071..2680248e5d5 100644 --- a/src/mod_fail2ban.erl +++ b/src/mod_fail2ban.erl @@ -5,7 +5,7 @@ %%% Created : 15 Aug 2014 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2014-2024 ProcessOne +%%% ejabberd, Copyright (C) 2014-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index b78f7c6e30b..219267ef931 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -5,7 +5,7 @@ %%% Created : 15 Sep 2014 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_http_fileserver.erl b/src/mod_http_fileserver.erl index 19d59c958eb..3f8db94f559 100644 --- a/src/mod_http_fileserver.erl +++ b/src/mod_http_fileserver.erl @@ -5,7 +5,7 @@ %%% Created : %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_http_upload.erl b/src/mod_http_upload.erl index 1b67a518bf3..fddf27f46ee 100644 --- a/src/mod_http_upload.erl +++ b/src/mod_http_upload.erl @@ -5,7 +5,7 @@ %%% Created : 20 Aug 2015 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2015-2024 ProcessOne +%%% ejabberd, Copyright (C) 2015-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_http_upload_quota.erl b/src/mod_http_upload_quota.erl index 4e522a83b6e..76b99ca056d 100644 --- a/src/mod_http_upload_quota.erl +++ b/src/mod_http_upload_quota.erl @@ -5,7 +5,7 @@ %%% Created : 15 Oct 2015 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2015-2024 ProcessOne +%%% ejabberd, Copyright (C) 2015-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_jidprep.erl b/src/mod_jidprep.erl index 75a0c7280d8..3de051156c9 100644 --- a/src/mod_jidprep.erl +++ b/src/mod_jidprep.erl @@ -5,7 +5,7 @@ %%% Created : 11 Sep 2019 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2019-2024 ProcessOne +%%% ejabberd, Copyright (C) 2019-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_last.erl b/src/mod_last.erl index b839ccf9afa..ed701ea50ea 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -5,7 +5,7 @@ %%% Created : 24 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_last_mnesia.erl b/src/mod_last_mnesia.erl index f4ce111cf82..f108101c969 100644 --- a/src/mod_last_mnesia.erl +++ b/src/mod_last_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_last_sql.erl b/src/mod_last_sql.erl index 317dc1daa14..b61300fd2f1 100644 --- a/src/mod_last_sql.erl +++ b/src/mod_last_sql.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_legacy_auth.erl b/src/mod_legacy_auth.erl index 24129926e7f..1fb772d2c93 100644 --- a/src/mod_legacy_auth.erl +++ b/src/mod_legacy_auth.erl @@ -2,7 +2,7 @@ %%% Created : 11 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 198a3373806..1e2d13f3d2d 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -5,7 +5,7 @@ %%% Created : 4 Jul 2013 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2013-2024 ProcessOne +%%% ejabberd, Copyright (C) 2013-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl index f643da1fc5f..0895c994fe4 100644 --- a/src/mod_mam_mnesia.erl +++ b/src/mod_mam_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 15 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_mam_sql.erl b/src/mod_mam_sql.erl index 2646b0397c5..de97eaaa5d1 100644 --- a/src/mod_mam_sql.erl +++ b/src/mod_mam_sql.erl @@ -4,7 +4,7 @@ %%% Created : 15 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_matrix_gw.erl b/src/mod_matrix_gw.erl index d880d745e80..aefbba9242d 100644 --- a/src/mod_matrix_gw.erl +++ b/src/mod_matrix_gw.erl @@ -5,7 +5,7 @@ %%% Created : 23 Apr 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 6ceff2141ef..aeedc599fd8 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -5,7 +5,7 @@ %%% Created : 1 May 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_matrix_gw_s2s.erl b/src/mod_matrix_gw_s2s.erl index 533f250c57c..ceeb0708c36 100644 --- a/src/mod_matrix_gw_s2s.erl +++ b/src/mod_matrix_gw_s2s.erl @@ -5,7 +5,7 @@ %%% Created : 1 May 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_matrix_gw_sup.erl b/src/mod_matrix_gw_sup.erl index f7730a26612..f08f36e6859 100644 --- a/src/mod_matrix_gw_sup.erl +++ b/src/mod_matrix_gw_sup.erl @@ -2,7 +2,7 @@ %%% Created : 1 May 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl index 00257ed4246..77b690867a5 100644 --- a/src/mod_metrics.erl +++ b/src/mod_metrics.erl @@ -5,7 +5,7 @@ %%% Created : 22 Oct 2015 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_mqtt.erl b/src/mod_mqtt.erl index 974b035494d..e38c7aae6a6 100644 --- a/src/mod_mqtt.erl +++ b/src/mod_mqtt.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_mqtt_bridge.erl b/src/mod_mqtt_bridge.erl index 2842d18ef7b..cb60594e9b8 100644 --- a/src/mod_mqtt_bridge.erl +++ b/src/mod_mqtt_bridge.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Pawel Chmielowski -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_mqtt_bridge_session.erl b/src/mod_mqtt_bridge_session.erl index 887883ac4f7..1c5f53f9d74 100644 --- a/src/mod_mqtt_bridge_session.erl +++ b/src/mod_mqtt_bridge_session.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Pawel Chmielowski -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_mqtt_mnesia.erl b/src/mod_mqtt_mnesia.erl index efab7322416..5c2902d2bd2 100644 --- a/src/mod_mqtt_mnesia.erl +++ b/src/mod_mqtt_mnesia.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_mqtt_session.erl b/src/mod_mqtt_session.erl index c5a17756531..c6d0338d9be 100644 --- a/src/mod_mqtt_session.erl +++ b/src/mod_mqtt_session.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_mqtt_sql.erl b/src/mod_mqtt_sql.erl index f7bfea717b2..0f2b05b3574 100644 --- a/src/mod_mqtt_sql.erl +++ b/src/mod_mqtt_sql.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_mqtt_ws.erl b/src/mod_mqtt_ws.erl index b9e1623b84f..fd1e7d871f0 100644 --- a/src/mod_mqtt_ws.erl +++ b/src/mod_mqtt_ws.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 2e617f8a7b2..ca9d21800b0 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -5,7 +5,7 @@ %%% Created : 19 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 3f4c1c6a830..6c4c9d3a44d 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -5,7 +5,7 @@ %%% Created : 8 Sep 2007 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index 84d9abf347a..c075b954cf0 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -5,7 +5,7 @@ %%% Created : 12 Mar 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl index d5a89b36d8d..9e16a56c519 100644 --- a/src/mod_muc_mnesia.erl +++ b/src/mod_muc_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_occupantid.erl b/src/mod_muc_occupantid.erl index 6ae05a189e7..338697b34e2 100644 --- a/src/mod_muc_occupantid.erl +++ b/src/mod_muc_occupantid.erl @@ -5,7 +5,7 @@ %%% Created : %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 85fb5424956..f9fb9f88295 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -5,7 +5,7 @@ %%% Created : 19 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_rtbl.erl b/src/mod_muc_rtbl.erl index 4a63e05df58..d7504ab7c99 100644 --- a/src/mod_muc_rtbl.erl +++ b/src/mod_muc_rtbl.erl @@ -5,7 +5,7 @@ %%% Created : 17 kwi 2023 by Paweł Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index 9e193a7df86..b6cff55d1e6 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc_sup.erl b/src/mod_muc_sup.erl index 01dd10a1cc7..744e20c4547 100644 --- a/src/mod_muc_sup.erl +++ b/src/mod_muc_sup.erl @@ -2,7 +2,7 @@ %%% Created : 4 Jul 2019 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_multicast.erl b/src/mod_multicast.erl index 1a7dd7d1422..369d5f92dd5 100644 --- a/src/mod_multicast.erl +++ b/src/mod_multicast.erl @@ -5,7 +5,7 @@ %%% Created : 29 May 2007 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_offline.erl b/src/mod_offline.erl index abb209b7765..32277ba7d2b 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_offline_mnesia.erl b/src/mod_offline_mnesia.erl index 77839c30c71..24406c5ac74 100644 --- a/src/mod_offline_mnesia.erl +++ b/src/mod_offline_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 15 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_offline_sql.erl b/src/mod_offline_sql.erl index ea49015392c..9078b082cc9 100644 --- a/src/mod_offline_sql.erl +++ b/src/mod_offline_sql.erl @@ -4,7 +4,7 @@ %%% Created : 15 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_ping.erl b/src/mod_ping.erl index 796a83738ed..b760db68c96 100644 --- a/src/mod_ping.erl +++ b/src/mod_ping.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jul 2009 by Brian Cully %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_pres_counter.erl b/src/mod_pres_counter.erl index 58029eadc7b..bb1b43af891 100644 --- a/src/mod_pres_counter.erl +++ b/src/mod_pres_counter.erl @@ -5,7 +5,7 @@ %%% Created : 23 Sep 2010 by Ahmed Omar %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index b520007626a..c28e6fd8993 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -5,7 +5,7 @@ %%% Created : 21 Jul 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_privacy_mnesia.erl b/src/mod_privacy_mnesia.erl index c39221f3eef..b8657e7198f 100644 --- a/src/mod_privacy_mnesia.erl +++ b/src/mod_privacy_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 14 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl index b00b6274140..e0dc4476bde 100644 --- a/src/mod_privacy_sql.erl +++ b/src/mod_privacy_sql.erl @@ -4,7 +4,7 @@ %%% Created : 14 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_private.erl b/src/mod_private.erl index 2dea64c4597..3f73a3bcac4 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -5,7 +5,7 @@ %%% Created : 16 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_private_mnesia.erl b/src/mod_private_mnesia.erl index f08756d62b1..42bab447f85 100644 --- a/src/mod_private_mnesia.erl +++ b/src/mod_private_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_private_sql.erl b/src/mod_private_sql.erl index 2c242a78a5f..d493b05872b 100644 --- a/src/mod_private_sql.erl +++ b/src/mod_private_sql.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl index 65e962f2a82..bdf512f34fd 100644 --- a/src/mod_privilege.erl +++ b/src/mod_privilege.erl @@ -4,7 +4,7 @@ %%% Purpose : XEP-0356: Privileged Entity %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65.erl b/src/mod_proxy65.erl index 3ea9f05ba4b..4143defaa5f 100644 --- a/src/mod_proxy65.erl +++ b/src/mod_proxy65.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65_lib.erl b/src/mod_proxy65_lib.erl index 554b2e070cf..1f5b25ed031 100644 --- a/src/mod_proxy65_lib.erl +++ b/src/mod_proxy65_lib.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65_mnesia.erl b/src/mod_proxy65_mnesia.erl index 94c892b511f..3661b62c054 100644 --- a/src/mod_proxy65_mnesia.erl +++ b/src/mod_proxy65_mnesia.erl @@ -2,7 +2,7 @@ %%% Created : 16 Jan 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65_redis.erl b/src/mod_proxy65_redis.erl index a6de6c2b0da..588bd55f3fd 100644 --- a/src/mod_proxy65_redis.erl +++ b/src/mod_proxy65_redis.erl @@ -3,7 +3,7 @@ %%% Created : 31 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl index 74264926898..692ad146dc3 100644 --- a/src/mod_proxy65_service.erl +++ b/src/mod_proxy65_service.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65_sql.erl b/src/mod_proxy65_sql.erl index 67ceeac2100..c05f055b772 100644 --- a/src/mod_proxy65_sql.erl +++ b/src/mod_proxy65_sql.erl @@ -3,7 +3,7 @@ %%% Created : 30 Mar 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65_stream.erl b/src/mod_proxy65_stream.erl index d21b483a880..c12c67b633a 100644 --- a/src/mod_proxy65_stream.erl +++ b/src/mod_proxy65_stream.erl @@ -4,7 +4,7 @@ %%% Purpose : Bytestream process. %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index 767d102153a..3ebc69fa44d 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_pubsub_mnesia.erl b/src/mod_pubsub_mnesia.erl index e0d62d7c19b..a1dbc2ff3a1 100644 --- a/src/mod_pubsub_mnesia.erl +++ b/src/mod_pubsub_mnesia.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_pubsub_sql.erl b/src/mod_pubsub_sql.erl index f0b65a6b2a3..59b22c1101f 100644 --- a/src/mod_pubsub_sql.erl +++ b/src/mod_pubsub_sql.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_push.erl b/src/mod_push.erl index fca89fcebb6..20cb6394c68 100644 --- a/src/mod_push.erl +++ b/src/mod_push.erl @@ -5,7 +5,7 @@ %%% Created : 15 Jul 2017 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_push_keepalive.erl b/src/mod_push_keepalive.erl index 03cdc1e02be..2c43282cd55 100644 --- a/src/mod_push_keepalive.erl +++ b/src/mod_push_keepalive.erl @@ -5,7 +5,7 @@ %%% Created : 15 Jul 2017 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_push_mnesia.erl b/src/mod_push_mnesia.erl index 0fbfae10e40..6a5f068b908 100644 --- a/src/mod_push_mnesia.erl +++ b/src/mod_push_mnesia.erl @@ -5,7 +5,7 @@ %%% Created : 15 Jul 2017 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_push_sql.erl b/src/mod_push_sql.erl index 0b4d84afdc2..a36e50f8ec3 100644 --- a/src/mod_push_sql.erl +++ b/src/mod_push_sql.erl @@ -5,7 +5,7 @@ %%% Created : 26 Oct 2017 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2017-2024 ProcessOne +%%% ejabberd, Copyright (C) 2017-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_register.erl b/src/mod_register.erl index 08b461b285e..fed56b6eacd 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_register_web.erl b/src/mod_register_web.erl index 76d84d0684b..b91b4637b8a 100644 --- a/src/mod_register_web.erl +++ b/src/mod_register_web.erl @@ -5,7 +5,7 @@ %%% Created : 4 May 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_roster.erl b/src/mod_roster.erl index cc0838812a0..7765fc255b2 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -5,7 +5,7 @@ %%% Created : 11 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl index 75d1a7668b0..d8d4bd1c9ed 100644 --- a/src/mod_roster_mnesia.erl +++ b/src/mod_roster_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_roster_sql.erl b/src/mod_roster_sql.erl index 2f159d6812c..44d507e5e24 100644 --- a/src/mod_roster_sql.erl +++ b/src/mod_roster_sql.erl @@ -4,7 +4,7 @@ %%% Created : 14 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_s2s_bidi.erl b/src/mod_s2s_bidi.erl index 5d0ba699dc0..06a6b92aa02 100644 --- a/src/mod_s2s_bidi.erl +++ b/src/mod_s2s_bidi.erl @@ -2,7 +2,7 @@ %%% Created : 20 Oct 2024 by Pawel Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_s2s_dialback.erl b/src/mod_s2s_dialback.erl index 5a338739020..f6128b573d7 100644 --- a/src/mod_s2s_dialback.erl +++ b/src/mod_s2s_dialback.erl @@ -2,7 +2,7 @@ %%% Created : 16 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_scram_upgrade.erl b/src/mod_scram_upgrade.erl index d18e95f6644..e0ffabc703a 100644 --- a/src/mod_scram_upgrade.erl +++ b/src/mod_scram_upgrade.erl @@ -2,7 +2,7 @@ %%% Created : 20 Oct 2024 by Pawel Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 434798fd92c..533ff517f36 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -5,7 +5,7 @@ %%% Created : 24 Aug 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index c0c8c4b497f..3c454b0dfbe 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -5,7 +5,7 @@ %%% Created : 5 Mar 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl index ee3ee58234b..509334be13a 100644 --- a/src/mod_shared_roster_ldap.erl +++ b/src/mod_shared_roster_ldap.erl @@ -7,7 +7,7 @@ %%% Created : 5 Mar 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_shared_roster_mnesia.erl b/src/mod_shared_roster_mnesia.erl index e4a487c948f..02858445951 100644 --- a/src/mod_shared_roster_mnesia.erl +++ b/src/mod_shared_roster_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 14 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_shared_roster_sql.erl b/src/mod_shared_roster_sql.erl index 0bdd531d94c..4d582a1bf9c 100644 --- a/src/mod_shared_roster_sql.erl +++ b/src/mod_shared_roster_sql.erl @@ -4,7 +4,7 @@ %%% Created : 14 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_sic.erl b/src/mod_sic.erl index 09b752bdac6..f781c1690f0 100644 --- a/src/mod_sic.erl +++ b/src/mod_sic.erl @@ -5,7 +5,7 @@ %%% Created : 6 Mar 2010 by Karim Gemayel %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_sip.erl b/src/mod_sip.erl index cb77227bfda..aa98be2cc1b 100644 --- a/src/mod_sip.erl +++ b/src/mod_sip.erl @@ -5,7 +5,7 @@ %%% Created : 21 Apr 2014 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2014-2024 ProcessOne +%%% ejabberd, Copyright (C) 2014-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_sip_proxy.erl b/src/mod_sip_proxy.erl index 8fae2f545b0..8c5d8348c5a 100644 --- a/src/mod_sip_proxy.erl +++ b/src/mod_sip_proxy.erl @@ -5,7 +5,7 @@ %%% Created : 21 Apr 2014 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2014-2024 ProcessOne +%%% ejabberd, Copyright (C) 2014-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_sip_registrar.erl b/src/mod_sip_registrar.erl index 6bd8bad2607..ade4c0be0a2 100644 --- a/src/mod_sip_registrar.erl +++ b/src/mod_sip_registrar.erl @@ -5,7 +5,7 @@ %%% Created : 23 Apr 2014 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2014-2024 ProcessOne +%%% ejabberd, Copyright (C) 2014-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_stats.erl b/src/mod_stats.erl index 17235fa8f79..184407e8cee 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_stream_mgmt.erl b/src/mod_stream_mgmt.erl index 4a58e1d9300..359d2601ea9 100644 --- a/src/mod_stream_mgmt.erl +++ b/src/mod_stream_mgmt.erl @@ -3,7 +3,7 @@ %%% Created : 25 Dec 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_stun_disco.erl b/src/mod_stun_disco.erl index d70651a3a6d..c210868e7b1 100644 --- a/src/mod_stun_disco.erl +++ b/src/mod_stun_disco.erl @@ -5,7 +5,7 @@ %%% Created : 18 Apr 2020 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2020-2024 ProcessOne +%%% ejabberd, Copyright (C) 2020-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_time.erl b/src/mod_time.erl index 1dfdd201b36..fbebf03a723 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -6,7 +6,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index cce0ab22520..a225ba23b36 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 0c32923fc01..3ecf39ba196 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -4,7 +4,7 @@ %%% Created : 29 Jul 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl index a8e3ed24edb..e70b13fc04f 100644 --- a/src/mod_vcard_mnesia.erl +++ b/src/mod_vcard_mnesia.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard_sql.erl b/src/mod_vcard_sql.erl index 64e411ab8c4..18456f40277 100644 --- a/src/mod_vcard_sql.erl +++ b/src/mod_vcard_sql.erl @@ -4,7 +4,7 @@ %%% Created : 13 Apr 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl index 0b636768449..70ed707b2f7 100644 --- a/src/mod_vcard_xupdate.erl +++ b/src/mod_vcard_xupdate.erl @@ -5,7 +5,7 @@ %%% Created : 9 Mar 2007 by Igor Goryachev %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_version.erl b/src/mod_version.erl index f8a8dadcf2a..e10168c84ae 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mqtt_codec.erl b/src/mqtt_codec.erl index 7e0d31bff2c..1ef474dd568 100644 --- a/src/mqtt_codec.erl +++ b/src/mqtt_codec.erl @@ -1,6 +1,6 @@ %%%------------------------------------------------------------------- %%% @author Evgeny Khramtsov -%%% @copyright (C) 2002-2024 ProcessOne, SARL. All Rights Reserved. +%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved. %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. diff --git a/src/node_flat.erl b/src/node_flat.erl index b385e66e1ed..7093d4beb4c 100644 --- a/src/node_flat.erl +++ b/src/node_flat.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/node_flat_sql.erl b/src/node_flat_sql.erl index 6db0dd06b1e..acfdf333137 100644 --- a/src/node_flat_sql.erl +++ b/src/node_flat_sql.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/node_pep.erl b/src/node_pep.erl index 22846e3a6fb..3d208c73b67 100644 --- a/src/node_pep.erl +++ b/src/node_pep.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/node_pep_sql.erl b/src/node_pep_sql.erl index 26b458e3617..5d35c7bfe00 100644 --- a/src/node_pep_sql.erl +++ b/src/node_pep_sql.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/nodetree_tree.erl b/src/nodetree_tree.erl index 32841fcc646..facb4fd747e 100644 --- a/src/nodetree_tree.erl +++ b/src/nodetree_tree.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/nodetree_tree_sql.erl b/src/nodetree_tree_sql.erl index 64af45b5ddc..f7a31b8ae19 100644 --- a/src/nodetree_tree_sql.erl +++ b/src/nodetree_tree_sql.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/nodetree_virtual.erl b/src/nodetree_virtual.erl index 455db2619f3..18eb9ed30a3 100644 --- a/src/nodetree_virtual.erl +++ b/src/nodetree_virtual.erl @@ -5,7 +5,7 @@ %%% Created : 1 Dec 2007 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/prosody2ejabberd.erl b/src/prosody2ejabberd.erl index 193314f5090..cbfb49cd4c9 100644 --- a/src/prosody2ejabberd.erl +++ b/src/prosody2ejabberd.erl @@ -4,7 +4,7 @@ %%% Created : 20 Jan 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/proxy_protocol.erl b/src/proxy_protocol.erl index 8405cb03795..4ce0d31b455 100644 --- a/src/proxy_protocol.erl +++ b/src/proxy_protocol.erl @@ -5,7 +5,7 @@ %%% Created : 27 Nov 2018 by Paweł Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/pubsub_db_sql.erl b/src/pubsub_db_sql.erl index e3e16fb45fe..a67654c7cd8 100644 --- a/src/pubsub_db_sql.erl +++ b/src/pubsub_db_sql.erl @@ -5,7 +5,7 @@ %%% Created : 7 Aug 2009 by Pablo Polvorin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/pubsub_index.erl b/src/pubsub_index.erl index ffa11adc424..0c34ea63baf 100644 --- a/src/pubsub_index.erl +++ b/src/pubsub_index.erl @@ -5,7 +5,7 @@ %%% Created : 30 Apr 2009 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/pubsub_migrate.erl b/src/pubsub_migrate.erl index 9834c30229e..8d9fc619874 100644 --- a/src/pubsub_migrate.erl +++ b/src/pubsub_migrate.erl @@ -5,7 +5,7 @@ %%% Created : 26 Jul 2014 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/pubsub_subscription.erl b/src/pubsub_subscription.erl index 74766d1fb38..6db643af647 100644 --- a/src/pubsub_subscription.erl +++ b/src/pubsub_subscription.erl @@ -5,7 +5,7 @@ %%% Created : 29 May 2009 by Brian Cully %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/pubsub_subscription_sql.erl b/src/pubsub_subscription_sql.erl index 64207b696e5..8f1361b478b 100644 --- a/src/pubsub_subscription_sql.erl +++ b/src/pubsub_subscription_sql.erl @@ -6,7 +6,7 @@ %%% Created : 7 Aug 2009 by Pablo Polvorin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/rest.erl b/src/rest.erl index 7f4883295fc..7fde9e710ed 100644 --- a/src/rest.erl +++ b/src/rest.erl @@ -5,7 +5,7 @@ %%% Created : 16 Oct 2014 by Christophe Romain %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/str.erl b/src/str.erl index e69e8693dc6..6dafcfda6df 100644 --- a/src/str.erl +++ b/src/str.erl @@ -5,7 +5,7 @@ %%% Created : 23 Feb 2012 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/translate.erl b/src/translate.erl index e5d6d8b0974..5adde6e24f3 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -5,7 +5,7 @@ %%% Created : 6 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/win32_dns.erl b/src/win32_dns.erl index 3569e021793..f26f4cd34ed 100644 --- a/src/win32_dns.erl +++ b/src/win32_dns.erl @@ -5,7 +5,7 @@ %%% Created : 5 Mar 2009 by Geoff Cant %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/announce_tests.erl b/test/announce_tests.erl index 570f67df5de..724baba27bb 100644 --- a/test/announce_tests.erl +++ b/test/announce_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/carbons_tests.erl b/test/carbons_tests.erl index 2d9c4b606d9..eabd3af2a58 100644 --- a/test/carbons_tests.erl +++ b/test/carbons_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/commands_tests.erl b/test/commands_tests.erl index 7e77136b996..e98e288ed93 100644 --- a/test/commands_tests.erl +++ b/test/commands_tests.erl @@ -3,7 +3,7 @@ %%% Created : 2 Jul 2024 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/csi_tests.erl b/test/csi_tests.erl index 8886bb51908..f2b61abff8b 100644 --- a/test/csi_tests.erl +++ b/test/csi_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index b7c72a02bc3..935ccbba0f9 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -3,7 +3,7 @@ %%% Created : 2 Jun 2013 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/example_tests.erl b/test/example_tests.erl index ce699208b9f..5fd0a86ff08 100644 --- a/test/example_tests.erl +++ b/test/example_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/jidprep_tests.erl b/test/jidprep_tests.erl index 2091c4fc087..f18e150fb76 100644 --- a/test/jidprep_tests.erl +++ b/test/jidprep_tests.erl @@ -3,7 +3,7 @@ %%% Created : 11 Sep 2019 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2019-2024 ProcessOne +%%% ejabberd, Copyright (C) 2019-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/ldap_srv.erl b/test/ldap_srv.erl index 077c3de4b62..2d0cea9887f 100644 --- a/test/ldap_srv.erl +++ b/test/ldap_srv.erl @@ -3,7 +3,7 @@ %%% Created : 21 Jun 2013 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/mam_tests.erl b/test/mam_tests.erl index ed384cfa1cd..27988bf5e38 100644 --- a/test/mam_tests.erl +++ b/test/mam_tests.erl @@ -3,7 +3,7 @@ %%% Created : 14 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/muc_tests.erl b/test/muc_tests.erl index a6356748146..7a5d1d28f4e 100644 --- a/test/muc_tests.erl +++ b/test/muc_tests.erl @@ -3,7 +3,7 @@ %%% Created : 15 Oct 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/offline_tests.erl b/test/offline_tests.erl index 4ab366f052a..d859da622fc 100644 --- a/test/offline_tests.erl +++ b/test/offline_tests.erl @@ -3,7 +3,7 @@ %%% Created : 7 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/privacy_tests.erl b/test/privacy_tests.erl index 7faf59f5df3..51782dcf438 100644 --- a/test/privacy_tests.erl +++ b/test/privacy_tests.erl @@ -3,7 +3,7 @@ %%% Created : 18 Oct 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/private_tests.erl b/test/private_tests.erl index 5bb8b3a5094..e7077f4ba41 100644 --- a/test/private_tests.erl +++ b/test/private_tests.erl @@ -3,7 +3,7 @@ %%% Created : 23 Nov 2018 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/proxy65_tests.erl b/test/proxy65_tests.erl index 6de5c4fead9..612a926fb5e 100644 --- a/test/proxy65_tests.erl +++ b/test/proxy65_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/pubsub_tests.erl b/test/pubsub_tests.erl index 427893e1aa4..1cb02f020b4 100644 --- a/test/pubsub_tests.erl +++ b/test/pubsub_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/push_tests.erl b/test/push_tests.erl index 9314713530d..9e400cccc8d 100644 --- a/test/push_tests.erl +++ b/test/push_tests.erl @@ -3,7 +3,7 @@ %%% Created : 15 Jul 2017 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/replaced_tests.erl b/test/replaced_tests.erl index c8a81c9d3b7..37e22b3ac57 100644 --- a/test/replaced_tests.erl +++ b/test/replaced_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/roster_tests.erl b/test/roster_tests.erl index f218a85d6d3..8d096eea3de 100644 --- a/test/roster_tests.erl +++ b/test/roster_tests.erl @@ -3,7 +3,7 @@ %%% Created : 22 Oct 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/sm_tests.erl b/test/sm_tests.erl index f013ccfffaa..a55957856a9 100644 --- a/test/sm_tests.erl +++ b/test/sm_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/stundisco_tests.erl b/test/stundisco_tests.erl index f892805b2d8..ca941983fef 100644 --- a/test/stundisco_tests.erl +++ b/test/stundisco_tests.erl @@ -3,7 +3,7 @@ %%% Created : 22 Apr 2020 by Holger Weiss %%% %%% -%%% ejabberd, Copyright (C) 2020-2024 ProcessOne +%%% ejabberd, Copyright (C) 2020-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/suite.erl b/test/suite.erl index 198a4b596e6..0066b511670 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -3,7 +3,7 @@ %%% Created : 27 Jun 2013 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/upload_tests.erl b/test/upload_tests.erl index 0fb22dc29c7..7e2d89958be 100644 --- a/test/upload_tests.erl +++ b/test/upload_tests.erl @@ -3,7 +3,7 @@ %%% Created : 17 May 2018 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/vcard_tests.erl b/test/vcard_tests.erl index 4ee94ddcc35..fc3adb6117c 100644 --- a/test/vcard_tests.erl +++ b/test/vcard_tests.erl @@ -3,7 +3,7 @@ %%% Created : 16 Nov 2016 by Evgeny Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/test/webadmin_tests.erl b/test/webadmin_tests.erl index 753f8793087..6a4ff7cacc5 100644 --- a/test/webadmin_tests.erl +++ b/test/webadmin_tests.erl @@ -3,7 +3,7 @@ %%% Created : 23 Mar 2020 by Pawel Chmielowski %%% %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/tools/xml_compress_gen.erl b/tools/xml_compress_gen.erl index 8d9e770b0e5..63101ced22b 100644 --- a/tools/xml_compress_gen.erl +++ b/tools/xml_compress_gen.erl @@ -4,7 +4,7 @@ %% Created : 14 Sep 2018 Pawel Chmielowski %% %% -%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%% ejabberd, Copyright (C) 2002-2025 ProcessOne %% %% This program is free software; you can redistribute it and/or %% modify it under the terms of the GNU General Public License as diff --git a/vars.config.in b/vars.config.in index 69e51f07a5a..ded059b3e4d 100644 --- a/vars.config.in +++ b/vars.config.in @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2024 ProcessOne +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as From 457d8fc6ccd927304dad5abbd984b170914d2dae Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 3 Jan 2025 11:24:22 +0100 Subject: [PATCH 014/170] Container: Bump versions to Erlang/OTP 27.2 and Elixir 1.18.1 --- .github/container/Dockerfile | 4 ++-- CONTAINER.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index f9a97e0afdb..2a44b903550 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -1,7 +1,7 @@ #' Define default build variables ## specifc ARGs for METHOD='direct' -ARG OTP_VSN='26.2' -ARG ELIXIR_VSN='1.16.2' +ARG OTP_VSN='27.2' +ARG ELIXIR_VSN='1.18.1' ## specifc ARGs for METHOD='package' ARG ALPINE_VSN='3.19' ## general ARGs diff --git a/CONTAINER.md b/CONTAINER.md index 5284afd7fad..95115a6c248 100644 --- a/CONTAINER.md +++ b/CONTAINER.md @@ -19,7 +19,7 @@ that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service. This document explains how to use the `ejabberd` container image available in [ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd), built using the files in `.github/container/`. -This image is based in Alpine 3.19, includes Erlang/OTP 26.2 and Elixir 1.16.1. +This image is based in Alpine 3.19, includes Erlang/OTP 27.2 and Elixir 1.18.1. Alternatively, there is also the `ecs` container image available in [docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/), From 85b660fb4b0ecb558180f0c0e6d9f0ebff210286 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Jan 2025 14:57:16 +0100 Subject: [PATCH 015/170] rebar.config: Bump provider_asn1 version to 0.4.1 --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index f367477cf48..bc6a258c59d 100644 --- a/rebar.config +++ b/rebar.config @@ -154,7 +154,7 @@ {if_rebar3, {plugins, [{if_version_below, "21", {rebar3_hex, "7.0.7"}}, {if_version_above, "20", {rebar3_hex, "~> 7.0.8"}}, - {provider_asn1, "0.2.0"}, + {provider_asn1, "0.4.1"}, %% Protocol consolidation doesn't work correctly in upstream rebar_mix, see %% https://github.com/Supersonido/rebar_mix/issues/27#issuecomment-894873335 %% Let's use this fixed rebar_mix fork, see its PR: From 9d87193d80f9bdbb8d4dd70d4143a3a4d3a22d7f Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 7 Jan 2025 10:39:12 +0100 Subject: [PATCH 016/170] mix.lock: Update to recent versions --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index eeceba2ab8f..9842b9c9143 100644 --- a/mix.lock +++ b/mix.lock @@ -2,19 +2,19 @@ "base64url": {:hex, :base64url, "1.0.1", "f8c7f2da04ca9a5d0f5f50258f055e1d699f0e8bf4cfdb30b750865368403cf6", [:rebar3], [], "hexpm", "f9b3add4731a02a9b0410398b475b33e7566a695365237a6bdee1bb447719f5c"}, "cache_tab": {:hex, :cache_tab, "1.0.31", "e4097b50a6f373ab1e0a5f01bab0bef6626771a4cd6c93404ed6d54810e11fbc", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8582b60a4a09b247ef86355ba9e07fce9e11edc0345a775c9171f971c72b6351"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.42", "f23d856f41919f17cd06a493923a722d87a2d684f143a1e663c04a2b93100682", [:mix], [], "hexpm", "6915b6ca369b5f7346636a2f41c6a6d78b5af419d61a611079189233358b8b8b"}, "eimp": {:hex, :eimp, "1.0.23", "aaf32efab061143403dadbaa63e699ef8e81702fbfa96fd436d5e9be4d6a8d3a", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "907c780023cb2893e4fc4bdbe6a4f02c355913862ac67f0ecc26605e816b628a"}, "epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"}, "eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"}, - "ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"}, + "ex_doc": {:hex, :ex_doc, "0.36.1", "4197d034f93e0b89ec79fac56e226107824adcce8d2dd0a26f5ed3a95efc36b1", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d7d26a7cf965dacadcd48f9fa7b5953d7d0cfa3b44fa7a65514427da44eafd89"}, "exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"}, "ezlib": {:hex, :ezlib, "1.0.13", "3c7f62862850a241159c10b218ecf580bce54d0890601b65144dacc2633be2b0", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "9ee62ab3f8ed55a0fd11a9569fcb8e458683f95575417272192b069f092abfbb"}, "fast_tls": {:hex, :fast_tls, "1.1.22", "44356b256afad4399c2fc5059a3066669dafd8bd4e4e796c9c1cf8910ddd265e", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e65779aefb7ab15c4755230fef8077e687d20cc5a3984a5974f9f657e8e2485b"}, "fast_xml": {:hex, :fast_xml, "1.1.55", "ace020f2521f2a484ac8467d2822af85534a346e2aae03ffcbc34f29318befaf", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "83f3e23a780ed5f567cdec73953f06c95b838d709dbfa86b59a98a8d23c99f85"}, "fast_yaml": {:hex, :fast_yaml, "1.0.37", "f71d472fbf787ccd161b914d1eb486116a0f4f2e835337a378fbd31b59d2e74b", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8de868721bf7e2172414f7d3148ede0f3c922b496455cd625dd5c4429515a769"}, - "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, + "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jiffy": {:hex, :jiffy, "1.1.2", "a9b6c9a7ec268e7cf493d028f0a4c9144f59ccb878b1afe42841597800840a1b", [:rebar3], [], "hexpm", "bb61bc42a720bbd33cb09a410e48bb79a61012c74cb8b3e75f26d988485cf381"}, "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, @@ -27,7 +27,7 @@ "p1_acme": {:hex, :p1_acme, "1.0.25", "db91f0d6c193cd1d5c0b0fa3939a898dbf56a6075db4347cde26e802715de50c", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.17", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "a7b55b47495ddb4f98a15e65451ec3ad43f4637b955c74cd695d98e6a645d08c"}, "p1_mysql": {:hex, :p1_mysql, "1.0.25", "875d4cbdc7c9990270df3292cce2514e4c18a9fdfd19bef258cb4d0c45b4f243", [:rebar3], [], "hexpm", "e6187ffae95b726098e88f3ee6f2344ac259ce2c26e0ee403b05feef341ae434"}, "p1_oauth2": {:hex, :p1_oauth2, "0.6.14", "1c5f82535574de87e2059695ac4b91f8f9aebacbc1c80287dae6f02552d47aea", [:rebar3], [], "hexpm", "1fd3ac474e43722d9d5a87c6df8d36f698ed87af7bb81cbbb66361451d99ae8f"}, - "p1_pgsql": {:hex, :p1_pgsql, "1.1.29", "fae0c90cbc5931865958150f1b667fb0d20b063f6a46a17770a4e5232ded632c", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "a6ff58e8b174993f3895da3ea6211a9f9d0c54d1a6e28bb321da3b3cd68b38c1"}, + "p1_pgsql": {:hex, :p1_pgsql, "1.1.31", "8339beac1f0f4a45f476ff5306be5135020f02979a61df0d8cf7b1c67e85e2fd", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "b7fc45dfb2549187347871b7fd0573638ad5ea337f6263fba1b3840efab2ff49"}, "p1_utils": {:hex, :p1_utils, "1.0.26", "67b0c4ac9fa3ba3ef563b31aa111b0a004439a37fac85e027f1c3617e1c7ec6c", [:rebar3], [], "hexpm", "d0379e8c1156b98bd64f8129c1de022fcca4f2fdb7486ce73bf0ed2c3376b04c"}, "pkix": {:hex, :pkix, "1.0.10", "d3bfadf7b7cfe2a3636f1b256c9cce5f646a07ce31e57ee527668502850765a0", [:rebar3], [], "hexpm", "e02164f83094cb124c41b1ab28988a615d54b9adc38575f00f19a597a3ac5d0e"}, "sqlite3": {:hex, :sqlite3, "1.1.15", "e819defd280145c328457d7af897d2e45e8e5270e18812ee30b607c99cdd21af", [:rebar3], [], "hexpm", "3c0ba4e13322c2ad49de4e2ddd28311366adde54beae8dba9d9e3888f69d2857"}, From bc6c868c8a958b0f01e723fac33bae2b5b72d300 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 12 Jan 2025 19:38:08 +0100 Subject: [PATCH 017/170] Docs: Don't use backtick quotes for ejabberd name This change improves sentences legibility. In the Introduction page, use **strong** instead. Notice backtick quotes are for raw code in markdown, for example: - `ejabberd` container image - `ejabberd` script generated by OTP Release - `ejabberd` username in system, for example for MySQL or container host --- README.md | 2 +- src/ejabberd_options_doc.erl | 2 +- src/mod_register.erl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3e2f3ef1311..76eae7b554f 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ There are several places to get in touch with other ejabberd developers and admi License ------- -- `ejabberd` is released under the __GNU General Public License v2__ (see [COPYING](COPYING)) +- ejabberd is released under the __GNU General Public License v2__ (see [COPYING](COPYING)) - [ejabberd translations](https://github.com/processone/ejabberd-po/) under __MIT License__. [discussions]: https://github.com/processone/ejabberd/discussions diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 380b2b6054f..189debef49c 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -32,7 +32,7 @@ doc() -> desc => ?T("List of one or more " "_`../configuration/basic.md#host-names|host names`_ " - "(or domains) that 'ejabberd' will serve. This is a " + "(or domains) that ejabberd will serve. This is a " "**mandatory** option.")}}, {listen, #{value => "[Options, ...]", diff --git a/src/mod_register.erl b/src/mod_register.erl index fed56b6eacd..b811dcff080 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -661,7 +661,7 @@ mod_doc() -> {access_from, #{value => ?T("AccessName"), desc => - ?T("By default, 'ejabberd' doesn't allow the client to register new accounts " + ?T("By default, ejabberd doesn't allow the client to register new accounts " "from s2s or existing c2s sessions. You can change it by defining " "access rule in this option. Use with care: allowing registration " "from s2s leads to uncontrolled massive accounts creation by rogue users.")}}, From 29e6204bde8abb6e82ba05c97c752a03eba6b265 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 12 Jan 2025 19:44:07 +0100 Subject: [PATCH 018/170] Docs: Reword explanation about ACL names and definitions --- src/ejabberd_options_doc.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 189debef49c..19e7773da07 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -222,7 +222,7 @@ doc() -> "specified 'Pattern' according to the rules used by the " "Unix shell.")}}]}, {access_rules, - #{value => "{AccessName: {allow|deny: ACLRules|ACLName}}", + #{value => "{AccessName: {allow|deny: ACLName|ACLDefinition}}", desc => ?T("This option defines " "_`basic.md#access-rules|Access Rules`_. " @@ -1322,7 +1322,7 @@ doc() -> " normal: 1000", " fast: 50000"]}}, {shaper_rules, - #{value => "{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}", + #{value => "{ShaperRuleName: {Number|ShaperName: ACLName|ACLDefinition}}", desc => ?T("This option defines " "_`../configuration/basic.md#shaper-rules|shaper rules`_ " From 862cacabcb4ee79bf5482fd5bf0df5f94e9d1928 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 12 Jan 2025 23:48:31 +0100 Subject: [PATCH 019/170] ejabberdctl.template: Handle erts versions 9 o lower --- .github/container/ejabberdctl.template | 2 +- ejabberdctl.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/container/ejabberdctl.template b/.github/container/ejabberdctl.template index af2874fff98..a27a14587db 100755 --- a/.github/container/ejabberdctl.template +++ b/.github/container/ejabberdctl.template @@ -265,7 +265,7 @@ help() # dynamic node name helper uid() { - ERTSVERSION="$("$ERL" -version 2>&1 | sed 's|.*\([0-9][0-9]\).*|\1|g')" + ERTSVERSION="$("$ERL" -version 2>&1 | sed 's|.* \([0-9]*[0-9]\).*|\1|g')" if [ $ERTSVERSION -lt 11 ] ; then # otp 23.0 includes erts 11.0 # Erlang/OTP lower than 23, which doesn's support dynamic node code N=1 diff --git a/ejabberdctl.template b/ejabberdctl.template index 21be6430f47..b9f01535bba 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -253,7 +253,7 @@ help() # dynamic node name helper uid() { - ERTSVERSION="$("$ERL" -version 2>&1 | sed 's|.*\([0-9][0-9]\).*|\1|g')" + ERTSVERSION="$("$ERL" -version 2>&1 | sed 's|.* \([0-9]*[0-9]\).*|\1|g')" if [ $ERTSVERSION -lt 11 ] ; then # otp 23.0 includes erts 11.0 # Erlang/OTP lower than 23, which doesn's support dynamic node code N=1 From 4a363b6e76786f047b3dfd61a77500a6a629141c Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 13 Jan 2025 00:00:40 +0100 Subject: [PATCH 020/170] Test: Fixes to handle re-running test after update_sql Enable some modules so ejabberd creates their SQL tables and later those tables can be updated without errors by mod_admin_update_sql when ci.yml calls "make test" to check update_sql. However, mod_shared_roster should be stopped before running the actual tests, as it introduces undesired IQ queries On the other hand, a few SQL tables are global RAM, and cannot be created in SQL just for a vhost that is not the first one defined. --- test/ejabberd_SUITE.erl | 19 ++++++++++++++++++- test/ejabberd_SUITE_data/ejabberd.mssql.yml | 8 ++++++++ test/ejabberd_SUITE_data/ejabberd.mysql.yml | 8 ++++++++ test/ejabberd_SUITE_data/ejabberd.pgsql.yml | 8 ++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 935ccbba0f9..e240de59b92 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -100,6 +100,7 @@ do_init_per_group(mysql, Config) -> {selected, _, _} -> mod_muc:shutdown_rooms(?MYSQL_VHOST), update_sql(?MYSQL_VHOST, Config), + stop_temporary_modules(?MYSQL_VHOST), set_opt(server, ?MYSQL_VHOST, Config); Err -> {skip, {mysql_not_available, Err}} @@ -109,6 +110,7 @@ do_init_per_group(mssql, Config) -> {selected, _, _} -> mod_muc:shutdown_rooms(?MSSQL_VHOST), update_sql(?MSSQL_VHOST, Config), + stop_temporary_modules(?MSSQL_VHOST), set_opt(server, ?MSSQL_VHOST, Config); Err -> {skip, {mssql_not_available, Err}} @@ -118,6 +120,7 @@ do_init_per_group(pgsql, Config) -> {selected, _, _} -> mod_muc:shutdown_rooms(?PGSQL_VHOST), update_sql(?PGSQL_VHOST, Config), + stop_temporary_modules(?PGSQL_VHOST), set_opt(server, ?PGSQL_VHOST, Config); Err -> {skip, {pgsql_not_available, Err}} @@ -161,6 +164,10 @@ do_init_per_group(GroupName, Config) -> _ -> NewConfig end. +stop_temporary_modules(Host) -> + Modules = [mod_shared_roster], + [gen_mod:stop_module(Host, M) || M <- Modules]. + end_per_group(mnesia, _Config) -> ok; end_per_group(redis, _Config) -> @@ -1094,7 +1101,17 @@ clear_table_queries(Queries) -> fun(Query, Acc) -> case split(str:to_lower(Query)) of [<<"create">>, <<"table">>, Table|_] -> - [<<"DELETE FROM ", Table/binary, ";">>|Acc]; + GlobalRamTables = [<<"bosh">>, + <<"oauth_client">>, + <<"oauth_token">>, + <<"proxy65">>, + <<"route">>], + case lists:member(Table, GlobalRamTables) of + true -> + Acc; + false -> + [<<"DELETE FROM ", Table/binary, ";">>|Acc] + end; _ -> Acc end diff --git a/test/ejabberd_SUITE_data/ejabberd.mssql.yml b/test/ejabberd_SUITE_data/ejabberd.mssql.yml index 1ecf77ba871..66bfee3f99e 100644 --- a/test/ejabberd_SUITE_data/ejabberd.mssql.yml +++ b/test/ejabberd_SUITE_data/ejabberd.mssql.yml @@ -69,3 +69,11 @@ Welcome to this XMPP server." mod_stats: [] mod_time: [] mod_version: [] + mod_mix: + db_type: sql + mod_mix_pam: + db_type: sql + mod_mqtt: + db_type: sql + mod_shared_roster: + db_type: sql diff --git a/test/ejabberd_SUITE_data/ejabberd.mysql.yml b/test/ejabberd_SUITE_data/ejabberd.mysql.yml index 411901976b4..abb0a6937ca 100644 --- a/test/ejabberd_SUITE_data/ejabberd.mysql.yml +++ b/test/ejabberd_SUITE_data/ejabberd.mysql.yml @@ -70,3 +70,11 @@ Welcome to this XMPP server." mod_stats: [] mod_time: [] mod_version: [] + mod_mix: + db_type: sql + mod_mix_pam: + db_type: sql + mod_mqtt: + db_type: sql + mod_shared_roster: + db_type: sql diff --git a/test/ejabberd_SUITE_data/ejabberd.pgsql.yml b/test/ejabberd_SUITE_data/ejabberd.pgsql.yml index c0cd0b0d656..014e1c058cc 100644 --- a/test/ejabberd_SUITE_data/ejabberd.pgsql.yml +++ b/test/ejabberd_SUITE_data/ejabberd.pgsql.yml @@ -70,3 +70,11 @@ Welcome to this XMPP server." mod_stats: [] mod_time: [] mod_version: [] + mod_mix: + db_type: sql + mod_mix_pam: + db_type: sql + mod_mqtt: + db_type: sql + mod_shared_roster: + db_type: sql From 6959447c2ce47c90cae1be7b557165aff9b78300 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 12 Jan 2025 22:33:33 +0100 Subject: [PATCH 021/170] mod_admin_update_sql: Fix update_sql when using tables created by ejabberd internally --- src/mod_admin_update_sql.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod_admin_update_sql.erl b/src/mod_admin_update_sql.erl index 917c8d2bca4..b6594851a4f 100644 --- a/src/mod_admin_update_sql.erl +++ b/src/mod_admin_update_sql.erl @@ -286,6 +286,7 @@ update_tables(State) -> true -> drop_index(State, "private_storage", "i_private_storage_username"), drop_index(State, "private_storage", "i_private_storage_username_namespace"), + drop_pkey(State, "private_storage"), add_pkey(State, "private_storage", ["server_host", "username", "namespace"]), drop_sh_default(State, "private_storage"); false -> @@ -342,6 +343,7 @@ update_tables(State) -> true -> drop_index(State, "sm", "i_sm_sid"), drop_index(State, "sm", "i_sm_username"), + drop_pkey(State, "sm"), add_pkey(State, "sm", ["usec", "pid"]), create_index(State, "sm", "i_sm_sh_username", ["server_host", "username"]), drop_sh_default(State, "sm"); From 2e754a5557ecfa25868aca9757738a3387e3c827 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 13 Jan 2025 12:49:44 +0100 Subject: [PATCH 022/170] mod_admin_update_sql: Fix mysql support --- src/mod_admin_update_sql.erl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/mod_admin_update_sql.erl b/src/mod_admin_update_sql.erl index b6594851a4f..0c3f9095fd9 100644 --- a/src/mod_admin_update_sql.erl +++ b/src/mod_admin_update_sql.erl @@ -594,8 +594,22 @@ mssql_clustered(_) -> "CLUSTERED ". mysql_keylen(_, "bare_peer") -> "(191)"; mysql_keylen(_, "channel") -> "(191)"; mysql_keylen(_, "domain") -> "(75)"; +mysql_keylen(_, "grp") -> "(191)"; %% in mysql*.sql this is text, not varchar(191) mysql_keylen(_, "jid") -> "(75)"; +mysql_keylen(_, "lbday") -> "(191)"; +mysql_keylen(_, "lctry") -> "(191)"; +mysql_keylen(_, "lemail") -> "(191)"; +mysql_keylen(_, "lfamily") -> "(191)"; +mysql_keylen(_, "lfn") -> "(191)"; +mysql_keylen(_, "lgiven") -> "(191)"; +mysql_keylen(_, "llocality") -> "(191)"; +mysql_keylen(_, "lmiddle") -> "(191)"; +mysql_keylen(_, "lnickname") -> "(191)"; +mysql_keylen(_, "lorgname") -> "(191)"; +mysql_keylen(_, "lorgunit") -> "(191)"; +mysql_keylen(_, "lusername") -> "(191)"; mysql_keylen(_, "name") -> "(75)"; +mysql_keylen(_, "namespace") -> "(191)"; mysql_keylen(_, "node") -> "(75)"; mysql_keylen(_, "peer") -> "(191)"; mysql_keylen(_, "pid") -> "(75)"; From 056635119c8b9f169f1c59cccbf81faab88a6712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Tue, 14 Jan 2025 10:03:31 +0100 Subject: [PATCH 023/170] Fix json version of json_encode_with_kv_list for nested kv lists This should fix error reported in issue #4338 --- src/misc.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.erl b/src/misc.erl index 2bfb6ded855..46877538b26 100644 --- a/src/misc.erl +++ b/src/misc.erl @@ -141,7 +141,7 @@ json_decode(Bin) -> -else. json_encode_with_kv_lists(Term) -> iolist_to_binary(json:encode(Term, - fun([{_, _} | _] = Val, Encoder) -> + fun({Val}, Encoder) when is_list(Val) -> json:encode_key_value_list(Val, Encoder); (Val, Encoder) -> json:encode_value(Val, Encoder) From f72cfa9a1327e01aed229fc4d41b2a7658d9841f Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 15 Jan 2025 09:20:09 +0100 Subject: [PATCH 024/170] Test: Uninstall mod_example when the tests has finished --- test/commands_tests.erl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/commands_tests.erl b/test/commands_tests.erl index e98e288ed93..166415e8927 100644 --- a/test/commands_tests.erl +++ b/test/commands_tests.erl @@ -48,11 +48,12 @@ single_cases() -> single_test(http_list), single_test(http_tuple), single_test(http_list_tuple), - single_test(http_list_tuple_map)]}. + single_test(http_list_tuple_map), + single_test(clean)]}. setup(_Config) -> M = <<"mod_example">>, - execute(module_uninstall, [M]), + clean(_Config), case execute(module_install, [M]) of ok -> ok; @@ -63,6 +64,12 @@ setup(_Config) -> Installed = execute(modules_installed, []), ?match(true, lists:keymember(mod_example, 1, Installed)). +clean(_Config) -> + M = <<"mod_example">>, + execute(module_uninstall, [M]), + Installed = execute(modules_installed, []), + ?match(false, lists:keymember(mod_example, 1, Installed)). + %%%================================== %%%% ejabberdctl From ad1b577ca9ffe42c24d8616daec7700cf1869b31 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 15 Jan 2025 09:12:56 +0100 Subject: [PATCH 025/170] mix.exs: The ex_doc dependency is only relevant for the edoc Mix environment --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 4f46caf86d1..97487b84c79 100644 --- a/mix.exs +++ b/mix.exs @@ -133,7 +133,7 @@ defmodule Ejabberd.MixProject do [{:cache_tab, "~> 1.0"}, {:dialyxir, "~> 1.2", only: [:test], runtime: false}, {:eimp, "~> 1.0"}, - {:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false}, + {:ex_doc, "~> 0.31", only: [:edoc], runtime: false}, {:fast_tls, "~> 1.1.22"}, {:fast_xml, "~> 1.1.53"}, {:fast_yaml, "~> 1.0"}, From e0bb90065155ca5a6fc2fab7f4d474c9754d03f7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 15 Jan 2025 20:17:56 +0100 Subject: [PATCH 026/170] mod_muc_admin: Add forgotten support to set enable_hats room option --- src/mod_muc_admin.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 6c4c9d3a44d..f9592d53954 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -1860,6 +1860,7 @@ change_option(Option, Value, Config) -> anonymous -> Config#config{anonymous = Value}; captcha_protected -> Config#config{captcha_protected = Value}; description -> Config#config{description = Value}; + enable_hats -> Config#config{enable_hats = Value}; lang -> Config#config{lang = Value}; logging -> Config#config{logging = Value}; mam -> Config#config{mam = Value}; From 9827ad43e4338c40f51699705b5ff74bd12aba2c Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 15 Jan 2025 20:15:40 +0100 Subject: [PATCH 027/170] mod_muc_admin: Verify room option value before setting it (#4337) --- src/mod_muc_admin.erl | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index f9592d53954..36d37b89984 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -1722,9 +1722,8 @@ format_room_option(OptionString, ValueString) -> password -> ValueString; subject ->ValueString; subject_author ->ValueString; - presence_broadcast ->misc:expr_to_term(ValueString); - max_users -> binary_to_integer(ValueString); - voice_request_min_interval -> binary_to_integer(ValueString); + max_users -> try_convert_integer(Option, ValueString); + voice_request_min_interval -> try_convert_integer(Option, ValueString); vcard -> ValueString; vcard_xupdate when ValueString /= <<"undefined">>, ValueString /= <<"external">> -> @@ -1735,10 +1734,35 @@ format_room_option(OptionString, ValueString) -> [parse_affiliation_string(Opt) || Opt <- str:tokens(ValueString, <<",">>)]; subscribers -> [parse_subscription_string(Opt) || Opt <- str:tokens(ValueString, <<",">>)]; - _ -> misc:binary_to_atom(ValueString) + allow_private_messages_from_visitors when + (ValueString == <<"anyone">>) or + (ValueString == <<"moderators">>) or + (ValueString == <<"nobody">>) -> binary_to_existing_atom(ValueString); + allowpm when + (ValueString == <<"anyone">>) or + (ValueString == <<"participants">>) or + (ValueString == <<"moderators">>) or + (ValueString == <<"none">>) -> binary_to_existing_atom(ValueString); + presence_broadcast when + (ValueString == <<"participant">>) or + (ValueString == <<"moderator">>) or + (ValueString == <<"visitor">>) -> binary_to_existing_atom(ValueString); + _ when ValueString == <<"true">> -> true; + _ when ValueString == <<"false">> -> false; + _ -> throw_error(Option, ValueString) end, {Option, Value}. +try_convert_integer(Option, ValueString) -> + try binary_to_integer(ValueString) of + I when is_integer(I) -> I + catch _:badarg -> + throw_error(Option, ValueString) + end. + +throw_error(O, V) -> + throw({error, "Invalid value for that option", O, V}). + parse_affiliation_string(String) -> {Type, JidS} = case String of <<"owner:", Jid/binary>> -> {owner, Jid}; From aa612463cc93e48134ebce6a66f8374618cdcc39 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 15 Jan 2025 20:16:43 +0100 Subject: [PATCH 028/170] mod_muc: Document MUC room option vcard_xupdate --- src/mod_muc.erl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index ca9d21800b0..278b72014c0 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -1692,6 +1692,11 @@ mod_doc() -> " -", " work: true", " street: Elm Street"]}}, + {vcard_xupdate, + #{value => "undefined | external | AvatarHash", + desc => + ?T("Set the hash of the avatar image. " + "The default value is 'undefined'.")}}, {cleanup_affiliations_on_start, #{value => "true | false", note => "added in 22.05", From 6e4ac0c501ca4b5d0f7918980d5910dccb96252d Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 15 Jan 2025 20:49:53 +0100 Subject: [PATCH 029/170] Fix recent commit to work with Erlang/OTP 20 --- src/mod_muc_admin.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 36d37b89984..a260d43b286 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -1737,16 +1737,16 @@ format_room_option(OptionString, ValueString) -> allow_private_messages_from_visitors when (ValueString == <<"anyone">>) or (ValueString == <<"moderators">>) or - (ValueString == <<"nobody">>) -> binary_to_existing_atom(ValueString); + (ValueString == <<"nobody">>) -> binary_to_existing_atom(ValueString, utf8); allowpm when (ValueString == <<"anyone">>) or (ValueString == <<"participants">>) or (ValueString == <<"moderators">>) or - (ValueString == <<"none">>) -> binary_to_existing_atom(ValueString); + (ValueString == <<"none">>) -> binary_to_existing_atom(ValueString, utf8); presence_broadcast when (ValueString == <<"participant">>) or (ValueString == <<"moderator">>) or - (ValueString == <<"visitor">>) -> binary_to_existing_atom(ValueString); + (ValueString == <<"visitor">>) -> binary_to_existing_atom(ValueString, utf8); _ when ValueString == <<"true">> -> true; _ when ValueString == <<"false">> -> false; _ -> throw_error(Option, ValueString) From e7035f3235605a0b5ab07b90ebf0ec711a3ad910 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Mon, 20 Jan 2025 09:10:57 +0300 Subject: [PATCH 030/170] Fix handling of 3PI events in mod_matrix_gw_room --- src/mod_matrix_gw_room.erl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 90ecfec3fd8..07b5a74b0e1 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -1232,8 +1232,14 @@ check_event_auth(Event, StateMap, Data) -> <<"join">>}}}} -> case Event#event.type of ?ROOM_3PI -> - %% TODO - {todo, Event}; + SenderLevel = get_user_power_level(Event#event.sender, StateMap, Data), + InviteLevel = + case maps:find({?ROOM_POWER_LEVELS, <<"">>}, StateMap) of + {ok, #event{json = #{<<"content">> := #{<<"invite">> := S}}}} -> + get_int(S); + _ -> 0 + end, + SenderLevel >= InviteLevel; _ -> case check_event_power_level( Event, StateMap, Data) of From 9be76cce9ec51c7c93a6baa19bb14fcf95eef091 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 20 Jan 2025 18:18:22 +0100 Subject: [PATCH 031/170] Fix support for compiling in VSCode --- .vscode/launch.json | 2 +- .vscode/relive.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 6725568c306..78cdf45ae43 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,7 +19,7 @@ "cwd": "." }, { - "name": "Relive", + "name": "Relive (VSCode)", "type": "erlang", "request": "launch", "runinterminal": [ diff --git a/.vscode/relive.sh b/.vscode/relive.sh index c7db2f74eb0..b10b83fb044 100755 --- a/.vscode/relive.sh +++ b/.vscode/relive.sh @@ -1,6 +1,6 @@ [ ! -f Makefile ] \ && ./autogen.sh \ && ./configure --with-rebar=rebar3 \ - && make deps + && make make relive From cab96d21565ab57f080fccb31312b5a65071ce0b Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 21 Jan 2025 11:36:38 +0100 Subject: [PATCH 032/170] mod_shared_roster: Remove unnecesary double call to split_grouphost which was added in 5b0f0d8 --- src/mod_shared_roster.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 3c454b0dfbe..479956d595a 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -439,8 +439,7 @@ get_group_opts(Host1, Group1) -> {Host, Group} = split_grouphost(Host1, Group1), get_group_opts_int(Host, Group). -get_group_opts_int(Host1, Group1) -> - {Host, Group} = split_grouphost(Host1, Group1), +get_group_opts_int(Host, Group) -> Mod = gen_mod:db_mod(Host, ?MODULE), Res = case use_cache(Mod, Host) of true -> From 20a77cb9c7f4851505f209027b000c817dd0c6b4 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 21 Jan 2025 11:18:50 +0100 Subject: [PATCH 033/170] acl: Fixed bug matching the acl "shared_group: NAME" This config triggered a crash at client login: acl: tech: shared_group: techteam access_rules: announce: allow: tech configure: allow: tech --- src/acl.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index 9daa373b391..eaa0aa50f1b 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -106,8 +106,8 @@ match_acl(_Host, {shared_group, {G, H}}, #{usr := {U, S, _}}) -> undefined -> false; Mod -> Mod:is_user_in_group({U, S}, G, H) end; -match_acl(Host, {shared_group, G}, Map) -> - match_acl(Host, {shared_group, {G, Host}}, Map); +match_acl(Host, {shared_group, G}, #{usr := {_, S, _}} = Map) -> + match_acl(Host, {shared_group, {G, S}}, Map); match_acl(_Host, {user_regexp, {UR, S1}}, #{usr := {U, S2, _}}) -> S1 == S2 andalso match_regexp(U, UR); match_acl(_Host, {user_regexp, UR}, #{usr := {U, S, _}}) -> From 133d52d04023d603283a7796c46bc40ffc7cd3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 22 Jan 2025 14:12:32 +0100 Subject: [PATCH 034/170] Stop processing other handlers in mod_s2s_bidi:s2s_in_handle_info This should fix issue reported in #4344 --- src/mod_s2s_bidi.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_s2s_bidi.erl b/src/mod_s2s_bidi.erl index 06a6b92aa02..7b9556028a3 100644 --- a/src/mod_s2s_bidi.erl +++ b/src/mod_s2s_bidi.erl @@ -125,7 +125,7 @@ s2s_out_packet(State, _Pkt) -> State. s2s_in_handle_info(State, {route, Pkt}) when ?is_stanza(Pkt) -> - ejabberd_s2s_in:send(State, Pkt); + {stop, ejabberd_s2s_in:send(State, Pkt)}; s2s_in_handle_info(State, _Info) -> State. From a19ab9f4e3586d6298f739b88b9e624bc282f815 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Sat, 25 Jan 2025 22:21:43 +0100 Subject: [PATCH 035/170] Update xmpp to bring SSDP to XEP version 0.4 --- mix.exs | 2 +- mix.lock | 2 +- rebar.config | 2 +- rebar.lock | 7 ++++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mix.exs b/mix.exs index 97487b84c79..fb9a31dbbcd 100644 --- a/mix.exs +++ b/mix.exs @@ -144,7 +144,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, "~> 1.9.3"}, + {:xmpp, git: "https://github.com/processone/xmpp", ref: "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0", override: true}, {:yconf, "~> 1.0.17"}] ++ cond_deps() end diff --git a/mix.lock b/mix.lock index 9842b9c9143..8ce6a75c1a9 100644 --- a/mix.lock +++ b/mix.lock @@ -34,6 +34,6 @@ "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:hex, :xmpp, "1.9.3", "fa4f9eda52d789f4b9f5ff11fed17da2c43fa8d01ed7c4fadcb09ab602be9c18", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "d5c96fcb2cf8a8da43a5f81935b2e43fa9b959e1626fcecf082f4af9139bdbd2"}, + "xmpp": {:git, "https://github.com/processone/xmpp", "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0", [ref: "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"]}, "yconf": {:hex, :yconf, "1.0.17", "dcf242e27f3fc5d0743d6b8175dd39bc14a1f4ed7e6ea986366a44a6ff3b2a3a", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "dd2892923241449a46cc8457b9ec0fb14030700735a5885955677c735c341a25"}, } diff --git a/rebar.config b/rebar.config index bc6a258c59d..0e0e3154fae 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", {tag, "1.9.3"}}}, + {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"}}, {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", {tag, "1.0.17"}}} ]}. diff --git a/rebar.lock b/rebar.lock index 7a9e810bfbd..e96263cb97d 100644 --- a/rebar.lock +++ b/rebar.lock @@ -24,7 +24,10 @@ {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.30">>},0}, {<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, - {<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.3">>},0}, + {<<"xmpp">>, + {git,"https://github.com/processone/xmpp", + {ref,"64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"}}, + 0}, {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.17">>},0}]}. [ {pkg_hash,[ @@ -53,7 +56,6 @@ {<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>}, {<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>}, {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, - {<<"xmpp">>, <<"FA4F9EDA52D789F4B9F5FF11FED17DA2C43FA8D01ED7C4FADCB09AB602BE9C18">>}, {<<"yconf">>, <<"DCF242E27F3FC5D0743D6B8175DD39BC14A1F4ED7E6EA986366A44A6FF3B2A3A">>}]}, {pkg_hash_ext,[ {<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>}, @@ -81,6 +83,5 @@ {<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>}, {<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>}, {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, - {<<"xmpp">>, <<"D5C96FCB2CF8A8DA43A5F81935B2E43FA9B959E1626FCECF082F4AF9139BDBD2">>}, {<<"yconf">>, <<"DD2892923241449A46CC8457B9EC0FB14030700735A5885955677C735C341A25">>}]} ]. From eca3204e824a687b6f941b05fca61ee6125cee3b Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Tue, 28 Jan 2025 19:37:49 +0100 Subject: [PATCH 036/170] mod_private: Don't crash on invalid bookmarks Catch failures while decoding the conference bookmark element. --- src/mod_private.erl | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mod_private.erl b/src/mod_private.erl index 3f73a3bcac4..950b7d81883 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -447,17 +447,20 @@ pubsub_delete_item(_, _, _, _, _) -> -spec pubsub_item_to_storage_bookmark(#pubsub_item{}) -> {true, bookmark_conference()} | false. pubsub_item_to_storage_bookmark(#pubsub_item{itemid = {Id, _}, payload = [#xmlel{} = B | _]}) -> - case xmpp:decode(B) of + try #pep_bookmarks_conference{name = Name, autojoin = AutoJoin, nick = Nick, - password = Password} -> - try jid:decode(Id) of - #jid{} = Jid -> - {true, #bookmark_conference{jid = Jid, name = Name, autojoin = AutoJoin, nick = Nick, - password = Password}} - catch _:_ -> - false - end; - _ -> + password = Password} = xmpp:decode(B), + #jid{} = Jid = jid:decode(Id), + {true, #bookmark_conference{jid = Jid, name = Name, + autojoin = AutoJoin, nick = Nick, + password = Password}} + catch + _:{xmpp_codec, Why} -> + ?DEBUG("Failed to decode bookmark element (~ts): ~ts", + [Id, xmpp:format_error(Why)]), + false; + _:{bad_jid, _} -> + ?DEBUG("Failed to decode bookmark ID (~ts)", [Id]), false end; pubsub_item_to_storage_bookmark(_) -> From 20a0051578df86e4a7b30aaca9c738871cd8a30b Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 31 Jan 2025 13:49:22 +0100 Subject: [PATCH 037/170] mod_private: Handle invalid PEP-native bookmarks Don't crash while attempting to convert invalid XEP-0402 conference bookmark elements. --- src/mod_private.erl | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/mod_private.erl b/src/mod_private.erl index 950b7d81883..ab8b0aa2c08 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -490,15 +490,19 @@ storage_bookmark_to_xmpp_bookmark(#bookmark_conference{name = Name, autojoin = A -spec pubsub_item_to_map(#pubsub_item{}, map()) -> map(). pubsub_item_to_map(#pubsub_item{itemid = {Id, _}, payload = [#xmlel{} = B | _]}, Map) -> - case xmpp:decode(B) of - #pep_bookmarks_conference{} = B2 -> - try jid:decode(Id) of - #jid{} = Jid -> - maps:put(jid:tolower(Jid), B2#pep_bookmarks_conference{extensions = undefined}, Map) - catch _:_ -> - Map - end; - _ -> + try {xmpp:decode(B), jid:decode(Id)} of + {#pep_bookmarks_conference{} = B1, #jid{} = Jid} -> + B2 = B1#pep_bookmarks_conference{extensions = undefined}, + maps:put(jid:tolower(Jid), B2, Map); + {_, _} -> + Map + catch + _:{xmpp_codec, Why} -> + ?DEBUG("Failed to decode bookmark element (~ts): ~ts", + [Id, xmpp:format_error(Why)]), + Map; + _:{bad_jid, _} -> + ?DEBUG("Failed to decode bookmark ID (~ts)", [Id]), Map end; pubsub_item_to_map(_, Map) -> From e134d7f0b42888ee09edfee0d74820b29bc80b2b Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 31 Jan 2025 13:51:37 +0100 Subject: [PATCH 038/170] mod_private: Don't warn on conversion errors Clients publish invalid bookmark elements in practice (e.g., bookmarks with an empty element). The server admin can't address that issue, so don't spam the log with warnings. --- src/mod_private.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_private.erl b/src/mod_private.erl index ab8b0aa2c08..3244f351541 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -340,8 +340,8 @@ publish_pep_native_bookmarks(JID, Data) -> #bookmark_storage{conference = C} -> C; _ -> [] catch _:{xmpp_codec, Why} -> - ?WARNING_MSG("Failed to decode bookmarks of ~ts: ~ts", - [jid:encode(JID), xmpp:format_error(Why)]), + ?DEBUG("Failed to decode bookmarks of ~ts: ~ts", + [jid:encode(JID), xmpp:format_error(Why)]), [] end, PubOpts = [{persist_items, true}, {access_model, whitelist}, {max_items, max}, {notify_retract,true}, {notify_delete,true}, {send_last_published_item, never}], From 76baf58d5d1158a1f0d02484db807a041a6f96fc Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 31 Jan 2025 14:23:45 +0100 Subject: [PATCH 039/170] mod_private: Improve exception handling Properly isolate the code that should be subject to exception handling. --- src/mod_private.erl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/mod_private.erl b/src/mod_private.erl index 3244f351541..145edefcfd2 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -447,13 +447,15 @@ pubsub_delete_item(_, _, _, _, _) -> -spec pubsub_item_to_storage_bookmark(#pubsub_item{}) -> {true, bookmark_conference()} | false. pubsub_item_to_storage_bookmark(#pubsub_item{itemid = {Id, _}, payload = [#xmlel{} = B | _]}) -> - try - #pep_bookmarks_conference{name = Name, autojoin = AutoJoin, nick = Nick, - password = Password} = xmpp:decode(B), - #jid{} = Jid = jid:decode(Id), - {true, #bookmark_conference{jid = Jid, name = Name, - autojoin = AutoJoin, nick = Nick, - password = Password}} + try {xmpp:decode(B), jid:decode(Id)} of + {#pep_bookmarks_conference{name = Name, autojoin = AutoJoin, + nick = Nick, password = Password}, + #jid{} = Jid} -> + {true, #bookmark_conference{jid = Jid, name = Name, + autojoin = AutoJoin, nick = Nick, + password = Password}}; + {_, _} -> + false catch _:{xmpp_codec, Why} -> ?DEBUG("Failed to decode bookmark element (~ts): ~ts", From a4062f6ac0f07f788bbd1dd45753da2362c7a41c Mon Sep 17 00:00:00 2001 From: Matthew Stickney Date: Sat, 18 Jan 2025 13:57:26 -0500 Subject: [PATCH 040/170] mod_privilege: Accept non-privileged IQs from privileged components. mod_privilege current drops any non-privileged IQ received from a component with an error about it not being properly wrapped. While this might represent a mistake on the part of the component, it means that well- behaved components can no longer send non-privileged IQs (something they normally can do if mod_privilege isn't enabled). Since mod_privilege is intended to grant additional permissions, and not remove existing ones, route non-privileged IQs received from the component normally. This also removes the special-case for roster-query IQ stanzas, since those are also non-privileged and will be routed along with any other non-privileged IQ packet. This mirrors the privileged-IQ/everything-else structure of the XEP, which defined the handling of privileged IQ stanzas and leaves all other IQ stanzas as defined in their own specs. To make this clearer, the predicate function now returns distinct results indicating privileged IQs, non-privileged IQs, and error conditions, rather than treating non-privilege IQs as an error that gets handled by routing the packet normally. --- src/mod_privilege.erl | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl index bdf512f34fd..862f0c0be9e 100644 --- a/src/mod_privilege.erl +++ b/src/mod_privilege.erl @@ -272,7 +272,7 @@ component_send_packet({#iq{from = From, Permissions = get_permissions(ServerHost), Result = case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of - {{ok, Access}, {ok, EncapType, EncapNs, EncapFrom, EncIq}} + {{ok, Access}, {privileged_iq, EncapType, EncapNs, EncapFrom, EncIq}} when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) -> NsPermissions = proplists:get_value(iq, Access, []), Permission = @@ -297,20 +297,18 @@ component_send_packet({#iq{from = From, %% Component is disconnected ?INFO_MSG("IQ not forwarded: Component seems disconnected", []), drop; - {_, {ok, E, _, _, _}} when E /= Type -> + {_, {privileged_iq, E, _, _, _}} when E /= Type -> ?INFO_MSG("IQ not forwarded: The encapsulated IQ stanza type=~p " "does not match the top-level IQ stanza type=~p", [E, Type]), drop; - {_, {ok, _, _, EF, _}} when (EF /= undefined) and (EF /= To) -> + {_, {privileged_iq, _, _, EF, _}} when (EF /= undefined) and (EF /= To) -> ?INFO_MSG("IQ not forwarded: The FROM attribute in the encapsulated " "IQ stanza and the TO in top-level IQ stanza do not match", []), drop; - {_, {error, no_privileged_iq, _Err}} -> - ?INFO_MSG("IQ not forwarded: Component tried to send not wrapped IQ stanza.", []), - drop; - {_, {error, roster_query, _Err}} -> + {_, {unprivileged_iq}} -> + ?DEBUG("Component ~ts sent a not-wrapped IQ stanza, routing it as-is.", [From#jid.lserver]), IQ; {_, {error, ErrType, _Err}} -> ?INFO_MSG("IQ not forwarded: Component tried to send not valid IQ stanza: ~p.", @@ -566,7 +564,8 @@ forward_message(#message{to = To} = Msg) -> %% @format-begin -spec get_iq_encapsulated_details(iq()) -> - {ok, iq_type(), binary(), jid(), iq()} | + {privileged_iq, iq_type(), binary(), jid(), iq()} | + {unprivileged_iq} | {error, Why :: atom(), stanza_error()}. get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) -> Lang = xmpp:get_lang(Msg), @@ -575,21 +574,9 @@ get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) -> [IqSubSub] = xmpp:get_els(IqSub), [Element] = xmpp:get_els(IqSubSub), Ns = xmpp:get_ns(Element), - {ok, EncapsulatedType, Ns, From, EncIq}; + {privileged_iq, EncapsulatedType, Ns, From, EncIq}; _ -> - try xmpp:try_subtag(Msg, #roster_query{}) of - #roster_query{} -> - {error, roster_query, xmpp:err_bad_request()}; - _ -> - Txt = ?T("No element found"), - Err = xmpp:err_bad_request(Txt, Lang), - {error, no_privileged_iq, Err} - catch - _:{xmpp_codec, Why} -> - Txt = xmpp:io_format_error(Why), - Err = xmpp:err_bad_request(Txt, Lang), - {error, codec_error, Err} - end + {unprivileged_iq} catch _:{xmpp_codec, Why} -> Txt = xmpp:io_format_error(Why), From 64142de4fee88bc4c48289f8433cf3bd323e24b6 Mon Sep 17 00:00:00 2001 From: Matthew Stickney Date: Tue, 28 Jan 2025 14:50:44 -0500 Subject: [PATCH 041/170] Don't rewrite "self-addressed" privileged IQs as results. process_privilege_iq is meant to rewrite the result of a privileged IQ into the forwarded form required by XEP-0356 so it can be routed back to the original privileged requester. It checks whether the impersonated JID (`ReplacedJid`) of the original request matches the recipient of the IQ being processed to determine if this is a response to a a privileged IQ (assuming it has privileged-IQ metadata attached). Unfortunately, it doesn't check the packet type, and this check will also match a privileged-IQ _request_ that is being sent to the same user that's being impersonated. This results in the request itself being rewritten and forwarded back to the sending component, instead of being processed and having the result send back. Instead, just check for IQ results (either a regular result or an error), and as long as it is marked as being a response to a privileged-IQ, always rewrite it and forward it to the sending component. There's no circumstance under which we _shouldn't_ forward a privileged-IQ response, so we don't need to be tricky about checking whether impersonated-user and recipient match. --- src/ejabberd_router.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 2d80314c7c4..de088d8ba0b 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -408,9 +408,9 @@ do_route(OrigPacket1) -> %% @format-begin process_privilege_iq(Packet) -> - To = xmpp:get_to(Packet), + Type = xmpp:get_type(Packet), case xmpp:get_meta(Packet, privilege_iq, none) of - {OriginalId, OriginalHost, ReplacedJid} when ReplacedJid == To -> + {OriginalId, OriginalHost, ReplacedJid} when (Type == result) or (Type == error) -> Privilege = #privilege{forwarded = #forwarded{sub_els = [Packet]}}, #iq{type = xmpp:get_type(Packet), id = OriginalId, From e34b6f4204e67d55967b460ebf944a11410ec90b Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 24 Jan 2025 23:37:07 +0100 Subject: [PATCH 042/170] Update odbc:connection_reference mention to fix dialyzer with Erlang/OTP 28 --- mix.exs | 16 +--------------- rebar.config | 2 +- src/ejabberd_sql.erl | 19 +++++++++++++++---- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/mix.exs b/mix.exs index fb9a31dbbcd..af72070c9c6 100644 --- a/mix.exs +++ b/mix.exs @@ -79,20 +79,6 @@ defmodule Ejabberd.MixProject do end end - defp if_type_exported(module, typeDef, okResult) do - try do - {:ok, concrete} = :dialyzer_utils.get_core_from_beam(:code.which(module)) - {:ok, types} = :dialyzer_utils.get_record_and_type_info(concrete) - if Map.has_key?(types, typeDef) do - okResult - else - [] - end - rescue - _ -> [] - end - end - defp erlc_options do # Use our own includes + includes from all dependencies includes = ["include", deps_include()] @@ -113,7 +99,7 @@ defmodule Ejabberd.MixProject do if_version_below(~c"25", [{:d, :OTP_BELOW_25}]) ++ if_version_below(~c"26", [{:d, :OTP_BELOW_26}]) ++ if_version_below(~c"27", [{:d, :OTP_BELOW_27}]) ++ - if_type_exported(:odbc, {:opaque, :connection_reference, 0}, [{:d, :ODBC_HAS_TYPES}]) + if_version_below(~c"28", [{:d, :OTP_BELOW_28}]) defines = for {:d, value} <- result, do: {:d, value} result ++ [{:d, :ALL_DEFS, defines}] end diff --git a/rebar.config b/rebar.config index 0e0e3154fae..3b0942c8725 100644 --- a/rebar.config +++ b/rebar.config @@ -140,6 +140,7 @@ {if_version_below, "25", {d, 'OTP_BELOW_25'}}, {if_version_below, "26", {d, 'OTP_BELOW_26'}}, {if_version_below, "27", {d, 'OTP_BELOW_27'}}, + {if_version_below, "28", {d, 'OTP_BELOW_28'}}, {if_var_false, debug, no_debug_info}, {if_var_true, debug, debug_info}, {if_var_true, elixir, {d, 'ELIXIR_ENABLED'}}, @@ -147,7 +148,6 @@ {if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATEWAY_WORKAROUND'}}, {if_var_true, sip, {d, 'SIP'}}, {if_var_true, stun, {d, 'STUN'}}, - {if_type_exported, {odbc, {opaque, connection_reference, 0}}, {d, 'ODBC_HAS_TYPES'}}, {src_dirs, [src, {if_rebar3, sql}, {if_var_true, tools, tools}]}]}. diff --git a/src/ejabberd_sql.erl b/src/ejabberd_sql.erl index e6e06bc402b..36db77fee44 100644 --- a/src/ejabberd_sql.erl +++ b/src/ejabberd_sql.erl @@ -70,10 +70,21 @@ -export([connecting/2, connecting/3, session_established/2, session_established/3]). --ifdef(ODBC_HAS_TYPES). - -type(odbc_connection_reference() :: odbc:connection_reference()). +-ifdef(OTP_BELOW_28). +-ifdef(OTP_BELOW_26). +%% OTP 25 or lower +-type(odbc_connection_reference() :: pid()). +-type(db_ref_pid() :: pid()). -else. - -type(odbc_connection_reference() :: pid()). +%% OTP 26 or 27 +-type(odbc_connection_reference() :: odbc:connection_reference()). +-type(db_ref_pid() :: pid()). +-endif. +-else. +%% OTP 28 or higher +-nominal(odbc_connection_reference() :: odbc:connection_reference()). +-nominal(db_ref_pid() :: pid()). +-dialyzer([no_opaque_union]). -endif. -include("logger.hrl"). @@ -81,7 +92,7 @@ -include("ejabberd_stacktrace.hrl"). -record(state, - {db_ref :: undefined | pid() | odbc_connection_reference(), + {db_ref :: undefined | db_ref_pid() | odbc_connection_reference(), db_type = odbc :: pgsql | mysql | sqlite | odbc | mssql, db_version :: undefined | non_neg_integer() | {non_neg_integer(), atom(), non_neg_integer()}, reconnect_count = 0 :: non_neg_integer(), From 0732603a4e1374def9c9e74138942f30f460b2d6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 24 Jan 2025 18:50:48 +0100 Subject: [PATCH 043/170] Disable opaque_union dialyzer warnings as workaround for dialyzer with Erlang/OTP 28 See https://github.com/erlang/otp/commit/5dab31e9f991531f2e0de44b896229b686f753f9 --- src/ejabberd_config.erl | 4 ++++ src/ejabberd_shaper.erl | 4 ++++ src/ejabberd_websocket.erl | 5 +++++ src/mod_muc_room.erl | 4 ++++ 4 files changed, 17 insertions(+) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 8b55be2db36..c7849792bf7 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -68,6 +68,10 @@ -optional_callbacks([globals/0]). +-ifndef(OTP_BELOW_28). +-dialyzer([no_opaque_union]). +-endif. + %%%=================================================================== %%% API %%%=================================================================== diff --git a/src/ejabberd_shaper.erl b/src/ejabberd_shaper.erl index c47d72dbd37..af0b3faba50 100644 --- a/src/ejabberd_shaper.erl +++ b/src/ejabberd_shaper.erl @@ -36,6 +36,10 @@ -export_type([shaper/0, shaper_rule/0, shaper_rate/0]). +-ifndef(OTP_BELOW_28). +-dialyzer([no_opaque_union]). +-endif. + %%%=================================================================== %%% API %%%=================================================================== diff --git a/src/ejabberd_websocket.erl b/src/ejabberd_websocket.erl index 43b6673d48d..dbcf8e2e015 100644 --- a/src/ejabberd_websocket.erl +++ b/src/ejabberd_websocket.erl @@ -62,6 +62,11 @@ ?AC_ALLOW_HEADERS, ?AC_MAX_AGE]). -define(HEADER, [?CT_XML, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]). +-ifndef(OTP_BELOW_28). +-dialyzer([no_opaque_union]). +-endif. + + is_valid_websocket_upgrade(_Path, Headers) -> HeadersToValidate = [{'Upgrade', <<"websocket">>}, {'Connection', ignore}, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index f9fb9f88295..f48e58a9439 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -116,6 +116,10 @@ -callback search_affiliation(binary(), binary(), binary(), affiliation()) -> {ok, [{ljid(), {affiliation(), binary()}}]} | {error, any()}. +-ifndef(OTP_BELOW_28). +-dialyzer([no_opaque_union]). +-endif. + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- From 22b3d0e49f7b2d7d9974e66c41591c837922b465 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Jan 2025 12:22:31 +0100 Subject: [PATCH 044/170] get_auto_url: Don't build auto URL if port is unix domain socket (#4345) --- src/ejabberd_captcha.erl | 17 ++++++++++------- src/mod_host_meta.erl | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index 794041a1993..d1d62e59b38 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -454,12 +454,15 @@ get_prog_name() -> maybe_warning_norequesthandler() -> Host = hd(ejabberd_option:hosts()), - URL = get_auto_url(https://github.com/any,%20?MODULE,%20Host), - case URL of - undefined -> - ?WARNING_MSG("The option captcha_cmd is configured, " - "but there is NO request_handler in listen option " - "configured with ejabberd_captcha. Please check " + AutoURL = get_auto_url(https://github.com/any,%20?MODULE,%20Host), + ManualURL = ejabberd_option:captcha_url(), + case (AutoURL == undefined) and not is_binary(ManualURL) of + true -> + ?CRITICAL_MSG("The option captcha_cmd is configured " + "and captcha_url is set to auto, " + "but I couldn't find a request_handler in listen option " + "configured with ejabberd_captcha and integer port. " + "Please setup the URL with option captcha_url, see " "https://docs.ejabberd.im/admin/configuration/basic/#captcha", []); _ -> @@ -523,7 +526,7 @@ find_handler_port_path(Tls, Module) -> fun({{Port, _, _}, ejabberd_http, #{tls := ThisTls, request_handlers := Handlers}}) - when (Tls == any) or (Tls == ThisTls) -> + when is_integer(Port) and ((Tls == any) or (Tls == ThisTls)) -> case lists:keyfind(Module, 2, Handlers) of false -> false; {Path, Module} -> {true, {ThisTls, Port, Path}} diff --git a/src/mod_host_meta.erl b/src/mod_host_meta.erl index 80b4dbe8488..c99da63a252 100644 --- a/src/mod_host_meta.erl +++ b/src/mod_host_meta.erl @@ -168,7 +168,7 @@ find_handler_port_path(Tls, Module) -> fun({{Port, _, _}, ejabberd_http, #{tls := ThisTls, request_handlers := Handlers}}) - when (Tls == any) or (Tls == ThisTls) -> + when is_integer(Port) and ((Tls == any) or (Tls == ThisTls)) -> case lists:keyfind(Module, 2, Handlers) of false -> false; {Path, Module} -> {true, {ThisTls, Port, Path}} From 4f90d1a0d97f2194c7d191ea76f98c1a3b1c7ad5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Jan 2025 12:26:20 +0100 Subject: [PATCH 045/170] Document that XEP-0474 0.4.0 was recently upgraded Thanks to https://github.com/processone/xmpp/pull/99 --- src/ejabberd.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 579c9c628aa..89cbd229c3e 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -42,7 +42,7 @@ -protocol({xep, 388, '0.4.0', '24.02', "complete", ""}). -protocol({xep, 424, '0.4.0', '24.02', "complete", ""}). -protocol({xep, 440, '0.4.0', '24.02', "complete", ""}). --protocol({xep, 474, '0.3.0', '24.02', "complete", ""}). +-protocol({xep, 474, '0.4.0', '24.02', "complete", "0.4.0 since 25.xx"}). -protocol({xep, 485, '0.2.0', '24.02', "complete", "mod_pubsub_serverinfo in ejabberd-contrib.git"}). -export([start/0, stop/0, halt/0, start_app/1, start_app/2, From cae40c3f725dd0beb811e0e763e2a85590653c69 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Jan 2025 16:58:16 +0100 Subject: [PATCH 046/170] mod_http_api: Define the option type that opt_type.sh cannot derive itself --- src/mod_http_api.erl | 2 ++ src/mod_http_api_opt.erl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index 219267ef931..b2fe7b7c0e1 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -571,6 +571,8 @@ mod_opt_type(default_version) -> end end)). +-spec mod_options(binary()) -> [{default_version, integer()}]. + mod_options(_) -> [{default_version, ?DEFAULT_API_VERSION}]. diff --git a/src/mod_http_api_opt.erl b/src/mod_http_api_opt.erl index 7ab489b729a..326c53e02d0 100644 --- a/src/mod_http_api_opt.erl +++ b/src/mod_http_api_opt.erl @@ -5,7 +5,7 @@ -export([default_version/1]). --spec default_version(gen_mod:opts() | global | binary()) -> any(). +-spec default_version(gen_mod:opts() | global | binary()) -> integer(). default_version(Opts) when is_map(Opts) -> gen_mod:get_opt(default_version, Opts); default_version(Host) -> From a9c7bf97efc137795def1da6d4595c778c37dfda Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 4 Feb 2025 13:38:03 +0100 Subject: [PATCH 047/170] Add define_macro to globals() because it's useless inside host_config --- src/ejabberd_options.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index 673de29d7e9..6c0ed08f291 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -750,6 +750,7 @@ globals() -> certfiles, cluster_backend, cluster_nodes, + define_macro, domain_balancing, ext_api_path_oauth, fqdn, From 480e2442ee5313910533e8f7e0d8d10d48879d0c Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 3 Feb 2025 12:07:02 +0100 Subject: [PATCH 048/170] Improve define_macro option validator --- src/ejabberd_options.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index 6c0ed08f291..6caee7624c7 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -139,7 +139,7 @@ opt_type(default_db) -> opt_type(default_ram_db) -> econf:enum([mnesia, sql, redis]); opt_type(define_macro) -> - econf:any(); + econf:map(econf:binary(), econf:any(), [unique]); opt_type(disable_sasl_scram_downgrade_protection) -> econf:bool(); opt_type(disable_sasl_mechanisms) -> From 07b102bb806d4e8b43e7124b11f8562b4f53948b Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 4 Feb 2025 13:09:14 +0100 Subject: [PATCH 049/170] Docs: Fix markdown of some toplevel options --- src/ejabberd_options_doc.erl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 19e7773da07..ae2d7538bf5 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -472,8 +472,8 @@ doc() -> note => "improved in 23.01", desc => ?T("Full path to a script that generates _`basic.md#captcha|CAPTCHA`_ images. " - "'@VERSION@' is replaced with ejabberd version number in 'XX.YY' format. " - "'@SEMVER@' is replaced with ejabberd version number in semver format " + "The keyword '@VERSION@' is replaced with ejabberd version number in 'XX.YY' format. " + "The keyword '@SEMVER@' is replaced with ejabberd version number in semver format " "when compiled with Elixir's mix, or XX.YY format otherwise. " "Alternatively, it can be the name of a module that implements ejabberd CAPTCHA support. " "There is no default value: when this option is not " @@ -845,18 +845,18 @@ doc() -> "as alternatives for getting the JID, where 'Attr' is " "an LDAP attribute which holds the user's part of the JID and " "'AttrFormat' must contain one and only one pattern variable " - "\"%u\" which will be replaced by the user's part of the JID. " - "For example, \"%u@example.org\". If the value is in the form " - "of '[Attr]' then 'AttrFormat' is assumed to be \"%u\".")}}, + "'\"%u\"' which will be replaced by the user's part of the JID. " + "For example, '\"%u@example.org\"'. If the value is in the form " + "of '[Attr]' then 'AttrFormat' is assumed to be '\"%u\"'.")}}, {ldap_filter, #{value => ?T("Filter"), desc => ?T("An LDAP filter as defined in " "https://tools.ietf.org/html/rfc4515[RFC4515]." "There is no default value. Example: " - "\"(&(objectClass=shadowAccount)(memberOf=XMPP Users))\". " + "'\"(&(objectClass=shadowAccount)(memberOf=XMPP Users))\"'. " "NOTE: don't forget to close brackets and don't use superfluous " - "whitespaces. Also you must not use \"uid\" attribute in the " + "whitespaces. Also you must not use '\"uid\"' attribute in the " "filter because this attribute will be appended to the filter " "automatically.")}}, {ldap_dn_filter, @@ -866,11 +866,11 @@ doc() -> "filter. The filter performs an additional LDAP lookup to make " "the complete result. This is useful when you are unable to " "define all filter rules in 'ldap_filter'. You can define " - "\"%u\", \"%d\", \"%s\" and \"%D\" pattern variables in 'Filter': " - "\"%u\" is replaced by a user's part of the JID, \"%d\" is " - "replaced by the corresponding domain (virtual host), all \"%s\" " + "'\"%u\"', '\"%d\"', '\"%s\"' and '\"%D\"' pattern variables in 'Filter: " + "\"%u\"' is replaced by a user's part of the JID, '\"%d\"' is " + "replaced by the corresponding domain (virtual host), all '\"%s\"' " "variables are consecutively replaced by values from the attributes " - "in 'FilterAttrs' and \"%D\" is replaced by Distinguished Name from " + "in 'FilterAttrs' and '\"%D\"' is replaced by Distinguished Name from " "the result set. There is no default value, which means the " "result is not filtered. WARNING: Since this filter makes " "additional LDAP lookups, use it only as the last resort: " From d834a9c1c1786678af4bb51e17ab750473f19164 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Feb 2025 13:36:56 +0100 Subject: [PATCH 050/170] Delete ejabberd.cfg which apparently isn't needed anymore --- test/ejabberd_SUITE_data/ejabberd.cfg | 181 -------------------------- 1 file changed, 181 deletions(-) delete mode 100644 test/ejabberd_SUITE_data/ejabberd.cfg diff --git a/test/ejabberd_SUITE_data/ejabberd.cfg b/test/ejabberd_SUITE_data/ejabberd.cfg deleted file mode 100644 index 251f231188a..00000000000 --- a/test/ejabberd_SUITE_data/ejabberd.cfg +++ /dev/null @@ -1,181 +0,0 @@ -{loglevel, 4}. -{hosts, ["localhost", - "mnesia.localhost", - "mysql.localhost", - "mssql.localhost", - "pgsql.localhost", - "sqlite.localhost", - "extauth.localhost", - "ldap.localhost"]}. -{define_macro, 'CERTFILE', "cert.pem"}. -{listen, - [ - {5222, ejabberd_c2s, [ - {access, c2s}, - {shaper, c2s_shaper}, - starttls, zlib, - {certfile, 'CERTFILE'}, - {max_stanza_size, 65536} - ]}, - {5269, ejabberd_s2s_in, [ - {shaper, s2s_shaper}, - {max_stanza_size, 131072} - ]}, - {5280, ejabberd_http, [ - captcha - ]} - ]}. -{shaper, normal, {maxrate, 1000}}. -{shaper, fast, {maxrate, 50000}}. -{max_fsm_queue, 1000}. -{acl, local, {user_regexp, ""}}. -{access, max_user_sessions, [{10, all}]}. -{access, max_user_offline_messages, [{5000, admin}, {100, all}]}. -{access, local, [{allow, local}]}. -{access, c2s, [{deny, blocked}, - {allow, all}]}. -{access, c2s_shaper, [{none, admin}, - {normal, all}]}. -{access, s2s_shaper, [{fast, all}]}. -{access, announce, [{allow, admin}]}. -{access, configure, [{allow, admin}]}. -{access, muc_admin, [{allow, admin}]}. -{access, muc_create, [{allow, local}]}. -{access, muc, [{allow, all}]}. -{access, pubsub_createnode, [{allow, local}]}. -{access, register, [{allow, all}]}. -{registration_timeout, infinity}. -{language, "en"}. -{modules, - [ - {mod_adhoc, []}, - {mod_configure, []}, - {mod_disco, []}, - {mod_ping, []}, - {mod_proxy65, []}, - {mod_register, [ - {welcome_message, {"Welcome!", - "Hi.\nWelcome to this XMPP server."}} - ]}, - {mod_stats, []}, - {mod_time, []}, - {mod_version, []} -]}. -{host_config, "localhost", [{auth_method, internal}]}. -{host_config, "extauth.localhost", - [{auth_method, external}, - {extauth_program, "python3 extauth.py"}]}. -{host_config, "mnesia.localhost", - [{auth_method, internal}, - {{add, modules}, [{mod_announce, [{db_type, internal}]}, - {mod_blocking, [{db_type, internal}]}, - {mod_caps, [{db_type, internal}]}, - {mod_last, [{db_type, internal}]}, - {mod_muc, [{db_type, internal}]}, - {mod_offline, [{db_type, internal}]}, - {mod_privacy, [{db_type, internal}]}, - {mod_private, [{db_type, internal}]}, - {mod_pubsub, [{access_createnode, pubsub_createnode}, - {ignore_pep_from_offline, true}, - {last_item_cache, false}, - {plugins, ["flat", "hometree", "pep"]}]}, - {mod_roster, [{db_type, internal}]}, - {mod_vcard, [{db_type, internal}]}]} - ]}. -{host_config, "mysql.localhost", - [{auth_method, odbc}, - {odbc_pool_size, 1}, - {odbc_server, {mysql, "localhost", "ejabberd_test", - "ejabberd_test", "ejabberd_test"}}, - {{add, modules}, [{mod_announce, [{db_type, odbc}]}, - {mod_blocking, [{db_type, odbc}]}, - {mod_caps, [{db_type, odbc}]}, - {mod_last, [{db_type, odbc}]}, - {mod_muc, [{db_type, odbc}]}, - {mod_offline, [{db_type, odbc}]}, - {mod_privacy, [{db_type, odbc}]}, - {mod_private, [{db_type, odbc}]}, - {mod_pubsub, [{db_type, odbc}, - {access_createnode, pubsub_createnode}, - {ignore_pep_from_offline, true}, - {last_item_cache, false}, - {plugins, ["flat", "hometree", "pep"]}]}, - {mod_roster, [{db_type, odbc}]}, - {mod_vcard, [{db_type, odbc}]}]} - ]}. -{host_config, "mssql.localhost", - [{auth_method, odbc}, - {odbc_pool_size, 1}, - {odbc_server, {mssql, "localhost", "ejabberd_test", - "ejabberd_test", "ejabberd_Test1"}}, - {{add, modules}, [{mod_announce, [{db_type, odbc}]}, - {mod_blocking, [{db_type, odbc}]}, - {mod_caps, [{db_type, odbc}]}, - {mod_last, [{db_type, odbc}]}, - {mod_muc, [{db_type, odbc}]}, - {mod_offline, [{db_type, odbc}]}, - {mod_privacy, [{db_type, odbc}]}, - {mod_private, [{db_type, odbc}]}, - {mod_pubsub, [{db_type, odbc}, - {access_createnode, pubsub_createnode}, - {ignore_pep_from_offline, true}, - {last_item_cache, false}, - {plugins, ["flat", "hometree", "pep"]}]}, - {mod_roster, [{db_type, odbc}]}, - {mod_vcard, [{db_type, odbc}]}]} - ]}. -{host_config, "pgsql.localhost", - [{auth_method, odbc}, - {odbc_pool_size, 1}, - {odbc_server, {pgsql, "localhost", "ejabberd_test", - "ejabberd_test", "ejabberd_test"}}, - {{add, modules}, [{mod_announce, [{db_type, odbc}]}, - {mod_blocking, [{db_type, odbc}]}, - {mod_caps, [{db_type, odbc}]}, - {mod_last, [{db_type, odbc}]}, - {mod_muc, [{db_type, odbc}]}, - {mod_offline, [{db_type, odbc}]}, - {mod_privacy, [{db_type, odbc}]}, - {mod_private, [{db_type, odbc}]}, - {mod_pubsub, [{db_type, odbc}, - {access_createnode, pubsub_createnode}, - {ignore_pep_from_offline, true}, - {last_item_cache, false}, - {plugins, ["flat", "hometree", "pep"]}]}, - {mod_roster, [{db_type, odbc}]}, - {mod_vcard, [{db_type, odbc}]}]} - ]}. -{host_config, "sqlite.localhost", - [{auth_method, odbc}, - {odbc_pool_size, 1}, - {odbc_server, {sqlite, "/tmp/ejabberd_test.db"}}, - {{add, modules}, [{mod_announce, [{db_type, odbc}]}, - {mod_blocking, [{db_type, odbc}]}, - {mod_caps, [{db_type, odbc}]}, - {mod_last, [{db_type, odbc}]}, - {mod_muc, [{db_type, odbc}]}, - {mod_offline, [{db_type, odbc}]}, - {mod_privacy, [{db_type, odbc}]}, - {mod_private, [{db_type, odbc}]}, - {mod_pubsub, [{db_type, odbc}, - {access_createnode, pubsub_createnode}, - {ignore_pep_from_offline, true}, - {last_item_cache, false}, - {plugins, ["flat", "hometree", "pep"]}]}, - {mod_roster, [{db_type, odbc}]}, - {mod_vcard, [{db_type, odbc}]}]} - ]}. -{host_config, "ldap.localhost", - [{auth_method, ldap}, - {ldap_servers, ["localhost"]}, - {ldap_port, 1389}, - {ldap_rootdn, "cn=admin,dc=localhost"}, - {ldap_password, "password"}, - {ldap_base, "ou=users,dc=localhost"}, - {{add, modules}, [{mod_vcard_ldap, []}]} - ]}. - -%%% Local Variables: -%%% mode: erlang -%%% End: -%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker: From 21ae72d02ecef9df116e95030afe3448d710b0ed Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Feb 2025 11:00:32 +0100 Subject: [PATCH 051/170] Result of running "make doap options" --- ejabberd.doap | 4 ++-- src/ejabberd_option.erl | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ejabberd.doap b/ejabberd.doap index 28a68863c4c..c17c89ca7ff 100644 --- a/ejabberd.doap +++ b/ejabberd.doap @@ -767,10 +767,10 @@ - 0.3.0 + 0.4.0 24.02 complete - + , 0.4.0 since 25.xx diff --git a/src/ejabberd_option.erl b/src/ejabberd_option.erl index 68e959288f6..2677cf42ffb 100644 --- a/src/ejabberd_option.erl +++ b/src/ejabberd_option.erl @@ -38,7 +38,7 @@ -export([cluster_nodes/0]). -export([default_db/0, default_db/1]). -export([default_ram_db/0, default_ram_db/1]). --export([define_macro/0, define_macro/1]). +-export([define_macro/0]). -export([disable_sasl_mechanisms/0, disable_sasl_mechanisms/1]). -export([disable_sasl_scram_downgrade_protection/0, disable_sasl_scram_downgrade_protection/1]). -export([domain_balancing/0]). @@ -374,10 +374,7 @@ default_ram_db(Host) -> -spec define_macro() -> any(). define_macro() -> - define_macro(global). --spec define_macro(global | binary()) -> any(). -define_macro(Host) -> - ejabberd_config:get_option({define_macro, Host}). + ejabberd_config:get_option({define_macro, global}). -spec disable_sasl_mechanisms() -> [binary()]. disable_sasl_mechanisms() -> From 4188c062e7a42786647bca53d83f7992596ffd5c Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 7 Feb 2025 15:27:15 +0100 Subject: [PATCH 052/170] make-binaries: Bump crosstool-NG version to 1.27.0 --- .github/workflows/container.yml | 2 +- .github/workflows/installers.yml | 2 +- tools/make-binaries | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 33ae16960a6..7940c9b6860 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -32,7 +32,7 @@ jobs: uses: actions/cache@v4 with: path: ~/build/ - key: ${{runner.os}}-ctr-ct-ng-1.26.0 + key: ${{runner.os}}-ctr-ct-ng-1.27.0 - name: Get erlang/OTP version for bootstrapping run: | diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml index b820dd6d9e4..1e7f3e761b7 100644 --- a/.github/workflows/installers.yml +++ b/.github/workflows/installers.yml @@ -27,7 +27,7 @@ jobs: uses: actions/cache@v4 with: path: ~/build/ - key: ${{runner.os}}-ct-ng-1.26.0 + key: ${{runner.os}}-ct-ng-1.27.0 - name: Install prerequisites run: | sudo apt-get -qq update diff --git a/tools/make-binaries b/tools/make-binaries index 5c92b241bb8..43455233292 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -65,7 +65,7 @@ fi rel_name='ejabberd' rel_vsn=$(git describe --tags | sed -e 's/-g.*//' -e 's/-/./' | tr -d '[:space:]') mix_vsn=$(mix_version "$rel_vsn") -crosstool_vsn='1.26.0' +crosstool_vsn='1.27.0' termcap_vsn='1.3.1' expat_vsn='2.6.4' zlib_vsn='1.3.1' From d875e0280cd3c5d8b9355a20b2041b81be963a07 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 7 Feb 2025 15:45:59 +0100 Subject: [PATCH 053/170] make-binaries: Stick to Linux-PAM 1.6.1 Stick to Linux-PAM version 1.6.1 for the moment. Newer Linux-PAM versions are built using Meson instead of Autotools, so we need to add that to our toolchain before being able to update Linux-PAM. --- tools/make-binaries | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/make-binaries b/tools/make-binaries index 43455233292..d766002b490 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -73,7 +73,7 @@ yaml_vsn='0.2.5' ssl_vsn='3.4.0' otp_vsn='27.2' elixir_vsn='1.18.1' -pam_vsn='1.6.1' +pam_vsn='1.6.1' # Newer Linux-PAM versions use Meson, we don't support that yet. png_vsn='1.6.44' jpeg_vsn='9f' webp_vsn='1.5.0' @@ -199,9 +199,13 @@ check_configured_dep_vsns() check_vsn 'ODBC' "$odbc_vsn" \ 'http://www.unixodbc.org/download.html' \ 'unixODBC-\([1-9][0-9.]*\)\.tar\.gz' - check_vsn 'Linux-PAM' "$pam_vsn" \ - 'https://github.com/linux-pam/linux-pam/releases' \ - '[0-9]\]Linux-PAM \([1-9][0-9.]*\)' + # + # Linux-PAM uses Meson since version 1.7.0, we don't support that yet. + # + # check_vsn 'Linux-PAM' "$pam_vsn" \ + # 'https://github.com/linux-pam/linux-pam/releases' \ + # '[0-9]\]Linux-PAM \([1-9][0-9.]*\)' + # check_vsn 'libpng' "$png_vsn" \ 'http://www.libpng.org/pub/png/libpng.html' \ 'libpng-\([1-9][0-9.]*\)\.tar\.gz' From 5f849bdb3f03cb8a4a7b1c8ad03643b1c40f020d Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 7 Feb 2025 15:49:25 +0100 Subject: [PATCH 054/170] make-binaries: Bump dependency versions --- tools/make-binaries | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/make-binaries b/tools/make-binaries index d766002b490..edf56314fc2 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -71,15 +71,15 @@ expat_vsn='2.6.4' zlib_vsn='1.3.1' yaml_vsn='0.2.5' ssl_vsn='3.4.0' -otp_vsn='27.2' -elixir_vsn='1.18.1' +otp_vsn='27.2.2' +elixir_vsn='1.18.2' pam_vsn='1.6.1' # Newer Linux-PAM versions use Meson, we don't support that yet. -png_vsn='1.6.44' +png_vsn='1.6.45' jpeg_vsn='9f' webp_vsn='1.5.0' gd_vsn='2.3.3' odbc_vsn='2.3.12' -sqlite_vsn='3470200' +sqlite_vsn='3490000' root_dir="${BUILD_DIR:-$HOME/build}" bootstrap_dir="$root_dir/bootstrap" ct_prefix_dir="$root_dir/x-tools" From a49ec4d583f7050a96fb23cd36c29b5022ee4db1 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Fri, 7 Feb 2025 20:08:26 +0100 Subject: [PATCH 055/170] make-binaries: Fix building Termcap and Linux-PAM Building GNU Termcap and Linux-PAM using the updated toolchain both failed, since crosstool-NG now uses GCC 14.x, which turns the "implicit-function-declaration" warning into an error. See: https://gcc.gnu.org/gcc-14/porting_to.html#warnings-as-errors Therefore, specify "CFLAGS=-Wno-error=implicit-function-declaration" to turn this error back into a warning. --- tools/make-binaries | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/make-binaries b/tools/make-binaries index edf56314fc2..d5876807e43 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -547,6 +547,7 @@ build_deps() info "Building Termcap $termcap_vsn for $arch-$libc ..." cd "$target_src_dir/$termcap_dir" + sed -i 's/CFLAGS =/CFLAGS = -Wno-error=implicit-function-declaration/' 'Makefile.in' $configure --prefix="$prefix" cat >'config.h' <<-'EOF' #ifndef CONFIG_H @@ -630,7 +631,7 @@ build_deps() $configure --prefix="$prefix" --includedir="$prefix/include/security" \ --enable-static --disable-shared --disable-doc --disable-examples \ --enable-db=no \ - CFLAGS="$CFLAGS -O3 -fPIC" + CFLAGS="$CFLAGS -O3 -fPIC -Wno-error=implicit-function-declaration" make make install cd "$OLDPWD" From da61f3dfea03e0d9ab690b4774c76bc1a78abd8e Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Tue, 11 Feb 2025 16:46:45 +0100 Subject: [PATCH 056/170] make-binaries: Bump OpenSSL version to 3.4.1 --- tools/make-binaries | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/make-binaries b/tools/make-binaries index d5876807e43..e8b5cc75b22 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -70,7 +70,7 @@ termcap_vsn='1.3.1' expat_vsn='2.6.4' zlib_vsn='1.3.1' yaml_vsn='0.2.5' -ssl_vsn='3.4.0' +ssl_vsn='3.4.1' otp_vsn='27.2.2' elixir_vsn='1.18.2' pam_vsn='1.6.1' # Newer Linux-PAM versions use Meson, we don't support that yet. From 80423d7e69c508c3f8c6891ef90c832577b9e62c Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Thu, 13 Feb 2025 16:21:05 +0300 Subject: [PATCH 057/170] Support Matrix room aliases --- src/mod_matrix_gw_room.erl | 106 +++++++++++++++++++++++++++++-------- 1 file changed, 85 insertions(+), 21 deletions(-) diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 07b5a74b0e1..01f9e8b52f4 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -77,7 +77,8 @@ client_state}). -record(multi_user, - {join_ts :: integer()}). + {join_ts :: integer(), + room_jid :: jid()}). -record(multi, {users :: #{{binary(), binary()} => #{binary() => #multi_user{}}}}). @@ -105,6 +106,9 @@ -define(MAX_DEPTH, 16#7FFFFFFFFFFFFFFF). -define(MAX_TXN_RETRIES, 5). +-define(MATRIX_ROOM_ALIAS_CACHE, matrix_room_alias_cache). +-define(MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT, 60000). + %%%=================================================================== %%% API %%%=================================================================== @@ -140,6 +144,7 @@ create_db() -> [{ram_copies, [node()]}, {type, set}, {attributes, record_info(fields, matrix_direct)}]), + ets_cache:new(?MATRIX_ROOM_ALIAS_CACHE), ok. get_room_pid(Host, RoomID) -> @@ -170,11 +175,13 @@ join_direct(Host, MatrixServer, RoomID, Sender, UserID) -> Error end. -route(#presence{from = From, to = #jid{luser = <<$!, _/binary>>} = To, - type = Type} = Packet) -> - case room_id_from_xmpp(To#jid.luser) of +route(#presence{from = From, to = #jid{luser = <>} = To, + type = Type} = Packet) + when C == $!; + C == $# -> + Host = ejabberd_config:get_myname(), + case room_id_from_xmpp(Host, To#jid.luser) of {ok, RoomID} -> - Host = ejabberd_config:get_myname(), case From#jid.lserver of Host -> case Type of @@ -200,14 +207,20 @@ route(#presence{from = From, to = #jid{luser = <<$!, _/binary>>} = To, ok end; error -> + Lang = xmpp:get_lang(Packet), + Txt = <<"bad or non-existing room id">>, + Err = xmpp:err_not_acceptable(Txt, Lang), + ejabberd_router:route_error(Packet, Err), ok end; -route(#message{from = From, to = #jid{luser = <<$!, _/binary>>} = To, +route(#message{from = From, to = #jid{luser = <>} = To, type = groupchat, - body = Body}) -> - case room_id_from_xmpp(To#jid.luser) of + body = Body}) + when C == $!; + C == $# -> + Host = ejabberd_config:get_myname(), + case room_id_from_xmpp(Host, To#jid.luser) of {ok, RoomID} -> - Host = ejabberd_config:get_myname(), case From#jid.lserver of Host -> case user_id_from_jid(From, Host) of @@ -685,6 +698,7 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) -> #{{LUser, LServer} := Rs} -> Rs; _ -> #{} end, + RoomJID = jid:remove_resource(xmpp:get_to(Packet)), Data2 = Data#data{ kind = @@ -692,7 +706,8 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) -> users = Users#{{LUser, LServer} => Resources#{LResource => - #multi_user{join_ts = JoinTS}}}}}, + #multi_user{join_ts = JoinTS, + room_jid = RoomJID}}}}}, {keep_state, Data2, [{next_event, cast, {add_event, JSON}}]}; error -> ?INFO_MSG("bad join user id: ~p", [UserJID]), @@ -758,6 +773,7 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) -> {timeout, 60000}], [{sync, true}, {body_format, binary}]), + RoomJID = jid:remove_resource(xmpp:get_to(Packet)), ?DEBUG("send_join ~p~n", [SendJoinRes]), process_send_join_res( MatrixServer, SendJoinRes, RoomVersion, @@ -765,7 +781,8 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) -> kind = #multi{users = #{{LUser, LServer} => - #{LResource => #multi_user{join_ts = JoinTS}}}}, + #{LResource => #multi_user{join_ts = JoinTS, + room_jid = RoomJID}}}}, room_version = RoomVersion}) end; _JSON -> @@ -2642,12 +2659,13 @@ notify_event_xmpp( case Sender of <<$@, SenderUser/binary>> -> ?DEBUG("notify xmpp ~p", [Users]), - From = jid:replace_resource(Data#data.room_jid, SenderUser), maps:fold( fun({LUser, LServer}, Resources, ok) -> maps:fold( - fun(LResource, #multi_user{join_ts = JoinTS}, ok) + fun(LResource, #multi_user{join_ts = JoinTS, + room_jid = RoomJID}, ok) when JoinTS =< OriginTS -> + From = jid:replace_resource(RoomJID, SenderUser), UserJID = jid:make(LUser, LServer, LResource), Msg = #message{from = From, to = UserJID, @@ -2673,16 +2691,17 @@ notify_event_xmpp( case user_id_to_jid(Sender, Data) of #jid{} = SenderJID -> <<$@, SenderUser/binary>> = Sender, - From = jid:replace_resource(Data#data.room_jid, SenderUser), maps:fold( fun({LUser, LServer}, Resources, ok) -> maps:fold( - fun(LResource, #multi_user{join_ts = JoinTS}, ok) + fun(LResource, #multi_user{join_ts = JoinTS, + room_jid = RoomJID}, ok) when JoinTS =< OriginTS -> + From = jid:replace_resource(RoomJID, SenderUser), case jid:tolower(SenderJID) of {LUser, LServer, _} -> send_initial_presences( - SenderJID, Event, Data); + SenderJID, RoomJID, Event, Data); _ -> ok end, @@ -2709,12 +2728,13 @@ notify_event_xmpp( Membership == <<"ban">> -> case StateKey of <<$@, RUser/binary>> -> - From = jid:replace_resource(Data#data.room_jid, RUser), maps:fold( fun({LUser, LServer}, Resources, ok) -> maps:fold( - fun(LResource, #multi_user{join_ts = JoinTS}, ok) + fun(LResource, #multi_user{join_ts = JoinTS, + room_jid = RoomJID}, ok) when JoinTS =< OriginTS -> + From = jid:replace_resource(RoomJID, RUser), UserJID = jid:make(LUser, LServer, LResource), Pres = #presence{from = From, to = UserJID, @@ -2755,7 +2775,7 @@ notify_event_xmpp( notify_event_xmpp(_Event, Data) -> Data. -send_initial_presences(JID, Event, Data) -> +send_initial_presences(JID, RoomJID, Event, Data) -> ?DEBUG("send_initial_presences ~p", [{JID, Event}]), maps:fold( fun({?ROOM_MEMBER, _}, EID, ok) -> @@ -2764,7 +2784,7 @@ send_initial_presences(JID, Event, Data) -> sender = <<$@, SenderUser/binary>>, json = #{<<"content">> := #{<<"membership">> := <<"join">>}}}} -> - From = jid:replace_resource(Data#data.room_jid, SenderUser), + From = jid:replace_resource(RoomJID, SenderUser), Pres = #presence{from = From, to = JID, type = available @@ -3148,7 +3168,7 @@ room_id_to_xmpp(RoomID) -> error end. -room_id_from_xmpp(RID) -> +room_id_from_xmpp(Host, RID) -> case RID of <<$!, Parts/binary>> -> case binary:split(Parts, <<"%">>) of @@ -3159,10 +3179,54 @@ room_id_from_xmpp(RID) -> {ok, <<$!, RoomID/binary, $:, S/binary>>}; _ -> error end; + <<$#, Parts/binary>> -> + case binary:split(Parts, <<"%">>) of + [R, S] -> + Alias = <<$#, R/binary, $:, S/binary>>, + case resolve_alias(Host, S, Alias) of + {ok, <<$!, _/binary>> = RoomID} -> + {ok, RoomID}; + error -> + error + end; + _ -> error + end; _ -> error end. +resolve_alias(Host, Origin, Alias) -> + ets_cache:lookup( + ?MATRIX_ROOM_ALIAS_CACHE, Alias, + fun() -> + Res = + mod_matrix_gw:send_request( + Host, get, Origin, + [<<"_matrix">>, <<"federation">>, + <<"v1">>, <<"query">>, <<"directory">>], + [{<<"room_alias">>, Alias}], + none, + [{timeout, 5000}], + [{sync, true}, + {body_format, binary}]), + case Res of + {ok, {{_, 200, _}, _Headers, Body}} -> + try + case misc:json_decode(Body) of + #{<<"room_id">> := RoomID} -> + {ok, RoomID} + end + catch + Class:Reason:ST -> + ?DEBUG("failed resolve_alias: ~p", [{Class, Reason, ST}]), + {cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT} + end; + {ok, {{_, _Status, _Reason}, _Headers, _Body}} -> + {cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT}; + {error, _Reason} -> + {cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT} + end + end). escape(S) -> From 376f7b261e8e8b86757778fc10d8638f105736ae Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 7 Feb 2025 19:27:26 +0100 Subject: [PATCH 058/170] mod_mam: Mention in documentation that MAM should use some SQL storage --- src/mod_mam.erl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 1e2d13f3d2d..aa4bb3b84af 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -1760,13 +1760,17 @@ mod_options(Host) -> mod_doc() -> #{desc => - ?T("This module implements " + [?T("This module implements " "https://xmpp.org/extensions/xep-0313.html" "[XEP-0313: Message Archive Management] and " "https://xmpp.org/extensions/xep-0441.html" "[XEP-0441: Message Archive Management Preferences]. " "Compatible XMPP clients can use it to store their " - "chat history on the server."), + "chat history on the server."), "", + ?T("NOTE: Mnesia backend for mod_mam is not recommended: it's limited " + "to 2GB and often gets corrupted when reaching this limit. " + "SQL backend is recommended. Namely, for small servers SQLite " + "is a preferred choice because it's very easy to configure.")], opts => [{access_preferences, #{value => ?T("AccessName"), From 8a7e9554536bf8407a3be33dae27c10b79483eb5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 13 Feb 2025 14:55:37 +0100 Subject: [PATCH 059/170] Update yconf to support macro inside string --- mix.exs | 2 +- mix.lock | 2 +- rebar.config | 2 +- rebar.lock | 11 ++++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mix.exs b/mix.exs index af72070c9c6..b3a26eb3f97 100644 --- a/mix.exs +++ b/mix.exs @@ -131,7 +131,7 @@ defmodule Ejabberd.MixProject do {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, {:xmpp, git: "https://github.com/processone/xmpp", ref: "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0", override: true}, - {:yconf, "~> 1.0.17"}] + {:yconf, git: "https://github.com/processone/yconf", ref: "9682a6025ed543eedf34637e4cfcc66837074af6", override: true}] ++ cond_deps() end diff --git a/mix.lock b/mix.lock index 8ce6a75c1a9..3f6fb7dfa76 100644 --- a/mix.lock +++ b/mix.lock @@ -35,5 +35,5 @@ "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "xmpp": {:git, "https://github.com/processone/xmpp", "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0", [ref: "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"]}, - "yconf": {:hex, :yconf, "1.0.17", "dcf242e27f3fc5d0743d6b8175dd39bc14a1f4ed7e6ea986366a44a6ff3b2a3a", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "dd2892923241449a46cc8457b9ec0fb14030700735a5885955677c735c341a25"}, + "yconf": {:git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6", [ref: "9682a6025ed543eedf34637e4cfcc66837074af6"]}, } diff --git a/rebar.config b/rebar.config index 3b0942c8725..4a851c7892c 100644 --- a/rebar.config +++ b/rebar.config @@ -78,7 +78,7 @@ {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"}}, - {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", {tag, "1.0.17"}}} + {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6"}} ]}. {gitonly_deps, [ejabberd_po]}. diff --git a/rebar.lock b/rebar.lock index e96263cb97d..c699f3c36f1 100644 --- a/rebar.lock +++ b/rebar.lock @@ -28,7 +28,10 @@ {git,"https://github.com/processone/xmpp", {ref,"64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"}}, 0}, - {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.17">>},0}]}. + {<<"yconf">>, + {git,"https://github.com/processone/yconf", + {ref,"9682a6025ed543eedf34637e4cfcc66837074af6"}}, + 0}]}. [ {pkg_hash,[ {<<"base64url">>, <<"F8C7F2DA04CA9A5D0F5F50258F055E1D699F0E8BF4CFDB30B750865368403CF6">>}, @@ -55,8 +58,7 @@ {<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>}, {<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>}, {<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>}, - {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, - {<<"yconf">>, <<"DCF242E27F3FC5D0743D6B8175DD39BC14A1F4ED7E6EA986366A44A6FF3B2A3A">>}]}, + {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]}, {pkg_hash_ext,[ {<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>}, {<<"cache_tab">>, <<"8582B60A4A09B247EF86355BA9E07FCE9E11EDC0345A775C9171F971C72B6351">>}, @@ -82,6 +84,5 @@ {<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>}, {<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>}, {<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>}, - {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, - {<<"yconf">>, <<"DD2892923241449A46CC8457B9EC0FB14030700735A5885955677C735C341A25">>}]} + {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]} ]. From 983c016bbac0b211c57da85da06d3c2d56baf296 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 14 Feb 2025 12:50:48 +0100 Subject: [PATCH 060/170] Update xmpp to get XEP-0317 Hats namespaces version 0.2.0 --- mix.exs | 2 +- mix.lock | 2 +- rebar.config | 2 +- rebar.lock | 4 ---- src/mod_muc.erl | 2 ++ src/mod_muc_room.erl | 8 ++++---- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/mix.exs b/mix.exs index b3a26eb3f97..feb1666c26a 100644 --- a/mix.exs +++ b/mix.exs @@ -130,7 +130,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp", ref: "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0", override: true}, + {:xmpp, git: "https://github.com/processone/xmpp", ref: "e295055dd1cb3dafb4b3134bc7462a775ff16b5c", override: true}, {:yconf, git: "https://github.com/processone/yconf", ref: "9682a6025ed543eedf34637e4cfcc66837074af6", override: true}] ++ cond_deps() end diff --git a/mix.lock b/mix.lock index 3f6fb7dfa76..6782741782d 100644 --- a/mix.lock +++ b/mix.lock @@ -34,6 +34,6 @@ "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:git, "https://github.com/processone/xmpp", "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0", [ref: "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"]}, + "xmpp": {:git, "https://github.com/processone/xmpp", "e295055dd1cb3dafb4b3134bc7462a775ff16b5c", [ref: "e295055dd1cb3dafb4b3134bc7462a775ff16b5c"]}, "yconf": {:git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6", [ref: "9682a6025ed543eedf34637e4cfcc66837074af6"]}, } diff --git a/rebar.config b/rebar.config index 4a851c7892c..ca2658b225b 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"}}, + {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "e295055dd1cb3dafb4b3134bc7462a775ff16b5c"}}, {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6"}} ]}. diff --git a/rebar.lock b/rebar.lock index c699f3c36f1..2e867dd9dde 100644 --- a/rebar.lock +++ b/rebar.lock @@ -24,10 +24,6 @@ {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.30">>},0}, {<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, - {<<"xmpp">>, - {git,"https://github.com/processone/xmpp", - {ref,"64d6d292015a7ec4de0b9e963d20b7ac5b63c7f0"}}, - 0}, {<<"yconf">>, {git,"https://github.com/processone/yconf", {ref,"9682a6025ed543eedf34637e4cfcc66837074af6"}}, diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 278b72014c0..1c33d064b14 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -1770,8 +1770,10 @@ mod_doc() -> "The default value is an empty string.")}}, {enable_hats, #{value => "true | false", + note => "improved in 25.xx", desc => ?T("Allow extended roles as defined in XEP-0317 Hats. " + "Check the _`../../tutorials/muc-hats.md|MUC Hats`_ tutorial. " "The default value is 'false'.")}}, {lang, #{value => ?T("Language"), diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index f48e58a9439..973759b2752 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -27,7 +27,7 @@ -author('alexey@process-one.net'). --protocol({xep, 317, '0.1', '21.12', "complete", "conversejs/prosody compatible"}). +-protocol({xep, 317, '0.2.0', '25.xx', "complete", ""}). -protocol({xep, 410, '1.1.0', '18.12', "complete", ""}). -behaviour(p1_fsm). @@ -79,9 +79,9 @@ -define(MAX_USERS_DEFAULT_LIST, [5, 10, 20, 30, 50, 100, 200, 500, 1000, 2000, 5000]). --define(MUC_HAT_ADD_CMD, <<"http://prosody.im/protocol/hats#add">>). --define(MUC_HAT_REMOVE_CMD, <<"http://prosody.im/protocol/hats#remove">>). --define(MUC_HAT_LIST_CMD, <<"p1:hats#list">>). +-define(MUC_HAT_ADD_CMD, <<"urn:xmpp:hats:commands:don">>). +-define(MUC_HAT_REMOVE_CMD, <<"urn:xmpp:hats:commands:doff">>). +-define(MUC_HAT_LIST_CMD, <<"urn:xmpp:hats:commands:dlist">>). -define(MAX_HATS_USERS, 100). -define(MAX_HATS_PER_USER, 10). -define(CLEAN_ROOM_TIMEOUT, 30000). From ceee3d3be1fc1053e61bbc81881bd40dbbbc1e89 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 14 Feb 2025 17:10:57 +0100 Subject: [PATCH 061/170] Fix placement of vcard_xupdate documentation --- src/mod_muc.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 1c33d064b14..c1ad7a8baa5 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -1692,11 +1692,6 @@ mod_doc() -> " -", " work: true", " street: Elm Street"]}}, - {vcard_xupdate, - #{value => "undefined | external | AvatarHash", - desc => - ?T("Set the hash of the avatar image. " - "The default value is 'undefined'.")}}, {cleanup_affiliations_on_start, #{value => "true | false", note => "added in 22.05", @@ -1840,6 +1835,11 @@ mod_doc() -> desc => ?T("A custom vCard for the room. See the equivalent mod_muc option." "The default value is an empty string.")}}, + {vcard_xupdate, + #{value => "undefined | external | AvatarHash", + desc => + ?T("Set the hash of the avatar image. " + "The default value is 'undefined'.")}}, {voice_request_min_interval, #{value => ?T("Number"), desc => From 44782001e20584029d997d476f2dadb40ce6ba96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 06:36:13 +0000 Subject: [PATCH 062/170] mix.lock: bump ex_doc from 0.36.1 to 0.37.1 Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.36.1 to 0.37.1. - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.36.1...v0.37.1) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- mix.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mix.lock b/mix.lock index 6782741782d..8eb5566d3df 100644 --- a/mix.lock +++ b/mix.lock @@ -2,13 +2,13 @@ "base64url": {:hex, :base64url, "1.0.1", "f8c7f2da04ca9a5d0f5f50258f055e1d699f0e8bf4cfdb30b750865368403cf6", [:rebar3], [], "hexpm", "f9b3add4731a02a9b0410398b475b33e7566a695365237a6bdee1bb447719f5c"}, "cache_tab": {:hex, :cache_tab, "1.0.31", "e4097b50a6f373ab1e0a5f01bab0bef6626771a4cd6c93404ed6d54810e11fbc", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8582b60a4a09b247ef86355ba9e07fce9e11edc0345a775c9171f971c72b6351"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.42", "f23d856f41919f17cd06a493923a722d87a2d684f143a1e663c04a2b93100682", [:mix], [], "hexpm", "6915b6ca369b5f7346636a2f41c6a6d78b5af419d61a611079189233358b8b8b"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"}, "eimp": {:hex, :eimp, "1.0.23", "aaf32efab061143403dadbaa63e699ef8e81702fbfa96fd436d5e9be4d6a8d3a", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "907c780023cb2893e4fc4bdbe6a4f02c355913862ac67f0ecc26605e816b628a"}, "epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"}, "eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"}, - "ex_doc": {:hex, :ex_doc, "0.36.1", "4197d034f93e0b89ec79fac56e226107824adcce8d2dd0a26f5ed3a95efc36b1", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d7d26a7cf965dacadcd48f9fa7b5953d7d0cfa3b44fa7a65514427da44eafd89"}, + "ex_doc": {:hex, :ex_doc, "0.37.1", "65ca30d242082b95aa852b3b73c9d9914279fff56db5dc7b3859be5504417980", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6774f75477733ea88ce861476db031f9399c110640752ca2b400dbbb50491224"}, "exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"}, "ezlib": {:hex, :ezlib, "1.0.13", "3c7f62862850a241159c10b218ecf580bce54d0890601b65144dacc2633be2b0", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "9ee62ab3f8ed55a0fd11a9569fcb8e458683f95575417272192b069f092abfbb"}, "fast_tls": {:hex, :fast_tls, "1.1.22", "44356b256afad4399c2fc5059a3066669dafd8bd4e4e796c9c1cf8910ddd265e", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e65779aefb7ab15c4755230fef8077e687d20cc5a3984a5974f9f657e8e2485b"}, @@ -21,9 +21,9 @@ "luerl": {:hex, :luerl, "1.2.3", "df25f41944e57a7c4d9ef09d238bc3e850276c46039cfc12b8bb42eccf36fcb1", [:rebar3], [], "hexpm", "1b4b9d0ca5d7d280d1d2787a6a5ee9f5a212641b62bff91556baa53805df3aed"}, "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, - "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.2", "03e1804074b3aa64d5fad7aa64601ed0fb395337b982d9bcf04029d68d51b6a7", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "af33ff7ef368d5893e4a267933e7744e46ce3cf1f61e2dccf53a111ed3aa3727"}, "mqtree": {:hex, :mqtree, "1.0.17", "82f54b8f2d22b4445db1d6cccb7fe9ead049d61410c29e32475f3ceb3ee62a89", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "5fe8b7cf8fbc4783d0fceb94654ac2bbf3242a58cd0397d249ded8ae021be2a3"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "p1_acme": {:hex, :p1_acme, "1.0.25", "db91f0d6c193cd1d5c0b0fa3939a898dbf56a6075db4347cde26e802715de50c", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.17", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "a7b55b47495ddb4f98a15e65451ec3ad43f4637b955c74cd695d98e6a645d08c"}, "p1_mysql": {:hex, :p1_mysql, "1.0.25", "875d4cbdc7c9990270df3292cce2514e4c18a9fdfd19bef258cb4d0c45b4f243", [:rebar3], [], "hexpm", "e6187ffae95b726098e88f3ee6f2344ac259ce2c26e0ee403b05feef341ae434"}, "p1_oauth2": {:hex, :p1_oauth2, "0.6.14", "1c5f82535574de87e2059695ac4b91f8f9aebacbc1c80287dae6f02552d47aea", [:rebar3], [], "hexpm", "1fd3ac474e43722d9d5a87c6df8d36f698ed87af7bb81cbbb66361451d99ae8f"}, From 78f7a9a244f6cdb3b3dfbeefc9d5aea51ae628dc Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 18 Feb 2025 11:54:49 +0100 Subject: [PATCH 063/170] CI: Fix step name, remove obsolete step reference --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d95bcc15563..28efecd1d1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,7 @@ jobs: ~/.cache/rebar3/ key: ${{matrix.otp}}-${{hashFiles('rebar.config')}} - - name: Get compatible Rebar binaries + - name: Get old eredis for old Erlang if: matrix.otp < 21 run: ./rebar3 unlock eredis @@ -185,7 +185,7 @@ jobs: ./rebar3 cover - name: Check results - if: always() && (steps.ct.outcome != 'skipped' || steps.ct2.outcome != 'skipped') + if: always() && (steps.ct.outcome != 'skipped') id: ctresults run: | [[ -d _build ]] && ln -s _build/test/logs/last/ logs || true From a32bfd1215450b35f88e19f0dbbef22483967c5a Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 19 Feb 2025 10:56:58 +0100 Subject: [PATCH 064/170] Show warning also when deprecated listener option is set as disabled (#4345) --- src/ejabberd_config_transformer.erl | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ejabberd_config_transformer.erl b/src/ejabberd_config_transformer.erl index a04e8771f9a..025db6dc362 100644 --- a/src/ejabberd_config_transformer.erl +++ b/src/ejabberd_config_transformer.erl @@ -271,25 +271,25 @@ replace_request_handlers(Opts) -> Handlers = proplists:get_value(request_handlers, Opts, []), Handlers1 = lists:foldl( - fun({captcha, true}, Acc) -> + fun({captcha, IsEnabled}, Acc) -> Handler = {<<"/captcha">>, ejabberd_captcha}, - warn_replaced_handler(captcha, Handler), + warn_replaced_handler(captcha, Handler, IsEnabled), [Handler|Acc]; - ({register, true}, Acc) -> + ({register, IsEnabled}, Acc) -> Handler = {<<"/register">>, mod_register_web}, - warn_replaced_handler(register, Handler), + warn_replaced_handler(register, Handler, IsEnabled), [Handler|Acc]; - ({web_admin, true}, Acc) -> + ({web_admin, IsEnabled}, Acc) -> Handler = {<<"/admin">>, ejabberd_web_admin}, - warn_replaced_handler(web_admin, Handler), + warn_replaced_handler(web_admin, Handler, IsEnabled), [Handler|Acc]; - ({http_bind, true}, Acc) -> + ({http_bind, IsEnabled}, Acc) -> Handler = {<<"/bosh">>, mod_bosh}, - warn_replaced_handler(http_bind, Handler), + warn_replaced_handler(http_bind, Handler, IsEnabled), [Handler|Acc]; - ({xmlrpc, true}, Acc) -> + ({xmlrpc, IsEnabled}, Acc) -> Handler = {<<"/">>, ejabberd_xmlrpc}, - warn_replaced_handler(xmlrpc, Handler), + warn_replaced_handler(xmlrpc, Handler, IsEnabled), Acc ++ [Handler]; (_, Acc) -> Acc @@ -538,7 +538,12 @@ warn_removed_module(Mod) -> ?WARNING_MSG("Module ~ts is deprecated and was automatically " "removed from the configuration. ~ts", [Mod, adjust_hint()]). -warn_replaced_handler(Opt, {Path, Module}) -> +warn_replaced_handler(Opt, {Path, Module}, false) -> + ?WARNING_MSG("Listening option '~ts' is deprecated, " + "please use instead the " + "HTTP request handler: \"~ts\" -> ~ts. ~ts", + [Opt, Path, Module, adjust_hint()]); +warn_replaced_handler(Opt, {Path, Module}, true) -> ?WARNING_MSG("Listening option '~ts' is deprecated " "and was automatically replaced by " "HTTP request handler: \"~ts\" -> ~ts. ~ts", From 45dafbcdcc96292e0dbc171888f772b5a281491c Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 19 Feb 2025 11:03:56 +0100 Subject: [PATCH 065/170] Result of running "make format" --- src/mod_privilege.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl index 862f0c0be9e..d614c8a350e 100644 --- a/src/mod_privilege.erl +++ b/src/mod_privilege.erl @@ -308,7 +308,8 @@ component_send_packet({#iq{from = From, []), drop; {_, {unprivileged_iq}} -> - ?DEBUG("Component ~ts sent a not-wrapped IQ stanza, routing it as-is.", [From#jid.lserver]), + ?DEBUG("Component ~ts sent a not-wrapped IQ stanza, routing it as-is.", + [From#jid.lserver]), IQ; {_, {error, ErrType, _Err}} -> ?INFO_MSG("IQ not forwarded: Component tried to send not valid IQ stanza: ~p.", From 6bd4399aeec7a733d1b3f8193b98b4cf6a09ade3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 20 Feb 2025 14:48:45 +0100 Subject: [PATCH 066/170] Bubble up db errors in nodetree_tree_sql:set_node --- src/nodetree_tree_sql.erl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/nodetree_tree_sql.erl b/src/nodetree_tree_sql.erl index f7a31b8ae19..09959099ea7 100644 --- a/src/nodetree_tree_sql.erl +++ b/src/nodetree_tree_sql.erl @@ -82,17 +82,22 @@ set_node(Record) when is_record(Record, pubsub_node) -> " parent=%(Parent)s, plugin=%(Type)s " "where nodeid=%(OldNidx)d")), OldNidx; - _ -> + {error, not_found} -> catch ejabberd_sql:sql_query_t( ?SQL("insert into pubsub_node(host, node, parent, plugin) " "values(%(H)s, %(Node)s, %(Parent)s, %(Type)s)")), case nodeidx(Host, Node) of {result, NewNidx} -> NewNidx; - _ -> none % this should not happen - end + {error, not_found} -> none; % this should not happen + {error, _} -> db_error + end; + {error, _} -> + db_error end, case Nidx of + db_error -> + {error, xmpp:err_internal_server_error(?T("Database failure"), ejabberd_option:language())}; none -> Txt = ?T("Node index not found"), {error, xmpp:err_internal_server_error(Txt, ejabberd_option:language())}; From 41232ccb393ccaa3b83100e6d2e6c4ef1f313024 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Fri, 21 Feb 2025 04:15:08 +0300 Subject: [PATCH 067/170] Properly handle IQ requests in mod_matrix_gw --- src/mod_matrix_gw.erl | 49 +++++++++++++++++++++++++++++++++++++- src/mod_matrix_gw_room.erl | 36 ++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/mod_matrix_gw.erl b/src/mod_matrix_gw.erl index bd788211718..312eced8ca6 100644 --- a/src/mod_matrix_gw.erl +++ b/src/mod_matrix_gw.erl @@ -46,6 +46,8 @@ prune_event/2, get_event_id/2, content_hash/1, sign_event/3, sign_pruned_event/2, sign_json/2, send_request/8, s2s_out_bounce_packet/2, user_receive_packet/1, + process_disco_info/1, + process_disco_items/1, route/1]). -include_lib("xmpp/include/xmpp.hrl"). @@ -516,6 +518,10 @@ init([Host]) -> Opts = gen_mod:get_module_opts(Host, ?MODULE), MyHost = gen_mod:get_opt(host, Opts), register_routes(Host, [MyHost]), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO, + ?MODULE, process_disco_info), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS, + ?MODULE, process_disco_items), {ok, #state{server_host = Host, host = MyHost}}. -spec handle_call(term(), {pid(), term()}, state()) -> @@ -536,7 +542,11 @@ handle_info(Info, State) -> -spec terminate(term(), state()) -> any(). terminate(_Reason, #state{host = Host}) -> - unregister_routes([Host]). + unregister_routes([Host]), + gen_iq_handler:del_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, + ?MODULE, process_disco_info), + gen_iq_handler:del_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, + ?MODULE, process_disco_items). -spec code_change(term(), state(), term()) -> {ok, state()}. code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -873,9 +883,46 @@ user_receive_packet({Pkt, C2SState} = Acc) -> end end. +-spec route(stanza()) -> ok. +route(#iq{to = #jid{luser = <<"">>, lresource = <<"">>}} = IQ) -> + ejabberd_router:process_iq(IQ); route(Pkt) -> mod_matrix_gw_room:route(Pkt). +-spec process_disco_info(iq()) -> iq(). +process_disco_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = ?T("Value 'set' of 'type' attribute is not allowed"), + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_info(#iq{type = get, + sub_els = [#disco_info{node = <<"">>}]} = IQ) -> + Features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, ?NS_MUC], + Identity = #identity{category = <<"gateway">>, + type = <<"matrix">>}, + xmpp:make_iq_result( + IQ, #disco_info{features = Features, + identities = [Identity]}); +process_disco_info(#iq{type = get, lang = Lang, + sub_els = [#disco_info{}]} = IQ) -> + xmpp:make_error(IQ, xmpp:err_item_not_found(?T("Node not found"), Lang)); +process_disco_info(#iq{lang = Lang} = IQ) -> + Txt = ?T("No module is handling this query"), + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). + +-spec process_disco_items(iq()) -> iq(). +process_disco_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = ?T("Value 'set' of 'type' attribute is not allowed"), + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_items(#iq{type = get, + sub_els = [#disco_items{node = <<>>}]} = IQ) -> + xmpp:make_iq_result(IQ, #disco_items{}); +process_disco_items(#iq{type = get, lang = Lang, + sub_els = [#disco_items{}]} = IQ) -> + xmpp:make_error(IQ, xmpp:err_item_not_found(?T("Node not found"), Lang)); +process_disco_items(#iq{lang = Lang} = IQ) -> + Txt = ?T("No module is handling this query"), + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). + + depends(_Host, _Opts) -> []. diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 01f9e8b52f4..91abf257350 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -356,6 +356,42 @@ route(#message{from = From, to = To, body = Body} = _Pkt) -> error -> ok end; +route(#iq{type = Type}) when Type == error; Type == result -> + ok; +route(#iq{type = Type, lang = Lang, sub_els = [_]} = IQ0) -> + try xmpp:decode_els(IQ0) of + #iq{sub_els = [SubEl]} = IQ -> + Result = + case {Type, SubEl} of + {set, _} -> + {error, xmpp:err_not_allowed()}; + {get, #disco_info{node = <<>>}} -> + {result, + #disco_info{identities = + [#identity{category = <<"conference">>, + type = <<"text">>}], + features = [?NS_MUC, ?NS_DISCO_INFO, ?NS_DISCO_ITEMS]}}; + {get, #disco_info{node = _}} -> + {error, xmpp:err_item_not_found()}; + {get, #disco_items{node = <<>>}} -> + {result, #disco_items{}}; + {get, #disco_items{node = _}} -> + {error, xmpp:err_item_not_found()}; + _ -> + {error, xmpp:err_service_unavailable()} + end, + case Result of + {result, Res} -> + ejabberd_router:route(xmpp:make_iq_result(IQ, Res)); + {error, Error} -> + ejabberd_router:route(xmpp:make_error(IQ, Error)) + end + catch _:{xmpp_codec, Why} -> + ErrTxt = xmpp:io_format_error(Why), + Err = xmpp:err_bad_request(ErrTxt, Lang), + ejabberd_router:route_error(IQ0, Err), + ok + end; route(_) -> ok. From 7018b8b164368f034cded92efd010e20829639d8 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Fri, 21 Feb 2025 12:05:34 +0300 Subject: [PATCH 068/170] Fix gen_iq_handler:remove_iq_handler call in mod_matrix_gw --- src/mod_matrix_gw.erl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mod_matrix_gw.erl b/src/mod_matrix_gw.erl index 312eced8ca6..173e823569a 100644 --- a/src/mod_matrix_gw.erl +++ b/src/mod_matrix_gw.erl @@ -543,10 +543,8 @@ handle_info(Info, State) -> -spec terminate(term(), state()) -> any(). terminate(_Reason, #state{host = Host}) -> unregister_routes([Host]), - gen_iq_handler:del_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, - ?MODULE, process_disco_info), - gen_iq_handler:del_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, - ?MODULE, process_disco_items). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS). -spec code_change(term(), state(), term()) -> {ok, state()}. code_change(_OldVsn, State, _Extra) -> {ok, State}. From 2a85c0a47466076e23d869f6ebb506b8c487f18b Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Mon, 24 Feb 2025 17:39:57 +0300 Subject: [PATCH 069/170] Add muc#user element to presences and an initial empty subject --- src/mod_matrix_gw_room.erl | 56 ++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 91abf257350..095b6fa52f9 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -2734,19 +2734,42 @@ notify_event_xmpp( room_jid = RoomJID}, ok) when JoinTS =< OriginTS -> From = jid:replace_resource(RoomJID, SenderUser), - case jid:tolower(SenderJID) of - {LUser, LServer, _} -> - send_initial_presences( - SenderJID, RoomJID, Event, Data); - _ -> - ok - end, + IsSelfPresence = + case jid:tolower(SenderJID) of + {LUser, LServer, _} -> + send_initial_presences( + SenderJID, RoomJID, Event, Data), + true; + _ -> + false + end, UserJID = jid:make(LUser, LServer, LResource), - Pres = #presence{from = From, - to = UserJID, - type = available - }, - ejabberd_router:route(Pres); + Item = #muc_item{affiliation = member, + role = participant}, + Status = case IsSelfPresence of + true -> [110]; + false -> [] + end, + Pres = #presence{ + from = From, + to = UserJID, + type = available, + sub_els = [#muc_user{items = [Item], + status_codes = Status}] + }, + ejabberd_router:route(Pres), + case IsSelfPresence of + true -> + Subject = + #message{ + from = RoomJID, + to = UserJID, + type = groupchat, + subject = [#text{}] + }, + ejabberd_router:route(Subject); + false -> ok + end; (_, _, _) -> ok end, ok, Resources) end, ok, Users), @@ -2772,9 +2795,12 @@ notify_event_xmpp( when JoinTS =< OriginTS -> From = jid:replace_resource(RoomJID, RUser), UserJID = jid:make(LUser, LServer, LResource), + Item = #muc_item{affiliation = member, + role = none}, Pres = #presence{from = From, to = UserJID, - type = unavailable + type = unavailable, + sub_els = [#muc_user{items = [Item]}] }, ejabberd_router:route(Pres); (_, _, _) -> ok @@ -2821,9 +2847,11 @@ send_initial_presences(JID, RoomJID, Event, Data) -> json = #{<<"content">> := #{<<"membership">> := <<"join">>}}}} -> From = jid:replace_resource(RoomJID, SenderUser), + Item = #muc_item{affiliation = member, role = participant}, Pres = #presence{from = From, to = JID, - type = available + type = available, + sub_els = [#muc_user{items = [Item]}] }, ejabberd_router:route(Pres), ok; From 051093f4f871cb0d5f300dd57fadcb4391bf3c6a Mon Sep 17 00:00:00 2001 From: p Date: Tue, 25 Feb 2025 14:11:02 +0330 Subject: [PATCH 070/170] ref: c2s_handle_bind hook --- src/ejabberd_c2s.erl | 93 ++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index c68e6ad30e7..f00755625bf 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -49,8 +49,9 @@ get_fast_tokens_fun/2, fast_mechanisms/1]). %% Hooks -export([handle_unexpected_cast/2, handle_unexpected_call/3, - process_auth_result/3, reject_unauthenticated_packet/2, - process_closed/2, process_terminated/2, process_info/2]). + process_auth_result/3, c2s_handle_bind/1, + reject_unauthenticated_packet/2, process_closed/2, + process_terminated/2, process_info/2]). %% API -export([get_presence/1, set_presence/2, resend_presence/1, resend_presence/2, open_session/1, call/3, cast/2, send/2, close/1, close/2, stop_async/1, @@ -165,6 +166,7 @@ host_up(Host) -> ejabberd_hooks:add(c2s_closed, Host, ?MODULE, process_closed, 100), ejabberd_hooks:add(c2s_terminated, Host, ?MODULE, process_terminated, 100), + ejabberd_hooks:add(c2s_handle_bind, Host, ?MODULE, c2s_handle_bind, 100), ejabberd_hooks:add(c2s_unauthenticated_packet, Host, ?MODULE, reject_unauthenticated_packet, 100), ejabberd_hooks:add(c2s_handle_info, Host, ?MODULE, @@ -181,6 +183,7 @@ host_down(Host) -> ejabberd_hooks:delete(c2s_closed, Host, ?MODULE, process_closed, 100), ejabberd_hooks:delete(c2s_terminated, Host, ?MODULE, process_terminated, 100), + ejabberd_hooks:delete(c2s_handle_bind, Host, ?MODULE, c2s_handle_bind, 100), ejabberd_hooks:delete(c2s_unauthenticated_packet, Host, ?MODULE, reject_unauthenticated_packet, 100), ejabberd_hooks:delete(c2s_handle_info, Host, ?MODULE, @@ -285,6 +288,11 @@ handle_unexpected_cast(State, Msg) -> ?WARNING_MSG("Unexpected cast: ~p", [Msg]), State. +c2s_handle_bind({<<"">>, {ok, State}}) -> + {new_uniq_id(), {ok, State}}; +c2s_handle_bind(Acc) -> + Acc. + reject_unauthenticated_packet(State, _Pkt) -> Err = xmpp:serr_not_authorized(), send(State, Err). @@ -480,33 +488,60 @@ fast_mechanisms(#{lserver := LServer}) -> _ -> mod_auth_fast:get_mechanisms(LServer) end. -bind(<<"">>, State) -> - bind(new_uniq_id(), State); -bind(R, #{user := U, server := S, access := Access, lang := Lang, - lserver := LServer, socket := Socket, - ip := IP} = State) -> - case resource_conflict_action(U, S, R) of - closenew -> - {error, xmpp:err_conflict(), State}; - {accept_resource, Resource} -> - JID = jid:make(U, S, Resource), - case acl:match_rule(LServer, Access, - #{usr => jid:split(JID), ip => IP}) of - allow -> - State1 = open_session(State#{resource => Resource, - sid => ejabberd_sm:make_sid()}), - State2 = ejabberd_hooks:run_fold( - c2s_session_opened, LServer, State1, []), - ?INFO_MSG("(~ts) Opened c2s session for ~ts", - [xmpp_socket:pp(Socket), jid:encode(JID)]), - {ok, State2}; - deny -> - ejabberd_hooks:run(forbidden_session_hook, LServer, [JID]), - ?WARNING_MSG("(~ts) Forbidden c2s session for ~ts", - [xmpp_socket:pp(Socket), jid:encode(JID)]), - Txt = ?T("Access denied by service policy"), - {error, xmpp:err_not_allowed(Txt, Lang), State} - end +bind( + R, + #{ + user := U, + server := S, + lserver := LServer, + access := Access, + lang := Lang, + socket := Socket, + ip := IP + }=State +) -> + case ejabberd_hooks:run_fold(c2s_handle_bind, LServer, {R, {ok, State}}, []) of + {R2, {ok, State2}} -> + case resource_conflict_action(U, S, R2) of + closenew -> + {error, xmpp:err_conflict(), State2}; + {accept_resource, Resource} -> + JID = jid:make(U, S, Resource), + case acl:match_rule(LServer, Access, #{usr => jid:split(JID), ip => IP}) of + allow -> + State3 = open_session( + State2#{resource => Resource, sid => ejabberd_sm:make_sid()} + ), + State4 = ejabberd_hooks:run_fold( + c2s_session_opened, LServer, State3, [] + ), + ?INFO_MSG( + "(~ts) Opened c2s session for ~ts", [xmpp_socket:pp(Socket), jid:encode(JID)] + ), + {ok, State4}; + deny -> + ejabberd_hooks:run(forbidden_session_hook, LServer, [JID]), + ?WARNING_MSG( + "(~ts) Forbidden c2s session for ~ts", + [xmpp_socket:pp(Socket), jid:encode(JID)] + ), + Txt = ?T("Access denied by service policy"), + {error, xmpp:err_not_allowed(Txt, Lang), State2} + end + end; + {R2, {error, XmppErr, _State2}=Err} -> + case XmppErr of + #stanza_error{reason = 'not-allowed'} -> + JID = jid:make(U, S, R2), + ejabberd_hooks:run(forbidden_session_hook, LServer, [JID]), + ?WARNING_MSG( + "(~ts) Forbidden c2s session for ~ts", + [xmpp_socket:pp(Socket), jid:encode(JID)] + ); + _ -> + ok + end, + Err end. handle_stream_start(StreamStart, #{lserver := LServer} = State) -> From b38d8618b269fee1d76f33d5c3b091eae0400f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 26 Feb 2025 11:17:55 +0100 Subject: [PATCH 071/170] Fix crashes when ouath is feed with invalid jid This should fix issue #4355 --- src/ejabberd_oauth.erl | 191 ++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 88 deletions(-) diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 5275673fef8..971f2340265 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -595,61 +595,71 @@ process(_Handlers, RedirectURI = proplists:get_value(<<"redirect_uri">>, Q, <<"">>), SScope = proplists:get_value(<<"scope">>, Q, <<"">>), StringJID = proplists:get_value(<<"username">>, Q, <<"">>), - #jid{user = Username, server = Server} = jid:decode(StringJID), - Password = proplists:get_value(<<"password">>, Q, <<"">>), - State = proplists:get_value(<<"state">>, Q, <<"">>), - Scope = str:tokens(SScope, <<" ">>), - TTL = proplists:get_value(<<"ttl">>, Q, <<"">>), - ExpiresIn = case TTL of - <<>> -> undefined; - _ -> binary_to_integer(TTL) - end, - case oauth2:authorize_password({Username, Server}, - ClientId, - RedirectURI, - Scope, - #oauth_ctx{password = Password}) of - {ok, {_AppContext, Authorization}} -> - {ok, {_AppContext2, Response}} = - oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined ]), - {ok, AccessToken} = oauth2_response:access_token(Response), - {ok, Type} = oauth2_response:token_type(Response), - %%Ugly: workardound to return the correct expirity time, given than oauth2 lib doesn't really have - %%per-case expirity time. - Expires = case ExpiresIn of - undefined -> - {ok, Ex} = oauth2_response:expires_in(Response), - Ex; - _ -> - ExpiresIn - end, - {ok, VerifiedScope} = oauth2_response:scope(Response), - %oauth2_wrq:redirected_access_token_response(ReqData, - % RedirectURI, - % AccessToken, - % Type, - % Expires, - % VerifiedScope, - % State, - % Context); - {302, [{<<"Location">>, - <>))/binary, - "&state=", State/binary>> - }], - ejabberd_web:make_xhtml([?XC(<<"h1">>, <<"302 Found">>)])}; - {error, Error} when is_atom(Error) -> - %oauth2_wrq:redirected_error_response( - % ReqData, RedirectURI, Error, State, Context) - {302, [{<<"Location">>, - <>, <<"302 Found">>)])} + try jid:decode(StringJID) of + #jid{user = Username, server = Server} -> + Password = proplists:get_value(<<"password">>, Q, <<"">>), + State = proplists:get_value(<<"state">>, Q, <<"">>), + Scope = str:tokens(SScope, <<" ">>), + TTL = proplists:get_value(<<"ttl">>, Q, <<"">>), + ExpiresIn = case TTL of + <<>> -> undefined; + _ -> binary_to_integer(TTL) + end, + case oauth2:authorize_password({Username, Server}, + ClientId, + RedirectURI, + Scope, + #oauth_ctx{password = Password}) of + {ok, {_AppContext, Authorization}} -> + {ok, {_AppContext2, Response}} = + oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined]), + {ok, AccessToken} = oauth2_response:access_token(Response), + {ok, Type} = oauth2_response:token_type(Response), + %%Ugly: workardound to return the correct expirity time, given than oauth2 lib doesn't really have + %%per-case expirity time. + Expires = case ExpiresIn of + undefined -> + {ok, Ex} = oauth2_response:expires_in(Response), + Ex; + _ -> + ExpiresIn + end, + {ok, VerifiedScope} = oauth2_response:scope(Response), + %oauth2_wrq:redirected_access_token_response(ReqData, + % RedirectURI, + % AccessToken, + % Type, + % Expires, + % VerifiedScope, + % State, + % Context); + {302, [{<<"Location">>, + <>))/binary, + "&state=", State/binary>> + }], + ejabberd_web:make_xhtml([?XC(<<"h1">>, <<"302 Found">>)])}; + {error, Error} when is_atom(Error) -> + %oauth2_wrq:redirected_error_response( + % ReqData, RedirectURI, Error, State, Context) + {302, [{<<"Location">>, + <>, <<"302 Found">>)])} + end + catch _:{bad_jid, _} -> + State = proplists:get_value(<<"state">>, Q, <<"">>), + {400, [{<<"Location">>, + <>, <<"400 Invalid request">>)])} end; process(_Handlers, #request{method = 'POST', q = Q, lang = _Lang, @@ -701,38 +711,42 @@ process(_Handlers, password -> SScope = proplists:get_value(<<"scope">>, Q, <<"">>), StringJID = proplists:get_value(<<"username">>, Q, <<"">>), - #jid{user = Username, server = Server} = jid:decode(StringJID), - Password = proplists:get_value(<<"password">>, Q, <<"">>), - Scope = str:tokens(SScope, <<" ">>), - TTL = proplists:get_value(<<"ttl">>, Q, <<"">>), - ExpiresIn = case TTL of - <<>> -> undefined; - _ -> binary_to_integer(TTL) - end, - case oauth2:authorize_password({Username, Server}, - Scope, - #oauth_ctx{password = Password}) of - {ok, {_AppContext, Authorization}} -> - {ok, {_AppContext2, Response}} = - oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined ]), - {ok, AccessToken} = oauth2_response:access_token(Response), - {ok, Type} = oauth2_response:token_type(Response), - %%Ugly: workardound to return the correct expirity time, given than oauth2 lib doesn't really have - %%per-case expirity time. - Expires = case ExpiresIn of - undefined -> - {ok, Ex} = oauth2_response:expires_in(Response), - Ex; - _ -> - ExpiresIn - end, - {ok, VerifiedScope} = oauth2_response:scope(Response), - json_response(200, #{<<"access_token">> => AccessToken, - <<"token_type">> => Type, - <<"scope">> => str:join(VerifiedScope, <<" ">>), - <<"expires_in">> => Expires}); - {error, Error} when is_atom(Error) -> - json_error(400, <<"invalid_grant">>, Error) + try jid:decode(StringJID) of + #jid{user = Username, server = Server} -> + Password = proplists:get_value(<<"password">>, Q, <<"">>), + Scope = str:tokens(SScope, <<" ">>), + TTL = proplists:get_value(<<"ttl">>, Q, <<"">>), + ExpiresIn = case TTL of + <<>> -> undefined; + _ -> binary_to_integer(TTL) + end, + case oauth2:authorize_password({Username, Server}, + Scope, + #oauth_ctx{password = Password}) of + {ok, {_AppContext, Authorization}} -> + {ok, {_AppContext2, Response}} = + oauth2:issue_token(Authorization, [{expiry_time, ExpiresIn} || ExpiresIn /= undefined]), + {ok, AccessToken} = oauth2_response:access_token(Response), + {ok, Type} = oauth2_response:token_type(Response), + %%Ugly: workardound to return the correct expirity time, given than oauth2 lib doesn't really have + %%per-case expirity time. + Expires = case ExpiresIn of + undefined -> + {ok, Ex} = oauth2_response:expires_in(Response), + Ex; + _ -> + ExpiresIn + end, + {ok, VerifiedScope} = oauth2_response:scope(Response), + json_response(200, #{<<"access_token">> => AccessToken, + <<"token_type">> => Type, + <<"scope">> => str:join(VerifiedScope, <<" ">>), + <<"expires_in">> => Expires}); + {error, Error} when is_atom(Error) -> + json_error(400, <<"invalid_grant">>, Error) + end + catch _:{bad_jid, _} -> + json_error(400, <<"invalid_request">>, invalid_jid) end; unsupported_grant_type -> json_error(400, <<"unsupported_grant_type">>, @@ -774,7 +788,8 @@ json_error(Code, Error, Reason) -> json_error_desc(access_denied) -> <<"Access denied">>; json_error_desc(badpass) -> <<"Bad password">>; json_error_desc(unsupported_grant_type) -> <<"Unsupported grant type">>; -json_error_desc(invalid_scope) -> <<"Invalid scope">>. +json_error_desc(invalid_scope) -> <<"Invalid scope">>; +json_error_desc(invalid_jid) -> <<"Invalid JID">>. web_head() -> [?XA(<<"meta">>, [{<<"http-equiv">>, <<"X-UA-Compatible">>}, From 54f89e75687333113c4f55a42d571bfba97eb1df Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 19 Feb 2025 12:16:51 +0100 Subject: [PATCH 072/170] Update XEP-0280 supported version to 1.0.1 --- src/mod_carboncopy.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index dfd723c9920..b2e1ff544d6 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -27,7 +27,7 @@ -module (mod_carboncopy). -author ('ecestari@process-one.net'). --protocol({xep, 280, '0.13.2', '13.06', "complete", ""}). +-protocol({xep, 280, '1.0.1', '13.06', "complete", ""}). -behaviour(gen_mod). From 6af2a65e53b8cc7e7b74a937c060c2ba04d41e4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 06:31:59 +0000 Subject: [PATCH 073/170] build(deps): bump stringprep from 1.0.30 to 1.0.31 Bumps [stringprep](https://github.com/processone/stringprep) from 1.0.30 to 1.0.31. - [Changelog](https://github.com/processone/stringprep/blob/master/CHANGELOG.md) - [Commits](https://github.com/processone/stringprep/compare/1.0.30...1.0.31) --- updated-dependencies: - dependency-name: stringprep dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 8eb5566d3df..28d2412cefb 100644 --- a/mix.lock +++ b/mix.lock @@ -31,7 +31,7 @@ "p1_utils": {:hex, :p1_utils, "1.0.26", "67b0c4ac9fa3ba3ef563b31aa111b0a004439a37fac85e027f1c3617e1c7ec6c", [:rebar3], [], "hexpm", "d0379e8c1156b98bd64f8129c1de022fcca4f2fdb7486ce73bf0ed2c3376b04c"}, "pkix": {:hex, :pkix, "1.0.10", "d3bfadf7b7cfe2a3636f1b256c9cce5f646a07ce31e57ee527668502850765a0", [:rebar3], [], "hexpm", "e02164f83094cb124c41b1ab28988a615d54b9adc38575f00f19a597a3ac5d0e"}, "sqlite3": {:hex, :sqlite3, "1.1.15", "e819defd280145c328457d7af897d2e45e8e5270e18812ee30b607c99cdd21af", [:rebar3], [], "hexpm", "3c0ba4e13322c2ad49de4e2ddd28311366adde54beae8dba9d9e3888f69d2857"}, - "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, + "stringprep": {:hex, :stringprep, "1.0.31", "fa1688c156dd271722aa18c423a4163e710d2f4f475ad0bc220910df669b53af", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e9699c88e8db16b3a41f0e45ac6874a4da81a6e4854a77d76ede6d09b08e3530"}, "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "xmpp": {:git, "https://github.com/processone/xmpp", "e295055dd1cb3dafb4b3134bc7462a775ff16b5c", [ref: "e295055dd1cb3dafb4b3134bc7462a775ff16b5c"]}, From c124dbdd6af30d99613487d8c0b299908135ccec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 06:32:10 +0000 Subject: [PATCH 074/170] build(deps-dev): bump ex_doc from 0.37.1 to 0.37.2 Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.37.1 to 0.37.2. - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.37.1...v0.37.2) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 28d2412cefb..2b1065bf837 100644 --- a/mix.lock +++ b/mix.lock @@ -8,7 +8,7 @@ "eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"}, - "ex_doc": {:hex, :ex_doc, "0.37.1", "65ca30d242082b95aa852b3b73c9d9914279fff56db5dc7b3859be5504417980", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "6774f75477733ea88ce861476db031f9399c110640752ca2b400dbbb50491224"}, + "ex_doc": {:hex, :ex_doc, "0.37.2", "2a3aa7014094f0e4e286a82aa5194a34dd17057160988b8509b15aa6c292720c", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "4dfa56075ce4887e4e8b1dcc121cd5fcb0f02b00391fd367ff5336d98fa49049"}, "exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"}, "ezlib": {:hex, :ezlib, "1.0.13", "3c7f62862850a241159c10b218ecf580bce54d0890601b65144dacc2633be2b0", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "9ee62ab3f8ed55a0fd11a9569fcb8e458683f95575417272192b069f092abfbb"}, "fast_tls": {:hex, :fast_tls, "1.1.22", "44356b256afad4399c2fc5059a3066669dafd8bd4e4e796c9c1cf8910ddd265e", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e65779aefb7ab15c4755230fef8077e687d20cc5a3984a5974f9f657e8e2485b"}, From 70980efe399080fb94e777c9aa8d4b009de2aa52 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Mar 2025 23:22:11 +0100 Subject: [PATCH 075/170] make-binaries: Bump versions to Erlang/OTP 27.3 and Elixir 1.18.3 --- tools/make-binaries | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/make-binaries b/tools/make-binaries index e8b5cc75b22..eaf0b155708 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -71,8 +71,8 @@ expat_vsn='2.6.4' zlib_vsn='1.3.1' yaml_vsn='0.2.5' ssl_vsn='3.4.1' -otp_vsn='27.2.2' -elixir_vsn='1.18.2' +otp_vsn='27.3' +elixir_vsn='1.18.3' pam_vsn='1.6.1' # Newer Linux-PAM versions use Meson, we don't support that yet. png_vsn='1.6.45' jpeg_vsn='9f' From 178b09f5bb65a147a5733a00c2b858337471c8a9 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Mar 2025 15:57:57 +0100 Subject: [PATCH 076/170] ejabberd_admin: Fix crash in list_cluster_detailed when a node is down --- src/ejabberd_admin.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 2452e86b761..c6e955ab20f 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -931,14 +931,14 @@ get_cluster_node_details(Node, RunningNodes) -> get_cluster_node_details2(Node, lists:member(Node, RunningNodes)). get_cluster_node_details2(Node, false) -> - {Node, "false", "", -1, -1, -1, "unknown"}; + {Node, "false", "", -1, -1, -1, unknown}; get_cluster_node_details2(Node, true) -> try ejabberd_cluster:call(Node, ejabberd_admin, get_cluster_node_details3, []) of Result -> Result catch E:R -> Status = io_lib:format("~p: ~p", [E, R]), - {Node, "true", Status, -1, -1, -1, "unknown"} + {Node, "true", Status, -1, -1, -1, unknown} end. get_cluster_node_details3() -> From b75c3257bd8bc125c5b72070521cadf74c65c748 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 19 Feb 2025 16:37:33 +0100 Subject: [PATCH 077/170] ejabberd_oauth: Commands description should be plain text The desc field is displayed in "ejabberdctl help", which has no markdown processing. If adding links is important, they can be added in the longdesc field. --- src/ejabberd_oauth.erl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 971f2340265..a18596d4645 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -83,7 +83,7 @@ get_commands_spec() -> [ #ejabberd_commands{name = oauth_issue_token, tags = [oauth], - desc = "Issue an _`oauth.md|OAuth`_ token for the given jid", + desc = "Issue an OAuth token for the given jid", module = ?MODULE, function = oauth_issue_token, args = [{jid, string},{ttl, integer}, {scopes, string}], policy = restricted, @@ -94,7 +94,7 @@ get_commands_spec() -> result = {result, {tuple, [{token, string}, {scopes, string}, {expires_in, string}]}} }, #ejabberd_commands{name = oauth_issue_token, tags = [oauth], - desc = "Issue an _`oauth.md|OAuth`_ optionredir token for the given jid", + desc = "Issue an OAuth token for the given jid", module = ?MODULE, function = oauth_issue_token, version = 1, note = "updated in 24.02", @@ -107,15 +107,15 @@ get_commands_spec() -> result = {result, {tuple, [{token, string}, {scopes, {list, {scope, string}}}, {expires_in, string}]}} }, #ejabberd_commands{name = oauth_list_tokens, tags = [oauth], - desc = "List _`oauth.md|OAuth`_ tokens, user, scope, and seconds to expire (only Mnesia)", - longdesc = "List OAuth tokens, their user and scope, and how many seconds remain until expirity", + desc = "List OAuth tokens, user, scope, and seconds to expire (only Mnesia)", + longdesc = "List _`oauth.md|OAuth`_ tokens, their user and scope, and how many seconds remain until expiry", module = ?MODULE, function = oauth_list_tokens, args = [], policy = restricted, result = {tokens, {list, {token, {tuple, [{token, string}, {user, string}, {scope, string}, {expires_in, string}]}}}} }, #ejabberd_commands{name = oauth_revoke_token, tags = [oauth], - desc = "Revoke authorization for an _`oauth.md|OAuth`_ token", + desc = "Revoke authorization for an OAuth token", note = "changed in 22.05", module = ?MODULE, function = oauth_revoke_token, args = [{token, binary}], @@ -124,7 +124,7 @@ get_commands_spec() -> result_desc = "Result code" }, #ejabberd_commands{name = oauth_add_client_password, tags = [oauth], - desc = "Add _`oauth.md|OAuth`_ client_id with password grant type", + desc = "Add OAuth client_id with password grant type", module = ?MODULE, function = oauth_add_client_password, args = [{client_id, binary}, {client_name, binary}, @@ -133,7 +133,7 @@ get_commands_spec() -> result = {res, restuple} }, #ejabberd_commands{name = oauth_add_client_implicit, tags = [oauth], - desc = "Add _`oauth.md|OAuth`_ client_id with implicit grant type", + desc = "Add OAuth client_id with implicit grant type", module = ?MODULE, function = oauth_add_client_implicit, args = [{client_id, binary}, {client_name, binary}, @@ -142,7 +142,7 @@ get_commands_spec() -> result = {res, restuple} }, #ejabberd_commands{name = oauth_remove_client, tags = [oauth], - desc = "Remove _`oauth.md|OAuth`_ client_id", + desc = "Remove OAuth client_id", module = ?MODULE, function = oauth_remove_client, args = [{client_id, binary}], policy = restricted, From 90c4fa2a842522b7708cce06ba655d13db58fab2 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Mar 2025 22:01:22 +0100 Subject: [PATCH 078/170] mod_admin_extra: If policy=user, ejabberd adds the user/host args --- src/mod_admin_extra.erl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index d5149708faa..11b0fbb95ff 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -729,7 +729,6 @@ get_commands_spec() -> policy = user, module = ?MODULE, function = get_roster_count, args = [], - args_example = [<<"sun">>, <<"localhost">>], args_rename = [{server, host}], result_example = 5, result_desc = "Number", From 6bf59307033b04df1e05a13df4faf1bde9c9550d Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Mar 2025 18:28:53 +0100 Subject: [PATCH 079/170] mod_announce: Improve documentation syntax --- src/mod_announce.erl | 49 ++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 366a81e428a..b382dc3a6e6 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -920,38 +920,43 @@ mod_doc() -> [?T("This module enables configured users to broadcast " "announcements and to set the message of the day (MOTD). " "Configured users can perform these actions with an XMPP " - "client either using Ad-hoc Commands or sending messages " + "client either using Ad-Hoc Commands or sending messages " "to specific JIDs."), "", - ?T("Note that this module can be resource intensive on large " + ?T("NOTE: This module can be resource intensive on large " "deployments as it may broadcast a lot of messages. This module " "should be disabled for instances of ejabberd with hundreds of " "thousands users."), "", - ?T("The Ad-hoc Commands are listed in the Server Discovery. " - "For this feature to work, _`mod_adhoc`_ must be enabled."), "", - ?T("The specific JIDs where messages can be sent are listed below. " - "The first JID in each entry will apply only to the specified " - "virtual host example.org, while the JID between brackets " - "will apply to all virtual hosts in ejabberd:"), "", - "- example.org/announce/all (example.org/announce/all-hosts/all)::", - ?T("The message is sent to all registered users. If the user is " + ?T("To send announcements using " + "https://xmpp.org/extensions/xep-0050.html[XEP-0050:%20Ad-Hoc%20Commands]," + "this module requires _`mod_adhoc`_ (to execute the commands), " + "and recommends _`mod_disco`_ (to discover the commands)."), "", + ?T("To send announcements by sending messages to specific JIDs, these are the destination JIDs:"), "", + "- 'example.org/announce/all':", + ?T("Send the message to all registered users in that vhost. If the user is " "online and connected to several resources, only the resource " "with the highest priority will receive the message. " - "If the registered user is not connected, the message will be " + "If the registered user is not connected, the message is " "stored offline in assumption that offline storage (see _`mod_offline`_) " "is enabled."), - "- example.org/announce/online (example.org/announce/all-hosts/online)::", - ?T("The message is sent to all connected users. If the user is " + "- 'example.org/announce/online':", + ?T("Send the message to all connected users. If the user is " "online and connected to several resources, all resources will " "receive the message."), - "- example.org/announce/motd (example.org/announce/all-hosts/motd)::", - ?T("The message is set as the message of the day (MOTD) and is sent " - "to users when they login. In addition the message is sent to all " - "connected users (similar to announce/online)."), - "- example.org/announce/motd/update (example.org/announce/all-hosts/motd/update)::", - ?T("The message is set as message of the day (MOTD) and is sent to users " - "when they login. The message is not sent to any currently connected user."), - "- example.org/announce/motd/delete (example.org/announce/all-hosts/motd/delete)::", - ?T("Any message sent to this JID removes the existing message of the day (MOTD).")], + "- 'example.org/announce/motd':", + ?T("Set the message of the day (MOTD) that is sent " + "to users when they login. Also sends the message to all " + "connected users (similar to 'announce/online')."), + "- 'example.org/announce/motd/update':", + ?T("Set the message of the day (MOTD) that is sent to users " + "when they login. This does not send the message to any currently connected user."), + "- 'example.org/announce/motd/delete':", + ?T("Remove the existing message of the day (MOTD) by sending a message to this JID."), "", + ?T("There are similar destination JIDs to apply to all virtual hosts in ejabberd:"), "", + "- 'example.org/announce/all-hosts/all': send to all registered accounts", + "- 'example.org/announce/all-hosts/online': send to online sessions", + "- 'example.org/announce/all-hosts/motd': set MOTD and send to online", + "- 'example.org/announce/all-hosts/motd/update': update MOTD", + "- 'example.org/announce/all-hosts/motd/delete': delete MOTD"], opts => [{access, #{value => ?T("AccessName"), From 087718c47a1da1871e3eda1bdee80be0eb9d350a Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Tue, 11 Mar 2025 15:05:54 +0100 Subject: [PATCH 080/170] fix greedy include path (fixes #4359) --- src/ext_mod.erl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 451467c6670..387ef1bd418 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -573,7 +573,7 @@ compile_and_install(Module, Spec, Config) -> true -> case compile_deps(SrcDir) of ok -> - case compile(SrcDir) of + case compile(SrcDir, filename:join(SrcDir, "deps")) of ok -> install(Module, Spec, SrcDir, LibDir, Config); Error -> Error end; @@ -589,25 +589,28 @@ compile_and_install(Module, Spec, Config) -> end. compile_deps(LibDir) -> - Deps = filename:join(LibDir, "deps"), - case filelib:is_dir(Deps) of + DepsDir = filename:join(LibDir, "deps"), + case filelib:is_dir(DepsDir) of true -> ok; % assume deps are included false -> fetch_rebar_deps(LibDir) end, - Rs = [compile(Dep) || Dep <- filelib:wildcard(filename:join(Deps, "*"))], + Rs = [compile(Dep, DepsDir) || Dep <- filelib:wildcard(filename:join(DepsDir, "*"))], compile_result(Rs). -compile(LibDir) -> +compile(LibDir, DepsDir) -> Bin = filename:join(LibDir, "ebin"), Lib = filename:join(LibDir, "lib"), Src = filename:join(LibDir, "src"), - Includes = [{i, Inc} || Inc <- filelib:wildcard(LibDir++"/../../**/include")], + Includes = [{i, Inc} || Inc <- filelib:wildcard(DepsDir++"/**/include")], Options = [{outdir, Bin}, {i, LibDir++"/.."} | Includes ++ compile_options()], + ?DEBUG("compile options: ~p", [Options]), filelib:ensure_dir(filename:join(Bin, ".")), [copy(App, filename:join(Bin, filename:basename(App, ".src"))) || App <- filelib:wildcard(Src++"/*.app*")], compile_c_files(LibDir), + ErlFiles = filelib:wildcard(Src++"/**/*.erl"), + ?DEBUG("erl files to compile: ~p", [ErlFiles]), Er = [compile_erlang_file(Bin, File, Options) - || File <- filelib:wildcard(Src++"/**/*.erl")], + || File <- ErlFiles], Ex = compile_elixir_files(Bin, filelib:wildcard(Lib ++ "/**/*.ex")), compile_result(lists:flatten([Er, Ex])). From 0145594adcefe09c6de35d67d5d05edc656f07ce Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Wed, 12 Mar 2025 08:11:07 +0100 Subject: [PATCH 081/170] add $libdir/include to include path --- src/ext_mod.erl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 387ef1bd418..e6ee3fa76d4 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -601,8 +601,11 @@ compile(LibDir, DepsDir) -> Bin = filename:join(LibDir, "ebin"), Lib = filename:join(LibDir, "lib"), Src = filename:join(LibDir, "src"), - Includes = [{i, Inc} || Inc <- filelib:wildcard(DepsDir++"/**/include")], - Options = [{outdir, Bin}, {i, LibDir++"/.."} | Includes ++ compile_options()], + Includes = [ {i, Inc} || Inc <- filelib:wildcard(DepsDir++"/**/include") ], + Options = [ {outdir, Bin}, + {i, LibDir++"/.."}, + {i, filename:join(LibDir, "include")} + | Includes ++ compile_options()], ?DEBUG("compile options: ~p", [Options]), filelib:ensure_dir(filename:join(Bin, ".")), [copy(App, filename:join(Bin, filename:basename(App, ".src"))) || App <- filelib:wildcard(Src++"/*.app*")], From 27f98f50d309ea999c9ee4f3d2c4a47feb24152c Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Wed, 12 Mar 2025 08:11:25 +0100 Subject: [PATCH 082/170] fix typo --- src/ejabberd_hooks.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 39a8c812cf6..0fedc1dfc02 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -152,7 +152,7 @@ unsubscribe(Hook, Host, Module, Function, InitArg) -> -spec run(atom(), list()) -> ok. -%% @doc Run the calls (and subscibers) of this hook in order, don't care about function results. +%% @doc Run the calls (and subscribers) of this hook in order, don't care about function results. %% If a call returns stop, no more calls are performed. run(Hook, Args) -> run(Hook, global, Args). @@ -475,7 +475,7 @@ call_subscriber_list([], _Host, _Hook, _CallbackOrArgs, _Event, Result) -> lists:reverse(Result); call_subscriber_list([{Mod, Func, InitArg} | SubscriberList], Host, Hook, CallbackOrArgs, Event, Result) -> SubscriberArgs = [InitArg, Event, Host, Hook, CallbackOrArgs], - ?DEBUG("Running hook subsciber ~p: ~p:~p/~B with event ~p", + ?DEBUG("Running hook subscriber ~p: ~p:~p/~B with event ~p", [Hook, Mod, Func, length(SubscriberArgs), Event]), try apply(Mod, Func, SubscriberArgs) of State -> From afc54aeb20b600d5b22fde6750c8f454504ca9db Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 12 Mar 2025 12:42:42 +0100 Subject: [PATCH 083/170] ext_mod: Provide output path when mix unpacks dependency from hex When installing a module with mix available in the system, mix downloads and uncompresses the dependency. By default the output dir is - [1], and that breaks compilation of the prometheus library: .../sources/ejabberd-contrib/mod_prometheus/deps/prometheus-4.11.0/src/metrics/prometheus_quantile_summary.erl:67:14: can't find include lib "quantile_estimator/include/quantile_estimator.hrl" % 67| -include_lib("quantile_estimator/include/quantile_estimator.hrl"). [1] https://hexdocs.pm/hex/Mix.Tasks.Hex.Package.html#module-command-line-options --- src/ext_mod.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ext_mod.erl b/src/ext_mod.erl index e6ee3fa76d4..2d34a91f92f 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -798,7 +798,7 @@ rebar_dep({App, Version, Git}) when Version /= ".*" -> Help = os:cmd("mix hex.package"), case string:find(Help, "mix hex.package fetch") /= nomatch of true -> - {App, "mix hex.package fetch "++AppS++" "++Version++" --unpack"}; + {App, "mix hex.package fetch "++AppS++" "++Version++" --unpack --output "++AppS}; false -> io:format("I'll download ~p using git because I can't use Mix " "to fetch from hex.pm:~n~s", [AppS, Help]), From bb2f398fa21cdd9b710b46f5a5d2f7ad01289587 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 6 Jan 2025 12:21:44 +0100 Subject: [PATCH 084/170] ejabberd_listener: Handle unix socket when logging remote client --- src/ejabberd_listener.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 2412eb54542..1e822992f62 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -562,10 +562,12 @@ format_error(Reason) -> end. -spec format_endpoint(endpoint()) -> string(). -format_endpoint({Port, IP, _Transport}) -> +format_endpoint({Port, IP, Transport}) -> case Port of <<"unix:", _/binary>> -> Port; + <<>> when (IP == local) and (Transport == tcp) -> + "local-unix-socket-domain"; Unix when is_binary(Unix) -> Def = get_definitive_udsocket_path(Unix), <<"unix:", Def/binary>>; From c9a9585573ef49e1d87653225256078545abd592 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 3 Jan 2025 12:30:38 +0100 Subject: [PATCH 085/170] ejabberd_listener: Add support for socket relative path If the 'port' option is set to "unix:some-filename" without absolute path, then the file is created in the mnesia spool directory --- src/ejabberd_listener.erl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 1e822992f62..639c581537c 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -236,7 +236,7 @@ get_definitive_udsocket_path(<<"unix", _>> = Unix) -> get_definitive_udsocket_path(ProvisionalPath) -> PathBase64 = filename:basename(ProvisionalPath), {term, Path} = misc:base64_to_term(PathBase64), - Path. + relative_socket_to_mnesia(Path). set_definitive_udsocket(<<"unix:", Path/binary>>, Opts) -> Prov = get_provisional_udsocket_path(Path), @@ -268,10 +268,19 @@ set_definitive_udsocket(<<"unix:", Path/binary>>, Opts) -> throw({error_setting_socket_group, Group, Prov}) end end, - file:rename(Prov, Path); + file:rename(Prov, relative_socket_to_mnesia(Path)); set_definitive_udsocket(_Port, _Opts) -> ok. +relative_socket_to_mnesia(Path1) -> + case filename:pathtype(Path1) of + absolute -> + Path1; + relative -> + MnesiaDir = mnesia:system_info(directory), + filename:join(MnesiaDir, Path1) + end. + %%% %%% %%% From 71dbbc1b5a9373326c4f0e8a34d90ff9fb7d83a5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 7 Jan 2025 13:53:26 +0100 Subject: [PATCH 086/170] ejabberd_listener: Use /tmp for temporary socket, as path is restricted to 107 chars --- src/ejabberd_listener.erl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 639c581537c..bac69f19b1f 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -216,18 +216,13 @@ listen_tcp(Port, SockOpts) -> setup_provisional_udsocket_dir(DefinitivePath) -> ProvisionalPath = get_provisional_udsocket_path(DefinitivePath), - SocketDir = filename:dirname(ProvisionalPath), - file:make_dir(SocketDir), - file:change_mode(SocketDir, 8#00700), ?DEBUG("Creating a Unix Domain Socket provisional file at ~ts for the definitive path ~s", [ProvisionalPath, DefinitivePath]), ProvisionalPath. get_provisional_udsocket_path(Path) -> - MnesiaDir = mnesia:system_info(directory), - SocketDir = filename:join(MnesiaDir, "socket"), PathBase64 = misc:term_to_base64(Path), - PathBuild = filename:join(SocketDir, PathBase64), + PathBuild = filename:join(os:getenv("HOME"), PathBase64), %% Shorthen the path, a long path produces a crash when opening the socket. binary:part(PathBuild, {0, erlang:min(107, byte_size(PathBuild))}). @@ -268,7 +263,15 @@ set_definitive_udsocket(<<"unix:", Path/binary>>, Opts) -> throw({error_setting_socket_group, Group, Prov}) end end, - file:rename(Prov, relative_socket_to_mnesia(Path)); + FinalPath = relative_socket_to_mnesia(Path), + FinalPathDir = filename:dirname(FinalPath), + case file:make_dir(FinalPathDir) of + ok -> + file:change_mode(FinalPathDir, 8#00700); + _ -> + ok + end, + file:rename(Prov, FinalPath); set_definitive_udsocket(_Port, _Opts) -> ok. From c5abe5d882d9495a20dc89bf6dea7377cb06c5ae Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Jan 2025 14:52:16 +0100 Subject: [PATCH 087/170] ejabberd_listener: Apparently the sleep 5 seconds isn't needed anymore --- src/ejabberd_listener.erl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index bac69f19b1f..be7d9191439 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -235,7 +235,6 @@ get_definitive_udsocket_path(ProvisionalPath) -> set_definitive_udsocket(<<"unix:", Path/binary>>, Opts) -> Prov = get_provisional_udsocket_path(Path), - timer:sleep(5000), Usd = maps:get(unix_socket, Opts), case maps:get(mode, Usd, undefined) of undefined -> ok; From d4fd987e84ef9b1ff4fa7c4f94bad4b936b2c019 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 23 Jan 2025 13:26:03 +0100 Subject: [PATCH 088/170] ejabberd_listener: When stopping listener, delete Unix Domain Socket file --- src/ejabberd_listener.erl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index be7d9191439..5b5cdeb206e 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -283,6 +283,12 @@ relative_socket_to_mnesia(Path1) -> filename:join(MnesiaDir, Path1) end. +maybe_delete_udsocket_file(<<"unix:", Path/binary>>) -> + PathAbsolute = relative_socket_to_mnesia(Path), + file:delete(PathAbsolute); +maybe_delete_udsocket_file(_Port) -> + ok. + %%% %%% %%% @@ -481,12 +487,13 @@ stop_listeners() -> Ports). -spec stop_listener(endpoint(), module(), opts()) -> ok | {error, any()}. -stop_listener({_, _, Transport} = EndPoint, Module, Opts) -> +stop_listener({Port, _, Transport} = EndPoint, Module, Opts) -> case supervisor:terminate_child(?MODULE, EndPoint) of ok -> ?INFO_MSG("Stop accepting ~ts connections at ~ts for ~p", [format_transport(Transport, Opts), format_endpoint(EndPoint), Module]), + maybe_delete_udsocket_file(Port), ets:delete(?MODULE, EndPoint), supervisor:delete_child(?MODULE, EndPoint); Err -> From 630301a7bac6632359ad5ebce3b0deb4edee83ad Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 16 Jan 2025 17:51:57 +0100 Subject: [PATCH 089/170] ejabberdctl: Document the --auth option The expected placement of --auth is not arbitrary, it should be provided immediately before the command+args --- src/ejabberd_ctl.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 6fcd46e1ca1..1504c26097d 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -550,7 +550,8 @@ print_usage(HelpMode, MaxC, ShCode, Version) -> AllCommands = get_list_commands(Version), print( - ["Usage: ", "ejabberdctl", " [--no-timeout] [--node ", ?A("nodename"), "] [--version ", ?A("api_version"), "] ", + ["Usage: ", "ejabberdctl", " [--no-timeout] [--node ", ?A("name"), "] [--version ", ?A("apiv"), "] ", + "[--auth ", ?A("user host pass"), "] ", ?C("command"), " [", ?A("arguments"), "]\n" "\n" "Available commands in this ejabberd node:\n"], []), From ab8a39e71fdc893c4bd21aae5e3d446b0fe78bee Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 23 Jan 2025 13:25:04 +0100 Subject: [PATCH 090/170] ejabberdctl: Improve explanation how to stop ejabberd in live mode --- ejabberdctl.template | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ejabberdctl.template b/ejabberdctl.template index b9f01535bba..37e018b084f 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -179,7 +179,9 @@ livewarning() echo "Please be extremely cautious with your actions," echo "and exit immediately if you are not completely sure." echo "" - echo "To exit and detach this shell from ejabberd, press:" + echo "To stop ejabberd gracefully:" + echo " ejabberd:stop()." + echo "To quit erlang immediately, press:" echo " control+g and then q" echo "" echo "--------------------------------------------------------------------" From 46a64c0f68007370f478ccd5d6b93adfb2fc14cd Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 6 Jan 2025 19:05:58 +0100 Subject: [PATCH 091/170] New ejabberdctl option CTL_OVER_HTTP This uses an HTTP connection to execute the command, which is way faster than starting an erlang node --- ejabberdctl.cfg.example | 11 +++++++++ ejabberdctl.template | 52 +++++++++++++++++++++++++++++++++-------- src/ejabberd_ctl.erl | 49 +++++++++++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 16 deletions(-) diff --git a/ejabberdctl.cfg.example b/ejabberdctl.cfg.example index 6887fb4cc99..88f99cd7820 100644 --- a/ejabberdctl.cfg.example +++ b/ejabberdctl.cfg.example @@ -198,6 +198,17 @@ # #CONTRIB_MODULES_CONF_DIR=/etc/ejabberd/modules +#. +#' CTL_OVER_HTTP: Path to ejabberdctl HTTP listener socket +# +# To speedup ejabberdctl execution time for ejabberd commands, +# you can setup an ejabberd_http listener with ejabberd_ctl handling requests, +# listening in a unix domain socket. +# +# Default: disabled +# +#CTL_OVER_HTTP=sockets/ctl_over_http.sock + #. #' # vim: foldmarker=#',#. foldmethod=marker: diff --git a/ejabberdctl.template b/ejabberdctl.template index 37e018b084f..bf590acba18 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -334,6 +334,47 @@ wait_status() [ $timeout -gt 0 ] } +exec_other_command() +{ + if [ -z "$CTL_OVER_HTTP" ] || [ ! -S "$CTL_OVER_HTTP" ] \ + || [ ! -x "$(command -v curl)" ] || [ -z "$1" ] || [ "$1" = "help" ] \ + || [ "$1" = "mnesia_info_ctl" ]|| [ "$1" = "print_sql_schema" ] ; then + exec_erl "$(uid ctl)" -hidden -noinput \ + -eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \ + -s ejabberd_ctl \ + -extra "$ERLANG_NODE" $NO_TIMEOUT "$@" + result=$? + case $result in + 3) help;; + *) :;; + esac + exit $result + else + exec_ctl_over_http_socket "$@" + fi +} + +exec_ctl_over_http_socket() +{ + CARGS='{"ctl-command-line": "'${*}'"}' + TEMPHEADERS=temp-headers.log + curl \ + --unix-socket ${CTL_OVER_HTTP} \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --data "${CARGS}" \ + --dump-header ${TEMPHEADERS} \ + --no-progress-meter \ + "http://localhost/ctl/$%7B1%7D" + result=$(sed -n 's/.*status-code: \([0-9]*\).*/\1/p' < $TEMPHEADERS) + rm ${TEMPHEADERS} + case $result in + 2|3) exec_other_command help ${1};; + *) :;; + esac + exit $result +} + # ensure we can change current directory to SPOOL_DIR [ -d "$SPOOL_DIR" ] || exec_cmd mkdir -p "$SPOOL_DIR" cd "$SPOOL_DIR" || { @@ -402,15 +443,6 @@ case $1 in ;; *) set_dist_client - exec_erl "$(uid ctl)" -hidden -noinput \ - -eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \ - -s ejabberd_ctl \ - -extra "$ERLANG_NODE" $NO_TIMEOUT "$@" - result=$? - case $result in - 2|3) help;; - *) :;; - esac - exit $result + exec_other_command "$@" ;; esac diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 1504c26097d..9533632f879 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -28,7 +28,7 @@ -behaviour(gen_server). -author('alexey@process-one.net'). --export([start/0, start_link/0, process/1, process2/2]). +-export([start/0, start_link/0, process/1, process/2, process2/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -37,6 +37,7 @@ -include("ejabberd_ctl.hrl"). -include("ejabberd_commands.hrl"). +-include("ejabberd_http.hrl"). -include("logger.hrl"). -include("ejabberd_stacktrace.hrl"). @@ -115,15 +116,51 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. %%----------------------------- -%% Process +%% Process http +%%----------------------------- + +-spec process_http([binary()], tuple()) -> {non_neg_integer(), [{binary(), binary()}], string()}. + +process_http([Call], #request{data = Data} = Request) when is_binary(Call) and is_record(Request, request) -> + [{<<"ctl-command-line">>, LineBin}] = extract_args(Data), + LineStrings = string:split(binary_to_list(LineBin), " ", all), + process_http2(LineStrings, ?DEFAULT_VERSION). + +process_http2(["--version", Arg | Args], _) -> + Version = + try + list_to_integer(Arg) + catch _:_ -> + throw({invalid_version, Arg}) + end, + process_http2(Args, Version); + +process_http2(Args, Version) -> + {String, Code} = process2(Args, [], Version), + String2 = case String of + [] -> String; + _ -> [String, "\n"] + end, + {200, [{<<"status-code">>, integer_to_binary(Code)}], String2}. + +%% Be tolerant to make API more easily usable from command-line pipe. +extract_args(<<"\n">>) -> []; +extract_args(Data) -> + Maps = misc:json_decode(Data), + maps:to_list(Maps). + +%%----------------------------- +%% Process command line %%----------------------------- -spec process([string()]) -> non_neg_integer(). process(Args) -> process(Args, ?DEFAULT_VERSION). +-spec process([string() | binary()], non_neg_integer() | tuple()) -> non_neg_integer(). --spec process([string()], non_neg_integer()) -> non_neg_integer(). +process([Call], Request) when is_binary(Call) and is_record(Request, request) -> + process_http([Call], Request); %% The commands status, stop and restart are defined here to ensure %% they are usable even if ejabberd is completely stopped. @@ -232,7 +269,7 @@ process2(Args, AccessCommands, Auth, Version) -> io:format(lists:flatten(["\n" | String]++["\n"])), [CommandString | _] = Args, process(["help" | [CommandString]], Version), - {lists:flatten(String), ?STATUS_ERROR}; + {lists:flatten(String), ?STATUS_USAGE}; {String, Code} when is_list(String) and is_integer(Code) -> {lists:flatten(String), Code}; @@ -271,7 +308,7 @@ try_run_ctp(Args, Auth, AccessCommands, Version) -> try_call_command(Args, Auth, AccessCommands, Version); false -> print_usage(Version), - {"", ?STATUS_USAGE}; + {"", ?STATUS_BADRPC}; Status -> {"", Status} catch @@ -288,7 +325,7 @@ try_run_ctp(Args, Auth, AccessCommands, Version) -> try_call_command(Args, Auth, AccessCommands, Version) -> try call_command(Args, Auth, AccessCommands, Version) of {Reason, wrong_command_arguments} -> - {Reason, ?STATUS_ERROR}; + {Reason, ?STATUS_USAGE}; Res -> Res catch From f789495c3957d28537840ff092767c95f01c9987 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 16 Jan 2025 13:17:01 +0100 Subject: [PATCH 092/170] ejabberdctl: Improve method to pass command arguments --- ejabberdctl.template | 13 ++++++++++--- src/ejabberd_ctl.erl | 13 +++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ejabberdctl.template b/ejabberdctl.template index bf590acba18..7858067d16d 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -356,7 +356,14 @@ exec_other_command() exec_ctl_over_http_socket() { - CARGS='{"ctl-command-line": "'${*}'"}' + COMMAND=${1} + CARGS="" + while [ $# -gt 0 ]; do + [ -z "$CARGS" ] && CARGS="[" || CARGS="${CARGS}, " + CARGS="${CARGS}\"$1\"" + shift + done + CARGS="${CARGS}]" TEMPHEADERS=temp-headers.log curl \ --unix-socket ${CTL_OVER_HTTP} \ @@ -365,11 +372,11 @@ exec_ctl_over_http_socket() --data "${CARGS}" \ --dump-header ${TEMPHEADERS} \ --no-progress-meter \ - "http://localhost/ctl/$%7B1%7D" + "http://localhost/ctl/$%7BCOMMAND%7D" result=$(sed -n 's/.*status-code: \([0-9]*\).*/\1/p' < $TEMPHEADERS) rm ${TEMPHEADERS} case $result in - 2|3) exec_other_command help ${1};; + 2|3) exec_other_command help ${COMMAND};; *) :;; esac exit $result diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 9533632f879..72aac378050 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -121,10 +121,9 @@ code_change(_OldVsn, State, _Extra) -> -spec process_http([binary()], tuple()) -> {non_neg_integer(), [{binary(), binary()}], string()}. -process_http([Call], #request{data = Data} = Request) when is_binary(Call) and is_record(Request, request) -> - [{<<"ctl-command-line">>, LineBin}] = extract_args(Data), - LineStrings = string:split(binary_to_list(LineBin), " ", all), - process_http2(LineStrings, ?DEFAULT_VERSION). +process_http([_Call], #request{data = Data, path = [<<"ctl">> | _]}) -> + Args = [binary_to_list(E) || E <- misc:json_decode(Data)], + process_http2(Args, ?DEFAULT_VERSION). process_http2(["--version", Arg | Args], _) -> Version = @@ -143,12 +142,6 @@ process_http2(Args, Version) -> end, {200, [{<<"status-code">>, integer_to_binary(Code)}], String2}. -%% Be tolerant to make API more easily usable from command-line pipe. -extract_args(<<"\n">>) -> []; -extract_args(Data) -> - Maps = misc:json_decode(Data), - maps:to_list(Maps). - %%----------------------------- %% Process command line %%----------------------------- From 4d62f545c51b4a26b881de59031e08d79362980a Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 6 Jan 2025 20:49:49 +0100 Subject: [PATCH 093/170] ejabberd_admin: Separate Status command result with newline This is useful for CTL_OVER_HTTP --- src/ejabberd_admin.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index c6e955ab20f..259831d7f76 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -663,7 +663,7 @@ status() -> {value, {_, _, Version}} -> {ok, io_lib:format("ejabberd ~s is running in that node", [Version])} end, - {Is_running, String1 ++ " " ++String2}. + {Is_running, String1 ++ "\n" ++String2}. stop() -> _ = supervisor:terminate_child(ejabberd_sup, ejabberd_sm), From e761b22c611ba310d1af2760e0e0f7ea182d8012 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Jan 2025 14:52:45 +0100 Subject: [PATCH 094/170] ejabberd_listener: When opening ctl_over_http connection, log in DEBUG --- src/ejabberd_listener.erl | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 5b5cdeb206e..67f3db2deff 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -358,11 +358,20 @@ accept(ListenSocket, Module, State, Sup, Interval, Proxy, Arity) -> gen_tcp:close(Socket), none end, - ?INFO_MSG("(~p) Accepted connection ~ts -> ~ts", - [Receiver, - ejabberd_config:may_hide_data( - format_endpoint({PPort, PAddr, tcp})), - format_endpoint({Port, Addr, tcp})]); + case is_ctl_over_http(State) of + false -> + ?INFO_MSG("(~p) Accepted connection ~ts -> ~ts", + [Receiver, + ejabberd_config:may_hide_data( + format_endpoint({PPort, PAddr, tcp})), + format_endpoint({Port, Addr, tcp})]); + true -> + ?DEBUG("(~p) Accepted connection ~ts -> ~ts", + [Receiver, + ejabberd_config:may_hide_data( + format_endpoint({PPort, PAddr, tcp})), + format_endpoint({Port, Addr, tcp})]) + end; _ -> gen_tcp:close(Socket) end, @@ -373,6 +382,16 @@ accept(ListenSocket, Module, State, Sup, Interval, Proxy, Arity) -> accept(ListenSocket, Module, State, Sup, NewInterval, Proxy, Arity) end. +is_ctl_over_http(State) -> + case lists:keyfind(request_handlers, 1, State) of + {request_handlers, Handlers} -> + case lists:keyfind(ejabberd_ctl, 2, Handlers) of + {_, ejabberd_ctl} -> true; + _ -> false + end; + _ -> false + end. + -spec udp_recv(inet:socket(), module(), state()) -> no_return(). udp_recv(Socket, Module, State) -> case gen_udp:recv(Socket, 0) of From 9f28098d04a87b0db232e2c4dec3aeb2c76b6da9 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 26 Dec 2024 18:26:24 +0100 Subject: [PATCH 095/170] Container: Copy files to stable path, add ecs backwards compatibility Copy captcha scripts to stable path for referencing in compose files: /usr/local/bin/ which is included in $PATH For backwards compatibility with ecs, link: /opt/ -> /home/ /usr/local/bin/ -> /opt/ejabberd/bin/ Copy sql files to stable path for referencing: /opt/ejabberd/sql/ For backwards compatibility with ecs, copy also to /opt/ejabberd/database/ ecs image implemented this in ejabberdctl since 2019: edb0373fd0ae0b24807a41ba2c3bf04b5b514844 Keep SQL init scripts in container (#42) --- .github/container/Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 2a44b903550..840ac2944a8 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -137,6 +137,11 @@ RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ ARG UID RUN chown -R $UID:$UID $HOME +ARG VERSION +RUN cp /rootfs/$HOME-$VERSION/lib/captcha*.sh usr/local/bin/ +RUN mkdir $HOME/sql \ + && find /rootfs/$HOME-$VERSION/lib/ -name *.sql -exec cp {} $HOME/sql \; -exec cp {} $HOME/database \; + ################################################################################ #' METHOD='direct' - Remove erlang/OTP & rebar3 FROM docker.io/erlang:${OTP_VSN}-alpine AS runtime-direct @@ -167,6 +172,10 @@ ARG HOME RUN addgroup $USER -g $UID \ && adduser -s /sbin/nologin -D -u $UID -h /$HOME -G $USER $USER +RUN ln -fs /usr/local/bin/ /opt/ejabberd/bin +RUN rm -rf /home \ + && ln -fs /opt /home + ################################################################################ #' Build together production image FROM scratch AS prod From 3d49bed0cf500ae828367eb1585b1c511416651e Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Dec 2024 21:49:49 +0100 Subject: [PATCH 096/170] Container: Copy main example configuration file, will be customized --- .github/container/Dockerfile | 1 + .github/container/ejabberd.yml.example | 244 +++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 .github/container/ejabberd.yml.example diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 840ac2944a8..90a10ec3869 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -50,6 +50,7 @@ COPY / $BUILD_DIR/ WORKDIR $BUILD_DIR RUN mv .github/container/ejabberdctl.template . \ + && mv .github/container/ejabberd.yml.example . \ && ./autogen.sh \ && ./configure --with-rebar=mix --enable-all \ && make deps \ diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example new file mode 100644 index 00000000000..39e423a6449 --- /dev/null +++ b/.github/container/ejabberd.yml.example @@ -0,0 +1,244 @@ +### +### ejabberd configuration file +### +### The parameters used in this configuration file are explained at +### +### https://docs.ejabberd.im/admin/configuration +### +### The configuration file is written in YAML. +### ******************************************************* +### ******* !!! WARNING !!! ******* +### ******* YAML IS INDENTATION SENSITIVE ******* +### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY ******* +### ******************************************************* +### Refer to http://en.wikipedia.org/wiki/YAML for the brief description. +### + +hosts: + - localhost + +loglevel: info + +## If you already have certificates, list them here +# certfiles: +# - /etc/letsencrypt/live/domain.tld/fullchain.pem +# - /etc/letsencrypt/live/domain.tld/privkey.pem + +listen: + - + port: 5222 + ip: "::" + module: ejabberd_c2s + max_stanza_size: 262144 + shaper: c2s_shaper + access: c2s + starttls_required: true + - + port: 5223 + ip: "::" + module: ejabberd_c2s + max_stanza_size: 262144 + shaper: c2s_shaper + access: c2s + tls: true + - + port: 5269 + ip: "::" + module: ejabberd_s2s_in + max_stanza_size: 524288 + shaper: s2s_shaper + - + port: 5443 + ip: "::" + module: ejabberd_http + tls: true + request_handlers: + /admin: ejabberd_web_admin + /api: mod_http_api + /bosh: mod_bosh + /captcha: ejabberd_captcha + /upload: mod_http_upload + /ws: ejabberd_http_ws + - + port: 5280 + ip: "::" + module: ejabberd_http + request_handlers: + /admin: ejabberd_web_admin + /.well-known/acme-challenge: ejabberd_acme + - + port: 5478 + ip: "::" + transport: udp + module: ejabberd_stun + use_turn: true + ## The server's public IPv4 address: + # turn_ipv4_address: "203.0.113.3" + ## The server's public IPv6 address: + # turn_ipv6_address: "2001:db8::3" + - + port: 1883 + ip: "::" + module: mod_mqtt + backlog: 1000 + +s2s_use_starttls: optional + +acl: + local: + user_regexp: "" + loopback: + ip: + - 127.0.0.0/8 + - ::1/128 + +access_rules: + local: + allow: local + c2s: + deny: blocked + allow: all + announce: + allow: admin + configure: + allow: admin + muc_create: + allow: local + pubsub_createnode: + allow: local + trusted_network: + allow: loopback + +api_permissions: + "console commands": + from: ejabberd_ctl + who: all + what: "*" + "webadmin commands": + from: ejabberd_web_admin + who: admin + what: "*" + "admin access": + who: + access: + allow: + - acl: loopback + - acl: admin + oauth: + scope: "ejabberd:admin" + access: + allow: + - acl: loopback + - acl: admin + what: + - "*" + - "!stop" + - "!start" + "public commands": + who: + ip: 127.0.0.1/8 + what: + - status + - connected_users_number + +shaper: + normal: + rate: 3000 + burst_size: 20000 + fast: 100000 + +shaper_rules: + max_user_sessions: 10 + max_user_offline_messages: + 5000: admin + 100: all + c2s_shaper: + none: admin + normal: all + s2s_shaper: fast + +modules: + mod_adhoc: {} + mod_admin_extra: {} + mod_announce: + access: announce + mod_avatar: {} + mod_blocking: {} + mod_bosh: {} + mod_caps: {} + mod_carboncopy: {} + mod_client_state: {} + mod_configure: {} + mod_disco: {} + mod_fail2ban: {} + mod_http_api: {} + mod_http_upload: + put_url: https://@HOST@:5443/upload + custom_headers: + "Access-Control-Allow-Origin": "https://@HOST@" + "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS" + "Access-Control-Allow-Headers": "Content-Type" + mod_last: {} + mod_mam: + ## Mnesia is limited to 2GB, better to use an SQL backend + ## For small servers SQLite is a good fit and is very easy + ## to configure. Uncomment this when you have SQL configured: + ## db_type: sql + assume_mam_usage: true + default: always + mod_mqtt: {} + mod_muc: + access: + - allow + access_admin: + - allow: admin + access_create: muc_create + access_persistent: muc_create + access_mam: + - allow + default_room_options: + mam: true + mod_muc_admin: {} + mod_offline: + access_max_user_messages: max_user_offline_messages + mod_ping: {} + mod_privacy: {} + mod_private: {} + mod_proxy65: + access: local + max_connections: 5 + mod_pubsub: + access_createnode: pubsub_createnode + plugins: + - flat + - pep + force_node_config: + ## Avoid buggy clients to make their bookmarks public + storage:bookmarks: + access_model: whitelist + mod_push: {} + mod_push_keepalive: {} + mod_register: + ## Only accept registration requests from the "trusted" + ## network (see access_rules section above). + ## Think twice before enabling registration from any + ## address. See the Jabber SPAM Manifesto for details: + ## https://github.com/ge0rg/jabber-spam-fighting-manifesto + ip_access: trusted_network + mod_roster: + versioning: true + mod_s2s_bidi: {} + mod_s2s_dialback: {} + mod_shared_roster: {} + mod_stream_mgmt: + resend_on_timeout: if_offline + mod_stun_disco: {} + mod_vcard: {} + mod_vcard_xupdate: {} + mod_version: + show_os: false + +### Local Variables: +### mode: yaml +### End: +### vim: set filetype=yaml tabstop=8 From 090a7e664ecd60b9f7f6150fcd02f982bb08b7f2 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Dec 2024 21:51:49 +0100 Subject: [PATCH 097/170] Container: Apply customizations directly in the configuration file --- .github/container/Dockerfile | 6 +----- .github/container/ejabberd.yml.example | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 90a10ec3869..1cb2ace6b17 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -68,11 +68,7 @@ RUN cp -p $BUILD_DIR/tools/captcha*.sh $HOME-$VERSION/lib RUN find "$HOME-$VERSION/bin" -name 'ejabberd' -delete \ && find "$HOME-$VERSION/releases" -name 'COOKIE' -delete -RUN wget -O "$HOME/conf/cacert.pem" 'https://curl.se/ca/cacert.pem' \ - && sed -i '/^loglevel:/a \ \ - \nca_file: /opt/ejabberd/conf/cacert.pem \ - \ncertfiles: \ - \n - /opt/ejabberd/conf/server.pem' "$HOME/conf/ejabberd.yml" +RUN wget -O "$HOME/conf/cacert.pem" 'https://curl.se/ca/cacert.pem' ################################################################################ #' METHOD='package' - install ejabberd from binary tarball package diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example index 39e423a6449..9aeab643a83 100644 --- a/.github/container/ejabberd.yml.example +++ b/.github/container/ejabberd.yml.example @@ -24,6 +24,10 @@ loglevel: info # - /etc/letsencrypt/live/domain.tld/fullchain.pem # - /etc/letsencrypt/live/domain.tld/privkey.pem +ca_file: /opt/ejabberd/conf/cacert.pem +certfiles: + - /opt/ejabberd/conf/server.pem + listen: - port: 5222 From 7df7daa0507d5d6e786775ec8369615b720e0577 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Dec 2024 22:01:25 +0100 Subject: [PATCH 098/170] Container: Define and use macros in the configuration file --- .github/container/ejabberd.yml.example | 32 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example index 9aeab643a83..613f38d4134 100644 --- a/.github/container/ejabberd.yml.example +++ b/.github/container/ejabberd.yml.example @@ -14,8 +14,20 @@ ### Refer to http://en.wikipedia.org/wiki/YAML for the brief description. ### +define_macro: + HOST: localhost + ADMIN: "admin@localhost" + PORT_C2S: 5222 + PORT_C2S_TLS: 5223 + PORT_S2S: 5269 + PORT_HTTP_TLS: 5443 + PORT_HTTP: 5280 + PORT_STUN: 5478 + PORT_MQTT: 1883 + PORT_PROXY65: 7777 + hosts: - - localhost + - HOST loglevel: info @@ -30,7 +42,7 @@ certfiles: listen: - - port: 5222 + port: PORT_C2S ip: "::" module: ejabberd_c2s max_stanza_size: 262144 @@ -38,7 +50,7 @@ listen: access: c2s starttls_required: true - - port: 5223 + port: PORT_C2S_TLS ip: "::" module: ejabberd_c2s max_stanza_size: 262144 @@ -46,13 +58,13 @@ listen: access: c2s tls: true - - port: 5269 + port: PORT_S2S ip: "::" module: ejabberd_s2s_in max_stanza_size: 524288 shaper: s2s_shaper - - port: 5443 + port: PORT_HTTP_TLS ip: "::" module: ejabberd_http tls: true @@ -64,14 +76,14 @@ listen: /upload: mod_http_upload /ws: ejabberd_http_ws - - port: 5280 + port: PORT_HTTP ip: "::" module: ejabberd_http request_handlers: /admin: ejabberd_web_admin /.well-known/acme-challenge: ejabberd_acme - - port: 5478 + port: PORT_STUN ip: "::" transport: udp module: ejabberd_stun @@ -81,7 +93,7 @@ listen: ## The server's public IPv6 address: # turn_ipv6_address: "2001:db8::3" - - port: 1883 + port: PORT_MQTT ip: "::" module: mod_mqtt backlog: 1000 @@ -95,6 +107,9 @@ acl: ip: - 127.0.0.0/8 - ::1/128 + admin: + user: + - ADMIN access_rules: local: @@ -211,6 +226,7 @@ modules: mod_proxy65: access: local max_connections: 5 + port: PORT_PROXY65 mod_pubsub: access_createnode: pubsub_createnode plugins: From dd7550dbad7399a1e2895630ca7338fde4f26c91 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Dec 2024 22:19:32 +0100 Subject: [PATCH 099/170] Container: Listen for webadmin in a port number lower than any other In the docker-desktop and podman-desktop, when user clicks their "Open Browser" buttons, those apps open a browser with / URL and the lowest exposed port number. --- .github/container/Dockerfile | 2 +- .github/container/ejabberd.yml.example | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 1cb2ace6b17..2847fad8921 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -192,7 +192,7 @@ HEALTHCHECK \ WORKDIR /$HOME USER $USER VOLUME ["/$HOME"] -EXPOSE 1883 4369-4399 5210 5222 5269 5280 5443 +EXPOSE 1880 1883 4369-4399 5210 5222 5269 5280 5443 ENTRYPOINT ["/sbin/tini","--","ejabberdctl"] CMD ["foreground"] diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example index 613f38d4134..ba6e08fbbe2 100644 --- a/.github/container/ejabberd.yml.example +++ b/.github/container/ejabberd.yml.example @@ -22,6 +22,7 @@ define_macro: PORT_S2S: 5269 PORT_HTTP_TLS: 5443 PORT_HTTP: 5280 + PORT_BROWSER: 1880 PORT_STUN: 5478 PORT_MQTT: 1883 PORT_PROXY65: 7777 @@ -82,6 +83,12 @@ listen: request_handlers: /admin: ejabberd_web_admin /.well-known/acme-challenge: ejabberd_acme + - + port: PORT_BROWSER + ip: "::" + module: ejabberd_http + request_handlers: + /: ejabberd_web_admin - port: PORT_STUN ip: "::" From 1d42d55064f5eb443df2aa4c729faab53d6efb53 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 30 Dec 2024 10:39:13 +0100 Subject: [PATCH 100/170] Container: Compile ejabberdapi during build Code written originally by sando38 for ecs's Dockerfile. --- .github/container/Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 2847fad8921..d389251c718 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -81,6 +81,13 @@ RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ && ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/') \ && tar -xzf /tmp/ejabberd-*-linux-musl-$ARCH.tar.gz -C $home_root_dir +################################################################################ +#' Compile ejabberdapi +FROM docker.io/golang:1.23-alpine AS api +RUN go install -v \ + github.com/processone/ejabberd-api/cmd/ejabberd@master \ + && mv bin/ejabberd bin/ejabberdapi + ################################################################################ #' Prepare ejabberd for runtime FROM ${METHOD} AS ejabberd @@ -131,6 +138,8 @@ RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ | sed -e "s|so:libc.so|so:libc.musl-$(uname -m).so.1|" \ > /tmp/runDeps +COPY --from=api /go/bin/ejabberdapi usr/local/bin/ + ARG UID RUN chown -R $UID:$UID $HOME From c924a47188a1afb195cb98a8a69ca6ac4db857e1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Dec 2024 21:46:03 +0100 Subject: [PATCH 101/170] Container: Improve entrypoint script: register account, or set random If password variable is set, register that account. Example kubernetes yaml file in podman: env: - name: EJABBERD_MACRO_ADMIN value: administrator@example.org - name: REGISTER_ADMIN_PASSWORD value: somePass0rd If admin and password are not set, grant admin rights only to a random account name. Notice that admin rights are granted to that variable in the default ejabberd.yml, so if the account is not created, somebody else could do. --- .github/container/Dockerfile | 22 ++++++++++++++++++++++ .github/container/ejabberd.yml.example | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index d389251c718..bb8bdf9e5ea 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -125,6 +125,28 @@ RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ && echo -e \ "#!/bin/sh \ \n[ -z \$ERLANG_NODE_ARG ] && export ERLANG_NODE_ARG=ejabberd@localhost \ + \nexport EMA=\"\$EJABBERD_MACRO_ADMIN\" \ + \nexport HOST=\"\${EJABBERD_MACRO_HOST:-localhost}\" \ + \nif [ -n \"\$EMA\" ] \ + \nthen \ + \n if [ \"\$EMA\" != \"\${EMA%%@*}\" ] \ + \n then \ + \n export USERNAME=\"\${EMA%%@*}\" \ + \n export HOST=\"\${EMA##*@}\" \ + \n else \ + \n export USERNAME=\"\$EMA\" \ + \n export SHOW_WARNING=\"true\" \ + \n fi \ + \nelif [ -n \"\$REGISTER_ADMIN_PASSWORD\" ] \ + \nthen \ + \n export USERNAME=\"admin\" \ + \nelse \ + \n export USERNAME=\"\$(od -A n -N 8 -t x8 /dev/urandom)\" \ + \nfi \ + \nexport EJABBERD_MACRO_ADMIN=\"\$USERNAME@\$HOST\" \ + \n[ -n \"\$SHOW_WARNING\" ] && echo \"WARNING: The EJABBERD_MACRO_ADMIN environment variable was set to '\$EMA', but it should include the host... I'll overwrite it to become '\$EJABBERD_MACRO_ADMIN'.\" \ + \n[ -n \"\$CTL_ON_CREATE\" ] && export SEPARATOR=\";\" \ + \n[ -n \"\$REGISTER_ADMIN_PASSWORD\" ] && export CTL_ON_CREATE=\"register \${EJABBERD_MACRO_ADMIN%%@*} \${EJABBERD_MACRO_ADMIN##*@} \$REGISTER_ADMIN_PASSWORD \$SEPARATOR \$CTL_ON_CREATE\" \ \nexport CONFIG_DIR=/$HOME/conf \ \nexport LOGS_DIR=/$HOME/logs \ \nexport SPOOL_DIR=/$HOME/database \ diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example index ba6e08fbbe2..72ac292aa91 100644 --- a/.github/container/ejabberd.yml.example +++ b/.github/container/ejabberd.yml.example @@ -16,7 +16,7 @@ define_macro: HOST: localhost - ADMIN: "admin@localhost" + ## ADMIN: ... # set by /usr/local/bin/ejabberdctl PORT_C2S: 5222 PORT_C2S_TLS: 5223 PORT_S2S: 5269 From 7832a6342a67665d6e31ef8ed565706cc1ac3387 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 2 Jan 2025 13:18:15 +0100 Subject: [PATCH 102/170] Container: Link path to mnesia spool dir for backwards compatibility The ejabberdctl script in ecs image sets mnesia spool dir as: : "${SPOOL_DIR:="$HOME_DIR/database/$ERLANG_NODE"}" --- .github/container/ejabberdctl.template | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/container/ejabberdctl.template b/.github/container/ejabberdctl.template index a27a14587db..d4b37cdac07 100755 --- a/.github/container/ejabberdctl.template +++ b/.github/container/ejabberdctl.template @@ -305,6 +305,8 @@ stop_epmd() # if all ok, ensure runtime directory exists and make it current directory check_start() { + ECSIMAGE_DBPATH=$HOME/database/$ERLANG_NODE + [ ! -d "$ECSIMAGE_DBPATH" ] && ln -s $HOME/database $HOME/database/$ERLANG_NODE [ -n "$ERL_DIST_PORT" ] && return "$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && { pgrep -f "$ERLANG_NODE" >/dev/null && { From 9305232f8c0490fd7f34260dcfadad2d573ec992 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 10 Jan 2025 21:58:01 +0100 Subject: [PATCH 103/170] Container: Remove runDeps file once it's used --- .github/container/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index bb8bdf9e5ea..c70061dc026 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -192,6 +192,7 @@ RUN apk -U upgrade --available --no-cache \ so:libcap.so.2 \ so:libtdsodbc.so.0 \ tini \ + && rm /tmp/runDeps \ && ln -fs /usr/lib/libtdsodbc.so.0 /usr/lib/libtdsodbc.so ARG USER From e887546c27121f9c90db22a3d43281b3335ec5f5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 7 Jan 2025 12:12:08 +0100 Subject: [PATCH 104/170] Container: Copy support for CTL_OVER_HTTP --- .github/container/Dockerfile | 1 + .github/container/ejabberdctl.template | 59 +++++++++++++++++++++----- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index c70061dc026..4c7d65af7b0 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -191,6 +191,7 @@ RUN apk -U upgrade --available --no-cache \ $(cat /tmp/runDeps) \ so:libcap.so.2 \ so:libtdsodbc.so.0 \ + curl \ tini \ && rm /tmp/runDeps \ && ln -fs /usr/lib/libtdsodbc.so.0 /usr/lib/libtdsodbc.so diff --git a/.github/container/ejabberdctl.template b/.github/container/ejabberdctl.template index d4b37cdac07..2353040d5a6 100755 --- a/.github/container/ejabberdctl.template +++ b/.github/container/ejabberdctl.template @@ -379,6 +379,54 @@ wait_status() [ $timeout -gt 0 ] } +exec_other_command() +{ + if [ -z "$CTL_OVER_HTTP" ] || [ ! -S "$CTL_OVER_HTTP" ] \ + || [ ! -x "$(command -v curl)" ] || [ -z "$1" ] || [ "$1" = "help" ] \ + || [ "$1" = "mnesia_info_ctl" ]|| [ "$1" = "print_sql_schema" ] ; then + run_erl "$(uid ctl)" -hidden -noinput \ + -eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \ + -s ejabberd_ctl \ + -extra "$ERLANG_NODE" $NO_TIMEOUT "$@" + result=$? + case $result in + 3) help;; + *) :;; + esac + exit $result + else + exec_ctl_over_http_socket "$@" + fi +} + +exec_ctl_over_http_socket() +{ + COMMAND=${1} + CARGS="" + while [ $# -gt 0 ]; do + [ -z "$CARGS" ] && CARGS="[" || CARGS="${CARGS}, " + CARGS="${CARGS}\"$1\"" + shift + done + CARGS="${CARGS}]" + TEMPHEADERS=temp-headers.log + curl \ + --unix-socket ${CTL_OVER_HTTP} \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --data "${CARGS}" \ + --dump-header ${TEMPHEADERS} \ + --no-progress-meter \ + "http://localhost/ctl/$%7BCOMMAND%7D" + result=$(sed -n 's/.*status-code: \([0-9]*\).*/\1/p' < $TEMPHEADERS) + rm ${TEMPHEADERS} + case $result in + 2|3) exec_other_command help ${COMMAND};; + *) :;; + esac + exit $result +} + # ensure we can change current directory to SPOOL_DIR [ -f "$SPOOL_DIR/schema.DAT" ] || FIRST_RUN=true [ -d "$SPOOL_DIR" ] || run_cmd mkdir -p "$SPOOL_DIR" @@ -454,15 +502,6 @@ case $1 in ;; *) set_dist_client - run_erl "$(uid ctl)" -hidden -noinput \ - -eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \ - -s ejabberd_ctl \ - -extra "$ERLANG_NODE" $NO_TIMEOUT "$@" - result=$? - case $result in - 2|3) help;; - *) :;; - esac - exit $result + exec_other_command "$@" ;; esac From 105a0c2029d485b8671814b302f62a7144ad066c Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Jan 2025 13:46:42 +0100 Subject: [PATCH 105/170] Container: Enable CTL_OVER_HTTP by default --- .github/container/Dockerfile | 2 ++ .github/container/ejabberd.yml.example | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 4c7d65af7b0..ed0dfe504f1 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -120,6 +120,8 @@ RUN export PEM=$HOME/conf/server.pem \ -days 3650 \ -subj "/CN=localhost" +RUN sed -i 's|^#CTL_OVER_HTTP=|CTL_OVER_HTTP=|' "$HOME/conf/ejabberdctl.cfg" + RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ && setcap 'cap_net_bind_service=+ep' $(find $home_root_dir -name beam.smp) \ && echo -e \ diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example index 72ac292aa91..b8a84fc926f 100644 --- a/.github/container/ejabberd.yml.example +++ b/.github/container/ejabberd.yml.example @@ -89,6 +89,13 @@ listen: module: ejabberd_http request_handlers: /: ejabberd_web_admin + - + port: "unix:sockets/ctl_over_http.sock" + module: ejabberd_http + unix_socket: + mode: '0600' + request_handlers: + /ctl: ejabberd_ctl - port: PORT_STUN ip: "::" From 8070a656fe99f7522893ab1e5e3bcbc40e1a3937 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 11 Mar 2025 17:41:26 +0100 Subject: [PATCH 106/170] Container: Use again direct METHOD, qemu got fixed (3983)(4280) Partially revert d15cf99: Container: Add METHOD to build container using packages (3983) --- .github/container/Dockerfile | 56 +++++++++------------------------ .github/workflows/container.yml | 49 ----------------------------- 2 files changed, 14 insertions(+), 91 deletions(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index ed0dfe504f1..7b502f2c49c 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -1,20 +1,22 @@ #' Define default build variables -## specifc ARGs for METHOD='direct' ARG OTP_VSN='27.2' ARG ELIXIR_VSN='1.18.1' -## specifc ARGs for METHOD='package' -ARG ALPINE_VSN='3.19' -## general ARGs ARG UID='9000' ARG USER='ejabberd' ARG HOME="opt/$USER" -ARG METHOD='direct' ARG BUILD_DIR="/$USER" ARG VERSION='master' ################################################################################ -#' METHOD='direct' - build and install ejabberd directly from source -FROM docker.io/erlang:${OTP_VSN}-alpine AS direct +#' Compile ejabberdapi +FROM docker.io/golang:1.23-alpine AS api +RUN go install -v \ + github.com/processone/ejabberd-api/cmd/ejabberd@master \ + && mv bin/ejabberd bin/ejabberdapi + +################################################################################ +#' build and install ejabberd directly from source +FROM docker.io/erlang:${OTP_VSN}-alpine AS ejabberd RUN apk -U add --no-cache \ autoconf \ @@ -70,37 +72,16 @@ RUN find "$HOME-$VERSION/bin" -name 'ejabberd' -delete \ RUN wget -O "$HOME/conf/cacert.pem" 'https://curl.se/ca/cacert.pem' -################################################################################ -#' METHOD='package' - install ejabberd from binary tarball package -FROM docker.io/alpine:${ALPINE_VSN} AS package -COPY tarballs/ejabberd-*-linux-musl-*.tar.gz /tmp/ -WORKDIR /rootfs -ARG HOME -RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ - && mkdir -p $home_root_dir \ - && ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/') \ - && tar -xzf /tmp/ejabberd-*-linux-musl-$ARCH.tar.gz -C $home_root_dir - -################################################################################ -#' Compile ejabberdapi -FROM docker.io/golang:1.23-alpine AS api -RUN go install -v \ - github.com/processone/ejabberd-api/cmd/ejabberd@master \ - && mv bin/ejabberd bin/ejabberdapi - -################################################################################ #' Prepare ejabberd for runtime -FROM ${METHOD} AS ejabberd RUN apk -U add --no-cache \ git \ libcap \ openssl -WORKDIR /rootfs -ARG HOME RUN mkdir -p usr/local/bin $HOME/conf $HOME/database $HOME/logs $HOME/upload -ARG BUILD_DIR +COPY --from=api /go/bin/ejabberdapi usr/local/bin/ + RUN if [ ! -d $HOME/.ejabberd-modules ]; \ then \ if [ -d $BUILD_DIR/.ejabberd-modules ]; \ @@ -162,31 +143,22 @@ RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ | sed -e "s|so:libc.so|so:libc.musl-$(uname -m).so.1|" \ > /tmp/runDeps -COPY --from=api /go/bin/ejabberdapi usr/local/bin/ - ARG UID RUN chown -R $UID:$UID $HOME -ARG VERSION RUN cp /rootfs/$HOME-$VERSION/lib/captcha*.sh usr/local/bin/ RUN mkdir $HOME/sql \ && find /rootfs/$HOME-$VERSION/lib/ -name *.sql -exec cp {} $HOME/sql \; -exec cp {} $HOME/database \; ################################################################################ -#' METHOD='direct' - Remove erlang/OTP & rebar3 -FROM docker.io/erlang:${OTP_VSN}-alpine AS runtime-direct +#' Remove erlang/OTP & rebar3 +FROM docker.io/erlang:${OTP_VSN}-alpine AS runtime RUN apk del .erlang-rundeps \ && rm -f $(which rebar3) \ && find /usr -type d -name 'erlang' -exec rm -rf {} + \ && find /usr -type l -exec test ! -e {} \; -delete -################################################################################ -#' METHOD='package' - define runtime base image -FROM docker.io/alpine:${ALPINE_VSN} AS runtime-package - -################################################################################ #' Update alpine, finalize runtime environment -FROM runtime-${METHOD} AS runtime COPY --from=ejabberd /tmp/runDeps /tmp/runDeps RUN apk -U upgrade --available --no-cache \ && apk add --no-cache \ @@ -210,7 +182,7 @@ RUN rm -rf /home \ ################################################################################ #' Build together production image -FROM scratch AS prod +FROM scratch ARG USER ARG HOME diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 7940c9b6860..567a2c8452f 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -1,8 +1,6 @@ name: Container on: - schedule: - - cron: '22 2 */6 * *' # every 6 days to avoid gha cache being evicted push: paths-ignore: - '.devcontainer/**' @@ -28,52 +26,6 @@ jobs: with: fetch-depth: 0 - - name: Cache build directory - uses: actions/cache@v4 - with: - path: ~/build/ - key: ${{runner.os}}-ctr-ct-ng-1.27.0 - - - name: Get erlang/OTP version for bootstrapping - run: | - echo "OTP_VSN=$(awk '/^otp_vsn=/ {{gsub(/[^0-9.rc-]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV - echo "ELIXIR_VSN=$(awk '/^elixir_vsn=/ {{gsub(/[^0-9.]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV - - - name: Install prerequisites - run: | - sudo apt-get -qq update - sudo apt-get -qq install makeself - # https://github.com/crosstool-ng/crosstool-ng/blob/master/testing/docker/ubuntu21.10/Dockerfile - sudo apt-get -qq install build-essential autoconf bison flex gawk - sudo apt-get -qq install help2man libncurses5-dev libtool libtool-bin - sudo apt-get -qq install python3-dev texinfo unzip - - - name: Install erlang/OTP - uses: erlef/setup-beam@v1 - with: - otp-version: ${{ env.OTP_VSN }} - elixir-version: ${{ env.ELIXIR_VSN }} - version-type: strict - - - name: Remove Elixir Matchers - run: | - echo "::remove-matcher owner=elixir-mixCompileWarning::" - echo "::remove-matcher owner=elixir-credoOutputDefault::" - echo "::remove-matcher owner=elixir-mixCompileError::" - echo "::remove-matcher owner=elixir-mixTestFailure::" - echo "::remove-matcher owner=elixir-dialyzerOutputDefault::" - - - name: Build musl-libc based binary archives - run: | - sed -i "s|targets='.*'|targets='x86_64-linux-musl aarch64-linux-musl'|" tools/make-binaries - mv .github/container/ejabberdctl.template . - CHECK_DEPS=false tools/make-binaries - - - name: Collect packages - run: | - mkdir tarballs - mv ejabberd-*.tar.gz tarballs - - name: Checkout ejabberd-contrib uses: actions/checkout@v4 with: @@ -111,7 +63,6 @@ jobs: uses: docker/build-push-action@v6 with: build-args: | - METHOD=package VERSION=${{ steps.gitdescribe.outputs.ver }} cache-from: type=gha cache-to: type=gha,mode=max From 74d6d53ac64e0802fa95f55e8601456fb26016e3 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 10 Jan 2025 21:05:42 +0100 Subject: [PATCH 107/170] Container: Add ERL_FLAGS to compile elixir on qemu cross-platform Without this, compiling Elixir on arm64 using QEMU fails with: <<"could not call Module.put_attribute/3 because the module ExUnit.DocTest is already compiled">> Solution found in: https://elixirforum.com/t/elixir-docker-image-wont-build-for-linux-arm64-v8-using-github-actions/56383/13 --- .github/container/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 7b502f2c49c..f5b5b6d12fb 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -42,6 +42,7 @@ RUN wget -O - https://github.com/elixir-lang/elixir/archive/v$ELIXIR_VSN.tar.gz | tar -xzf - WORKDIR elixir-$ELIXIR_VSN +ENV ERL_FLAGS="+JPperf true" RUN make install clean RUN mix local.hex --force \ From fa4a93c4651eae48e2644b737039c9cb9f2c302b Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 16 Jan 2025 11:44:37 +0100 Subject: [PATCH 108/170] Container: Place sockets/ outside database/ The socket file is useless outside the container, and also database/ may get mounted as volume, and can't handle socket file --- .github/container/Dockerfile | 2 +- .github/container/ejabberd.yml.example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index f5b5b6d12fb..2a47766aac9 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -102,7 +102,7 @@ RUN export PEM=$HOME/conf/server.pem \ -days 3650 \ -subj "/CN=localhost" -RUN sed -i 's|^#CTL_OVER_HTTP=|CTL_OVER_HTTP=|' "$HOME/conf/ejabberdctl.cfg" +RUN sed -i 's|^#CTL_OVER_HTTP=|CTL_OVER_HTTP=../|' "$HOME/conf/ejabberdctl.cfg" RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \ && setcap 'cap_net_bind_service=+ep' $(find $home_root_dir -name beam.smp) \ diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example index b8a84fc926f..62dff50c991 100644 --- a/.github/container/ejabberd.yml.example +++ b/.github/container/ejabberd.yml.example @@ -90,7 +90,7 @@ listen: request_handlers: /: ejabberd_web_admin - - port: "unix:sockets/ctl_over_http.sock" + port: "unix:../sockets/ctl_over_http.sock" module: ejabberd_http unix_socket: mode: '0600' From 3b01e4e4e0f9c509c01a4530fe4422949cd33d71 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Jan 2025 11:27:44 +0100 Subject: [PATCH 109/170] Container: Fix warning about relative workdir --- .github/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 2a47766aac9..ae2cc731195 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -41,7 +41,7 @@ ARG ELIXIR_VSN RUN wget -O - https://github.com/elixir-lang/elixir/archive/v$ELIXIR_VSN.tar.gz \ | tar -xzf - -WORKDIR elixir-$ELIXIR_VSN +WORKDIR /elixir-$ELIXIR_VSN ENV ERL_FLAGS="+JPperf true" RUN make install clean From cfa6575b4fd0d216c34e66daab45710bf3a59a5e Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 30 Dec 2024 13:11:28 +0100 Subject: [PATCH 110/170] CONTAINER.md: Update with all the recent improvements --- CONTAINER.md | 60 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/CONTAINER.md b/CONTAINER.md index 95115a6c248..1f2588cb496 100644 --- a/CONTAINER.md +++ b/CONTAINER.md @@ -96,20 +96,30 @@ Next steps ### Register the administrator account -The default ejabberd configuration does not grant admin privileges -to any account, -you may want to register a new account in ejabberd -and grant it admin rights. +If you set the `REGISTER_ADMIN_PASSWORD` environment variable, +an account is registered with that password, +and admin privileges are granted to it. +The account created may be: -Register an account using the `ejabberdctl` script: +- `EJABBERD_MACRO_ADMIN=juliet@example.org` --> `juliet@example.org` +- `EJABBERD_MACRO_HOST=example.org` --> `admin@example.org` +- None of those variables are set --> `admin@localhost` + +The account registration is shown in the container log: + +``` +:> ejabberdctl register admin example.org somePassw0rd +User admin@example.org successfully registered +``` + +Alternatively, you can register the account manually yourself +and edit conf/ejabberd.yml and add the ACL as explained in +[ejabberd Docs: Administration Account](https://docs.ejabberd.im/admin/install/next-steps/#administration-account): ```bash docker exec -it ejabberd ejabberdctl register admin localhost passw0rd ``` -Then edit conf/ejabberd.yml and add the ACL as explained in -[ejabberd Docs: Administration Account](https://docs.ejabberd.im/admin/install/next-steps/#administration-account) - ### Check ejabberd log files @@ -185,7 +195,8 @@ This container image exposes the ports: - `5222`: The default port for XMPP clients. - `5269`: For XMPP federation. Only needed if you want to communicate with users on other servers. -- `5280`: For admin interface. +- `5280`: For admin interface (URL is `admin/`). +- `1880`: For admin interface (URL is `/`, useful for podman-desktop and docker-desktop) - `5443`: With encryption, used for admin interface, API, CAPTCHA, OAuth, Websockets and XMPP BOSH. - `1883`: Used for MQTT - `4369-4399`: EPMD and Erlang connectivity, used for `ejabberdctl` and clustering @@ -299,8 +310,8 @@ Example using environment variables (see full example [docker-compose.yml](https ``` -Build a Container Image ------------------------ +Build `ejabberd` Container Image +-------------------------------- This container image includes ejabberd as a standalone OTP release built using Elixir. That OTP release is configured with: @@ -370,6 +381,33 @@ docker buildx build \ . ``` +Build `ecs` Container Image +--------------------------- + +### Configuration + +Image is built by embedding an ejabberd Erlang/OTP standalone release in the image. + +The configuration of ejabberd Erlang/OTP release is customized with: + +- `rel/config.exs`: Customize ejabberd release +- `rel/dev.exs`: ejabberd environment configuration for development release +- `rel/prod.exs`: ejabberd environment configuration for production release +- `vars.config`: ejabberd compilation configuration options +- `conf/ejabberd.yml`: ejabberd default config file + +Build ejabberd Community Server base image from ejabberd master on Github: + +```bash +docker build -t docker.io/ejabberd/ecs . +``` + +Build ejabberd Community Server base image for a given ejabberd version: + +```bash +./build.sh 18.03 +``` + Composer Examples ----------------- From 60324d4b7ad3d860bf3ea2c76bdec8a106e2a4d6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 3 Jan 2025 12:28:20 +0100 Subject: [PATCH 111/170] CONTAINER.md: Include documentation for ecs container image --- CONTAINER.md | 568 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 364 insertions(+), 204 deletions(-) diff --git a/CONTAINER.md b/CONTAINER.md index 1f2588cb496..b8a483e07f6 100644 --- a/CONTAINER.md +++ b/CONTAINER.md @@ -1,10 +1,10 @@ [![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/processone/ejabberd?sort=semver&logo=embarcadero&label=&color=49c0c4)](https://github.com/processone/ejabberd/tags) -[![ejabberd Container on GitHub](https://img.shields.io/github/v/tag/processone/ejabberd?label=ejabberd&sort=semver&logo=docker)](https://github.com/processone/ejabberd/pkgs/container/ejabberd) +[![ejabberd Container on GitHub](https://img.shields.io/github/v/tag/processone/ejabberd?label=ejabberd&sort=semver&logo=opencontainersinitiative&logoColor=2094f3)](https://github.com/processone/ejabberd/pkgs/container/ejabberd) [![ecs Container on Docker](https://img.shields.io/docker/v/ejabberd/ecs?label=ecs&sort=semver&logo=docker)](https://hub.docker.com/r/ejabberd/ecs/) -`ejabberd` Container Image -========================== +ejabberd Container Images +========================= [ejabberd][home] is an open-source, robust, scalable and extensible realtime platform built using [Erlang/OTP][erlang], @@ -16,26 +16,29 @@ that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service. [mqtt]: https://mqtt.org/ [sip]: https://en.wikipedia.org/wiki/Session_Initiation_Protocol -This document explains how to use the `ejabberd` container image available in -[ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd), -built using the files in `.github/container/`. -This image is based in Alpine 3.19, includes Erlang/OTP 27.2 and Elixir 1.18.1. +This page documents those container images ([images comparison](#images-comparison)): -Alternatively, there is also the `ecs` container image available in -[docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/), -built using the -[docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs) -repository. -Check the [differences between `ejabberd` and `ecs` images](https://github.com/processone/docker-ejabberd/blob/master/ecs/HUB-README.md#alternative-image-in-github). +- [![ejabberd Container](https://img.shields.io/badge/ejabberd-grey?logo=opencontainersinitiative&logoColor=2094f3)](https://github.com/processone/ejabberd/pkgs/container/ejabberd) + published in [ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd), + built using [ejabberd](https://github.com/processone/ejabberd/tree/master/.github/container) repository, + both for stable ejabberd releases and the `master` branch, in x64 and arm64 architectures. -If you are using a Windows operating system, check the tutorials mentioned in -[ejabberd Docs > Docker Image](https://docs.ejabberd.im/admin/install/container/#ejabberd-container-image). +- [![ecs Container](https://img.shields.io/badge/ecs-grey?logo=docker&logoColor=2094f3)](https://hub.docker.com/r/ejabberd/ecs/) + published in [docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/), + built using [docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs) repository + for ejabberd stable releases in x64 architectures. + +For Microsoft Windows, see +[Docker Desktop for Windows 10](https://www.process-one.net/blog/install-ejabberd-on-windows-10-using-docker-desktop/), +and [Docker Toolbox for Windows 7](https://www.process-one.net/blog/install-ejabberd-on-windows-7-using-docker-toolbox/). + +For Kubernetes Helm, see [help-ejabberd](https://github.com/sando38/helm-ejabberd). Start ejabberd -------------- -### With default configuration +### daemon Start ejabberd in a new container: @@ -46,22 +49,28 @@ docker run --name ejabberd -d -p 5222:5222 ghcr.io/processone/ejabberd That runs the container as a daemon, using ejabberd default configuration file and XMPP domain `localhost`. +Restart the stopped ejabberd container: + +```bash +docker restart ejabberd +``` + Stop the running container: ```bash docker stop ejabberd ``` -Restart the stopped ejabberd container: +Remove the ejabberd container: ```bash -docker restart ejabberd +docker rm ejabberd ``` -### Start with Erlang console attached +### with Erlang console -Start ejabberd with an Erlang console attached using the `live` command: +Start ejabberd with an interactive Erlang console attached using the `live` command: ```bash docker run --name ejabberd -it -p 5222:5222 ghcr.io/processone/ejabberd live @@ -70,40 +79,42 @@ docker run --name ejabberd -it -p 5222:5222 ghcr.io/processone/ejabberd live That uses the default configuration file and XMPP domain `localhost`. -### Start with your configuration and database +### with your data Pass a configuration file as a volume and share the local directory to store database: ```bash -mkdir database -chown ejabberd database +mkdir conf && cp ejabberd.yml.example conf/ejabberd.yml -cp ejabberd.yml.example ejabberd.yml +mkdir database && chown ejabberd database docker run --name ejabberd -it \ - -v $(pwd)/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml \ + -v $(pwd)/conf/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml \ -v $(pwd)/database:/opt/ejabberd/database \ -p 5222:5222 ghcr.io/processone/ejabberd live ``` -Notice that ejabberd runs in the container with an account named `ejabberd`, +Notice that ejabberd runs in the container with an account named `ejabberd` +with UID 9000 and group `ejabberd` with GID 9000, and the volumes you mount must grant proper rights to that account. Next steps ---------- -### Register the administrator account +### Register admin account + +#### [![ejabberd Container](https://img.shields.io/badge/ejabberd-grey?logo=opencontainersinitiative&logoColor=2094f3)](https://github.com/processone/ejabberd/pkgs/container/ejabberd) [:orange_circle:](#images-comparison) If you set the `REGISTER_ADMIN_PASSWORD` environment variable, -an account is registered with that password, +an account is automatically registered with that password, and admin privileges are granted to it. -The account created may be: +The account created depends on what variables you have set: -- `EJABBERD_MACRO_ADMIN=juliet@example.org` --> `juliet@example.org` -- `EJABBERD_MACRO_HOST=example.org` --> `admin@example.org` -- None of those variables are set --> `admin@localhost` +- `EJABBERD_MACRO_ADMIN=juliet@example.org` -> `juliet@example.org` +- `EJABBERD_MACRO_HOST=example.org` -> `admin@example.org` +- None of those variables are set -> `admin@localhost` The account registration is shown in the container log: @@ -113,15 +124,22 @@ User admin@example.org successfully registered ``` Alternatively, you can register the account manually yourself -and edit conf/ejabberd.yml and add the ACL as explained in -[ejabberd Docs: Administration Account](https://docs.ejabberd.im/admin/install/next-steps/#administration-account): +and edit `conf/ejabberd.yml` and add the ACL as explained in +[ejabberd Docs: Administration Account](https://docs.ejabberd.im/admin/install/next-steps/#administration-account). + +--- + +#### [![ecs Container](https://img.shields.io/badge/ecs-grey?logo=docker&logoColor=2094f3)](https://hub.docker.com/r/ejabberd/ecs/) + +The default ejabberd configuration has already granted admin privilege +to an account that would be called `admin@localhost`, +so you just need to register it, for example: ```bash docker exec -it ejabberd ejabberdctl register admin localhost passw0rd ``` - -### Check ejabberd log files +### Check ejabberd log Check the content of the log files inside the container, even if you do not put it on a shared persistent drive: @@ -131,7 +149,7 @@ docker exec -it ejabberd tail -f logs/ejabberd.log ``` -### Inspect the container files +### Inspect container files The container uses Alpine Linux. Start a shell inside the container: @@ -140,7 +158,7 @@ docker exec -it ejabberd sh ``` -### Open ejabberd debug console +### Open debug console Open an interactive debug Erlang console attached to a running ejabberd in a running container: @@ -165,7 +183,7 @@ docker exec -it ejabberd vi conf/ejabberd.yml and add this option: ```yaml -captcha_cmd: /opt/ejabberd-22.04/lib/captcha.sh +captcha_cmd: "$HOME/bin/captcha.sh" ``` Finally, reload the configuration file or restart the container: @@ -186,21 +204,22 @@ For more details about CAPTCHA options, please check the documentation section. -Advanced Container Configuration --------------------------------- +Advanced +-------- ### Ports -This container image exposes the ports: +The container image exposes several ports +(check also [Docs: Firewall Settings](https://docs.ejabberd.im/admin/guide/security/#firewall-settings)): - `5222`: The default port for XMPP clients. - `5269`: For XMPP federation. Only needed if you want to communicate with users on other servers. - `5280`: For admin interface (URL is `admin/`). -- `1880`: For admin interface (URL is `/`, useful for podman-desktop and docker-desktop) +- `1880`: For admin interface (URL is `/`, useful for [podman-desktop](https://podman-desktop.io/) and [docker-desktop](https://www.docker.com/products/docker-desktop/)) [:orange_circle:](#images-comparison) - `5443`: With encryption, used for admin interface, API, CAPTCHA, OAuth, Websockets and XMPP BOSH. - `1883`: Used for MQTT - `4369-4399`: EPMD and Erlang connectivity, used for `ejabberdctl` and clustering -- `5210`: Erlang connectivity when `ERL_DIST_PORT` is set, alternative to EPMD +- `5210`: Erlang connectivity when `ERL_DIST_PORT` is set, alternative to EPMD [:orange_circle:](#images-comparison) ### Volumes @@ -217,11 +236,26 @@ You should back up or export the content of the directory to persistent storage - `/opt/ejabberd/logs/`: Directory containing log files - `/opt/ejabberd/upload/`: Directory containing uploaded files. This should also be backed up. -All these files are owned by `ejabberd` user inside the container. +All these files are owned by an account named `ejabberd` with group `ejabberd` in the container. +Its corresponding `UID:GID` is `9000:9000`. +If you prefer bind mounts instead of volumes, then +you need to map this to valid `UID:GID` on your host to get read/write access on +mounted directories. -It's possible to install additional ejabberd modules using volumes, -[this comment](https://github.com/processone/docker-ejabberd/issues/81#issuecomment-1036115146) -explains how to install an additional module using docker-compose. +If using Docker, try: +```bash +mkdir database +sudo chown 9000:9000 database +``` + +If using Podman, try: +```bash +mkdir database +podman unshare chown 9000:9000 database +``` + +It's possible to install additional ejabberd modules using volumes, check +[this Docs tutorial](http://docs.ejabberd.im/developer/extending-ejabberd/modules/#your-module-in-ejabberd-modules-with-ejabberd-container). ### Commands on start @@ -245,10 +279,10 @@ Example usage (or check the [full example](#customized-example)): ``` -### Macros in environment +### Macros in environment [:high_brightness:](#images-comparison) ejabberd reads `EJABBERD_MACRO_*` environment variables -and uses them to define the `*` +and uses them to define the corresponding [macros](https://docs.ejabberd.im/admin/configuration/file-format/#macros-in-configuration-file), overwriting the corresponding macro definition if it was set in the configuration file. This is supported since ejabberd 24.12. @@ -258,18 +292,61 @@ For example, if you configure this in `ejabberd.yml`: ```yaml acl: admin: - user: ADMINJID + user: ADMIN ``` now you can define the admin account JID using an environment variable: ```yaml environment: - - EJABBERD_MACRO_ADMINJID=admin@localhost + - EJABBERD_MACRO_ADMIN=admin@localhost ``` Check the [full example](#customized-example) for other example. +### ejabberdapi + +When the container is running (and thus ejabberd), you can exec commands inside the container +using `ejabberdctl` or any other of the available interfaces, see +[Understanding ejabberd "commands"](https://docs.ejabberd.im/developer/ejabberd-api/#understanding-ejabberd-commands) + +Additionally, the container image includes the `ejabberdapi` executable. +Please check the [ejabberd-api homepage](https://github.com/processone/ejabberd-api) +for configuration and usage details. + +For example, if you configure ejabberd like this: +```yaml +listen: + - + port: 5282 + module: ejabberd_http + request_handlers: + "/api": mod_http_api + +acl: + loopback: + ip: + - 127.0.0.0/8 + - ::1/128 + - ::FFFF:127.0.0.1/128 + +api_permissions: + "admin access": + who: + access: + allow: + acl: loopback + what: + - "register" +``` + +Then you could register new accounts with this query: + +```bash +docker exec -it ejabberd ejabberdapi register --endpoint=http://127.0.0.1:5282/ --jid=admin@localhost --password=passw0rd +``` + + ### Clustering When setting several containers to form a @@ -284,6 +361,8 @@ For this you can either: - edit `conf/ejabberdctl.cfg` and set variables `ERLANG_NODE` and `ERLANG_COOKIE` - set the environment variables `ERLANG_NODE_ARG` and `ERLANG_COOKIE` +--- + Example to connect a local `ejabberdctl` to a containerized ejabberd: 1. When creating the container, export port 5210, and set `ERLANG_COOKIE`: @@ -293,7 +372,7 @@ Example to connect a local `ejabberdctl` to a containerized ejabberd: -p 5210:5210 -p 5222:5222 \ ghcr.io/processone/ejabberd ``` -2. Set `ERL_DIST_PORT=5210` in ejabberdctl.cfg of container and local ejabberd +2. Set `ERL_DIST_PORT=5210` in `ejabberdctl.cfg` of container and local ejabberd 3. Restart the container 4. Now use `ejabberdctl` in your local ejabberd deployment @@ -309,19 +388,175 @@ Example using environment variables (see full example [docker-compose.yml](https - ERLANG_COOKIE=dummycookie123 ``` +--- + +Once you have the ejabberd nodes properly set and running, +you can tell the secondary nodes to join the master node using the +[`join_cluster`](https://docs.ejabberd.im/developer/ejabberd-api/admin-api/#join-cluster) +API call. + +Example using environment variables (see the full +[`docker-compose.yml` clustering example](#clustering-example)): +```yaml +environment: + - ERLANG_NODE_ARG=ejabberd@replica + - ERLANG_COOKIE=dummycookie123 + - CTL_ON_CREATE=join_cluster ejabberd@main +``` + +### Change Mnesia Node Name + +To use the same Mnesia database in a container with a different hostname, +it is necessary to change the old hostname stored in Mnesia. + +This section is equivalent to the ejabberd Documentation +[Change Computer Hostname](https://docs.ejabberd.im/admin/guide/managing/#change-computer-hostname), +but particularized to containers that use this +ecs container image from ejabberd 23.01 or older. + +#### Setup Old Container + +Let's assume a container running ejabberd 23.01 (or older) from +this ecs container image, with the database directory binded +and one registered account. +This can be produced with: +```bash +OLDCONTAINER=ejaold +NEWCONTAINER=ejanew + +mkdir database +sudo chown 9000:9000 database +docker run -d --name $OLDCONTAINER -p 5222:5222 \ + -v $(pwd)/database:/opt/ejabberd/database \ + ghcr.io/processone/ejabberd:23.01 +docker exec -it $OLDCONTAINER ejabberdctl started +docker exec -it $OLDCONTAINER ejabberdctl register user1 localhost somepass +docker exec -it $OLDCONTAINER ejabberdctl registered_users localhost +``` + +Methods to know the Erlang node name: +```bash +ls database/ | grep ejabberd@ +docker exec -it $OLDCONTAINER ejabberdctl status +docker exec -it $OLDCONTAINER grep "started in the node" logs/ejabberd.log +``` + +#### Change Mnesia Node + +First of all let's store the Erlang node names and paths in variables. +In this example they would be: +```bash +OLDCONTAINER=ejaold +NEWCONTAINER=ejanew +OLDNODE=ejabberd@95145ddee27c +NEWNODE=ejabberd@localhost +OLDFILE=/opt/ejabberd/database/old.backup +NEWFILE=/opt/ejabberd/database/new.backup +``` + +1. Start your old container that can still read the Mnesia database correctly. +If you have the Mnesia spool files, +but don't have access to the old container anymore, go to +[Create Temporary Container](#create-temporary-container) +and later come back here. + +2. Generate a backup file and check it was created: +```bash +docker exec -it $OLDCONTAINER ejabberdctl backup $OLDFILE +ls -l database/*.backup +``` + +3. Stop ejabberd: +```bash +docker stop $OLDCONTAINER +``` + +4. Create the new container. For example: +```bash +docker run \ + --name $NEWCONTAINER \ + -d \ + -p 5222:5222 \ + -v $(pwd)/database:/opt/ejabberd/database \ + ghcr.io/processone/ejabberd:latest +``` + +5. Convert the backup file to new node name: +```bash +docker exec -it $NEWCONTAINER ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE +``` + +6. Install the backup file as a fallback: +```bash +docker exec -it $NEWCONTAINER ejabberdctl install_fallback $NEWFILE +``` + +7. Restart the container: +```bash +docker restart $NEWCONTAINER +``` + +8. Check that the information of the old database is available. +In this example, it should show that the account `user1` is registered: +```bash +docker exec -it $NEWCONTAINER ejabberdctl registered_users localhost +``` + +9. When the new container is working perfectly with the converted Mnesia database, +you may want to remove the unneeded files: +the old container, the old Mnesia spool files, and the backup files. + +#### Create Temporary Container + +In case the old container that used the Mnesia database is not available anymore, +a temporary container can be created just to read the Mnesia database +and make a backup of it, as explained in the previous section. + +This method uses `--hostname` command line argument for docker, +and `ERLANG_NODE_ARG` environment variable for ejabberd. +Their values must be the hostname of your old container +and the Erlang node name of your old ejabberd node. +To know the Erlang node name please check +[Setup Old Container](#setup-old-container). + +Command line example: +```bash +OLDHOST=${OLDNODE#*@} +docker run \ + -d \ + --name $OLDCONTAINER \ + --hostname $OLDHOST \ + -p 5222:5222 \ + -v $(pwd)/database:/opt/ejabberd/database \ + -e ERLANG_NODE_ARG=$OLDNODE \ + ghcr.io/processone/ejabberd:latest +``` + +Check the old database content is available: +```bash +docker exec -it $OLDCONTAINER ejabberdctl registered_users localhost +``` + +Now that you have ejabberd running with access to the Mnesia database, +you can continue with step 2 of previous section +[Change Mnesia Node](#change-mnesia-node). + + +Build Container Image +---------------- + +The container image includes ejabberd as a standalone OTP release built using Elixir. -Build `ejabberd` Container Image --------------------------------- +### Build `ejabberd` [![ejabberd Container](https://img.shields.io/badge/ejabberd-grey?logo=opencontainersinitiative&logoColor=2094f3)](https://github.com/processone/ejabberd/pkgs/container/ejabberd) -This container image includes ejabberd as a standalone OTP release built using Elixir. -That OTP release is configured with: +The ejabberd Erlang/OTP release is configured with: - `mix.exs`: Customize ejabberd release - `vars.config`: ejabberd compilation configuration options - `config/runtime.exs`: Customize ejabberd paths - `ejabberd.yml.template`: ejabberd default config file -### Direct build +#### Direct build Build ejabberd Community Server container image from ejabberd master git repository: @@ -332,7 +567,7 @@ docker buildx build \ . ``` -### Podman build +#### Podman build To build the image using Podman, please notice: @@ -357,38 +592,9 @@ podman stop eja1 podman run --name eja1 -it -e EJABBERD_BYPASS_WARNINGS=true -p 5222:5222 localhost/ejabberd live ``` -### Package build for `arm64` +### Build `ecs` [![ecs Container](https://img.shields.io/badge/ecs-grey?logo=docker&logoColor=2094f3)](https://hub.docker.com/r/ejabberd/ecs/) -By default, `.github/container/Dockerfile` builds this container by directly compiling ejabberd, -it is a fast and direct method. -However, a problem with QEMU prevents building the container in QEMU using Erlang/OTP 25 -for the `arm64` architecture. - -Providing `--build-arg METHOD=package` is an alternate method to build the container -used by the Github Actions workflow that provides `amd64` and `arm64` container images. -It first builds an ejabberd binary package, and later installs it in the image. -That method avoids using QEMU, so it can build `arm64` container images, but is extremely -slow the first time it's used, and consequently not recommended for general use. - -In this case, to build the ejabberd container image for arm64 architecture: - -```bash -docker buildx build \ - --build-arg METHOD=package \ - --platform linux/arm64 \ - -t personal/ejabberd:$VERSION \ - -f .github/container/Dockerfile \ - . -``` - -Build `ecs` Container Image ---------------------------- - -### Configuration - -Image is built by embedding an ejabberd Erlang/OTP standalone release in the image. - -The configuration of ejabberd Erlang/OTP release is customized with: +The ejabberd Erlang/OTP release is configured with: - `rel/config.exs`: Customize ejabberd release - `rel/dev.exs`: ejabberd environment configuration for development release @@ -399,7 +605,7 @@ The configuration of ejabberd Erlang/OTP release is customized with: Build ejabberd Community Server base image from ejabberd master on Github: ```bash -docker build -t docker.io/ejabberd/ecs . +docker build -t personal/ejabberd . ``` Build ejabberd Community Server base image for a given ejabberd version: @@ -408,7 +614,6 @@ Build ejabberd Community Server base image for a given ejabberd version: ./build.sh 18.03 ``` - Composer Examples ----------------- @@ -468,26 +673,21 @@ stores the mnesia database in a local path, registers an account when it's created, and checks the number of registered accounts every time it's started. -Download or copy the ejabberd configuration file: +Prepare an ejabberd configuration file: ```bash -wget https://raw.githubusercontent.com/processone/ejabberd/master/ejabberd.yml.example -mv ejabberd.yml.example ejabberd.yml -``` - -Use a macro in `ejabberd.yml` to set the served vhost, with `localhost` as default value: -```yaml -define_macro: - XMPPHOST: localhost - -hosts: - - XMPPHOST +mkdir conf && cp ejabberd.yml.example conf/ejabberd.yml ``` Create the database directory and allow the container access to it: -```bash -mkdir database -sudo chown 9000:9000 database -``` + +- Docker: + ```bash + mkdir database && sudo chown 9000:9000 database + ``` +- Podman: + ```bash + mkdir database && podman unshare chown 9000:9000 database + ``` If using Docker, write this `docker-compose.yml` file and start it with `docker-compose up`: @@ -501,8 +701,9 @@ services: image: ghcr.io/processone/ejabberd container_name: ejabberd environment: - - EJABBERD_MACRO_XMPPHOST=example.com - - CTL_ON_CREATE=register admin example.com asd + - EJABBERD_MACRO_HOST=example.com + - EJABBERD_MACRO_ADMIN=admin@example.com + - REGISTER_ADMIN_PASSWORD=somePassw0rd - CTL_ON_START=registered_users example.com ; status ports: @@ -511,7 +712,7 @@ services: - "5280:5280" - "5443:5443" volumes: - - ./ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml:ro + - ./conf/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml:ro - ./database:/opt/ejabberd/database ``` @@ -532,8 +733,12 @@ spec: - name: ejabberd image: ghcr.io/processone/ejabberd env: - - name: CTL_ON_CREATE - value: register admin example.com asd + - name: EJABBERD_MACRO_HOST + value: example.com + - name: EJABBERD_MACRO_ADMIN + value: admin@example.com + - name: REGISTER_ADMIN_PASSWORD + value: somePassw0rd - name: CTL_ON_START value: registered_users example.com ; status @@ -556,7 +761,7 @@ spec: volumes: - name: config hostPath: - path: ./ejabberd.yml + path: ./conf/ejabberd.yml type: File - name: db hostPath: @@ -589,11 +794,17 @@ services: main: image: ghcr.io/processone/ejabberd - container_name: ejabberd + container_name: main environment: - ERLANG_NODE_ARG=ejabberd@main - ERLANG_COOKIE=dummycookie123 - CTL_ON_CREATE=! register admin localhost asd + healthcheck: + test: netstat -nl | grep -q 5222 + start_period: 5s + interval: 5s + timeout: 5s + retries: 120 replica: image: ghcr.io/processone/ejabberd @@ -692,92 +903,41 @@ spec: ``` -Your configuration file should use those macros to allow each ejabberd node -use different listening port numbers: - -```diff -diff --git a/ejabberd.yml.example b/ejabberd.yml.example -index 39e423a64..6e875b48f 100644 ---- a/ejabberd.yml.example -+++ b/ejabberd.yml.example -@@ -24,9 +24,19 @@ loglevel: info - # - /etc/letsencrypt/live/domain.tld/fullchain.pem - # - /etc/letsencrypt/live/domain.tld/privkey.pem - -+define_macro: -+ PORT_C2S: 5222 -+ PORT_C2S_TLS: 5223 -+ PORT_S2S: 5269 -+ PORT_HTTP_TLS: 5443 -+ PORT_HTTP: 5280 -+ PORT_STUN: 5478 -+ PORT_MQTT: 1883 -+ PORT_PROXY65: 7777 -+ - listen: - - -- port: 5222 -+ port: PORT_C2S - ip: "::" - module: ejabberd_c2s - max_stanza_size: 262144 -@@ -34,7 +44,7 @@ listen: - access: c2s - starttls_required: true - - -- port: 5223 -+ port: PORT_C2S_TLS - ip: "::" - module: ejabberd_c2s - max_stanza_size: 262144 -@@ -42,13 +52,13 @@ listen: - access: c2s - tls: true - - -- port: 5269 -+ port: PORT_S2S - ip: "::" - module: ejabberd_s2s_in - max_stanza_size: 524288 - shaper: s2s_shaper - - -- port: 5443 -+ port: PORT_HTTP_TLS - ip: "::" - module: ejabberd_http - tls: true -@@ -60,14 +70,14 @@ listen: - /upload: mod_http_upload - /ws: ejabberd_http_ws - - -- port: 5280 -+ port: PORT_HTTP - ip: "::" - module: ejabberd_http - request_handlers: - /admin: ejabberd_web_admin - /.well-known/acme-challenge: ejabberd_acme - - -- port: 5478 -+ port: PORT_STUN - ip: "::" - transport: udp - module: ejabberd_stun -@@ -77,7 +87,7 @@ listen: - ## The server's public IPv6 address: - # turn_ipv6_address: "2001:db8::3" - - -- port: 1883 -+ port: PORT_MQTT - ip: "::" - module: mod_mqtt - backlog: 1000 -@@ -207,6 +217,7 @@ modules: - mod_proxy65: - access: local - max_connections: 5 -+ port: PORT_PROXY65 - mod_pubsub: - access_createnode: pubsub_createnode - plugins: -``` + +Images Comparison +----------------- + +Let's summarize the differences between both container images. Legend: + +- :sparkle: is the recommended alternative +- :orange_circle: added in the latest release (ejabberd 25.xx) +- :high_brightness: added in the previous release (ejabberd 24.12) +- :low_brightness: added in the pre-previous release (ejabberd 24.10) + +| | [![ejabberd Container](https://img.shields.io/badge/ejabberd-grey?logo=opencontainersinitiative&logoColor=2094f3)](https://github.com/processone/ejabberd/pkgs/container/ejabberd) | [![ecs Container](https://img.shields.io/badge/ecs-grey?logo=docker&logoColor=2094f3)](https://hub.docker.com/r/ejabberd/ecs/) | +|:----------------------|:------------------|:-----------------------| +| Source code | [ejabberd/.github/container](https://github.com/processone/ejabberd/tree/master/.github/container) | [docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs) | +| Generated by | [container.yml](https://github.com/processone/ejabberd/blob/master/.github/workflows/container.yml) | [tests.yml](https://github.com/processone/docker-ejabberd/blob/master/.github/workflows/tests.yml) | +| Built for | stable releases
`master` branch | stable releases
[`master` branch zip](https://github.com/processone/docker-ejabberd/actions/workflows/tests.yml) | +| Architectures | `linux/amd64`
`linux/arm64` | `linux/amd64` | +| Software | Erlang/OTP 27.2-alpine
Elixir 1.18.1 | Alpine 3.19
Erlang/OTP 26.2
Elixir 1.15.7 | +| Published in | [ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd) | [docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/)
[ghcr.io/processone/ecs](https://github.com/processone/docker-ejabberd/pkgs/container/ecs) | +| :black_square_button: **Additional content** | +| [ejabberd-contrib](https://docs.ejabberd.im/admin/guide/modules/#ejabberd-contrib) | included | not included | +| [ejabberdapi](#ejabberdapi) | included :orange_circle: | included | +| :black_square_button: **Ports** | +| [1880](#ports) for WebAdmin | yes :orange_circle: | yes :orange_circle: | +| [5210](#ports) for `ERL_DIST_PORT` | supported | supported :orange_circle: | +| :black_square_button: **Paths** | +| `$HOME` | `/opt/ejabberd/` | `/home/ejabberd/` | +| User data | `$HOME` :sparkle:
`/home/ejabberd/` :orange_circle: | `$HOME`
`/opt/ejabberd/` :sparkle: :low_brightness: | +| `ejabberdctl` | `ejabberdctl` :sparkle:
`bin/ejabberdctl` :orange_circle: | `bin/ejabberdctl`
`ejabberdctl` :sparkle: :low_brightness: | +| [`captcha.sh`](#captcha) | `$HOME/bin/captcha.sh` :orange_circle: | `$HOME/bin/captcha.sh` :orange_circle: | +| `*.sql` files | `$HOME/sql/*.sql` :sparkle: :orange_circle:
`$HOME/database/*.sql` :orange_circle: | `$HOME/database/*.sql`
`$HOME/sql/*.sql` :sparkle: :orange_circle: | +| Mnesia spool files | `$HOME/database/` :sparkle:
`$HOME/database/NODENAME/` :orange_circle: | `$HOME/database/NODENAME/`
`$HOME/database/` :sparkle: :orange_circle: | +| :black_square_button: **Variables** | +| [`EJABBERD_MACRO_*`](#macros-in-environment) | supported :high_brightness: | supported :high_brightness: | +| Macros used in `ejabberd.yml` | yes :orange_circle: | yes :orange_circle: | +| [`EJABBERD_MACRO_ADMIN`](#register-admin-account) | Grant admin rights :orange_circle:
(default `admin@localhost`)
| Hardcoded `admin@localhost` | +| [`REGISTER_ADMIN_PASSWORD`](#register-admin-account) | Register admin account :orange_circle: | unsupported | +| `CTL_OVER_HTTP` | enabled :orange_circle: | unsupported | From 62a165e4cf599c031794d91fe99d499df0348611 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 13 Mar 2025 16:30:47 +0100 Subject: [PATCH 112/170] ejabberd_web_admin: Support commands with tuple arguments; fix list indent --- src/ejabberd_web_admin.erl | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl index 02cd3c13d9a..96b2321845c 100644 --- a/src/ejabberd_web_admin.erl +++ b/src/ejabberd_web_admin.erl @@ -2359,11 +2359,21 @@ format_result([], {_Name, {list, _ElementsDef}}) -> ""; format_result([FirstElement | Elements], {_Name, {list, ElementsDef}}) -> Separator = ",", - [format_result(FirstElement, ElementsDef) | lists:map(fun(Element) -> - [Separator | format_result(Element, - ElementsDef)] - end, - Elements)]; + Head = format_result(FirstElement, ElementsDef), + Tail = + lists:map(fun(Element) -> [Separator | format_result(Element, ElementsDef)] end, + Elements), + [Head | Tail]; +format_result([], {_Name, {tuple, _ElementsDef}}) -> + ""; +format_result(Value, {_Name, {tuple, [FirstDef | ElementsDef]}}) -> + [FirstElement | Elements] = tuple_to_list(Value), + Separator = ":", + Head = format_result(FirstElement, FirstDef), + Tail = + lists:map(fun(Element) -> [Separator | format_result(Element, ElementsDef)] end, + Elements), + [Head | Tail]; format_result(Value, _ResultFormat) when is_atom(Value) -> misc:atom_to_binary(Value); format_result(Value, _ResultFormat) when is_list(Value) -> From b901a69f5c56e6ce33654934ff6ffb2317eecef1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 17 Mar 2025 12:30:19 +0100 Subject: [PATCH 113/170] mix.exs: Keep debug info when building dev release (thanks to Stefan Strigler) --- mix.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/mix.exs b/mix.exs index feb1666c26a..3f63e90f896 100644 --- a/mix.exs +++ b/mix.exs @@ -267,6 +267,7 @@ defmodule Ejabberd.MixProject do ejabberd: [ include_executables_for: [:unix], # applications: [runtime_tools: :permanent] + strip_beams: Mix.env() != :dev, steps: [©_extra_files/1, :assemble | maybe_tar] ] ] From ad8e32513918700643f143ec0b706ba5c228ece3 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 18 Mar 2025 12:02:17 +0100 Subject: [PATCH 114/170] Disable commands tests for old Erlang/OTP versions Since recently, this test fails with Erlang/OTP 22 and lower: =result failed: {test_case_failed, "Received input: [{error,{compilation_failed, \"/home/runner/.ejabberd-modules/sources/ejabberd-contrib/mod_example/src/mod_example.erl\"}}] don't match expected patterns:ok"}, --- test/commands_tests.erl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/commands_tests.erl b/test/commands_tests.erl index 166415e8927..52933e409e6 100644 --- a/test/commands_tests.erl +++ b/test/commands_tests.erl @@ -34,6 +34,13 @@ %%%================================== %%%% setup +-ifdef(OTP_BELOW_24). + +single_cases() -> + {commands_single, [sequence], []}. + +-else. + single_cases() -> {commands_single, [sequence], @@ -51,6 +58,8 @@ single_cases() -> single_test(http_list_tuple_map), single_test(clean)]}. +-endif. + setup(_Config) -> M = <<"mod_example">>, clean(_Config), From 19482529eea11a0fd240860e12d9641be681d7ca Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Jan 2025 13:06:39 +0100 Subject: [PATCH 115/170] Inform that define_macro cannot be used inside host_config --- src/ejabberd_config_transformer.erl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ejabberd_config_transformer.erl b/src/ejabberd_config_transformer.erl index 025db6dc362..362bbecea1c 100644 --- a/src/ejabberd_config_transformer.erl +++ b/src/ejabberd_config_transformer.erl @@ -128,6 +128,11 @@ transform(Host, s2s_use_starttls, required_trusted, Acc) -> Hosts = maps:get(remove_s2s_dialback, Acc, []), Acc1 = maps:put(remove_s2s_dialback, [Host|Hosts], Acc), {{true, {s2s_use_starttls, required}}, Acc1}; +transform(Host, define_macro, Macro, Acc) when is_binary(Host) -> + ?WARNING_MSG("The option 'define_macro' is not supported inside 'host_config'. " + "Consequently those macro definitions for host '~ts' are unused: ~ts", + [Host, io_lib:format("~p", [Macro])]), + {true, Acc}; transform(_Host, _Opt, _Val, Acc) -> {true, Acc}. From b769de0690b94011a8aed5222ac42fd3a13e6705 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Feb 2025 11:07:11 +0100 Subject: [PATCH 116/170] New option define_keyword --- src/ejabberd_option.erl | 8 ++++++++ src/ejabberd_options.erl | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/ejabberd_option.erl b/src/ejabberd_option.erl index 2677cf42ffb..cb3765b585a 100644 --- a/src/ejabberd_option.erl +++ b/src/ejabberd_option.erl @@ -38,6 +38,7 @@ -export([cluster_nodes/0]). -export([default_db/0, default_db/1]). -export([default_ram_db/0, default_ram_db/1]). +-export([define_keyword/0, define_keyword/1]). -export([define_macro/0]). -export([disable_sasl_mechanisms/0, disable_sasl_mechanisms/1]). -export([disable_sasl_scram_downgrade_protection/0, disable_sasl_scram_downgrade_protection/1]). @@ -372,6 +373,13 @@ default_ram_db() -> default_ram_db(Host) -> ejabberd_config:get_option({default_ram_db, Host}). +-spec define_keyword() -> any(). +define_keyword() -> + define_keyword(global). +-spec define_keyword(global | binary()) -> any(). +define_keyword(Host) -> + ejabberd_config:get_option({define_keyword, Host}). + -spec define_macro() -> any(). define_macro() -> ejabberd_config:get_option({define_macro, global}). diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index 6caee7624c7..bcd697733b6 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -138,6 +138,8 @@ opt_type(default_db) -> econf:enum([mnesia, sql]); opt_type(default_ram_db) -> econf:enum([mnesia, sql, redis]); +opt_type(define_keyword) -> + econf:map(econf:binary(), econf:any(), [unique]); opt_type(define_macro) -> econf:map(econf:binary(), econf:any(), [unique]); opt_type(disable_sasl_scram_downgrade_protection) -> @@ -510,6 +512,7 @@ opt_type(jwt_auth_only_rule) -> {jwt_key, jose_jwk:key() | undefined} | {append_host_config, [{binary(), any()}]} | {host_config, [{binary(), any()}]} | + {define_keyword, any()} | {define_macro, any()} | {include_config_file, any()} | {atom(), any()}]. @@ -567,6 +570,7 @@ options() -> {certfiles, undefined}, {cluster_backend, mnesia}, {cluster_nodes, []}, + {define_keyword, []}, {define_macro, []}, {disable_sasl_scram_downgrade_protection, false}, {disable_sasl_mechanisms, []}, From 69b190775c6baded248ea514c2529a166e7c2bfb Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 10 Feb 2025 16:35:41 +0100 Subject: [PATCH 117/170] Implement internal functions get_predefined and replace keywords --- src/ejabberd_config.erl | 88 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index c7849792bf7..f13235c5b88 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -38,6 +38,7 @@ -export([dump/0, dump/1, convert_to_yaml/1, convert_to_yaml/2]). -export([callback_modules/1]). -export([set_option/2]). +-export([get_defined_keywords/1, get_predefined_keywords/1, replace_keywords/2, replace_keywords/3]). %% Deprecated functions -export([get_option/2]). @@ -404,6 +405,93 @@ format_error({error, {exception, Class, Reason, St}}) -> "file attached and the following stacktrace included:~n** ~ts", [misc:format_exception(2, Class, Reason, St)])). +%% @format-begin + +replace_keywords(Host, Value) -> + Keywords = get_defined_keywords(Host) ++ get_predefined_keywords(Host), + replace_keywords(Host, Value, Keywords). + +replace_keywords(Host, List, Keywords) when is_list(List) -> + [replace_keywords(Host, Element, Keywords) || Element <- List]; +replace_keywords(_Host, Atom, Keywords) when is_atom(Atom) -> + Str = atom_to_list(Atom), + case Str == string:uppercase(Str) of + false -> + Atom; + true -> + MacroName = iolist_to_binary(Str), + case proplists:get_value(MacroName, Keywords) of + undefined -> + Atom; + Replacement -> + Replacement + end + end; +replace_keywords(_Host, Binary, Keywords) when is_binary(Binary) -> + lists:foldl(fun ({Key, Replacement}, V) when is_binary(Replacement) -> + misc:expand_keyword(<<"@", Key/binary, "@">>, V, Replacement); + ({_, _}, V) -> + V + end, + Binary, + Keywords); +replace_keywords(Host, {Element1, Element2}, Keywords) -> + {Element1, replace_keywords(Host, Element2, Keywords)}; +replace_keywords(_Host, Value, _DK) -> + Value. + +get_defined_keywords(Host) -> + Tab = case get_tmp_config() of + undefined -> + ejabberd_options; + T -> + T + end, + get_defined_keywords(Tab, Host). + +get_defined_keywords(Tab, Host) -> + KeysHost = + case ets:lookup(Tab, {define_keyword, Host}) of + [{_, List}] -> + List; + _ -> + [] + end, + KeysGlobal = + case Host /= global andalso ets:lookup(Tab, {define_keyword, global}) of + [{_, ListG}] -> + ListG; + _ -> + [] + end, + %% Trying to get defined keywords in host_config when starting ejabberd, + %% the options are not yet stored in ets + KeysTemp = case not is_atom(Tab) andalso KeysHost == [] andalso KeysGlobal == [] of + true -> + get_defined_keywords_yaml_config(ets:lookup_element(Tab, {yaml_config, global}, 2)); + false -> + [] + end, + lists:reverse(KeysTemp ++ KeysGlobal ++ KeysHost). + +get_defined_keywords_yaml_config(Y) -> + [{erlang:atom_to_binary(KwAtom, latin1), KwValue} + || {KwAtom, KwValue} <- proplists:get_value(define_keyword, Y, [])]. + +get_predefined_keywords(Host) -> + HostList = case Host of + global -> []; + _ -> [{<<"HOST">>, Host}] + end, + {ok, [[Home]]} = init:get_argument(home), + HostList ++ + [{<<"HOME">>, list_to_binary(Home)}, + {<<"SEMVER">>, ejabberd_option:version()}, + {<<"VERSION">>, + misc:semver_to_xxyy( + ejabberd_option:version())}]. +%% @format-end + %%%=================================================================== %%% Internal functions %%%=================================================================== From 896b7c75590835cc49b6d2413b6b2bd0c09dfc8b Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 10 Feb 2025 16:34:04 +0100 Subject: [PATCH 118/170] Add support to replace keywords in toplevel options --- src/ejabberd_config.erl | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index f13235c5b88..e48006afb51 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -343,12 +343,20 @@ env_binary_to_list(Application, Parameter) -> Other end. +%% ejabberd_options calls this function when parsing options inside host_config -spec validators([atom()]) -> {econf:validators(), [atom()]}. validators(Disallowed) -> + Host = global, + DefinedKeywords = get_defined_keywords(Host), + validators(Disallowed, DefinedKeywords). + +%% validate/1 calls this function when parsing toplevel options +-spec validators([atom()], [any()]) -> {econf:validators(), [atom()]}. +validators(Disallowed, DK) -> Modules = callback_modules(all), Validators = lists:foldl( fun(M, Vs) -> - maps:merge(Vs, validators(M, Disallowed)) + maps:merge(Vs, validators(M, Disallowed, DK)) end, #{}, Modules), Required = lists:flatmap( fun(M) -> @@ -560,19 +568,27 @@ callback_modules(external) -> callback_modules(all) -> callback_modules(local) ++ callback_modules(external). --spec validators(module(), [atom()]) -> econf:validators(). -validators(Mod, Disallowed) -> +-spec validators(module(), [atom()], [any()]) -> econf:validators(). +validators(Mod, Disallowed, DK) -> + Keywords = DK ++ get_predefined_keywords(global), maps:from_list( lists:filtermap( fun(O) -> case lists:member(O, Disallowed) of true -> false; false -> - {true, - try {O, Mod:opt_type(O)} + Type = + try Mod:opt_type(O) catch _:_ -> - {O, ejabberd_options:opt_type(O)} - end} + ejabberd_options:opt_type(O) + end, + TypeProcessed = + econf:and_then( + fun(B) -> + replace_keywords(global, B, Keywords) + end, + Type), + {true, {O, TypeProcessed}} end end, proplists:get_keys(Mod:options()))). @@ -665,12 +681,13 @@ validate(Y1) -> {ok, Y3} -> Hosts = proplists:get_value(hosts, Y3), Version = proplists:get_value(version, Y3, version()), + DK = get_defined_keywords_yaml_config(Y3), create_tmp_config(), set_option(hosts, Hosts), set_option(host, hd(Hosts)), set_option(version, Version), set_option(yaml_config, Y3), - {Validators, Required} = validators([]), + {Validators, Required} = validators([], DK), Validator = econf:options(Validators, [{required, Required}, unique]), From 6e68c2ec020c8d705b804db3a37403989d13db6b Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 12 Feb 2025 22:47:41 +0100 Subject: [PATCH 119/170] Add support to replace keywords in listener options --- src/ejabberd_listener.erl | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 67f3db2deff..4fd7115a7e0 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -677,13 +677,21 @@ validator(M, T) -> true -> [] end, + Keywords = ejabberd_config:get_defined_keywords(global) ++ ejabberd_config:get_predefined_keywords(global), Validator = maps:from_list( lists:map( fun(Opt) -> - try {Opt, M:listen_opt_type(Opt)} + Type = try M:listen_opt_type(Opt) catch _:_ when M /= ?MODULE -> - {Opt, listen_opt_type(Opt)} - end + listen_opt_type(Opt) + end, + TypeProcessed = + econf:and_then( + fun(B) -> + ejabberd_config:replace_keywords(global, B, Keywords) + end, + Type), + {Opt, TypeProcessed} end, proplists:get_keys(Options))), econf:options( Validator, From 998690f58ceec058ce1dea874b16e0891d1a495d Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 10 Feb 2025 16:34:38 +0100 Subject: [PATCH 120/170] Add support to replace keywords in modules options --- src/gen_mod.erl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 9d40e0c1795..be815606d1f 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -551,10 +551,10 @@ validator(Host, Module, Opts) -> lists:mapfoldl( fun({Opt, Def}, {DAcc1, VAcc1}) -> {[], {DAcc1#{Opt => Def}, - VAcc1#{Opt => get_opt_type(Module, M, Opt)}}}; + VAcc1#{Opt => get_opt_type(Host, Module, M, Opt)}}}; (Opt, {DAcc1, VAcc1}) -> {[Opt], {DAcc1, - VAcc1#{Opt => get_opt_type(Module, M, Opt)}}} + VAcc1#{Opt => get_opt_type(Host, Module, M, Opt)}}} end, {DAcc, VAcc}, DefOpts) end, {#{}, #{}}, get_defaults(Host, Module, Opts)), econf:and_then( @@ -604,11 +604,16 @@ get_defaults(Host, Module, Opts) -> false end, DefaultOpts)]. --spec get_opt_type(module(), module(), atom()) -> econf:validator(). -get_opt_type(Mod, SubMod, Opt) -> - try SubMod:mod_opt_type(Opt) +-spec get_opt_type(binary(), module(), module(), atom()) -> econf:validator(). +get_opt_type(Host, Mod, SubMod, Opt) -> + Type = try SubMod:mod_opt_type(Opt) catch _:_ -> Mod:mod_opt_type(Opt) - end. + end, + econf:and_then( + fun(B) -> + ejabberd_config:replace_keywords(Host, B) + end, + Type). -spec sort_modules(binary(), [{module(), opts()}]) -> {ok, [{module(), opts(), integer()}]}. sort_modules(Host, ModOpts) -> From c8abff33c1c376061202c7e3289035e9ff415ff4 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Feb 2025 19:58:02 +0100 Subject: [PATCH 121/170] Remove some options keyword expansion, as they are now predefined --- src/econf.erl | 10 +++------- src/ejabberd_http.erl | 7 +------ src/ejabberd_options.erl | 10 +--------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/econf.erl b/src/econf.erl index a2a884e76b6..a6abdb647f9 100644 --- a/src/econf.erl +++ b/src/econf.erl @@ -546,14 +546,10 @@ sip_uri() -> -spec host() -> yconf:validator(binary()). host() -> fun(Domain) -> - Host = ejabberd_config:get_myname(), Hosts = ejabberd_config:get_option(hosts), - Domain1 = (binary())(Domain), - Domain2 = misc:expand_keyword(<<"@HOST@">>, Domain1, Host), - Domain3 = (domain())(Domain2), - case lists:member(Domain3, Hosts) of - true -> fail({route_conflict, Domain3}); - false -> Domain3 + case lists:member(Domain, Hosts) of + true -> fail({route_conflict, Domain}); + false -> Domain end end. diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl index 76fd80c4007..8a3a45f5446 100644 --- a/src/ejabberd_http.erl +++ b/src/ejabberd_http.erl @@ -932,12 +932,7 @@ listen_opt_type(default_host) -> listen_opt_type(custom_headers) -> econf:map( econf:binary(), - econf:and_then( - econf:binary(), - fun(V) -> - misc:expand_keyword(<<"@VERSION@">>, V, - ejabberd_option:version()) - end)). + econf:binary()). listen_options() -> [{ciphers, undefined}, diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index bcd697733b6..0e471059eb4 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -112,14 +112,7 @@ opt_type(cache_missed) -> opt_type(cache_size) -> econf:pos_int(infinity); opt_type(captcha_cmd) -> - econf:and_then( - econf:binary(), - fun(V) -> - V2 = misc:expand_keyword(<<"@SEMVER@">>, V, - ejabberd_option:version()), - misc:expand_keyword(<<"@VERSION@">>, V2, - misc:semver_to_xxyy(ejabberd_option:version())) - end); + econf:binary(); opt_type(captcha_host) -> econf:binary(); opt_type(captcha_limit) -> @@ -493,7 +486,6 @@ opt_type(jwt_auth_only_rule) -> {c2s_protocol_options, undefined | binary()} | {s2s_ciphers, undefined | binary()} | {c2s_ciphers, undefined | binary()} | - {captcha_cmd, undefined | binary()} | {websocket_origin, [binary()]} | {disable_sasl_mechanisms, [binary()]} | {s2s_zlib, boolean()} | From 352ee3a318a3cda428b00a9aaac3e4d3601eb01b Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Feb 2025 19:52:49 +0100 Subject: [PATCH 122/170] Docs: Document define_keyword and simplify define_macro --- src/ejabberd_options_doc.erl | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index ae2d7538bf5..84c2ae992a2 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -534,18 +534,26 @@ doc() -> ?T("A list of Erlang nodes to connect on ejabberd startup. " "This option is mostly intended for ejabberd customization " "and sophisticated setups. The default value is an empty list.")}}, + {define_keyword, + #{value => "{NAME: Value}", + desc => + ?T("Allows to define configuration " + "_`../configuration/file-format.md#keywords|keywords`_. "), + example => + ["define_keyword:", + " SQL_USERNAME: \"eja.global\"", + "", + "host_config:", + " localhost:", + " define_keyword:", + " SQL_USERNAME: \"eja.localhost\"", + "", + "sql_username: \"prefix.@SQL_USERNAME@\""]}}, {define_macro, - #{value => "{MacroName: MacroValue}", - desc => - ?T("Defines a " - "_`../configuration/file-format.md#macros-in-configuration-file|macro`_. " - "The value can be any valid arbitrary " - "YAML value. For convenience, it's recommended to define " - "a 'MacroName' in capital letters. Duplicated macros are not allowed. " - "Macros are processed after additional configuration files have " - "been included, so it is possible to use macros that are defined " - "in configuration files included before the usage. " - "It is possible to use a 'MacroValue' in the definition of another macro."), + #{value => "{NAME: Value}", + desc => + ?T("Allows to define configuration " + "_`../configuration/file-format.md#macros|macros`_. "), example => ["define_macro:", " DEBUG: debug", From 4dcf97c4c1644123754751d09f6d11f89768e4cc Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 12 Feb 2025 15:35:36 +0100 Subject: [PATCH 123/170] Now, when running tests, external may contain duplicate module --- src/ejabberd_config.erl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index e48006afb51..d744616f539 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -566,7 +566,15 @@ callback_modules(external) -> end end, beams(external)); callback_modules(all) -> - callback_modules(local) ++ callback_modules(external). + lists_uniq(callback_modules(local) ++ callback_modules(external)). + +-ifdef(OTP_BELOW_25). +lists_uniq(List) -> + lists:usort(List). +-else. +lists_uniq(List) -> + lists:uniq(List). +-endif. -spec validators(module(), [atom()], [any()]) -> econf:validators(). validators(Mod, Disallowed, DK) -> From 888c335c2e7403f7bc4bb22b6da9b4ab0dd9e013 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Feb 2025 19:58:35 +0100 Subject: [PATCH 124/170] Add tests for config features define_macro and define_keyword --- test/configtest_tests.erl | 187 ++++++++++++++++++++++++ test/ejabberd_SUITE.erl | 2 + test/ejabberd_SUITE_data/configtest.yml | 119 +++++++++++++++ test/ejabberd_SUITE_data/ejabberd.yml | 3 + test/ejabberd_test_options.erl | 114 +++++++++++++++ test/mod_configtest.erl | 45 ++++++ test/suite.erl | 24 ++- 7 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 test/configtest_tests.erl create mode 100644 test/ejabberd_SUITE_data/configtest.yml create mode 100644 test/ejabberd_test_options.erl create mode 100644 test/mod_configtest.erl diff --git a/test/configtest_tests.erl b/test/configtest_tests.erl new file mode 100644 index 00000000000..3763b8645aa --- /dev/null +++ b/test/configtest_tests.erl @@ -0,0 +1,187 @@ +%%%------------------------------------------------------------------- +%%% Author : Badlop +%%% Created : 5 Feb 2025 by Badlop +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne +%%% +%%% 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 Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%------------------------------------------------------------------- + +-module(configtest_tests). + +-compile(export_all). + +-include("suite.hrl"). + +%%%================================== + +single_cases() -> + {configtest_single, + [sequence], + [single_test(macro_over_keyword), + single_test(keyword_inside_macro), + single_test(macro_and_keyword), + single_test(macro_double), + single_test(keyword_double), + + single_test(macro_toplevel_global_atom), + single_test(macro_toplevel_global_string), + single_test(macro_toplevel_global_string_inside), + single_test(macro_toplevel_local_atom), + single_test(macro_toplevel_local_string), + single_test(macro_toplevel_local_string_inside), + + single_test(keyword_toplevel_global_atom), + single_test(keyword_toplevel_global_string), + single_test(keyword_toplevel_global_string_inside), + single_test(keyword_toplevel_local_atom), + single_test(keyword_toplevel_local_string), + single_test(keyword_toplevel_local_string_inside), + + single_test(macro_module_atom), + single_test(macro_module_string), + single_test(macro_module_string_inside), + + single_test(keyword_module_atom), + single_test(keyword_module_string), + single_test(keyword_module_string_inside), + + single_test(toplevel_global_predefined), + single_test(toplevel_local_predefined), + single_test(module_predefined)]}. + +%% Interactions + +macro_over_keyword(_) -> + toplevel_global(macro, macro_over_keyword). + +keyword_inside_macro(_) -> + toplevel_global(<<"+macro+/-keyword-">>, keyword_inside_macro). + +macro_and_keyword(_) -> + toplevel_global(<<"+macro+&-keyword-">>, macro_and_keyword). + +macro_double(_) -> + toplevel_global(<<"macro--macro">>, macro_double). + +keyword_double(_) -> + toplevel_global(<<"keyword--keyword">>, keyword_double). + +%% Macro Toplevel + +macro_toplevel_global_atom(_) -> + toplevel_global(mtga, mtga). + +macro_toplevel_global_string(_) -> + toplevel_global(<<"Mtgs">>, mtgs). + +macro_toplevel_global_string_inside(_) -> + toplevel_global(<<"Mtgsi">>, mtgsi). + +macro_toplevel_local_atom(_) -> + toplevel_local(mtla, mtla). + +macro_toplevel_local_string(_) -> + toplevel_local(<<"Mtls">>, mtls). + +macro_toplevel_local_string_inside(_) -> + toplevel_local(<<"Mtlsi">>, mtlsi). + +%% Keyword Toplevel + +keyword_toplevel_global_atom(_) -> + toplevel_global(ktga, ktga). + +keyword_toplevel_global_string(_) -> + toplevel_global(<<"Ktgs">>, ktgs). + +keyword_toplevel_global_string_inside(_) -> + toplevel_global(<<"Ktgsi">>, ktgsi). + +keyword_toplevel_local_atom(_) -> + toplevel_local(ktla, ktla). + +keyword_toplevel_local_string(_) -> + toplevel_local(<<"Ktls">>, ktls). + +keyword_toplevel_local_string_inside(_) -> + toplevel_local(<<"Ktlsi">>, ktlsi). + +%% Macro Module + +macro_module_atom(_) -> + module(mma, mma). + +macro_module_string(_) -> + module(<<"Mms">>, mms). + +macro_module_string_inside(_) -> + module(<<"Mmsi">>, mmsi). + +%% Keyword Module + +keyword_module_atom(_) -> + module(kma, kma). + +keyword_module_string(_) -> + module(<<"Kms">>, kms). + +keyword_module_string_inside(_) -> + module(<<"Kmsi">>, kmsi). + +%% Predefined + +toplevel_global_predefined(_) -> + Semver = ejabberd_option:version(), + Version = misc:semver_to_xxyy(Semver), + String = <<"tgp - semver: ", Semver/binary, ", version: ", Version/binary>>, + toplevel_global(String, tgp). + +toplevel_local_predefined(_) -> + Semver = ejabberd_option:version(), + Version = misc:semver_to_xxyy(Semver), + String = <<"tlp - semver: ", Semver/binary, ", version: ", Version/binary>>, + toplevel_local(String, tlp). + +module_predefined(_) -> + Host = <<"configtest.localhost">>, + Semver = ejabberd_option:version(), + Version = misc:semver_to_xxyy(Semver), + String = <<"mp - host: ", Host/binary, ", semver: ", Semver/binary, ", version: ", Version/binary>>, + module(String, predefined_keywords). + +%%%================================== +%%%% internal functions + +single_test(T) -> + list_to_atom("configtest_" ++ atom_to_list(T)). + +toplevel_global(Result, Option) -> + ?match(Result, ejabberd_config:get_option(Option)). + +toplevel_local(Result, Option) -> + Host = <<"configtest.localhost">>, + ?match(Result, ejabberd_config:get_option({Option, Host})). + +module(Result, Option) -> + Host = <<"configtest.localhost">>, + Module = mod_configtest, + ?match(Result, gen_mod:get_module_opt(Host, Module, Option)). + +%%%================================== + +%%% vim: set foldmethod=marker foldmarker=%%%%,%%%=: diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index e240de59b92..0a9e73d4dfb 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -60,6 +60,7 @@ init_per_suite(Config) -> NewConfig. start_ejabberd(_) -> + application:set_env(ejabberd, external_beams, "../../lib/ejabberd/test/"), {ok, _} = application:ensure_all_started(ejabberd, transient). end_per_suite(_Config) -> @@ -398,6 +399,7 @@ no_db_tests() -> auth_external_wrong_server, auth_external_invalid_cert, commands_tests:single_cases(), + configtest_tests:single_cases(), jidprep_tests:single_cases(), sm_tests:single_cases(), sm_tests:master_slave_cases(), diff --git a/test/ejabberd_SUITE_data/configtest.yml b/test/ejabberd_SUITE_data/configtest.yml new file mode 100644 index 00000000000..cdd8b002330 --- /dev/null +++ b/test/ejabberd_SUITE_data/configtest.yml @@ -0,0 +1,119 @@ + +define_macro: + CONFIGTEST_CONFIG: + modules: + mod_mam: {} + mod_muc: {} + +## Interactions + +define_macro: + MOK: macro + +define_keyword: + MOK: keyword + +macro_over_keyword: MOK + +## + +define_keyword: + KIM_KEYWORD: "-keyword-" + +define_macro: + KIM_MACRO: "+macro+/@KIM_KEYWORD@" + +keyword_inside_macro: KIM_MACRO + +## + +define_macro: + MAK_MACRO: "+macro+" + +define_keyword: + MAK_KEYWORD: "-keyword-" + +macro_and_keyword: "@MAK_MACRO@&@MAK_KEYWORD@" + +## + +define_macro: + MD: "macro" + +macro_double: "@MD@--@MD@" + +## + +define_keyword: + KD: "keyword" + +keyword_double: "@KD@--@KD@" + +## Macro Toplevel + +define_macro: + MTGA: mtga + MTGS: "Mtgs" + MTLA: mtla + MTLS: "Mtls" + +mtga: MTGA +mtgs: MTGS +mtgsi: "@MTGS@i" + +host_config: + configtest.localhost: + mtla: MTLA + mtls: MTLS + mtlsi: "@MTLS@i" + +## Keyword Toplevel + +define_keyword: + KTGA: ktga + KTLA: ktla + KTGS: "Ktgs" + KTLS: "Ktls" + +ktga: KTGA +ktgs: KTGS +ktgsi: "@KTGS@i" + +host_config: + configtest.localhost: + ktla: KTLA + ktls: KTLS + ktlsi: "@KTLS@i" + +## Macro Module +## Keyword Module +## Predefined Module + +define_macro: + MMA: mma + MMS: "Mms" + +define_keyword: + KMA: kma + KMS: "Kms" + +append_host_config: + configtest.localhost: + modules: + mod_configtest: + mma: MMA + mms: MMS + mmsi: "@MMS@i" + kma: KMA + kms: KMS + kmsi: "@KMS@i" + predefined_keywords: "mp - host: @HOST@, semver: @SEMVER@, version: @VERSION@" + +## Predefined + +tgp: "tgp - semver: @SEMVER@, version: @VERSION@" + +host_config: + configtest.localhost: + tlp: "tlp - semver: @SEMVER@, version: @VERSION@" + diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index 0155e8f9024..e3aa43c3d40 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -1,5 +1,6 @@ include_config_file: - macros.yml + - configtest.yml - ejabberd.extauth.yml - ejabberd.ldap.yml - ejabberd.mnesia.yml @@ -10,6 +11,7 @@ include_config_file: - ejabberd.sqlite.yml host_config: + configtest.localhost: CONFIGTEST_CONFIG pgsql.localhost: PGSQL_CONFIG sqlite.localhost: SQLITE_CONFIG mysql.localhost: MYSQL_CONFIG @@ -25,6 +27,7 @@ host_config: hosts: - localhost + - configtest.localhost - mnesia.localhost - redis.localhost - mysql.localhost diff --git a/test/ejabberd_test_options.erl b/test/ejabberd_test_options.erl new file mode 100644 index 00000000000..10cfcab3ef1 --- /dev/null +++ b/test/ejabberd_test_options.erl @@ -0,0 +1,114 @@ +%%%---------------------------------------------------------------------- +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne +%%% +%%% 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 Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- +-module(ejabberd_test_options). +-behaviour(ejabberd_config). + +-export([opt_type/1, options/0, globals/0, doc/0]). + +%%%=================================================================== +%%% API +%%%=================================================================== +-spec opt_type(atom()) -> econf:validator(). + +opt_type(macro_over_keyword) -> + econf:atom(); + +opt_type(keyword_inside_macro) -> + econf:binary(); + +opt_type(macro_and_keyword) -> + econf:binary(); + +opt_type(macro_double) -> + econf:binary(); + +opt_type(keyword_double) -> + econf:binary(); + +opt_type(mtga) -> + econf:atom(); + +opt_type(mtgs) -> + econf:binary(); + +opt_type(mtgsi) -> + econf:binary(); + +opt_type(mtla) -> + econf:atom(); + +opt_type(mtls) -> + econf:binary(); + +opt_type(mtlsi) -> + econf:binary(); + +opt_type(ktga) -> + econf:atom(); + +opt_type(ktgs) -> + econf:binary(); + +opt_type(ktgsi) -> + econf:binary(); + +opt_type(ktla) -> + econf:atom(); + +opt_type(ktls) -> + econf:binary(); + +opt_type(ktlsi) -> + econf:binary(); + +opt_type(tgp) -> + econf:binary(); + +opt_type(tlp) -> + econf:binary(). + +options() -> + [{macro_over_keyword, undefined}, + {keyword_inside_macro, undefined}, + {macro_and_keyword, undefined}, + {macro_double, undefined}, + {keyword_double, undefined}, + {mtga, undefined}, + {mtgs, undefined}, + {mtgsi, undefined}, + {mtla, undefined}, + {mtls, undefined}, + {mtlsi, undefined}, + {ktga, undefined}, + {ktgs, undefined}, + {ktgsi, undefined}, + {ktla, undefined}, + {ktls, undefined}, + {ktlsi, undefined}, + {tgp, undefined}, + {tlp, undefined} + ]. + +-spec globals() -> [atom()]. +globals() -> + []. + +doc() -> + ejabberd_options_doc:doc(). + diff --git a/test/mod_configtest.erl b/test/mod_configtest.erl new file mode 100644 index 00000000000..a4ca36f3323 --- /dev/null +++ b/test/mod_configtest.erl @@ -0,0 +1,45 @@ +-module(mod_configtest). +-behaviour(gen_mod). + +-export([start/2, stop/1, reload/3, mod_opt_type/1, mod_options/1, depends/2, mod_doc/0]). + +start(_Host, _Opts) -> + ok. + +stop(_Host) -> + ok. + +reload(_Host, _NewOpts, _OldOpts) -> + ok. + +depends(_Host, _Opts) -> + []. + +mod_opt_type(mma) -> + econf:atom(); +mod_opt_type(mms) -> + econf:binary(); +mod_opt_type(mmsi) -> + econf:binary(); + +mod_opt_type(kma) -> + econf:atom(); +mod_opt_type(kms) -> + econf:binary(); +mod_opt_type(kmsi) -> + econf:binary(); + +mod_opt_type(predefined_keywords) -> + econf:binary(). + +mod_options(_) -> + [{mma, undefined}, + {mms, undefined}, + {mmsi, undefined}, + {kma, undefined}, + {kms, undefined}, + {kmsi, undefined}, + {predefined_keywords, undefined}]. + +mod_doc() -> + #{}. diff --git a/test/suite.erl b/test/suite.erl index 0066b511670..28825b1d13b 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -84,6 +84,7 @@ init_config(Config) -> {priv_dir, PrivDir}]), MacrosPath = filename:join([CWD, "macros.yml"]), ok = file:write_file(MacrosPath, MacrosContent), + copy_configtest_yml(DataDir, CWD), copy_backend_configs(DataDir, CWD, Backends), setup_ejabberd_lib_path(Config), case application:load(sasl) of @@ -137,11 +138,32 @@ init_config(Config) -> {backends, Backends} |Config]. +copy_configtest_yml(DataDir, CWD) -> + Files = filelib:wildcard(filename:join([DataDir, "configtest.yml"])), + lists:foreach( + fun(Src) -> + ct:pal("copying ~p", [Src]), + File = filename:basename(Src), + case string:tokens(File, ".") of + ["configtest", "yml"] -> + Dst = filename:join([CWD, File]), + case true of + true -> + {ok, _} = file:copy(Src, Dst); + false -> + ok + end; + _ -> + ok + end + end, Files). + + copy_backend_configs(DataDir, CWD, Backends) -> Files = filelib:wildcard(filename:join([DataDir, "ejabberd.*.yml"])), lists:foreach( fun(Src) -> - io:format("copying ~p", [Src]), + ct:pal("copying ~p", [Src]), File = filename:basename(Src), case string:tokens(File, ".") of ["ejabberd", SBackend, "yml"] -> From c87ba45a869ec25ef8b64451d802436653a68632 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 18 Mar 2025 19:57:38 +0100 Subject: [PATCH 125/170] Result of running "make format" --- src/ejabberd_config.erl | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index d744616f539..7b08c446909 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -474,12 +474,13 @@ get_defined_keywords(Tab, Host) -> end, %% Trying to get defined keywords in host_config when starting ejabberd, %% the options are not yet stored in ets - KeysTemp = case not is_atom(Tab) andalso KeysHost == [] andalso KeysGlobal == [] of - true -> - get_defined_keywords_yaml_config(ets:lookup_element(Tab, {yaml_config, global}, 2)); - false -> - [] - end, + KeysTemp = + case not is_atom(Tab) andalso KeysHost == [] andalso KeysGlobal == [] of + true -> + get_defined_keywords_yaml_config(ets:lookup_element(Tab, {yaml_config, global}, 2)); + false -> + [] + end, lists:reverse(KeysTemp ++ KeysGlobal ++ KeysHost). get_defined_keywords_yaml_config(Y) -> @@ -487,17 +488,20 @@ get_defined_keywords_yaml_config(Y) -> || {KwAtom, KwValue} <- proplists:get_value(define_keyword, Y, [])]. get_predefined_keywords(Host) -> - HostList = case Host of - global -> []; - _ -> [{<<"HOST">>, Host}] - end, + HostList = + case Host of + global -> + []; + _ -> + [{<<"HOST">>, Host}] + end, {ok, [[Home]]} = init:get_argument(home), - HostList ++ - [{<<"HOME">>, list_to_binary(Home)}, - {<<"SEMVER">>, ejabberd_option:version()}, - {<<"VERSION">>, - misc:semver_to_xxyy( - ejabberd_option:version())}]. + HostList + ++ [{<<"HOME">>, list_to_binary(Home)}, + {<<"SEMVER">>, ejabberd_option:version()}, + {<<"VERSION">>, + misc:semver_to_xxyy( + ejabberd_option:version())}]. %% @format-end %%%=================================================================== From 53dea7b6d79ac35eb6ae5a488499fd7714febea4 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 18 Mar 2025 19:01:13 +0100 Subject: [PATCH 126/170] Fix email addresses in modules headers --- src/ejabberd_regexp.erl | 4 ++-- src/mod_muc_admin.erl | 6 +++--- src/mod_muc_log.erl | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ejabberd_regexp.erl b/src/ejabberd_regexp.erl index 7644810cda1..0d18deac680 100644 --- a/src/ejabberd_regexp.erl +++ b/src/ejabberd_regexp.erl @@ -1,8 +1,8 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_regexp.erl -%%% Author : Badlop +%%% Author : Badlop %%% Purpose : Frontend to Re OTP module -%%% Created : 8 Dec 2011 by Badlop +%%% Created : 8 Dec 2011 by Badlop %%% %%% %%% ejabberd, Copyright (C) 2002-2025 ProcessOne diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index a260d43b286..35a0f2f94d6 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -1,8 +1,8 @@ %%%---------------------------------------------------------------------- %%% File : mod_muc_admin.erl -%%% Author : Badlop +%%% Author : Badlop %%% Purpose : Tools for additional MUC administration -%%% Created : 8 Sep 2007 by Badlop +%%% Created : 8 Sep 2007 by Badlop %%% %%% %%% ejabberd, Copyright (C) 2002-2025 ProcessOne @@ -24,7 +24,7 @@ %%%---------------------------------------------------------------------- -module(mod_muc_admin). --author('badlop@ono.com'). +-author('badlop@process-one.net'). -behaviour(gen_mod). diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index c075b954cf0..57a975b0bfc 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% File : mod_muc_log.erl -%%% Author : Badlop@process-one.net +%%% Author : Badlop %%% Purpose : MUC room logging %%% Created : 12 Mar 2006 by Alexey Shchepin %%% From 1ea0dde417d1b96782f8f13e2b9c6616cb5d084b Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Mar 2025 18:10:01 +0100 Subject: [PATCH 127/170] ejabberd_admin: Allow using mnesia_list_tables and mnesia_table_change_storage --- src/ejabberd_admin.erl | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 259831d7f76..9f2cc84b816 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -598,8 +598,9 @@ get_commands_spec() -> args = [{node, atom}, {table, binary}, {page, integer}], result = {res, any}}, - #ejabberd_commands{name = mnesia_list_tables, tags = [internal, mnesia], + #ejabberd_commands{name = mnesia_list_tables, tags = [mnesia], desc = "List of Mnesia tables", + note = "added in 25.xx", module = ?MODULE, function = mnesia_list_tables, result = {tables, {list, {table, {tuple, [{name, atom}, {storage_type, binary}, @@ -615,8 +616,10 @@ get_commands_spec() -> {value, binary} ]}}}}}, - #ejabberd_commands{name = mnesia_table_change_storage, tags = [internal, mnesia], - desc = "Change storage type of a Mnesia table to: ram_copies, disc_copies, or disc_only_copies.", + #ejabberd_commands{name = mnesia_table_change_storage, tags = [mnesia], + desc = "Change storage type of a Mnesia table", + note = "added in 25.xx", + longdesc = "Storage type can be: `ram_copies`, `disc_copies`, `disc_only_copies`, `remote_copy`.", module = ?MODULE, function = mnesia_table_change_storage, args = [{table, binary}, {storage_type, binary}], result = {res, restuple}}, @@ -1281,13 +1284,12 @@ is_my_host(Host) -> %% @format-begin -%% mnesia:del_table_copy(Table, Node); -%% mnesia:change_table_copy_type(Table, Node, Type); - mnesia_table_change_storage(STable, SType) -> Table = binary_to_existing_atom(STable, latin1), Type = case SType of + <<"remote_copy">> -> + remote_copy; <<"ram_copies">> -> ram_copies; <<"disc_copies">> -> @@ -1297,7 +1299,24 @@ mnesia_table_change_storage(STable, SType) -> _ -> false end, - mnesia:add_table_copy(Table, node(), Type). + Node = node(), + Result = + case Type of + false -> + "Nothing to do"; + remote_copy -> + mnesia:del_table_copy(Table, Node), + "Deleted table copy"; + _ -> + case mnesia:add_table_copy(Table, Node, Type) of + {aborted, _} -> + mnesia:change_table_copy_type(Table, Node, Type), + "Changed table copy type"; + _ -> + "Added table copy" + end + end, + {ok, Result}. mnesia_table_clear(STable) -> Table = binary_to_existing_atom(STable, latin1), From 6151674e64a595b66d98bcd83582b9ae1f547a75 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Mar 2025 21:10:19 +0100 Subject: [PATCH 128/170] ejabberd_commands: Show warning when registering command with an existing name In ejabberd modules, only register/unregister commands if module is not running for any other vhost. --- src/ejabberd_commands.erl | 35 +++++++++++++++++++++++++++++++---- src/mod_admin_extra.erl | 11 +++-------- src/mod_admin_update_sql.erl | 8 ++++---- src/mod_fail2ban.erl | 9 ++------- src/mod_mam.erl | 9 ++------- src/mod_muc_admin.erl | 11 +++-------- src/mod_private.erl | 9 ++------- src/mod_pubsub.erl | 9 ++------- src/mod_push.erl | 9 ++------- 9 files changed, 51 insertions(+), 59 deletions(-) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 5028f05fc4c..2318564bac7 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -42,7 +42,9 @@ get_tags_commands/1, register_commands/1, register_commands/2, + register_commands/3, unregister_commands/1, + unregister_commands/3, get_commands_spec/0, get_commands_definition/0, get_commands_definition/1, @@ -142,19 +144,34 @@ code_change(_OldVsn, State, _Extra) -> register_commands(Commands) -> register_commands(unknown, Commands). +-spec register_commands(atom(), [ejabberd_commands()]) -> ok. + register_commands(Definer, Commands) -> + ExistingCommands = list_commands(), lists:foreach( fun(Command) -> - %% XXX check if command exists - mnesia:dirty_write(register_command_prepare(Command, Definer)) - %% ?DEBUG("This command is already defined:~n~p", [Command]) + Name = Command#ejabberd_commands.name, + case lists:keyfind(Name, 1, ExistingCommands) of + false -> + mnesia:dirty_write(register_command_prepare(Command, Definer)); + _ -> + OtherCommandDef = get_command_definition(Name), + ?CRITICAL_MSG("Error trying to define a command: another one already exists with the same name:~n Existing: ~p~n New: ~p", [OtherCommandDef, Command]) + end end, Commands), ejabberd_access_permissions:invalidate(), ok. +-spec register_commands(binary(), atom(), [ejabberd_commands()]) -> ok. - +register_commands(Host, Definer, Commands) -> + case gen_mod:is_loaded_elsewhere(Host, Definer) of + false -> + register_commands(Definer, Commands); + true -> + ok + end. register_command_prepare(Command, Definer) -> Tags1 = Command#ejabberd_commands.tags, @@ -175,6 +192,16 @@ unregister_commands(Commands) -> Commands), ejabberd_access_permissions:invalidate(). +-spec unregister_commands(binary(), atom(), [ejabberd_commands()]) -> ok. + +unregister_commands(Host, Definer, Commands) -> + case gen_mod:is_loaded_elsewhere(Host, Definer) of + false -> + unregister_commands(Commands); + true -> + ok + end. + -spec list_commands() -> [{atom(), [aterm()], string()}]. list_commands() -> diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 11b0fbb95ff..d461edc8991 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -104,8 +104,8 @@ %%% gen_mod %%% -start(_Host, _Opts) -> - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), +start(Host, _Opts) -> + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), {ok, [{hook, webadmin_menu_main, web_menu_main, 50, global}, {hook, webadmin_page_main, web_page_main, 50, global}, {hook, webadmin_menu_host, web_menu_host, 50}, @@ -118,12 +118,7 @@ start(_Host, _Opts) -> {hook, webadmin_page_node, web_page_node, 50, global}]}. stop(Host) -> - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end. + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). reload(_Host, _NewOpts, _OldOpts) -> ok. diff --git a/src/mod_admin_update_sql.erl b/src/mod_admin_update_sql.erl index 0c3f9095fd9..c5b4ab86505 100644 --- a/src/mod_admin_update_sql.erl +++ b/src/mod_admin_update_sql.erl @@ -47,11 +47,11 @@ %%% gen_mod %%% -start(_Host, _Opts) -> - ejabberd_commands:register_commands(?MODULE, get_commands_spec()). +start(Host, _Opts) -> + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()). -stop(_Host) -> - ejabberd_commands:unregister_commands(get_commands_spec()). +stop(Host) -> + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). reload(_Host, _NewOpts, _OldOpts) -> ok. diff --git a/src/mod_fail2ban.erl b/src/mod_fail2ban.erl index 2680248e5d5..2dbd8575c23 100644 --- a/src/mod_fail2ban.erl +++ b/src/mod_fail2ban.erl @@ -107,16 +107,11 @@ c2s_stream_started(#{ip := {Addr, _}} = State, _) -> start(Host, Opts) -> catch ets:new(failed_auth, [named_table, public, {heir, erlang:group_leader(), none}]), - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), gen_mod:start_child(?MODULE, Host, Opts). stop(Host) -> - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end, + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()), gen_mod:stop_child(?MODULE, Host). reload(_Host, _NewOpts, _OldOpts) -> diff --git a/src/mod_mam.erl b/src/mod_mam.erl index aa4bb3b84af..a7b47fe91e3 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -182,7 +182,7 @@ start(Host, Opts) -> ejabberd_hooks:add(check_create_room, Host, ?MODULE, check_create_room, 50) end, - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), ok; Err -> Err @@ -263,12 +263,7 @@ stop(Host) -> ejabberd_hooks:delete(check_create_room, Host, ?MODULE, check_create_room, 50) end, - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end. + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). reload(Host, NewOpts, OldOpts) -> NewMod = gen_mod:db_mod(NewOpts, ?MODULE), diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 35a0f2f94d6..c1c6ccf5456 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -68,8 +68,8 @@ %% gen_mod %%---------------------------- -start(_Host, _Opts) -> - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), +start(Host, _Opts) -> + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), {ok, [{hook, webadmin_menu_main, web_menu_main, 50, global}, {hook, webadmin_page_main, web_page_main, 50, global}, {hook, webadmin_menu_host, web_menu_host, 50}, @@ -79,12 +79,7 @@ start(_Host, _Opts) -> ]}. stop(Host) -> - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end. + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). reload(_Host, _NewOpts, _OldOpts) -> ok. diff --git a/src/mod_private.erl b/src/mod_private.erl index 145edefcfd2..3bb93ed7795 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -71,7 +71,7 @@ start(Host, Opts) -> Mod = gen_mod:db_mod(Opts, ?MODULE), Mod:init(Host, Opts), init_cache(Mod, Host, Opts), - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), {ok, [{hook, remove_user, remove_user, 50}, {hook, disco_sm_features, get_sm_features, 50}, {hook, pubsub_publish_item, pubsub_publish_item, 50}, @@ -82,12 +82,7 @@ start(Host, Opts) -> {iq_handler, ejabberd_sm, ?NS_PRIVATE, process_sm_iq}]}. stop(Host) -> - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end. + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). reload(Host, NewOpts, OldOpts) -> NewMod = gen_mod:db_mod(NewOpts, ?MODULE), diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index 3ebc69fa44d..059fa9518c9 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -338,7 +338,7 @@ init([ServerHost|_]) -> false -> ok end, - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), + ejabberd_commands:register_commands(ServerHost, ?MODULE, get_commands_spec()), NodeTree = config(ServerHost, nodetree), Plugins = config(ServerHost, plugins), PepMapping = config(ServerHost, pep_mapping), @@ -809,12 +809,7 @@ terminate(_Reason, terminate_plugins(Host, ServerHost, Plugins, TreePlugin), ejabberd_router:unregister_route(Host) end, Hosts), - case gen_mod:is_loaded_elsewhere(ServerHost, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end. + ejabberd_commands:unregister_commands(ServerHost, ?MODULE, get_commands_spec()). %%-------------------------------------------------------------------- %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} diff --git a/src/mod_push.erl b/src/mod_push.erl index 20cb6394c68..7d2792eb45b 100644 --- a/src/mod_push.erl +++ b/src/mod_push.erl @@ -96,7 +96,7 @@ start(Host, Opts) -> Mod = gen_mod:db_mod(Opts, ?MODULE), Mod:init(Host, Opts), init_cache(Mod, Host, Opts), - ejabberd_commands:register_commands(?MODULE, get_commands_spec()), + ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), {ok, [{iq_handler, ejabberd_sm, ?NS_PUSH_0, process_iq}, {hook, disco_sm_features, disco_sm_features, 50}, {hook, c2s_session_pending, c2s_session_pending, 50}, @@ -111,12 +111,7 @@ start(Host, Opts) -> -spec stop(binary()) -> ok. stop(Host) -> - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_commands:unregister_commands(get_commands_spec()); - true -> - ok - end. + ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). -spec reload(binary(), gen_mod:opts(), gen_mod:opts()) -> ok. reload(Host, NewOpts, OldOpts) -> From aa78362c7f5bfabc56183837233e24cf2a45ad09 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 21 Feb 2025 13:45:20 +0100 Subject: [PATCH 129/170] mod_configure: Add option 'access' to let configure the access name --- src/mod_configure.erl | 85 +++++++++++++++++++++++++++------------ src/mod_configure_opt.erl | 13 ++++++ 2 files changed, 73 insertions(+), 25 deletions(-) create mode 100644 src/mod_configure_opt.erl diff --git a/src/mod_configure.erl b/src/mod_configure.erl index d213ae9d957..08380a16ab3 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : mod_configure.erl %%% Author : Alexey Shchepin -%%% Purpose : Support for online configuration of ejabberd +%%% Purpose : Support for online configuration of ejabberd using XEP-0050 %%% Created : 19 Jan 2003 by Alexey Shchepin %%% %%% @@ -36,6 +36,7 @@ adhoc_local_items/4, adhoc_local_commands/4, get_sm_identity/5, get_sm_features/5, get_sm_items/5, adhoc_sm_items/4, adhoc_sm_commands/4, mod_options/1, + mod_opt_type/1, depends/2, mod_doc/0]). -include("logger.hrl"). @@ -92,6 +93,10 @@ depends(_Host, _Opts) -> -spec tokenize(binary()) -> [binary()]. tokenize(Node) -> str:tokens(Node, <<"/#">>). +acl_match_rule(Host, From) -> + Access = mod_configure_opt:access(Host), + acl:match_rule(Host, Access, From). + -spec get_sm_identity([identity()], jid(), jid(), binary(), binary()) -> [identity()]. get_sm_identity(Acc, _From, _To, Node, Lang) -> case Node of @@ -167,7 +172,7 @@ get_sm_features(Acc, From, case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; _ -> - Allow = acl:match_rule(LServer, configure, From), + Allow = acl_match_rule(LServer, From), case Node of <<"config">> -> ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); _ -> Acc @@ -182,7 +187,7 @@ get_local_features(Acc, From, false -> Acc; _ -> LNode = tokenize(Node), - Allow = acl:match_rule(LServer, configure, From), + Allow = acl_match_rule(LServer, From), case LNode of [<<"config">>] -> ?INFO_RESULT(Allow, [], Lang); [<<"user">>] -> ?INFO_RESULT(Allow, [], Lang); @@ -240,7 +245,7 @@ get_local_features(Acc, From, jid(), jid(), binary()) -> mod_disco:items_acc(). adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To, Lang) -> - case acl:match_rule(LServer, configure, From) of + case acl_match_rule(LServer, From) of allow -> Items = case Acc of {result, Its} -> Its; @@ -266,7 +271,7 @@ get_sm_items(Acc, From, {result, Its} -> Its; empty -> [] end, - case {acl:match_rule(LServer, configure, From), Node} of + case {acl_match_rule(LServer, From), Node} of {allow, <<"">>} -> Nodes = [?NODEJID(To, ?T("Configuration"), <<"config">>), @@ -295,13 +300,13 @@ get_user_resources(User, Server) -> jid(), jid(), binary()) -> mod_disco:items_acc(). adhoc_local_items(Acc, From, #jid{lserver = LServer, server = Server} = To, Lang) -> - case acl:match_rule(LServer, configure, From) of + case acl_match_rule(LServer, From) of allow -> Items = case Acc of {result, Its} -> Its; empty -> [] end, - PermLev = get_permission_level(From), + PermLev = get_permission_level(From, LServer), Nodes = recursively_get_local_items(PermLev, LServer, <<"">>, Server, Lang), Nodes1 = lists:filter( @@ -348,9 +353,10 @@ recursively_get_local_items(PermLev, LServer, Node, end, Items)). --spec get_permission_level(jid()) -> global | vhost. -get_permission_level(JID) -> - case acl:match_rule(global, configure, JID) of +-spec get_permission_level(jid(), binary()) -> global | vhost. +get_permission_level(JID, Host) -> + Access = mod_configure_opt:access(Host), + case acl:match_rule(global, Access, JID) of allow -> global; deny -> vhost end. @@ -361,7 +367,7 @@ get_permission_level(JID) -> case Allow of deny -> Fallback; allow -> - PermLev = get_permission_level(From), + PermLev = get_permission_level(From, LServer), case get_local_items({PermLev, LServer}, LNode, jid:encode(To), Lang) of @@ -381,11 +387,11 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, {result, Its} -> Its; empty -> [] end, - Allow = acl:match_rule(LServer, configure, From), + Allow = acl_match_rule(LServer, From), case Allow of deny -> {result, Items}; allow -> - PermLev = get_permission_level(From), + PermLev = get_permission_level(From, LServer), case get_local_items({PermLev, LServer}, [], jid:encode(To), Lang) of @@ -400,7 +406,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, false -> Acc; _ -> LNode = tokenize(Node), - Allow = acl:match_rule(LServer, configure, From), + Allow = acl_match_rule(LServer, From), Err = xmpp:err_forbidden(?T("Access denied by service policy"), Lang), case LNode of [<<"config">>] -> @@ -690,7 +696,7 @@ get_stopped_nodes(_Lang) -> -define(COMMANDS_RESULT(LServerOrGlobal, From, To, Request, Lang), - case acl:match_rule(LServerOrGlobal, configure, From) of + case acl_match_rule(LServerOrGlobal, From) of deny -> {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)}; allow -> adhoc_local_commands(From, To, Request) end). @@ -1268,7 +1274,7 @@ set_form(From, Host, ?NS_ADMINL(<<"add-user">>), _Lang, Server = AccountJID#jid.lserver, true = lists:member(Server, ejabberd_option:hosts()), true = Server == Host orelse - get_permission_level(From) == global, + get_permission_level(From, Host) == global, case ejabberd_auth:try_register(User, Server, Password) of ok -> {result, undefined}; {error, exists} -> {error, xmpp:err_conflict()}; @@ -1284,7 +1290,7 @@ set_form(From, Host, ?NS_ADMINL(<<"delete-user">>), User = JID#jid.luser, Server = JID#jid.lserver, true = Server == Host orelse - get_permission_level(From) == global, + get_permission_level(From, Host) == global, true = ejabberd_auth:user_exists(User, Server), {User, Server} end, @@ -1298,7 +1304,7 @@ set_form(From, Host, ?NS_ADMINL(<<"end-user-session">>), JID = jid:decode(AccountString), LServer = JID#jid.lserver, true = LServer == Host orelse - get_permission_level(From) == global, + get_permission_level(From, Host) == global, case JID#jid.lresource of <<>> -> ejabberd_sm:kick_user(JID#jid.luser, JID#jid.lserver); @@ -1314,7 +1320,7 @@ set_form(From, Host, User = JID#jid.luser, Server = JID#jid.lserver, true = Server == Host orelse - get_permission_level(From) == global, + get_permission_level(From, Host) == global, true = ejabberd_auth:user_exists(User, Server), ejabberd_auth:set_password(User, Server, Password), {result, undefined}; @@ -1325,7 +1331,7 @@ set_form(From, Host, User = JID#jid.luser, Server = JID#jid.lserver, true = Server == Host orelse - get_permission_level(From) == global, + get_permission_level(From, Host) == global, FLast = case ejabberd_sm:get_user_resources(User, Server) of @@ -1357,7 +1363,7 @@ set_form(From, Host, ?NS_ADMINL(<<"user-stats">>), Lang, User = JID#jid.luser, Server = JID#jid.lserver, true = Server == Host orelse - get_permission_level(From) == global, + get_permission_level(From, Host) == global, Resources = ejabberd_sm:get_user_resources(User, Server), IPs1 = [ejabberd_sm:get_user_ip(User, Server, Resource) @@ -1448,7 +1454,7 @@ adhoc_sm_commands(_Acc, From, #jid{user = User, server = Server, lserver = LServer}, #adhoc_command{lang = Lang, node = <<"config">>, action = Action, xdata = XData} = Request) -> - case acl:match_rule(LServer, configure, From) of + case acl_match_rule(LServer, From) of deny -> {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)}; allow -> @@ -1530,12 +1536,41 @@ set_sm_form(_User, _Server, _Node, _Request) -> tr(Lang, Text) -> translate:translate(Lang, Text). -mod_options(_) -> []. +-spec mod_opt_type(atom()) -> econf:validator(). +mod_opt_type(access) -> + econf:acl(). + +-spec mod_options(binary()) -> [{services, [tuple()]} | {atom(), any()}]. +mod_options(_Host) -> + [{access, configure}]. + +%% @format-begin mod_doc() -> #{desc => ?T("The module provides server configuration functionality via " "https://xmpp.org/extensions/xep-0050.html[XEP-0050:%20Ad-Hoc%20Commands]." - "Implements many commands as defined in " + "It also implements many commands as defined in " "https://xmpp.org/extensions/xep-0133.html[XEP-0133:%20Service%20Administration]." - "This module requires _`mod_adhoc`_ to be loaded.")}. + "This module requires _`mod_adhoc`_ (to execute the commands), " + "and recommends _`mod_disco`_ (to discover the commands). "), + opts => + [{access, + #{value => ?T("AccessName"), + note => "added in 25.xx", + desc => + ?T("This option defines which access rule will be used to " + "control who is allowed to access the features provided by this module. " + "The default value is 'configure'.")}}], + example => + ["acl:", + " admin:", + " user: sun@localhost", + "", + "access_rules:", + " configure:", + " allow: admin", + "", + "modules:", + " mod_configure:", + " access: configure"]}. diff --git a/src/mod_configure_opt.erl b/src/mod_configure_opt.erl new file mode 100644 index 00000000000..0a8c190fd05 --- /dev/null +++ b/src/mod_configure_opt.erl @@ -0,0 +1,13 @@ +%% Generated automatically +%% DO NOT EDIT: run `make options` instead + +-module(mod_configure_opt). + +-export([access/1]). + +-spec access(gen_mod:opts() | global | binary()) -> 'configure' | acl:acl(). +access(Opts) when is_map(Opts) -> + gen_mod:get_opt(access, Opts); +access(Host) -> + gen_mod:get_module_opt(Host, mod_configure, access). + From 6d77ace5c969e531f8793dbc878e98583ad777ea Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Mar 2025 19:20:41 +0100 Subject: [PATCH 130/170] mod_http_api: Sort list elements in a command result --- src/mod_http_api.erl | 9 ++++++--- test/commands_tests.erl | 14 +++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index b2fe7b7c0e1..f5c9b3c2a5d 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -473,14 +473,17 @@ format_result(Code, {Name, restuple}) -> {[{<<"res">>, Code == true orelse Code == ok}, {<<"text">>, <<"">>}]}}; -format_result(Els, {Name, {list, {_, {tuple, [{_, atom}, _]}} = Fmt}}) -> +format_result(Els1, {Name, {list, {_, {tuple, [{_, atom}, _]}} = Fmt}}) -> + Els = lists:keysort(1, Els1), {misc:atom_to_binary(Name), {[format_result(El, Fmt) || El <- Els]}}; -format_result(Els, {Name, {list, {_, {tuple, [{name, string}, {value, _}]}} = Fmt}}) -> +format_result(Els1, {Name, {list, {_, {tuple, [{name, string}, {value, _}]}} = Fmt}}) -> + Els = lists:keysort(1, Els1), {misc:atom_to_binary(Name), {[format_result(El, Fmt) || El <- Els]}}; %% Covered by command_test_list and command_test_list_tuple -format_result(Els, {Name, {list, Def}}) -> +format_result(Els1, {Name, {list, Def}}) -> + Els = lists:sort(Els1), {misc:atom_to_binary(Name), [element(2, format_result(El, Def)) || El <- Els]}; format_result(Tuple, {_Name, {tuple, [{_, atom}, ValFmt]}}) -> diff --git a/test/commands_tests.erl b/test/commands_tests.erl index 52933e409e6..a1c60c5e492 100644 --- a/test/commands_tests.erl +++ b/test/commands_tests.erl @@ -130,7 +130,7 @@ http_restuple(Config) -> http_list(Config) -> ListS = ["one", "first", "primary"], - ListB = [<<"one">>, <<"first">>, <<"primary">>], + ListB = lists:sort([<<"one">>, <<"first">>, <<"primary">>]), ?match(ListB, query(Config, "command_test_list", #{arg_list => ListS})), ?match(ListB, query(Config, "command_test_list", #{arg_list => ListB})). @@ -148,20 +148,20 @@ http_tuple(Config) -> http_list_tuple(Config) -> LTA = [#{element1 => "one", element2 => "uno"}, - #{element1 => "dos", element2 => "two"}, + #{element1 => "two", element2 => "dos"}, #{element1 => "three", element2 => "tres"}], - LTB = [#{<<"element1">> => <<"one">>, <<"element2">> => <<"uno">>}, - #{<<"element1">> => <<"dos">>, <<"element2">> => <<"two">>}, - #{<<"element1">> => <<"three">>, <<"element2">> => <<"tres">>}], + LTB = lists:sort([#{<<"element1">> => <<"one">>, <<"element2">> => <<"uno">>}, + #{<<"element1">> => <<"two">>, <<"element2">> => <<"dos">>}, + #{<<"element1">> => <<"three">>, <<"element2">> => <<"tres">>}]), ?match(LTB, query(Config, "command_test_list_tuple", #{arg_list => LTA})), ?match(LTB, query(Config, "command_test_list_tuple", #{arg_list => LTB})). http_list_tuple_map(Config) -> LTA = #{<<"one">> => <<"uno">>, - <<"dos">> => <<"two">>, + <<"two">> => <<"dos">>, <<"three">> => <<"tres">>}, LTB = lists:sort([#{<<"element1">> => <<"one">>, <<"element2">> => <<"uno">>}, - #{<<"element1">> => <<"dos">>, <<"element2">> => <<"two">>}, + #{<<"element1">> => <<"two">>, <<"element2">> => <<"dos">>}, #{<<"element1">> => <<"three">>, <<"element2">> => <<"tres">>}]), ?match(LTB, lists:sort(query(Config, "command_test_list_tuple", #{arg_list => LTA}))). From 573e06cc0cb2432b2eb69a446f41b37ce53d5a22 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 3 Mar 2025 13:07:46 +0100 Subject: [PATCH 131/170] mod_muc_admin: create_room_with_opts command recommends using ; and = separators --- src/mod_muc_admin.erl | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index c1c6ccf5456..06995daedd6 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -189,14 +189,20 @@ get_commands_spec() -> #ejabberd_commands{name = create_room_with_opts, tags = [muc_room, muc_sub], desc = "Create a MUC room name@service in host with given options", longdesc = - "The syntax of `affiliations` is: `Type:JID,Type:JID`. " - "The syntax of `subscribers` is: `JID:Nick:Node:Node2:Node3,JID:Nick:Node`.", + "Options `affiliations` and `subscribers` are lists of tuples. " + "The tuples in the list are separated with `;` and " + "the elements in each tuple are separated with `=` " + "(until ejabberd 24.12 the separators were `,` and `:` respectively). " + "Each subscriber can have one or more nodes. " + "In summary, `affiliations` is like `Type1=JID1;Type2=JID2` " + "and `subscribers` is like `JID1=Nick1=Node1A=Node1B=Node1C;JID2=Nick2=Node2`.", + note = "modified in 25.xx", module = ?MODULE, function = create_room_with_opts, args_desc = ["Room name", "MUC service", "Server host", "List of options"], args_example = ["room1", "conference.example.com", "localhost", [{"members_only","true"}, - {"affiliations", "owner:bob@example.com,member:peter@example.com"}, - {"subscribers", "bob@example.com:Bob:messages:subject,anne@example.com:Anne:messages"}]], + {"affiliations", "owner=user1@localhost;member=user2@localhost"}, + {"subscribers", "user3@localhost=User3=messages=subject;user4@localhost=User4=messages"}]], args = [{room, binary}, {service, binary}, {host, binary}, {options, {list, @@ -1726,9 +1732,9 @@ format_room_option(OptionString, ValueString) -> lang -> ValueString; pubsub -> ValueString; affiliations -> - [parse_affiliation_string(Opt) || Opt <- str:tokens(ValueString, <<",">>)]; + [parse_affiliation_string(Opt) || Opt <- str:tokens(ValueString, <<";,">>)]; subscribers -> - [parse_subscription_string(Opt) || Opt <- str:tokens(ValueString, <<",">>)]; + [parse_subscription_string(Opt) || Opt <- str:tokens(ValueString, <<";,">>)]; allow_private_messages_from_visitors when (ValueString == <<"anyone">>) or (ValueString == <<"moderators">>) or @@ -1760,10 +1766,16 @@ throw_error(O, V) -> parse_affiliation_string(String) -> {Type, JidS} = case String of + %% Old syntax <<"owner:", Jid/binary>> -> {owner, Jid}; <<"admin:", Jid/binary>> -> {admin, Jid}; <<"member:", Jid/binary>> -> {member, Jid}; <<"outcast:", Jid/binary>> -> {outcast, Jid}; + %% New syntax + <<"owner=", Jid/binary>> -> {owner, Jid}; + <<"admin=", Jid/binary>> -> {admin, Jid}; + <<"member=", Jid/binary>> -> {member, Jid}; + <<"outcast=", Jid/binary>> -> {outcast, Jid}; _ -> throw({error, "Invalid 'affiliation'"}) end, try jid:decode(JidS) of @@ -1774,7 +1786,7 @@ parse_affiliation_string(String) -> end. parse_subscription_string(String) -> - case str:tokens(String, <<":">>) of + case str:tokens(String, <<"=:">>) of [_] -> throw({error, "Invalid 'subscribers' - missing nick"}); [_, _] -> From 496daf9220e0916d77f1d607de7b208d5a0884bd Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 19 Mar 2025 10:39:53 +0100 Subject: [PATCH 132/170] mod_adhoc_api: New module to execute API Commands using Ad-Hoc Commands --- ejabberd.yml.example | 8 +- src/ejabberd_access_permissions.erl | 14 +- src/ejabberd_commands.erl | 11 + src/mod_adhoc_api.erl | 729 ++++++++++++++++++++++++++ src/mod_adhoc_api_opt.erl | 13 + src/mod_http_api.erl | 9 +- test/commands_tests.erl | 280 +++++++++- test/ejabberd_SUITE_data/ejabberd.yml | 1 + 8 files changed, 1046 insertions(+), 19 deletions(-) create mode 100644 src/mod_adhoc_api.erl create mode 100644 src/mod_adhoc_api_opt.erl diff --git a/ejabberd.yml.example b/ejabberd.yml.example index 0964afa0632..07019441209 100644 --- a/ejabberd.yml.example +++ b/ejabberd.yml.example @@ -118,7 +118,12 @@ api_permissions: from: ejabberd_web_admin who: admin what: "*" - "admin access": + "adhoc commands": + from: mod_adhoc_api + who: admin + what: "*" + "http access": + from: mod_http_api who: access: allow: @@ -159,6 +164,7 @@ shaper_rules: modules: mod_adhoc: {} + mod_adhoc_api: {} mod_admin_extra: {} mod_announce: access: announce diff --git a/src/ejabberd_access_permissions.erl b/src/ejabberd_access_permissions.erl index 1889ca8dfa8..57b3637e38a 100644 --- a/src/ejabberd_access_permissions.erl +++ b/src/ejabberd_access_permissions.erl @@ -344,10 +344,20 @@ validator(from) -> fun(L) when is_list(L) -> lists:map( fun({K, V}) -> {(econf:enum([tag]))(K), (econf:binary())(V)}; - (A) -> (econf:enum([ejabberd_xmlrpc, mod_cron, mod_http_api, ejabberd_ctl, ejabberd_web_admin]))(A) + (A) -> (econf:enum([ejabberd_ctl, + ejabberd_web_admin, + ejabberd_xmlrpc, + mod_adhoc_api, + mod_cron, + mod_http_api]))(A) end, lists:flatten(L)); (A) -> - [(econf:enum([ejabberd_xmlrpc, mod_cron, mod_http_api, ejabberd_ctl, ejabberd_web_admin]))(A)] + [(econf:enum([ejabberd_ctl, + ejabberd_web_admin, + ejabberd_xmlrpc, + mod_adhoc_api, + mod_cron, + mod_http_api]))(A)] end; validator(what) -> econf:and_then( diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 2318564bac7..243a594edd0 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -33,6 +33,7 @@ -export([start_link/0, list_commands/0, list_commands/1, + list_commands/2, get_command_format/1, get_command_format/2, get_command_format/3, @@ -217,6 +218,16 @@ list_commands(Version) -> desc = Desc} <- Commands, not lists:member(internal, Tags)]. +-spec list_commands(integer(), map()) -> [{atom(), [aterm()], string()}]. + +list_commands(Version, CallerInfo) -> + lists:filter( + fun({Name, _Args, _Desc}) -> + allow == ejabberd_access_permissions:can_access(Name, CallerInfo) + end, + list_commands(Version) + ). + -spec get_command_format(atom()) -> {[aterm()], [{atom(),atom()}], rterm()}. get_command_format(Name) -> diff --git a/src/mod_adhoc_api.erl b/src/mod_adhoc_api.erl new file mode 100644 index 00000000000..397f9be6c1b --- /dev/null +++ b/src/mod_adhoc_api.erl @@ -0,0 +1,729 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_adhoc_api.erl +%%% Author : Badlop +%%% Purpose : Frontend for ejabberd API Commands via XEP-0050 Ad-Hoc Commands +%%% Created : 21 Feb 2025 by Badlop +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2025 ProcessOne +%%% +%%% 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 Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- + +%%%% definitions +%% @format-begin + +-module(mod_adhoc_api). + +-behaviour(gen_mod). + +-author('badlop@process-one.net'). + +%% gen_mod callbacks +-export([start/2, stop/1, reload/3, mod_opt_type/1, mod_options/1, depends/2, mod_doc/0]). +%% hooks +-export([adhoc_local_commands/4, adhoc_local_items/4, disco_local_features/5, + disco_local_identity/5, disco_local_items/5]). + +-include("ejabberd_commands.hrl"). +-include("ejabberd_sm.hrl"). +-include("logger.hrl"). +-include("translate.hrl"). + +-include_lib("stdlib/include/ms_transform.hrl"). +-include_lib("xmpp/include/xmpp.hrl"). + +-define(DEFAULT_API_VERSION, 1000000). + +%%%================================== +%%%% gen_mod + +start(_Host, _Opts) -> + {ok, + [{hook, adhoc_local_commands, adhoc_local_commands, 40}, + {hook, adhoc_local_items, adhoc_local_items, 40}, + {hook, disco_local_features, disco_local_features, 40}, + {hook, disco_local_identity, disco_local_identity, 40}, + {hook, disco_local_items, disco_local_items, 40}]}. + +stop(_Host) -> + ok. + +reload(_Host, _NewOpts, _OldOpts) -> + ok. + +mod_opt_type(default_version) -> + econf:either( + econf:int(0, 3), + econf:and_then( + econf:binary(), + fun(Binary) -> + case binary_to_list(Binary) of + F when F >= "24.06" -> + 2; + F when (F > "23.10") and (F < "24.06") -> + 1; + F when F =< "23.10" -> + 0 + end + end)). + +-spec mod_options(binary()) -> [{default_version, integer()}]. +mod_options(_) -> + [{default_version, ?DEFAULT_API_VERSION}]. + +depends(_Host, _Opts) -> + [{mod_adhoc, hard}, {mod_last, soft}]. + +mod_doc() -> + #{desc => + ?T("Execute https://docs.ejabberd.im/developer/ejabberd-api/[API Commands] " + "in a XMPP client using " + "https://xmpp.org/extensions/xep-0050.html[XEP-0050:%20Ad-Hoc%20Commands]." + "This module requires _`mod_adhoc`_ (to execute the commands), " + "and recommends _`mod_disco`_ (to discover the commands)."), + note => "added in 25.xx", + opts => + [{default_version, + #{value => "integer() | string()", + desc => + ?T("What API version to use. " + "If setting an ejabberd version, it will use the latest API " + "version that was available in that ejabberd version. " + "For example, setting '\"24.06\"' in this option implies '2'. " + "The default value is the latest version.")}}], + example => + ["acl:", + " admin:", + " user: jan@localhost", + "", + "api_permissions:", + " \"adhoc commands\":", + " from: mod_adhoc_api", + " who: admin", + " what:", + " - \"[tag:roster]\"", + " - \"[tag:session]\"", + " - stats", + " - status", + "", + "modules:", + " mod_adhoc_api:", + " default_version: 2"]}. + +%%%================================== +%%%% Ad-Hoc Commands (copied from mod_configure) + +-define(INFO_IDENTITY(Category, Type, Name, Lang), + [#identity{category = Category, + type = Type, + name = tr(Lang, Name)}]). +-define(INFO_COMMAND(Name, Lang), + ?INFO_IDENTITY(<<"automation">>, <<"command-node">>, Name, Lang)). +-define(NODE(Name, Node), + #disco_item{jid = jid:make(Server), + node = Node, + name = tr(Lang, Name)}). + +-spec tokenize(binary()) -> [binary()]. +tokenize(Node) -> + str:tokens(Node, <<"/#">>). + +-spec tr(binary(), binary()) -> binary(). +tr(Lang, Text) -> + translate:translate(Lang, Text). + +%%%================================== +%%%% - disco identity + +-spec disco_local_identity([identity()], jid(), jid(), binary(), binary()) -> + [identity()]. +disco_local_identity(Acc, _From, #jid{lserver = LServer} = _To, Node, Lang) -> + case tokenize(Node) of + [<<"api-commands">>] -> + ?INFO_COMMAND(?T("API Commands"), Lang); + [<<"api-commands">>, CommandName] -> + ?INFO_COMMAND(get_api_command_desc(CommandName, LServer), Lang); + _ -> + Acc + end. + +get_api_command_desc(NameAtom, Host) -> + iolist_to_binary((get_api_command(NameAtom, Host))#ejabberd_commands.desc). + +%%%================================== +%%%% - disco features + +-spec disco_local_features(mod_disco:features_acc(), jid(), jid(), binary(), binary()) -> + mod_disco:features_acc(). +disco_local_features(Acc, _From, #jid{lserver = LServer} = _To, Node, _Lang) -> + case gen_mod:is_loaded(LServer, mod_adhoc) of + false -> + Acc; + _ -> + case tokenize(Node) of + [<<"api-commands">>] -> + {result, []}; + [<<"api-commands">>, _] -> + {result, [?NS_COMMANDS]}; + _ -> + Acc + end + end. + +%%%================================== +%%%% - adhoc items + +-spec adhoc_local_items(mod_disco:items_acc(), jid(), jid(), binary()) -> + mod_disco:items_acc(). +adhoc_local_items(Acc, From, #jid{lserver = LServer, server = Server} = To, Lang) -> + Items = + case Acc of + {result, Its} -> + Its; + empty -> + [] + end, + Nodes = recursively_get_local_items(From, global, LServer, <<"">>, Server, Lang), + Nodes1 = + lists:filter(fun(#disco_item{node = Nd}) -> + F = disco_local_features(empty, From, To, Nd, Lang), + case F of + {result, [?NS_COMMANDS]} -> + true; + _ -> + false + end + end, + Nodes), + {result, Items ++ Nodes1}. + +-spec recursively_get_local_items(jid(), + global | vhost, + binary(), + binary(), + binary(), + binary()) -> + [disco_item()]. +recursively_get_local_items(From, PermLev, LServer, Node, Server, Lang) -> + Items = + case get_local_items2(From, {PermLev, LServer}, tokenize(Node), Server, Lang) of + {result, Res} -> + Res; + {error, _Error} -> + [] + end, + lists:flatten( + lists:map(fun(#disco_item{jid = #jid{server = S}, node = Nd} = Item) -> + if (S /= Server) or (Nd == <<"">>) -> + []; + true -> + [Item, + recursively_get_local_items(From, PermLev, LServer, Nd, Server, Lang)] + end + end, + Items)). + +%%%================================== +%%%% - disco items + +-spec disco_local_items(mod_disco:items_acc(), jid(), jid(), binary(), binary()) -> + mod_disco:items_acc(). +disco_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) -> + case gen_mod:is_loaded(LServer, mod_adhoc) of + false -> + Acc; + _ -> + Items = + case Acc of + {result, Its} -> + Its; + empty -> + []; + Other -> + Other + end, + case tokenize(Node) of + LNode when (LNode == [<<"api-commands">>]) or (LNode == []) -> + case get_local_items2(From, {global, LServer}, LNode, jid:encode(To), Lang) of + {result, Res} -> + {result, Res}; + {error, Error} -> + {error, Error} + end; + _ -> + {result, Items} + end + end. + +%%%================================== +%%%% - get_local_items2 + +-spec get_local_items2(jid(), + {global | vhost, binary()}, + [binary()], + binary(), + binary()) -> + {result, [disco_item()]} | {error, stanza_error()}. +get_local_items2(_From, _Host, [], Server, Lang) -> + {result, [?NODE(?T("API Commands"), <<"api-commands">>)]}; +get_local_items2(From, {_, Host}, [<<"api-commands">>], _Server, Lang) -> + {result, get_api_commands(From, Host, Lang)}; +get_local_items2(_From, {_, _Host}, [<<"api-commands">>, _], _Server, _Lang) -> + {result, []}; +get_local_items2(_From, _Host, _, _Server, _Lang) -> + {error, xmpp:err_item_not_found()}. + +-spec get_api_commands(jid(), binary(), binary()) -> [disco_item()]. +get_api_commands(From, Server, Lang) -> + ApiVersion = mod_adhoc_api_opt:default_version(Server), + lists:map(fun({Name, _Args, _Desc}) -> + NameBin = list_to_binary(atom_to_list(Name)), + ?NODE(NameBin, <<"api-commands/", NameBin/binary>>) + end, + ejabberd_commands:list_commands(ApiVersion, get_caller_info(From))). + +%%%================================== +%%%% - adhoc commands + +-define(COMMANDS_RESULT(LServerOrGlobal, From, To, Request, Lang), + adhoc_local_commands(From, To, Request)). + +-spec adhoc_local_commands(adhoc_command(), jid(), jid(), adhoc_command()) -> + adhoc_command() | {error, stanza_error()}. +adhoc_local_commands(Acc, From, To, #adhoc_command{node = Node} = Request) -> + case tokenize(Node) of + [<<"api-commands">>, _CommandName] -> + ?COMMANDS_RESULT(LServer, From, To, Request, Lang); + _ -> + Acc + end. + +-spec adhoc_local_commands(jid(), jid(), adhoc_command()) -> + adhoc_command() | {error, stanza_error()}. +adhoc_local_commands(From, + #jid{lserver = LServer} = _To, + #adhoc_command{lang = Lang, + node = Node, + sid = SessionID, + action = Action, + xdata = XData} = + Request) -> + LNode = tokenize(Node), + ActionIsExecute = Action == execute orelse Action == complete, + if Action == cancel -> + #adhoc_command{status = canceled, + lang = Lang, + node = Node, + sid = SessionID}; + XData == undefined, ActionIsExecute -> + case get_form(LServer, LNode, Lang) of + {result, Form} -> + xmpp_util:make_adhoc_response(Request, + #adhoc_command{status = executing, xdata = Form}); + {error, Error} -> + {error, Error} + end; + XData /= undefined, ActionIsExecute -> + case set_form(From, LServer, LNode, Lang, XData) of + {result, Res} -> + xmpp_util:make_adhoc_response(Request, + #adhoc_command{xdata = Res, status = completed}); + %%{'EXIT', _} -> {error, xmpp:err_bad_request()}; + {error, Error} -> + {error, Error} + end; + true -> + {error, xmpp:err_bad_request(?T("Unexpected action"), Lang)} + end. + +-spec get_form(binary(), [binary()], binary()) -> + {result, xdata()} | {error, stanza_error()}. +get_form(Host, [<<"api-commands">>, CommandName], Lang) -> + get_form_api_command(CommandName, Host, Lang); +get_form(_Host, _, _Lang) -> + {error, xmpp:err_service_unavailable()}. + +-spec set_form(jid(), binary(), [binary()], binary(), xdata()) -> + {result, xdata() | undefined} | {error, stanza_error()}. +set_form(From, Host, [<<"api-commands">>, Command], Lang, XData) -> + set_form_api_command(From, Host, Command, XData, Lang); +set_form(_From, _Host, _, _Lang, _XData) -> + {error, xmpp:err_service_unavailable()}. + +%%%================================== +%%%% API Commands + +get_api_command(Name, Host) when is_binary(Name) -> + get_api_command(binary_to_existing_atom(Name, latin1), Host); +get_api_command(Name, Host) when is_atom(Name) -> + ApiVersion = mod_adhoc_api_opt:default_version(Host), + ejabberd_commands:get_command_definition(Name, ApiVersion). + +get_caller_info(#jid{user = User, server = Server} = From) -> + #{tag => <<>>, + usr => {User, Server, <<"">>}, + caller_server => Server, + ip => get_ip_address(From), + caller_module => ?MODULE}. + +get_ip_address(#jid{user = User, + server = Server, + resource = Resource}) -> + case ejabberd_sm:get_user_ip(User, Server, Resource) of + {IP, _Port} when is_tuple(IP) -> + IP; + _ -> + error_ip_address + end. + +%%%================================== +%%%% - get form + +get_form_api_command(NameBin, Host, _Lang) -> + Def = get_api_command(NameBin, Host), + Title = list_to_binary(atom_to_list(Def#ejabberd_commands.name)), + Instructions = get_instructions(Def), + FieldsArgs = + build_fields(Def#ejabberd_commands.args, + Def#ejabberd_commands.args_desc, + Def#ejabberd_commands.args_example, + Def#ejabberd_commands.policy, + get_replacements(Host), + true), + FieldsArgsWithHeads = + case FieldsArgs of + [] -> + []; + _ -> + [#xdata_field{type = fixed, label = ?T("Arguments")} | FieldsArgs] + end, + NodeFields = build_node_fields(), + {result, + #xdata{title = Title, + type = form, + instructions = Instructions, + fields = FieldsArgsWithHeads ++ NodeFields}}. + +get_replacements(Host) -> + [{user, <<"">>}, + {localuser, <<"">>}, + {host, Host}, + {localhost, Host}, + {password, <<"">>}, + {newpass, <<"">>}, + {service, mod_muc_admin:find_hosts(Host)}]. + +build_node_fields() -> + build_node_fields([node() | nodes()]). + +build_node_fields([_ThisNode]) -> + []; +build_node_fields(AtomNodes) -> + [ThisNode | _] = Nodes = [atom_to_binary(Atom, latin1) || Atom <- AtomNodes], + Options = [#xdata_option{label = N, value = N} || N <- Nodes], + [#xdata_field{type = fixed, label = ?T("Clustering")}, + #xdata_field{type = 'list-single', + label = <<"ejabberd node">>, + var = <<"mod_adhoc_api_target_node">>, + values = [ThisNode], + options = Options}]. + +%%%================================== +%%%% - set form + +set_form_api_command(From, Host, CommandNameBin, XData, _Lang) -> + %% Description + Def = get_api_command(CommandNameBin, Host), + Title = list_to_binary(atom_to_list(Def#ejabberd_commands.name)), + Instructions = get_instructions(Def), + + %% Arguments + FieldsArgs1 = [Field || Field <- XData#xdata.fields, Field#xdata_field.type /= fixed], + + {Node, FieldsArgs} = + case lists:keytake(<<"mod_adhoc_api_target_node">>, #xdata_field.var, FieldsArgs1) of + {value, #xdata_field{values = [TargetNode]}, FAs} -> + {binary_to_existing_atom(TargetNode, latin1), FAs}; + false -> + {node(), FieldsArgs1} + end, + + FieldsArgsWithHeads = + case FieldsArgs of + [] -> + []; + _ -> + [#xdata_field{type = fixed, label = ?T("Arguments")} | FieldsArgs] + end, + + %% Execute + Arguments = api_extract_fields(FieldsArgs, Def#ejabberd_commands.args), + ApiVersion = mod_adhoc_api_opt:default_version(Host), + CallResult = + ejabberd_cluster:call(Node, + mod_http_api, + handle, + [binary_to_existing_atom(CommandNameBin, latin1), + get_caller_info(From), + Arguments, + ApiVersion]), + + %% Command result + FieldsResult2 = + case CallResult of + {200, RR} -> + build_fields([Def#ejabberd_commands.result], + [Def#ejabberd_commands.result_desc], + [RR], + restricted, + [{host, Host}], + false); + {Code, _ApiErrorCode, MessageBin} -> + [#xdata_field{type = 'text-single', + label = <<"Error ", (integer_to_binary(Code))/binary>>, + values = encode(MessageBin, irrelevat_type), + var = <<"error">>}]; + {Code, MessageBin} -> + [#xdata_field{type = 'text-single', + label = <<"Error ", (integer_to_binary(Code))/binary>>, + values = encode(MessageBin, irrelevat_type), + var = <<"error">>}] + end, + FieldsResultWithHeads = + [#xdata_field{type = fixed, label = ?T("")}, + #xdata_field{type = fixed, label = ?T("Result")} + | FieldsResult2], + + %% Result stanza + {result, + #xdata{title = Title, + type = result, + instructions = Instructions, + fields = FieldsArgsWithHeads ++ FieldsResultWithHeads}}. + +api_extract_fields(Fields, ArgsDef) -> + lists:map(fun(#xdata_field{values = Values, var = ANameBin}) -> + ArgDef = proplists:get_value(binary_to_existing_atom(ANameBin, latin1), ArgsDef), + V = case {Values, ArgDef} of + {Values, {list, {_ElementName, {tuple, ElementsDef}}}} -> + [parse_tuple(ElementsDef, Value) || Value <- Values]; + {[Value], {tuple, ElementsDef}} -> + parse_tuple(ElementsDef, Value); + {[Value], _} -> + Value; + _ -> + Values + end, + {ANameBin, V} + end, + Fields). + +parse_tuple(ElementsDef, Value) -> + Values = str:tokens(Value, <<":">>), + List1 = + [{atom_to_binary(Name, latin1), Val} + || {{Name, _Type}, Val} <- lists:zip(ElementsDef, Values)], + maps:from_list(List1). + +%%%================================== +%%%% - get instructions + +get_instructions(Def) -> + Note2 = + case Def#ejabberd_commands.note of + [] -> + []; + Note -> + N = iolist_to_binary(Note), + [<<"Note: ", N/binary>>] + end, + Tags2 = + case Def#ejabberd_commands.tags of + [] -> + []; + Tags -> + T = str:join([atom_to_binary(Tag, latin1) || Tag <- Tags], <<", ">>), + [<<"Tags: ", T/binary>>] + end, + Module2 = + case Def#ejabberd_commands.definer of + unknown -> + []; + DefinerAtom -> + D = atom_to_binary(DefinerAtom, latin1), + [<<"Module: ", D/binary>>] + end, + Version2 = + case Def#ejabberd_commands.version of + 0 -> + []; + Version -> + V = integer_to_binary(Version), + [<<"API version: ", V/binary>>] + end, + get_instructions2([Def#ejabberd_commands.desc, Def#ejabberd_commands.longdesc] + ++ Note2 + ++ Tags2 + ++ Module2 + ++ Version2). + +get_instructions2(ListStrings) -> + [re:replace(String, "[\t]*[ ]+", " ", [{return, binary}, global]) + || String <- ListStrings, String /= ""]. + +%%%================================== +%%%% - build fields + +build_fields(NameTypes, none, Examples, Policy, Replacements, Required) -> + build_fields(NameTypes, [], Examples, Policy, Replacements, Required); +build_fields(NameTypes, Descs, none, Policy, Replacements, Required) -> + build_fields(NameTypes, Descs, [], Policy, Replacements, Required); +build_fields(NameTypes, [none], Examples, Policy, Replacements, Required) -> + build_fields(NameTypes, [], Examples, Policy, Replacements, Required); +build_fields(NameTypes, Descs, [none], Policy, Replacements, Required) -> + build_fields(NameTypes, Descs, [], Policy, Replacements, Required); +build_fields(NameTypes, Descs, Examples, Policy, Replacements, Required) -> + {NameTypes2, Descs2, Examples2} = + case Policy of + user -> + {[{user, binary}, {host, binary} | NameTypes], + ["Username", "Server host" | Descs], + ["tom", "example.com" | Examples]}; + _ -> + {NameTypes, Descs, Examples} + end, + build_fields2(NameTypes2, Descs2, Examples2, Replacements, Required). + +build_fields2([{_ArgName, {list, _ArgNameType}}] = NameTypes, + Descs, + Examples, + _Replacements, + Required) -> + Args = lists_zip3_pad(NameTypes, Descs, Examples), + lists:map(fun({{AName, AType}, ADesc, AExample}) -> + ANameBin = list_to_binary(atom_to_list(AName)), + #xdata_field{type = 'text-multi', + label = ANameBin, + desc = list_to_binary(ADesc), + values = encode(AExample, AType), + required = Required, + var = ANameBin} + end, + Args); +build_fields2(NameTypes, Descs, Examples, Replacements, Required) -> + Args = lists_zip3_pad(NameTypes, Descs, Examples), + lists:map(fun({{AName, AType}, ADesc, AExample}) -> + ANameBin = list_to_binary(atom_to_list(AName)), + AValue = proplists:get_value(AName, Replacements, AExample), + Values = encode(AValue, AType), + Type = + case {AType, Values} of + {{list, _}, _} -> + 'text-multi'; + {string, [_, _ | _]} -> + 'text-multi'; + _ -> + 'text-single' + end, + #xdata_field{type = Type, + label = ANameBin, + desc = make_desc(ADesc, AValue), + values = Values, + required = Required, + var = ANameBin} + end, + Args). + +-ifdef(OTP_BELOW_26). + +lists_zip3_pad(As, Bs, Cs) -> + lists_zip3_pad(As, Bs, Cs, []). + +lists_zip3_pad([A | As], [B | Bs], [C | Cs], Xs) -> + lists_zip3_pad(As, Bs, Cs, [{A, B, C} | Xs]); +lists_zip3_pad([A | As], [B | Bs], Nil, Xs) when (Nil == none) or (Nil == []) -> + lists_zip3_pad(As, Bs, [], [{A, B, ""} | Xs]); +lists_zip3_pad([A | As], Nil, [C | Cs], Xs) when (Nil == none) or (Nil == []) -> + lists_zip3_pad(As, [], Cs, [{A, "", C} | Xs]); +lists_zip3_pad([A | As], Nil, Nil, Xs) when (Nil == none) or (Nil == []) -> + lists_zip3_pad(As, [], [], [{A, "", ""} | Xs]); +lists_zip3_pad([], Nil, Nil, Xs) when (Nil == none) or (Nil == []) -> + lists:reverse(Xs). + +-else. + +lists_zip3_pad(As, Bs, Cs) -> + lists:zip3(As, Bs, Cs, {pad, {error_missing_args_def, "", ""}}). + +-endif. + +make_desc(ADesc, T) when is_tuple(T) -> + T3 = string:join(tuple_to_list(T), " : "), + iolist_to_binary([ADesc, " {", T3, "}"]); +make_desc(ADesc, M) when is_map(M) -> + M2 = [binary_to_list(V) || V <- maps:keys(M)], + M3 = string:join(M2, " : "), + iolist_to_binary([ADesc, " {", M3, "}"]); +make_desc(ADesc, _M) -> + iolist_to_binary(ADesc). + +%%%================================== +%%%% - encode + +encode({[T | _] = List}, Type) when is_tuple(T) -> + encode(List, Type); +encode([T | _] = List, Type) when is_tuple(T) -> + [encode(Element, Type) || Element <- List]; +encode(T, _Type) when is_tuple(T) -> + T2 = [x_to_binary(E) || E <- tuple_to_list(T)], + T3 = str:join(T2, <<":">>), + [T3]; +encode(M, {tuple, Types}) when is_map(M) -> + M2 = [x_to_list(maps:get(atom_to_binary(Key, latin1), M)) + || {Key, _ElementType} <- Types], + M3 = string:join(M2, " : "), + [iolist_to_binary(M3)]; +encode([S | _] = SList, _Type) when is_list(S) -> + [iolist_to_binary(A) || A <- SList]; +encode([B | _] = BList, _Type) when is_binary(B) -> + BList; +encode(I, _Type) when is_integer(I) -> + [integer_to_binary(I)]; +encode([M | _] = List, {list, {_Name, TupleType}}) when is_map(M) -> + [encode(M1, TupleType) || M1 <- List]; +encode(S, _Type) when is_list(S) -> + [iolist_to_binary(S)]; +encode(B, _Type) when is_binary(B) -> + str:tokens(B, <<"\n">>). + +x_to_list(B) when is_binary(B) -> + binary_to_list(B); +x_to_list(I) when is_integer(I) -> + integer_to_list(I); +x_to_list(L) when is_list(L) -> + L. + +x_to_binary(B) when is_binary(B) -> + B; +x_to_binary(I) when is_integer(I) -> + integer_to_binary(I); +x_to_binary(L) when is_list(L) -> + iolist_to_binary(L). + +%%%================================== + +%%% vim: set foldmethod=marker foldmarker=%%%%,%%%=: diff --git a/src/mod_adhoc_api_opt.erl b/src/mod_adhoc_api_opt.erl new file mode 100644 index 00000000000..bd7cdce42e2 --- /dev/null +++ b/src/mod_adhoc_api_opt.erl @@ -0,0 +1,13 @@ +%% Generated automatically +%% DO NOT EDIT: run `make options` instead + +-module(mod_adhoc_api_opt). + +-export([default_version/1]). + +-spec default_version(gen_mod:opts() | global | binary()) -> integer(). +default_version(Opts) when is_map(Opts) -> + gen_mod:get_opt(default_version, Opts); +default_version(Host) -> + gen_mod:get_module_opt(Host, mod_adhoc_api, default_version). + diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index f5c9b3c2a5d..68d5c4181f6 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -30,7 +30,7 @@ -behaviour(gen_mod). -export([start/2, stop/1, reload/3, process/2, depends/2, - format_arg/2, + format_arg/2, handle/4, mod_opt_type/1, mod_options/1, mod_doc/0]). -include_lib("xmpp/include/xmpp.hrl"). @@ -353,6 +353,9 @@ format_arg(Elements, || Element <- Elements]; %% Covered by command_test_list and command_test_list_tuple +format_arg(Element, {list, Def}) + when not is_list(Element) -> + format_arg([Element], {list, Def}); format_arg(Elements, {list, {_ElementDefName, ElementDefFormat}}) when is_list(Elements) -> @@ -395,6 +398,7 @@ format_arg(Elements, {list, ElementsDef}) || Element <- Elements]; format_arg(Arg, integer) when is_integer(Arg) -> Arg; +format_arg(Arg, integer) when is_binary(Arg) -> binary_to_integer(Arg); format_arg(Arg, binary) when is_list(Arg) -> process_unicode_codepoints(Arg); format_arg(Arg, binary) when is_binary(Arg) -> Arg; format_arg(Arg, string) when is_list(Arg) -> Arg; @@ -460,6 +464,9 @@ format_result([String | _] = StringList, {Name, string}) when is_list(String) -> format_result(String, {Name, string}) -> {misc:atom_to_binary(Name), iolist_to_binary(String)}; +format_result(Binary, {Name, binary}) -> + {misc:atom_to_binary(Name), Binary}; + format_result(Code, {Name, rescode}) -> {misc:atom_to_binary(Name), Code == true orelse Code == ok}; diff --git a/test/commands_tests.erl b/test/commands_tests.erl index a1c60c5e492..7b0675c3f02 100644 --- a/test/commands_tests.erl +++ b/test/commands_tests.erl @@ -23,8 +23,6 @@ %%%% definitions -%% @format-begin - -module(commands_tests). -compile(export_all). @@ -56,10 +54,29 @@ single_cases() -> single_test(http_tuple), single_test(http_list_tuple), single_test(http_list_tuple_map), + single_test(adhoc_list_commands), + single_test(adhoc_apiversion), + single_test(adhoc_apizero), + single_test(adhoc_apione), + single_test(adhoc_integer), + single_test(adhoc_string), + single_test(adhoc_binary), + single_test(adhoc_tuple), + single_test(adhoc_list), + single_test(adhoc_list_tuple), + single_test(adhoc_atom), + single_test(adhoc_rescode), + single_test(adhoc_restuple), + %%single_test(adhoc_all), single_test(clean)]}. -endif. +%% @format-begin + +single_test(T) -> + list_to_atom("commands_" ++ atom_to_list(T)). + setup(_Config) -> M = <<"mod_example">>, clean(_Config), @@ -90,6 +107,9 @@ ejabberdctl(_Config) -> Installed = execute(modules_installed, []), ?match(true, lists:keymember(mod_example, 1, Installed)). +execute(Name, Args) -> + ejabberd_commands:execute_command2(Name, Args, #{caller_module => ejabberd_ctl}, 1000000). + %%%================================== %%%% mod_http_api @@ -165,19 +185,7 @@ http_list_tuple_map(Config) -> #{<<"element1">> => <<"three">>, <<"element2">> => <<"tres">>}]), ?match(LTB, lists:sort(query(Config, "command_test_list_tuple", #{arg_list => LTA}))). -%%%================================== -%%%% internal functions - -single_test(T) -> - list_to_atom("commands_" ++ atom_to_list(T)). - -execute(Name, Args) -> - ejabberd_commands:execute_command2(Name, Args, #{caller_module => ejabberd_ctl}, 1000000). - -page(Config, Tail) -> - Server = ?config(server_host, Config), - Port = ct:get_config(web_port, 5280), - "http://" ++ Server ++ ":" ++ integer_to_list(Port) ++ "/api/" ++ Tail. +%%% internal functions query(Config, Tail, Map) -> BodyQ = misc:json_encode(Map), @@ -192,6 +200,248 @@ make_query(Config, Tail, BodyQ) -> [{body_format, binary}]), Body). +page(Config, Tail) -> + Server = ?config(server_host, Config), + Port = ct:get_config(web_port, 5280), + "http://" ++ Server ++ ":" ++ integer_to_list(Port) ++ "/api/" ++ Tail. + +%%%================================== +%%%% ad-hoc + +%%% list commands + +adhoc_list_commands(Config) -> + {ok, Result} = get_items(Config, <<"api-commands">>), + {value, #disco_item{name = <<"command_test_binary">>}} = + lists:keysearch(<<"command_test_binary">>, #disco_item.name, Result), + suite:disconnect(Config). + +get_items(Config, Node) -> + case suite:send_recv(Config, + #iq{type = get, + to = server_jid(Config), + sub_els = [#disco_items{node = Node}]}) + of + #iq{type = result, sub_els = [#disco_items{node = Node, items = Items}]} -> + {ok, Items}; + #iq{type = result, sub_els = []} -> + {empty, []}; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +%%% apiversion + +adhoc_apiversion(Config) -> + Node = <<"api-commands/command_test_apiversion">>, + ArgFields = make_fields_args([]), + ResFields = make_fields_res([{<<"apiversion">>, <<"2">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% apizero + +adhoc_apizero(Config) -> + Node = <<"api-commands/command_test_apizero">>, + ArgFields = make_fields_args([]), + ResFields = make_fields_res([{<<"apiversion">>, <<"0">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% apione + +adhoc_apione(Config) -> + Node = <<"api-commands/command_test_apione">>, + ArgFields = make_fields_args([]), + ResFields = make_fields_res([{<<"apiversion">>, <<"1">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% integer + +adhoc_integer(Config) -> + Node = <<"api-commands/command_test_integer">>, + ArgFields = make_fields_args([{<<"arg_integer">>, <<"12345">>}]), + ResFields = make_fields_res([{<<"res_integer">>, <<"12345">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% string + +adhoc_string(Config) -> + Node = <<"api-commands/command_test_string">>, + ArgFields = make_fields_args([{<<"arg_string">>, <<"Some string.">>}]), + ResFields = make_fields_res([{<<"res_string">>, <<"Some string.">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% binary + +adhoc_binary(Config) -> + Node = <<"api-commands/command_test_binary">>, + ArgFields = make_fields_args([{<<"arg_binary">>, <<"Some binary.">>}]), + ResFields = make_fields_res([{<<"res_string">>, <<"Some binary.">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% tuple + +adhoc_tuple(Config) -> + Node = <<"api-commands/command_test_tuple">>, + ArgFields = make_fields_args([{<<"arg_tuple">>, <<"one:two:three">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, + [{xdata_field, + <<"res_tuple">>, + 'text-single', + <<"res_tuple">>, + false, + <<" {element1 : element2 : element3}">>, + [<<"one : two : three">>], + [], + []}]}, + set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% list + +adhoc_list(Config) -> + Node = <<"api-commands/command_test_list">>, + ArgFields = make_fields_args([{<<"arg_list">>, [<<"one">>, <<"first">>, <<"primary">>]}]), + ResFields = + make_fields_res([{<<"res_list">>, lists:sort([<<"one">>, <<"first">>, <<"primary">>])}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% list_tuple + +adhoc_list_tuple(Config) -> + Node = <<"api-commands/command_test_list_tuple">>, + ArgFields = + make_fields_args([{<<"arg_list">>, [<<"one:uno">>, <<"two:dos">>, <<"three:tres">>]}]), + ResFields = + make_fields_res([{<<"res_list">>, + lists:sort([<<"one : uno">>, <<"two : dos">>, <<"three : tres">>])}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% atom + +adhoc_atom(Config) -> + Node = <<"api-commands/command_test_atom">>, + ArgFields = make_fields_args([{<<"arg_string">>, <<"a_test_atom">>}]), + ResFields = make_fields_res([{<<"res_atom">>, <<"a_test_atom">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% rescode + +adhoc_rescode(Config) -> + Node = <<"api-commands/command_test_rescode">>, + ArgFields = make_fields_args([{<<"code">>, <<"ok">>}]), + ResFields = make_fields_res([{<<"res_atom">>, <<"0">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% restuple + +adhoc_restuple(Config) -> + Node = <<"api-commands/command_test_restuple">>, + ArgFields = + make_fields_args([{<<"code">>, <<"ok">>}, {<<"text">>, <<"Just a result text">>}]), + ResFields = make_fields_res([{<<"res_atom">>, <<"Just a result text">>}]), + {ok, Sid, _FormFields} = get_form(Config, Node), + ?match({ok, ResFields}, set_form(Config, Node, Sid, ArgFields)), + suite:disconnect(Config). + +%%% internal functions + +server_jid(Config) -> + jid:make(<<>>, ?config(server, Config), <<>>). + +make_fields_args(Fields) -> + lists:map(fun ({Var, Values}) when is_list(Values) -> + #xdata_field{label = Var, + var = Var, + required = true, + type = 'text-multi', + values = Values}; + ({Var, Value}) -> + #xdata_field{label = Var, + var = Var, + required = true, + type = 'text-single', + values = [Value]} + end, + Fields). + +make_fields_res(Fields) -> + lists:map(fun ({Var, Values}) when is_list(Values) -> + #xdata_field{label = Var, + var = Var, + type = 'text-multi', + values = Values}; + ({Var, Value}) -> + #xdata_field{label = Var, + var = Var, + type = 'text-single', + values = [Value]} + end, + Fields). + +get_form(Config, Node) -> + case suite:send_recv(Config, + #iq{type = set, + to = server_jid(Config), + sub_els = [#adhoc_command{node = Node}]}) + of + #iq{type = result, + sub_els = + [#adhoc_command{node = Node, + action = execute, + status = executing, + sid = Sid, + actions = #adhoc_actions{execute = complete, complete = true}, + xdata = #xdata{fields = Fields}}]} -> + {ok, Sid, [F || F <- Fields, F#xdata_field.type /= fixed]}; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + +set_form(Config, Node, Sid, ArgFields) -> + Xdata = #xdata{type = submit, fields = ArgFields}, + case suite:send_recv(Config, + #iq{type = set, + to = server_jid(Config), + sub_els = + [#adhoc_command{node = Node, + action = complete, + sid = Sid, + xdata = Xdata}]}) + of + #iq{type = result, + sub_els = + [#adhoc_command{node = Node, + action = execute, + status = completed, + sid = Sid, + xdata = #xdata{fields = ResFields}}]} -> + ResFields2 = [F || F <- ResFields, F#xdata_field.type /= fixed], + {ok, ResFields2 -- ArgFields}; + #iq{type = error} = Err -> + xmpp:get_error(Err) + end. + %%%================================== %%% vim: set foldmethod=marker foldmarker=%%%%,%%%=: diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index e3aa43c3d40..0abc35c2a99 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -111,6 +111,7 @@ max_fsm_queue: 1000 queue_type: file modules: mod_adhoc: [] + mod_adhoc_api: [] mod_admin_extra: [] mod_admin_update_sql: [] mod_announce: [] From 9bf2d6ce5bea39734599e00df308aa83ae6af3e6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Mar 2025 20:11:36 +0100 Subject: [PATCH 133/170] mod_configure: Document available alternative API commands --- src/mod_configure.erl | 47 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 08380a16ab3..8e4c8840573 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1546,14 +1546,49 @@ mod_options(_Host) -> %% @format-begin +%% All ad-hoc commands implemented by mod_configure are available as API Commands: +%% - add-user -> register +%% - delete-user -> unregister +%% - end-user-session -> kick_session / kick_user +%% - change-user-password -> change_password +%% - get-user-lastlogin -> get_last +%% - user-stats -> user_sessions_info +%% - get-registered-users-list -> registered_users +%% - get-registered-users-num -> stats +%% - get-online-users-list -> connected_users +%% - get-online-users-num -> stats +%% - stopped nodes -> list_cluster_detailed +%% - DB -> mnesia_list_tables and mnesia_table_change_storage +%% - restart -> stop_kindly / restart +%% - shutdown -> stop_kindly +%% - backup -> backup +%% - restore -> restore +%% - textfile -> dump +%% - import/file -> import_file +%% - import/dir -> import_dir +%% +%% An exclusive feature available only in this module is to list items and discover them: +%% - outgoing s2s +%% - online users +%% - all users + mod_doc() -> #{desc => - ?T("The module provides server configuration functionality via " - "https://xmpp.org/extensions/xep-0050.html[XEP-0050:%20Ad-Hoc%20Commands]." - "It also implements many commands as defined in " - "https://xmpp.org/extensions/xep-0133.html[XEP-0133:%20Service%20Administration]." - "This module requires _`mod_adhoc`_ (to execute the commands), " - "and recommends _`mod_disco`_ (to discover the commands). "), + [?T("The module provides server configuration functionalities using " + "https://xmpp.org/extensions/xep-0030.html[XEP-0030:%20Service%20Discovery]%20and" + "https://xmpp.org/extensions/xep-0050.html[XEP-0050:%20Ad-Hoc%20Commands]:"), + "", + "- List and discover outgoing s2s, online client sessions and all registered accounts", + "- Most of the ad-hoc commands defined in https://xmpp.org/extensions/xep-0133.html[XEP-0133: Service Administration]", + "- Additional custom ad-hoc commands specific to ejabberd", + "", + ?T("This module requires _`mod_adhoc`_ (to execute the commands), " + "and recommends _`mod_disco`_ (to discover the commands). "), + "", + ?T("Please notice that all the ad-hoc commands implemented by this module " + "have an equivalent " + "https://docs.ejabberd.im/developer/ejabberd-api/[API%20Command]" + "that you can execute using _`mod_adhoc_api`_ or any other API frontend.")], opts => [{access, #{value => ?T("AccessName"), From 6d8e588b78054f3b3fef31e88ba810f3457077e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 19 Mar 2025 10:40:49 +0100 Subject: [PATCH 134/170] Allows test to be run using ct_run --- test/ejabberd_SUITE.erl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index 0a9e73d4dfb..eb5f724f406 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -60,7 +60,11 @@ init_per_suite(Config) -> NewConfig. start_ejabberd(_) -> - application:set_env(ejabberd, external_beams, "../../lib/ejabberd/test/"), + TestBeams = case filelib:is_dir("../../test/") of + true -> "../../test/"; + _ -> "../../lib/ejabberd/test/" + end, + application:set_env(ejabberd, external_beams, TestBeams), {ok, _} = application:ensure_all_started(ejabberd, transient). end_per_suite(_Config) -> From 1668cde93fcf0f3a1a7360f3777ec6d15754d4e5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 18 Mar 2025 20:00:15 +0100 Subject: [PATCH 135/170] Update xmpp to get support for webchat_url (#3041) --- mix.exs | 2 +- mix.lock | 6 +++--- rebar.config | 2 +- rebar.lock | 16 ++++++++++------ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/mix.exs b/mix.exs index 3f63e90f896..dc42f28d4fa 100644 --- a/mix.exs +++ b/mix.exs @@ -130,7 +130,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp", ref: "e295055dd1cb3dafb4b3134bc7462a775ff16b5c", override: true}, + {:xmpp, git: "https://github.com/processone/xmpp", ref: "be24923968261c2661a9e116650dce5ac95c9d23", override: true}, {:yconf, git: "https://github.com/processone/yconf", ref: "9682a6025ed543eedf34637e4cfcc66837074af6", override: true}] ++ cond_deps() end diff --git a/mix.lock b/mix.lock index 2b1065bf837..e8ef48a9c8c 100644 --- a/mix.lock +++ b/mix.lock @@ -2,13 +2,13 @@ "base64url": {:hex, :base64url, "1.0.1", "f8c7f2da04ca9a5d0f5f50258f055e1d699f0e8bf4cfdb30b750865368403cf6", [:rebar3], [], "hexpm", "f9b3add4731a02a9b0410398b475b33e7566a695365237a6bdee1bb447719f5c"}, "cache_tab": {:hex, :cache_tab, "1.0.31", "e4097b50a6f373ab1e0a5f01bab0bef6626771a4cd6c93404ed6d54810e11fbc", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8582b60a4a09b247ef86355ba9e07fce9e11edc0345a775c9171f971c72b6351"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "eimp": {:hex, :eimp, "1.0.23", "aaf32efab061143403dadbaa63e699ef8e81702fbfa96fd436d5e9be4d6a8d3a", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "907c780023cb2893e4fc4bdbe6a4f02c355913862ac67f0ecc26605e816b628a"}, "epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"}, "eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"}, - "ex_doc": {:hex, :ex_doc, "0.37.2", "2a3aa7014094f0e4e286a82aa5194a34dd17057160988b8509b15aa6c292720c", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "4dfa56075ce4887e4e8b1dcc121cd5fcb0f02b00391fd367ff5336d98fa49049"}, + "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, "exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"}, "ezlib": {:hex, :ezlib, "1.0.13", "3c7f62862850a241159c10b218ecf580bce54d0890601b65144dacc2633be2b0", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "9ee62ab3f8ed55a0fd11a9569fcb8e458683f95575417272192b069f092abfbb"}, "fast_tls": {:hex, :fast_tls, "1.1.22", "44356b256afad4399c2fc5059a3066669dafd8bd4e4e796c9c1cf8910ddd265e", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e65779aefb7ab15c4755230fef8077e687d20cc5a3984a5974f9f657e8e2485b"}, @@ -34,6 +34,6 @@ "stringprep": {:hex, :stringprep, "1.0.31", "fa1688c156dd271722aa18c423a4163e710d2f4f475ad0bc220910df669b53af", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e9699c88e8db16b3a41f0e45ac6874a4da81a6e4854a77d76ede6d09b08e3530"}, "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:git, "https://github.com/processone/xmpp", "e295055dd1cb3dafb4b3134bc7462a775ff16b5c", [ref: "e295055dd1cb3dafb4b3134bc7462a775ff16b5c"]}, + "xmpp": {:git, "https://github.com/processone/xmpp", "be24923968261c2661a9e116650dce5ac95c9d23", [ref: "be24923968261c2661a9e116650dce5ac95c9d23"]}, "yconf": {:git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6", [ref: "9682a6025ed543eedf34637e4cfcc66837074af6"]}, } diff --git a/rebar.config b/rebar.config index ca2658b225b..81cc3ec7f02 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "e295055dd1cb3dafb4b3134bc7462a775ff16b5c"}}, + {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "be24923968261c2661a9e116650dce5ac95c9d23"}}, {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6"}} ]}. diff --git a/rebar.lock b/rebar.lock index 2e867dd9dde..01d179d78d5 100644 --- a/rebar.lock +++ b/rebar.lock @@ -18,12 +18,16 @@ {<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.25">>},0}, {<<"p1_oauth2">>,{pkg,<<"p1_oauth2">>,<<"0.6.14">>},0}, {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.31">>},0}, - {<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.26">>},0}, + {<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.27">>},0}, {<<"pkix">>,{pkg,<<"pkix">>,<<"1.0.10">>},0}, {<<"sqlite3">>,{pkg,<<"sqlite3">>,<<"1.1.15">>},0}, - {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.30">>},0}, + {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.31">>},0}, {<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, + {<<"xmpp">>, + {git,"https://github.com/processone/xmpp", + {ref,"be24923968261c2661a9e116650dce5ac95c9d23"}}, + 0}, {<<"yconf">>, {git,"https://github.com/processone/yconf", {ref,"9682a6025ed543eedf34637e4cfcc66837074af6"}}, @@ -49,10 +53,10 @@ {<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>}, {<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>}, {<<"p1_pgsql">>, <<"8339BEAC1F0F4A45F476FF5306BE5135020F02979A61DF0D8CF7B1C67E85E2FD">>}, - {<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>}, + {<<"p1_utils">>, <<"F468D84C6FFA6E4B12A6160826DCF2D015527189D57865568A78B49C5ED972A1">>}, {<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>}, {<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>}, - {<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>}, + {<<"stringprep">>, <<"FA1688C156DD271722AA18C423A4163E710D2F4F475AD0BC220910DF669B53AF">>}, {<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>}, {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]}, {pkg_hash_ext,[ @@ -75,10 +79,10 @@ {<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>}, {<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>}, {<<"p1_pgsql">>, <<"B7FC45DFB2549187347871B7FD0573638AD5EA337F6263FBA1B3840EFAB2FF49">>}, - {<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>}, + {<<"p1_utils">>, <<"F1AF942B0A62BCFA0D59FBE30679BE4FFEB5E241A0C49ED5F094DB2F5B80F5E0">>}, {<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>}, {<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>}, - {<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>}, + {<<"stringprep">>, <<"E9699C88E8DB16B3A41F0E45AC6874A4DA81A6E4854A77D76EDE6D09B08E3530">>}, {<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>}, {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]} ]. From 7723951c05c49b9e677ec4a8d55acca9961e4df5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 18 Mar 2025 17:35:58 +0100 Subject: [PATCH 136/170] mod_muc_room: New muc_disco_info_extras event, useful for mod_muc_webchat_url (#3041) --- src/mod_muc_room.erl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 973759b2752..81254ec9147 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -4588,8 +4588,12 @@ iq_disco_info_extras(Lang, StateData, Static) -> _ -> Fs4 end, + Fs6 = ejabberd_hooks:run_fold(muc_disco_info_extras, + StateData#state.server_host, + Fs5, + [StateData]), #xdata{type = result, - fields = muc_roominfo:encode(Fs5, Lang)}. + fields = muc_roominfo:encode(Fs6, Lang)}. -spec process_iq_disco_items(jid(), iq(), state()) -> {error, stanza_error()} | {result, disco_items()}. From 16af90648ed4ff6f8257f7b3b673c018677fdd65 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 19 Mar 2025 12:40:38 +0100 Subject: [PATCH 137/170] Update moved or broken URLs in documentation --- CODE_OF_CONDUCT.md | 6 +++--- CONTAINER.md | 4 ++-- CONTRIBUTING.md | 2 +- README.md | 2 +- src/mod_admin_extra.erl | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 099c1be0b8e..e8855889e87 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +[homepage]: https://www.contributor-covenant.org/ +[version]: https://www.contributor-covenant.org/version/1/4/ diff --git a/CONTAINER.md b/CONTAINER.md index b8a483e07f6..ea29c2f4fb4 100644 --- a/CONTAINER.md +++ b/CONTAINER.md @@ -10,7 +10,7 @@ ejabberd Container Images robust, scalable and extensible realtime platform built using [Erlang/OTP][erlang], that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service. -[home]: https://ejabberd.im/ +[home]: https://www.ejabberd.im/ [erlang]: https://www.erlang.org/ [xmpp]: https://xmpp.org/ [mqtt]: https://mqtt.org/ @@ -255,7 +255,7 @@ podman unshare chown 9000:9000 database ``` It's possible to install additional ejabberd modules using volumes, check -[this Docs tutorial](http://docs.ejabberd.im/developer/extending-ejabberd/modules/#your-module-in-ejabberd-modules-with-ejabberd-container). +[this Docs tutorial](https://docs.ejabberd.im/developer/extending-ejabberd/modules/#your-module-in-ejabberd-modules-with-ejabberd-container). ### Commands on start diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5d4beda853..819921ee589 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -138,7 +138,7 @@ gives us the option to relicense the code with a more permissive license in the [coc]: https://github.com/processone/ejabberd/blob/master/CODE_OF_CONDUCT.md [stackoverflow]: https://stackoverflow.com/questions/tagged/ejabberd?sort=newest -[list]: https://lists.jabber.ru/mailman/listinfo/ejabberd +[list]: https://web.archive.org/web/20230319174915/http://lists.jabber.ru/mailman/listinfo/ejabberd [muc]: xmpp:ejabberd@conference.process-one.net [github]: https://github.com/processone/ejabberd [github-issues]: https://github.com/processone/ejabberd/issues diff --git a/README.md b/README.md index 76eae7b554f..646cc4a1770 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ License [fluux]: https://fluux.io/ [homebrew]: https://docs.ejabberd.im/admin/install/homebrew/ [hubecs]: https://hub.docker.com/r/ejabberd/ecs/ -[im]: https://ejabberd.im/ +[im]: https://www.ejabberd.im/ [issues]: https://github.com/processone/ejabberd/issues [localization]: https://docs.ejabberd.im/developer/extending-ejabberd/localization/ [mqtt]: https://mqtt.org/ diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index d461edc8991..38e29ec47f6 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -235,7 +235,7 @@ get_commands_spec() -> #ejabberd_commands{name = check_password_hash, tags = [accounts], desc = "Check if the password hash is correct", longdesc = "Allows hash methods from the Erlang/OTP " - "[crypto](https://www.erlang.org/doc/man/crypto) application.", + "[crypto](https://www.erlang.org/doc/apps/crypto/crypto.html) application.", module = ?MODULE, function = check_password_hash, args = [{user, binary}, {host, binary}, {passwordhash, binary}, {hashmethod, binary}], From 30a7b0ef3ba3c31975cbc492f06e715be6d281c8 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Thu, 20 Mar 2025 17:33:53 +0300 Subject: [PATCH 138/170] Better Matrix room topic and room roles to MUC conversion, support room aliases in invites --- src/mod_matrix_gw.erl | 8 +++- src/mod_matrix_gw_room.erl | 95 ++++++++++++++++++++++++++++++++------ 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/src/mod_matrix_gw.erl b/src/mod_matrix_gw.erl index 173e823569a..f0767ebe2ce 100644 --- a/src/mod_matrix_gw.erl +++ b/src/mod_matrix_gw.erl @@ -148,7 +148,7 @@ process([<<"federation">>, <<"v2">>, <<"invite">>, RoomID, EventID], <<"room_id">> := RoomID, <<"sender">> := Sender, <<"state_key">> := UserID} = Event, - <<"room_version">> := RoomVer}, + <<"room_version">> := RoomVer} = JSON, Origin} -> case mod_matrix_gw_room:binary_to_room_version(RoomVer) of #room_version{} = RoomVersion -> @@ -167,7 +167,11 @@ process([<<"federation">>, <<"v2">>, <<"invite">>, RoomID, EventID], #{<<"is_direct">> := true} -> mod_matrix_gw_room:join_direct(Host, Origin, RoomID, Sender, UserID); _ -> - mod_matrix_gw_room:send_muc_invite(Host, Origin, RoomID, Sender, UserID, Event) + IRS = case JSON of + #{<<"invite_room_state">> := IRS1} -> IRS1; + _ -> [] + end, + mod_matrix_gw_room:send_muc_invite(Host, Origin, RoomID, Sender, UserID, Event, IRS) end, ?DEBUG("res ~s~n", [misc:json_encode(ResJSON)]), {200, [{<<"Content-Type">>, <<"application/json;charset=UTF-8">>}], misc:json_encode(ResJSON)}; diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 095b6fa52f9..380c67e0694 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -36,7 +36,7 @@ create_new_room/3, room_add_event/3, binary_to_room_version/1, parse_user_id/1, - send_muc_invite/6, + send_muc_invite/7, escape/1, unescape/1, route/1]). @@ -102,6 +102,7 @@ -define(ROOM_3PI, <<"m.room.third_party_invite">>). -define(ROOM_MESSAGE, <<"m.room.message">>). -define(ROOM_HISTORY_VISIBILITY, <<"m.room.history_visibility">>). +-define(ROOM_TOPIC, <<"m.room.topic">>). -define(MAX_DEPTH, 16#7FFFFFFFFFFFFFFF). -define(MAX_TXN_RETRIES, 5). @@ -1206,6 +1207,16 @@ do_auth_and_store_external_events(EventList, Data) -> auth_and_store_external_events(Pid, EventList) -> gen_statem:call(Pid, {auth_and_store_external_events, EventList}). +statemap_find(Key, StateMap, Data) -> + case maps:find(Key, StateMap) of + {ok, #event{}} = Res -> + Res; + {ok, EventID} when is_binary(EventID) -> + maps:find(EventID, Data#data.events); + error -> + error + end. + check_event_auth(Event, Data) -> StateMap = maps:from_list( @@ -1572,7 +1583,7 @@ get_event_power_level(Type, PL) -> get_user_power_level(User, StateMap, Data) -> RoomVersion = Data#data.room_version, PL = - case maps:find({?ROOM_POWER_LEVELS, <<"">>}, StateMap) of + case statemap_find({?ROOM_POWER_LEVELS, <<"">>}, StateMap, Data) of {ok, #event{json = #{<<"content">> := C}}} -> C; _ -> #{} end, @@ -1580,12 +1591,12 @@ get_user_power_level(User, StateMap, Data) -> #{<<"users">> := #{User := Level}} -> get_int(Level); #{<<"users_default">> := Level} -> get_int(Level); _ -> - case {RoomVersion#room_version.implicit_room_creator, StateMap} of + case {RoomVersion#room_version.implicit_room_creator, + statemap_find({?ROOM_CREATE, <<"">>}, StateMap, Data)} of {false, - #{{?ROOM_CREATE, <<"">>} := - #event{json = #{<<"content">> := #{<<"creator">> := User}}}}} -> + {ok, #event{json = #{<<"content">> := #{<<"creator">> := User}}}}} -> 100; - {true, #{{?ROOM_CREATE, <<"">>} := #event{sender = User}}} -> + {true, {ok, #event{sender = User}}} -> 100; _ -> 0 @@ -2744,8 +2755,9 @@ notify_event_xmpp( false end, UserJID = jid:make(LUser, LServer, LResource), - Item = #muc_item{affiliation = member, - role = participant}, + Item = + get_user_muc_item( + Sender, Event#event.state_map, Data), Status = case IsSelfPresence of true -> [110]; false -> [] @@ -2760,12 +2772,24 @@ notify_event_xmpp( ejabberd_router:route(Pres), case IsSelfPresence of true -> + Topic = + case Event#event.state_map of + #{{?ROOM_TOPIC, <<"">>} := TEID} -> + case maps:find(TEID, Data#data.events) of + {ok, #event{json = #{<<"content">> := #{<<"topic">> := T}}}} when is_binary(T) -> + T; + _ -> + <<"">> + end; + _ -> + <<"">> + end, Subject = #message{ from = RoomJID, to = UserJID, type = groupchat, - subject = [#text{}] + subject = [#text{data = Topic}] }, ejabberd_router:route(Subject); false -> ok @@ -2795,7 +2819,7 @@ notify_event_xmpp( when JoinTS =< OriginTS -> From = jid:replace_resource(RoomJID, RUser), UserJID = jid:make(LUser, LServer, LResource), - Item = #muc_item{affiliation = member, + Item = #muc_item{affiliation = none, role = none}, Pres = #presence{from = From, to = UserJID, @@ -2843,11 +2867,13 @@ send_initial_presences(JID, RoomJID, Event, Data) -> fun({?ROOM_MEMBER, _}, EID, ok) -> case maps:find(EID, Data#data.events) of {ok, #event{ - sender = <<$@, SenderUser/binary>>, + sender = <<$@, SenderUser/binary>> = Sender, json = #{<<"content">> := #{<<"membership">> := <<"join">>}}}} -> From = jid:replace_resource(RoomJID, SenderUser), - Item = #muc_item{affiliation = member, role = participant}, + Item = + get_user_muc_item( + Sender, Event#event.state_map, Data), Pres = #presence{from = From, to = JID, type = available, @@ -2862,6 +2888,23 @@ send_initial_presences(JID, RoomJID, Event, Data) -> ok end, ok, Event#event.state_map). +get_user_muc_item(User, StateMap, Data) -> + SenderLevel = get_user_power_level(User, StateMap, Data), + BanLevel = + case statemap_find({?ROOM_POWER_LEVELS, <<"">>}, StateMap, Data) of + {ok, #event{json = #{<<"content">> := #{<<"ban">> := S}}}} -> + get_int(S); + _ -> 50 + end, + if + SenderLevel >= BanLevel -> + #muc_item{affiliation = admin, + role = moderator}; + true -> + #muc_item{affiliation = member, + role = participant} + end. + send_new_txn(Events, Server, Data) -> TxnID = p1_rand:get_string(), @@ -3198,12 +3241,36 @@ update_client(#data{kind = #multi{users = Users}} = Data) -> end. -send_muc_invite(Host, Origin, RoomID, Sender, UserID, Event) -> +send_muc_invite(Host, Origin, RoomID, Sender, UserID, Event, IRS) -> case {user_id_to_jid(Sender, Host), user_id_to_jid(UserID, Host)} of {#jid{} = SenderJID, #jid{lserver = Host} = UserJID} -> process_pdu(Host, Origin, Event), ServiceHost = mod_matrix_gw_opt:host(Host), - {ok, EscRoomID} = room_id_to_xmpp(RoomID), + Alias = + lists:foldl( + fun(#{<<"type">> := <<"m.room.canonical_alias">>, + <<"content">> := #{<<"alias">> := A}}, _) + when is_binary(A) -> A; + (_, Acc) -> Acc + end, none, IRS), + {ok, EscRoomID} = + case Alias of + <<$#, Parts/binary>> -> + case binary:split(Parts, <<":">>) of + [R, S] -> + User = <<$#, R/binary, $%, S/binary>>, + case jid:nodeprep(User) of + error -> + room_id_to_xmpp(RoomID); + _ -> + {ok, User} + end; + _ -> + room_id_to_xmpp(RoomID) + end; + _ -> + room_id_to_xmpp(RoomID) + end, RoomJID = jid:make(EscRoomID, ServiceHost), Invite = #muc_invite{to = undefined, from = SenderJID}, XUser = #muc_user{invites = [Invite]}, From 999ede59ce6164af9dbcadba386dbfbaf0ac3967 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 20 Mar 2025 19:59:22 +0100 Subject: [PATCH 139/170] Update a pair more URLs in documentation --- src/ejabberd_options_doc.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 84c2ae992a2..312e00f0e23 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -538,7 +538,7 @@ doc() -> #{value => "{NAME: Value}", desc => ?T("Allows to define configuration " - "_`../configuration/file-format.md#keywords|keywords`_. "), + "_`../configuration/file-format.md#macros-and-keywords|keywords`_. "), example => ["define_keyword:", " SQL_USERNAME: \"eja.global\"", @@ -553,7 +553,7 @@ doc() -> #{value => "{NAME: Value}", desc => ?T("Allows to define configuration " - "_`../configuration/file-format.md#macros|macros`_. "), + "_`../configuration/file-format.md#macros-and-keywords|macros`_. "), example => ["define_macro:", " DEBUG: debug", From a6fec278c399814998d1eaac440ea92afe59d5e2 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 21 Mar 2025 12:02:46 +0100 Subject: [PATCH 140/170] ejabberd_commands: Fix command unregistration --- src/ejabberd_commands.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 243a594edd0..f1e724da3fc 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -188,7 +188,7 @@ register_command_prepare(Command, Definer) -> unregister_commands(Commands) -> lists:foreach( fun(Command) -> - mnesia:dirty_delete_object(Command) + mnesia:dirty_delete(ejabberd_commands, Command#ejabberd_commands.name) end, Commands), ejabberd_access_permissions:invalidate(). From c180349fc65a02fad8bf97002400f5a8b56aa413 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 21 Mar 2025 10:50:10 +0100 Subject: [PATCH 141/170] gen_mod: Support registering commands and hook_subscribe in start/2 result --- src/gen_mod.erl | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/gen_mod.erl b/src/gen_mod.erl index be815606d1f..c07e1d691d2 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -45,6 +45,7 @@ -include("logger.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). -include("ejabberd_stacktrace.hrl"). +-include("ejabberd_commands.hrl"). -record(ejabberd_module, {module_host = {undefined, <<"">>} :: {atom(), binary()}, @@ -63,6 +64,11 @@ {hook, atom(), atom(), integer()} | {hook, atom(), atom(), integer(), binary() | global} | {hook, atom(), module(), atom(), integer()} | + {hook_subscribe, atom(), atom(), [any()]} | + {hook_subscribe, atom(), atom(), [any()], binary() | global} | + {hook_subscribe, atom(), module(), atom(), [any()]} | + {hook_subscribe, atom(), module(), atom(), [any()], binary() | global} | + {commands, [ejabberd_commands()]} | {iq_handler, component(), binary(), atom()} | {iq_handler, component(), binary(), module(), atom()}. -export_type([registration/0]). @@ -346,6 +352,16 @@ add_registrations(Host, Module, Registrations) -> ejabberd_hooks:add(Hook, Host1, Module, Function, Seq); ({hook, Hook, Module1, Function, Seq}) when is_integer(Seq) -> ejabberd_hooks:add(Hook, Host, Module1, Function, Seq); + ({hook_subscribe, Hook, Function, InitArg}) -> + ejabberd_hooks:subscribe(Hook, Host, Module, Function, InitArg); + ({hook_subscribe, Hook, Function, InitArg, Host1}) when is_binary(Host1) or (Host1 == global) -> + ejabberd_hooks:subscribe(Hook, Host1, Module, Function, InitArg); + ({hook_subscribe, Hook, Module1, Function, InitArg}) -> + ejabberd_hooks:subscribe(Hook, Host, Module1, Function, InitArg); + ({hook_subscribe, Hook, Module1, Function, InitArg, Host1}) -> + ejabberd_hooks:subscribe(Hook, Host1, Module1, Function, InitArg); + ({commands, Commands}) -> + ejabberd_commands:register_commands(Host, Module, Commands); ({iq_handler, Component, NS, Function}) -> gen_iq_handler:add_iq_handler( Component, Host, NS, Module, Function); @@ -363,6 +379,16 @@ del_registrations(Host, Module, Registrations) -> ejabberd_hooks:delete(Hook, Host1, Module, Function, Seq); ({hook, Hook, Module1, Function, Seq}) when is_integer(Seq) -> ejabberd_hooks:delete(Hook, Host, Module1, Function, Seq); + ({hook_subscribe, Hook, Function, InitArg}) -> + ejabberd_hooks:unsubscribe(Hook, Host, Module, Function, InitArg); + ({hook_subscribe, Hook, Function, InitArg, Host1}) when is_binary(Host1) or (Host1 == global) -> + ejabberd_hooks:unsubscribe(Hook, Host1, Module, Function, InitArg); + ({hook_subscribe, Hook, Module1, Function, InitArg}) -> + ejabberd_hooks:unsubscribe(Hook, Host, Module1, Function, InitArg); + ({hook_subscribe, Hook, Module1, Function, InitArg, Host1}) -> + ejabberd_hooks:unsubscribe(Hook, Host1, Module1, Function, InitArg); + ({commands, Commands}) -> + ejabberd_commands:unregister_commands(Host, Module, Commands); ({iq_handler, Component, NS, _Function}) -> gen_iq_handler:remove_iq_handler(Component, Host, NS); ({iq_handler, Component, NS, _Module, _Function}) -> From b8cb1bbdcfdd3b197557d57b122556a628e5a766 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 21 Mar 2025 12:23:43 +0100 Subject: [PATCH 142/170] Register commands using the new gen_mod support --- src/mod_admin_extra.erl | 10 +++++----- src/mod_admin_update_sql.erl | 8 ++++---- src/mod_muc_admin.erl | 10 +++++----- src/mod_private.erl | 8 ++++---- src/mod_push.erl | 8 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 38e29ec47f6..15d65bb0b56 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -104,9 +104,9 @@ %%% gen_mod %%% -start(Host, _Opts) -> - ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), - {ok, [{hook, webadmin_menu_main, web_menu_main, 50, global}, +start(_Host, _Opts) -> + {ok, [{commands, get_commands_spec()}, + {hook, webadmin_menu_main, web_menu_main, 50, global}, {hook, webadmin_page_main, web_page_main, 50, global}, {hook, webadmin_menu_host, web_menu_host, 50}, {hook, webadmin_page_host, web_page_host, 50}, @@ -117,8 +117,8 @@ start(Host, _Opts) -> {hook, webadmin_menu_node, web_menu_node, 50, global}, {hook, webadmin_page_node, web_page_node, 50, global}]}. -stop(Host) -> - ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). +stop(_Host) -> + ok. reload(_Host, _NewOpts, _OldOpts) -> ok. diff --git a/src/mod_admin_update_sql.erl b/src/mod_admin_update_sql.erl index c5b4ab86505..ba33f7e50eb 100644 --- a/src/mod_admin_update_sql.erl +++ b/src/mod_admin_update_sql.erl @@ -47,11 +47,11 @@ %%% gen_mod %%% -start(Host, _Opts) -> - ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()). +start(_Host, _Opts) -> + {ok, [{commands, get_commands_spec()}]}. -stop(Host) -> - ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). +stop(_Host) -> + ok. reload(_Host, _NewOpts, _OldOpts) -> ok. diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 06995daedd6..59c5a0e9382 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -68,9 +68,9 @@ %% gen_mod %%---------------------------- -start(Host, _Opts) -> - ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), - {ok, [{hook, webadmin_menu_main, web_menu_main, 50, global}, +start(_Host, _Opts) -> + {ok, [{commands, get_commands_spec()}, + {hook, webadmin_menu_main, web_menu_main, 50, global}, {hook, webadmin_page_main, web_page_main, 50, global}, {hook, webadmin_menu_host, web_menu_host, 50}, {hook, webadmin_page_host, web_page_host, 50}, @@ -78,8 +78,8 @@ start(Host, _Opts) -> {hook, webadmin_page_hostuser, web_page_hostuser, 50} ]}. -stop(Host) -> - ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). +stop(_Host) -> + ok. reload(_Host, _NewOpts, _OldOpts) -> ok. diff --git a/src/mod_private.erl b/src/mod_private.erl index 3bb93ed7795..6f70e1c9afa 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -71,8 +71,8 @@ start(Host, Opts) -> Mod = gen_mod:db_mod(Opts, ?MODULE), Mod:init(Host, Opts), init_cache(Mod, Host, Opts), - ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), - {ok, [{hook, remove_user, remove_user, 50}, + {ok, [{commands, get_commands_spec()}, + {hook, remove_user, remove_user, 50}, {hook, disco_sm_features, get_sm_features, 50}, {hook, pubsub_publish_item, pubsub_publish_item, 50}, {hook, pubsub_delete_item, pubsub_delete_item, 50}, @@ -81,8 +81,8 @@ start(Host, Opts) -> {hook, webadmin_page_hostuser, webadmin_page_hostuser, 50}, {iq_handler, ejabberd_sm, ?NS_PRIVATE, process_sm_iq}]}. -stop(Host) -> - ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). +stop(_Host) -> + ok. reload(Host, NewOpts, OldOpts) -> NewMod = gen_mod:db_mod(NewOpts, ?MODULE), diff --git a/src/mod_push.erl b/src/mod_push.erl index 7d2792eb45b..fb5ba1be4c8 100644 --- a/src/mod_push.erl +++ b/src/mod_push.erl @@ -96,8 +96,8 @@ start(Host, Opts) -> Mod = gen_mod:db_mod(Opts, ?MODULE), Mod:init(Host, Opts), init_cache(Mod, Host, Opts), - ejabberd_commands:register_commands(Host, ?MODULE, get_commands_spec()), - {ok, [{iq_handler, ejabberd_sm, ?NS_PUSH_0, process_iq}, + {ok, [{commands, get_commands_spec()}, + {iq_handler, ejabberd_sm, ?NS_PUSH_0, process_iq}, {hook, disco_sm_features, disco_sm_features, 50}, {hook, c2s_session_pending, c2s_session_pending, 50}, {hook, c2s_copy_session, c2s_copy_session, 50}, @@ -110,8 +110,8 @@ start(Host, Opts) -> -spec stop(binary()) -> ok. -stop(Host) -> - ejabberd_commands:unregister_commands(Host, ?MODULE, get_commands_spec()). +stop(_Host) -> + ok. -spec reload(binary(), gen_mod:opts(), gen_mod:opts()) -> ok. reload(Host, NewOpts, OldOpts) -> From d9e86600dc0c1a043cf5a3cbf5557a7ab1493e41 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 21 Mar 2025 12:46:05 +0100 Subject: [PATCH 143/170] Register hooks and iq_handler using the gen_mod support for registrations --- src/mod_mix_pam.erl | 31 ++++++++----------- src/mod_push_keepalive.erl | 62 +++++++++----------------------------- 2 files changed, 26 insertions(+), 67 deletions(-) diff --git a/src/mod_mix_pam.erl b/src/mod_mix_pam.erl index 9738205dee1..bae6133fbcf 100644 --- a/src/mod_mix_pam.erl +++ b/src/mod_mix_pam.erl @@ -64,29 +64,22 @@ start(Host, Opts) -> case Mod:init(Host, Opts) of ok -> init_cache(Mod, Host, Opts), - ejabberd_hooks:add(bounce_sm_packet, Host, ?MODULE, bounce_sm_packet, 50), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, disco_sm_features, 50), - ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), - ejabberd_hooks:add(roster_get, Host, ?MODULE, get_mix_roster_items, 50), - ejabberd_hooks:add(webadmin_user, Host, ?MODULE, webadmin_user, 50), - ejabberd_hooks:add(webadmin_menu_hostuser, Host, ?MODULE, webadmin_menu_hostuser, 50), - ejabberd_hooks:add(webadmin_page_hostuser, Host, ?MODULE, webadmin_page_hostuser, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_MIX_PAM_0, ?MODULE, process_iq), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_MIX_PAM_2, ?MODULE, process_iq); + {ok, + [{hook, bounce_sm_packet, bounce_sm_packet, 50}, + {hook, disco_sm_features, disco_sm_features, 50}, + {hook, remove_user, remove_user, 50}, + {hook, roster_get, get_mix_roster_items, 50}, + {hook, webadmin_user, webadmin_user, 50}, + {hook, webadmin_menu_hostuser, webadmin_menu_hostuser, 50}, + {hook, webadmin_page_hostuser, webadmin_page_hostuser, 50}, + {iq_handler, ejabberd_sm, ?NS_MIX_PAM_0, process_iq}, + {iq_handler, ejabberd_sm, ?NS_MIX_PAM_2, process_iq}]}; Err -> Err end. -stop(Host) -> - ejabberd_hooks:delete(bounce_sm_packet, Host, ?MODULE, bounce_sm_packet, 50), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, disco_sm_features, 50), - ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(roster_get, Host, ?MODULE, get_mix_roster_items, 50), - ejabberd_hooks:delete(webadmin_user, Host, ?MODULE, webadmin_user, 50), - ejabberd_hooks:delete(webadmin_menu_hostuser, Host, ?MODULE, webadmin_menu_hostuser, 50), - ejabberd_hooks:delete(webadmin_page_hostuser, Host, ?MODULE, webadmin_page_hostuser, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_MIX_PAM_0), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_MIX_PAM_2). +stop(_Host) -> + ok. reload(Host, NewOpts, OldOpts) -> NewMod = gen_mod:db_mod(NewOpts, ?MODULE), diff --git a/src/mod_push_keepalive.erl b/src/mod_push_keepalive.erl index 2c43282cd55..33bd2b53e2a 100644 --- a/src/mod_push_keepalive.erl +++ b/src/mod_push_keepalive.erl @@ -47,13 +47,22 @@ %%-------------------------------------------------------------------- %% gen_mod callbacks. %%-------------------------------------------------------------------- --spec start(binary(), gen_mod:opts()) -> ok. -start(Host, _Opts) -> - register_hooks(Host). +-spec start(binary(), gen_mod:opts()) -> {ok, [gen_mod:registration()]}. +start(_Host, _Opts) -> + {ok, + [{hook, c2s_session_pending, c2s_session_pending, 50}, + {hook, c2s_session_resumed, c2s_session_resumed, 50}, + {hook, c2s_copy_session, c2s_copy_session, 50}, + {hook, c2s_handle_cast, c2s_handle_cast, 40}, + {hook, c2s_handle_info, c2s_handle_info, 50}, + {hook, c2s_handle_send, c2s_stanza, 50}, + %% Wait for ejabberd_pkix before running our ejabberd_started/0, so that we + %% don't initiate s2s connections before certificates are loaded: + {hook, ejabberd_started, ejabberd_started, 90, global}]}. -spec stop(binary()) -> ok. -stop(Host) -> - unregister_hooks(Host). +stop(_Host) -> + ok. -spec reload(binary(), gen_mod:opts(), gen_mod:opts()) -> ok. reload(_Host, _NewOpts, _OldOpts) -> @@ -119,49 +128,6 @@ mod_doc() -> "out as per the 'resume_timeout' option. " "The default value is 'true'.")}}]}. -%%-------------------------------------------------------------------- -%% Register/unregister hooks. -%%-------------------------------------------------------------------- --spec register_hooks(binary()) -> ok. -register_hooks(Host) -> - ejabberd_hooks:add(c2s_session_pending, Host, ?MODULE, - c2s_session_pending, 50), - ejabberd_hooks:add(c2s_session_resumed, Host, ?MODULE, - c2s_session_resumed, 50), - ejabberd_hooks:add(c2s_copy_session, Host, ?MODULE, - c2s_copy_session, 50), - ejabberd_hooks:add(c2s_handle_cast, Host, ?MODULE, - c2s_handle_cast, 40), - ejabberd_hooks:add(c2s_handle_info, Host, ?MODULE, - c2s_handle_info, 50), - ejabberd_hooks:add(c2s_handle_send, Host, ?MODULE, - c2s_stanza, 50), - % Wait for ejabberd_pkix before running our ejabberd_started/0, so that we - % don't initiate s2s connections before certificates are loaded: - ejabberd_hooks:add(ejabberd_started, ?MODULE, ejabberd_started, 90). - --spec unregister_hooks(binary()) -> ok. -unregister_hooks(Host) -> - ejabberd_hooks:delete(c2s_session_pending, Host, ?MODULE, - c2s_session_pending, 50), - ejabberd_hooks:delete(c2s_session_resumed, Host, ?MODULE, - c2s_session_resumed, 50), - ejabberd_hooks:delete(c2s_copy_session, Host, ?MODULE, - c2s_copy_session, 50), - ejabberd_hooks:delete(c2s_handle_cast, Host, ?MODULE, - c2s_handle_cast, 40), - ejabberd_hooks:delete(c2s_handle_info, Host, ?MODULE, - c2s_handle_info, 50), - ejabberd_hooks:delete(c2s_handle_send, Host, ?MODULE, - c2s_stanza, 50), - case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of - false -> - ejabberd_hooks:delete( - ejabberd_started, ?MODULE, ejabberd_started, 90); - true -> - ok - end. - %%-------------------------------------------------------------------- %% Hook callbacks. %%-------------------------------------------------------------------- From 79a4dd4a26023249fbeea69ac718721fd7f44cde Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 24 Mar 2025 12:02:11 +0100 Subject: [PATCH 144/170] econf: Recover support for setting hosts as atoms in config file --- src/econf.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/econf.erl b/src/econf.erl index a6abdb647f9..bcee4622442 100644 --- a/src/econf.erl +++ b/src/econf.erl @@ -547,9 +547,10 @@ sip_uri() -> host() -> fun(Domain) -> Hosts = ejabberd_config:get_option(hosts), - case lists:member(Domain, Hosts) of + Domain3 = (domain())(Domain), + case lists:member(Domain3, Hosts) of true -> fail({route_conflict, Domain}); - false -> Domain + false -> Domain3 end end. From 12274a969a7a89f05f7279e2096d59d653fc9c7d Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 24 Mar 2025 12:05:43 +0100 Subject: [PATCH 145/170] ejabberd_config: Recover support for keywords in atom option that will be converted to binary --- src/ejabberd_config.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 7b08c446909..fd4fac591d5 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -421,14 +421,15 @@ replace_keywords(Host, Value) -> replace_keywords(Host, List, Keywords) when is_list(List) -> [replace_keywords(Host, Element, Keywords) || Element <- List]; -replace_keywords(_Host, Atom, Keywords) when is_atom(Atom) -> +replace_keywords(Host, Atom, Keywords) when is_atom(Atom) -> Str = atom_to_list(Atom), + Bin = iolist_to_binary(Str), case Str == string:uppercase(Str) of false -> - Atom; + BinaryReplaced = replace_keywords(Host, Bin, Keywords), + binary_to_atom(BinaryReplaced, utf8); true -> - MacroName = iolist_to_binary(Str), - case proplists:get_value(MacroName, Keywords) of + case proplists:get_value(Bin, Keywords) of undefined -> Atom; Replacement -> From 51e96433eadd9bbaac89459c3c383a0ad4526881 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 24 Mar 2025 10:55:06 +0100 Subject: [PATCH 146/170] Add XEPs that are indirectly supported and required by XEP-0479 --- src/mod_muc.erl | 1 + src/mod_pubsub.erl | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/mod_muc.erl b/src/mod_muc.erl index c1ad7a8baa5..42be73a9391 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -25,6 +25,7 @@ -module(mod_muc). -author('alexey@process-one.net'). -protocol({xep, 45, '1.25', '0.5.0', "complete", ""}). +-protocol({xep, 249, '1.2', '0.5.0', "complete", ""}). -ifndef(GEN_SERVER). -define(GEN_SERVER, gen_server). -endif. diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index 059fa9518c9..06f0af65741 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -35,8 +35,10 @@ -behaviour(gen_mod). -behaviour(gen_server). -author('christophe.romain@process-one.net'). +-protocol({xep, 48, '1.2', '0.5.0', "complete", ""}). -protocol({xep, 60, '1.14', '0.5.0', "partial", ""}). -protocol({xep, 163, '1.2', '2.0.0', "complete", ""}). +-protocol({xep, 223, '1.1.1', '2.0.0', "complete", ""}). -protocol({xep, 248, '0.2', '2.1.0', "complete", ""}). -include("logger.hrl"). From 239d4a5bfb6b6ec5ca6ced781a2ce10a1371ab6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 06:04:06 +0000 Subject: [PATCH 147/170] build(deps): bump golang in /.github/container Bumps golang from 1.23-alpine to 1.24-alpine. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index ae2cc731195..8aa35694902 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -9,7 +9,7 @@ ARG VERSION='master' ################################################################################ #' Compile ejabberdapi -FROM docker.io/golang:1.23-alpine AS api +FROM docker.io/golang:1.24-alpine AS api RUN go install -v \ github.com/processone/ejabberd-api/cmd/ejabberd@master \ && mv bin/ejabberd bin/ejabberdapi From cf13abdab62b321a071f6ca396af3d8c0f3542e5 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Mon, 24 Mar 2025 20:00:33 +0300 Subject: [PATCH 148/170] Preserve XMPP message IDs in Matrix rooms --- src/mod_matrix_gw_room.erl | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 380c67e0694..2fd1f3be6f3 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -216,7 +216,8 @@ route(#presence{from = From, to = #jid{luser = <>} = To, end; route(#message{from = From, to = #jid{luser = <>} = To, type = groupchat, - body = Body}) + body = Body, + id = MsgID}) when C == $!; C == $# -> Host = ejabberd_config:get_myname(), @@ -232,7 +233,8 @@ route(#message{from = From, to = #jid{luser = <>} = To, JSON = #{<<"content">> => #{<<"body">> => Text, - <<"msgtype">> => <<"m.text">>}, + <<"msgtype">> => <<"m.text">>, + <<"net.process-one.xmpp-id">> => MsgID}, <<"sender">> => UserID, <<"type">> => ?ROOM_MESSAGE}, gen_statem:cast(Pid, {add_event, JSON}), @@ -2700,7 +2702,7 @@ notify_event_xmpp( notify_event_xmpp( #event{type = ?ROOM_MESSAGE, sender = Sender, json = #{<<"content">> := #{<<"msgtype">> := <<"m.text">>, - <<"body">> := Body}, + <<"body">> := Body} = Content, <<"origin_server_ts">> := OriginTS}}, #data{kind = #multi{users = Users}} = Data) -> case Sender of @@ -2714,7 +2716,15 @@ notify_event_xmpp( when JoinTS =< OriginTS -> From = jid:replace_resource(RoomJID, SenderUser), UserJID = jid:make(LUser, LServer, LResource), - Msg = #message{from = From, + MsgID = + case Content of + #{<<"net.process-one.xmpp-id">> := MID} -> + MID; + _ -> + <<"">> + end, + Msg = #message{id = MsgID, + from = From, to = UserJID, type = groupchat, body = [#text{data = Body}] From ced72f4a89d202a2deee1a4d64f53fcfb3a72995 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Tue, 25 Mar 2025 17:42:31 +0300 Subject: [PATCH 149/170] Sanitize message ID coming from Matrix --- src/mod_matrix_gw_room.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index 9ac49bf8c90..002704f69ec 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -2718,7 +2718,8 @@ notify_event_xmpp( UserJID = jid:make(LUser, LServer, LResource), MsgID = case Content of - #{<<"net.process-one.xmpp-id">> := MID} -> + #{<<"net.process-one.xmpp-id">> := MID} + when is_binary(MID) -> MID; _ -> <<"">> From 7862c6a7db0687e2af3b21bc2ff0af1db4c4b393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 26 Mar 2025 10:27:39 +0100 Subject: [PATCH 150/170] Add support for storing multiple passwords formats per user This adds option 'auth_stored_password_types' that can be used to setup storage of multiple passwords for each user. When this is set, on each password set, database will now store password in each format specified. --- include/ejabberd_auth.hrl | 2 +- rebar.config | 2 +- rebar.lock | 2 +- sql/lite.new.sql | 3 +- sql/lite.sql | 6 +- sql/mssql.new.sql | 4 +- sql/mssql.sql | 4 +- sql/mysql.new.sql | 3 +- sql/mysql.sql | 6 +- sql/pg.new.sql | 3 +- sql/pg.sql | 6 +- src/ejabberd_auth.erl | 314 +++++++++++++++++++++++++---------- src/ejabberd_auth_mnesia.erl | 184 ++++++++++---------- src/ejabberd_auth_sql.erl | 238 ++++++++++++++++++-------- src/ejabberd_c2s.erl | 21 ++- src/ejabberd_option.erl | 8 + src/ejabberd_options.erl | 3 + src/ejabberd_options_doc.erl | 8 + src/mod_scram_upgrade.erl | 2 +- test/webadmin_tests.erl | 4 +- 20 files changed, 553 insertions(+), 270 deletions(-) diff --git a/include/ejabberd_auth.hrl b/include/ejabberd_auth.hrl index 1f9117efbfd..bf7660d3f8d 100644 --- a/include/ejabberd_auth.hrl +++ b/include/ejabberd_auth.hrl @@ -18,5 +18,5 @@ %%% %%%---------------------------------------------------------------------- --record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1', +-record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | {binary(), binary(), atom()} | '$1', password = <<"">> :: binary() | scram() | '_'}). diff --git a/rebar.config b/rebar.config index 81cc3ec7f02..f4795584147 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "be24923968261c2661a9e116650dce5ac95c9d23"}}, + {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "8929be60aa0c56653b13f5fcada1e460337a016b"}}, {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6"}} ]}. diff --git a/rebar.lock b/rebar.lock index 01d179d78d5..68e7d5ae721 100644 --- a/rebar.lock +++ b/rebar.lock @@ -26,7 +26,7 @@ {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, {<<"xmpp">>, {git,"https://github.com/processone/xmpp", - {ref,"be24923968261c2661a9e116650dce5ac95c9d23"}}, + {ref,"8929be60aa0c56653b13f5fcada1e460337a016b"}}, 0}, {<<"yconf">>, {git,"https://github.com/processone/yconf", diff --git a/sql/lite.new.sql b/sql/lite.new.sql index 7248d080b40..42f289fb38a 100644 --- a/sql/lite.new.sql +++ b/sql/lite.new.sql @@ -18,13 +18,14 @@ CREATE TABLE users ( username text NOT NULL, + type smallint, server_host text NOT NULL, password text NOT NULL, serverkey text NOT NULL DEFAULT '', salt text NOT NULL DEFAULT '', iterationcount integer NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (server_host, username) + PRIMARY KEY (server_host, username, type) ); diff --git a/sql/lite.sql b/sql/lite.sql index 2958a96289f..b31e02b793d 100644 --- a/sql/lite.sql +++ b/sql/lite.sql @@ -17,12 +17,14 @@ -- CREATE TABLE users ( - username text PRIMARY KEY, + username text, + type smallint, password text NOT NULL, serverkey text NOT NULL DEFAULT '', salt text NOT NULL DEFAULT '', iterationcount integer NOT NULL DEFAULT 0, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + primary key (username, type) ); diff --git a/sql/mssql.new.sql b/sql/mssql.new.sql index 3e6817012fd..f67033eedef 100644 --- a/sql/mssql.new.sql +++ b/sql/mssql.new.sql @@ -403,6 +403,7 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW CREATE TABLE [dbo].[users] ( [username] [varchar] (250) NOT NULL, [server_host] [varchar] (250) NOT NULL, + [type] [smallint] NOT NULL, [password] [text] NOT NULL, [serverkey] [text] NOT NULL DEFAULT '', [salt] [text] NOT NULL DEFAULT '', @@ -411,7 +412,8 @@ CREATE TABLE [dbo].[users] ( CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED ( [server_host] ASC, - [username] ASC + [username] ASC, + [type] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ) TEXTIMAGE_ON [PRIMARY]; diff --git a/sql/mssql.sql b/sql/mssql.sql index 5ee11d880f8..ab5596d4869 100644 --- a/sql/mssql.sql +++ b/sql/mssql.sql @@ -379,6 +379,7 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW CREATE TABLE [dbo].[users] ( [username] [varchar] (250) NOT NULL, + [type] [smallint] NOT NULL, [password] [text] NOT NULL, [serverkey] [text] NOT NULL DEFAULT '', [salt] [text] NOT NULL DEFAULT '', @@ -386,7 +387,8 @@ CREATE TABLE [dbo].[users] ( [created_at] [datetime] NOT NULL DEFAULT GETDATE(), CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED ( - [username] ASC + [username] ASC, + [type] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ) TEXTIMAGE_ON [PRIMARY]; diff --git a/sql/mysql.new.sql b/sql/mysql.new.sql index c5a4675b0ae..cf818ad3dd8 100644 --- a/sql/mysql.new.sql +++ b/sql/mysql.new.sql @@ -18,13 +18,14 @@ CREATE TABLE users ( username varchar(191) NOT NULL, + type smallint NOT NULL, server_host varchar(191) NOT NULL, password text NOT NULL, serverkey varchar(128) NOT NULL DEFAULT '', salt varchar(128) NOT NULL DEFAULT '', iterationcount integer NOT NULL DEFAULT 0, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (server_host(191), username) + PRIMARY KEY (server_host(191), username, type) ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- Add support for SCRAM auth to a database created before ejabberd 16.03: diff --git a/sql/mysql.sql b/sql/mysql.sql index 479ccb435f3..210f417131d 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -17,12 +17,14 @@ -- CREATE TABLE users ( - username varchar(191) PRIMARY KEY, + username varchar(191) NOT NULL, + type smallint NOT NULL,, password text NOT NULL, serverkey varchar(128) NOT NULL DEFAULT '', salt varchar(128) NOT NULL DEFAULT '', iterationcount integer NOT NULL DEFAULT 0, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (username, type) ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- Add support for SCRAM auth to a database created before ejabberd 16.03: diff --git a/sql/pg.new.sql b/sql/pg.new.sql index a7e79fee3b1..5bd107d9780 100644 --- a/sql/pg.new.sql +++ b/sql/pg.new.sql @@ -172,12 +172,13 @@ CREATE TABLE users ( username text NOT NULL, server_host text NOT NULL, + "type" smallint NOT NULL, "password" text NOT NULL, serverkey text NOT NULL DEFAULT '', salt text NOT NULL DEFAULT '', iterationcount integer NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT now(), - PRIMARY KEY (server_host, username) + PRIMARY KEY (server_host, username, "type") ); -- Add support for SCRAM auth to a database created before ejabberd 16.03: diff --git a/sql/pg.sql b/sql/pg.sql index 2cc8d4c951b..75674e3a867 100644 --- a/sql/pg.sql +++ b/sql/pg.sql @@ -17,12 +17,14 @@ -- CREATE TABLE users ( - username text PRIMARY KEY, + username text NOT NULL, + "type" smallint NOT NULL "password" text NOT NULL, serverkey text NOT NULL DEFAULT '', salt text NOT NULL DEFAULT '', iterationcount integer NOT NULL DEFAULT 0, - created_at TIMESTAMP NOT NULL DEFAULT now() + created_at TIMESTAMP NOT NULL DEFAULT now(), + PRIMARY KEY (username, "type") ); -- Add support for SCRAM auth to a database created before ejabberd 16.03: diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 4ead00f487b..aadbcf6315c 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -48,7 +48,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([auth_modules/1, convert_to_scram/1]). +-export([auth_modules/1, convert_to_scram/1, drop_password_type/2, set_password_instance/3]). -include_lib("xmpp/include/scram.hrl"). -include("logger.hrl"). @@ -76,26 +76,38 @@ -callback store_type(binary()) -> plain | external | scram. -callback set_password(binary(), binary(), password()) -> {ets_cache:tag(), {ok, password()} | {error, db_failure | not_allowed}}. +-callback set_password_multiple(binary(), binary(), [password()]) -> + {ets_cache:tag(), {ok, [password()]} | {error, db_failure | not_allowed}}. +-callback set_password_instance(binary(), binary(), password()) -> + ok | {error, db_failure | not_allowed}. -callback remove_user(binary(), binary()) -> ok | {error, db_failure | not_allowed}. -callback user_exists(binary(), binary()) -> {ets_cache:tag(), boolean() | {error, db_failure}}. -callback check_password(binary(), binary(), binary(), binary()) -> {ets_cache:tag(), boolean() | {stop, boolean()}}. -callback try_register(binary(), binary(), password()) -> {ets_cache:tag(), {ok, password()} | {error, exists | db_failure | not_allowed}}. +-callback try_register_multiple(binary(), binary(), [password()]) -> + {ets_cache:tag(), {ok, [password()]} | {error, exists | db_failure | not_allowed}}. -callback get_users(binary(), opts()) -> [{binary(), binary()}]. -callback count_users(binary(), opts()) -> number(). --callback get_password(binary(), binary()) -> {ets_cache:tag(), {ok, password()} | error}. +-callback get_password(binary(), binary()) -> {ets_cache:tag(), {ok, password() | [password()]} | error}. +-callback drop_password_type(binary(), atom()) -> + ok | {error, db_failure | not_allowed}. -callback use_cache(binary()) -> boolean(). -callback cache_nodes(binary()) -> boolean(). -optional_callbacks([reload/1, set_password/3, + set_password_multiple/3, + set_password_instance/3, remove_user/2, user_exists/2, check_password/4, try_register/3, + try_register_multiple/3, get_users/2, count_users/2, get_password/2, + drop_password_type/2, use_cache/1, cache_nodes/1]). @@ -265,15 +277,41 @@ check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGe false end. +convert_password_for_storage(_Server, #scram{} = Password) -> + {Password, [Password]}; +convert_password_for_storage(Server, Password) -> + P = case ejabberd_option:auth_stored_password_types(Server) of + [] -> + case ejabberd_option:auth_password_format(Server) of + plain -> + [Password]; + _ -> + [password_to_scram(Server, Password)] + end; + M -> + lists:sort(lists:map( + fun(scram_sha1) -> + password_to_scram(Server, Password, sha, ?SCRAM_DEFAULT_ITERATION_COUNT); + (scram_sha256) -> + password_to_scram(Server, Password, sha256, ?SCRAM_DEFAULT_ITERATION_COUNT); + (scram_sha512) -> + password_to_scram(Server, Password, sha512, ?SCRAM_DEFAULT_ITERATION_COUNT); + (plain) -> + Password + end, M)) + end, + {Password, P}. + -spec set_password(binary(), binary(), password()) -> ok | {error, db_failure | not_allowed | invalid_jid | invalid_password}. set_password(User, Server, Password) -> case validate_credentials(User, Server, Password) of {ok, LUser, LServer} -> + {Plain, Passwords} = convert_password_for_storage(Server, Password), lists:foldl( fun(M, {error, _}) -> - db_set_password(LUser, LServer, Password, M); + db_set_password(LUser, LServer, Plain, Passwords, M); (_, ok) -> ok end, {error, not_allowed}, auth_modules(LServer)); @@ -281,6 +319,32 @@ set_password(User, Server, Password) -> Err end. +set_password_instance(User, Server, Password) -> + case validate_credentials(User, Server, Password) of + {ok, LUser, LServer} -> + lists:foldl( + fun(Mod, {error, _} = Acc) -> + case erlang:function_exported(Mod, set_password_instance, 3) of + true -> + R = Mod:set_password_instance(LUser, LServer, Password), + case use_cache(Mod, LServer) of + true -> + ets_cache:delete(cache_tab(Mod), {LUser, LServer}, + cache_nodes(Mod, LServer)); + _ -> + ok + end, + R; + _ -> + Acc + end; + (_, ok) -> + ok + end, {error, not_allowed}, auth_modules(LServer)); + Err -> + Err + end. + -spec try_register(binary(), binary(), password()) -> ok | {error, db_failure | not_allowed | exists | invalid_jid | invalid_password}. @@ -293,22 +357,23 @@ try_register(User, Server, Password) -> false -> case ejabberd_router:is_my_host(LServer) of true -> - case ejabberd_hooks:run_fold(check_register_user, LServer, true, [User, Server, Password]) of + case ejabberd_hooks:run_fold(check_register_user, LServer, true, + [User, Server, Password]) of true -> - case lists:foldl( - fun(_, ok) -> - ok; - (Mod, _) -> - db_try_register( - LUser, LServer, Password, Mod) - end, {error, not_allowed}, - auth_modules(LServer)) of - ok -> - ejabberd_hooks:run( - register_user, LServer, [LUser, LServer]); - {error, _} = Err -> - Err - end; + {Plain, Passwords} = convert_password_for_storage(Server, Password), + case lists:foldl( + fun(_, ok) -> + ok; + (Mod, _) -> + db_try_register( + LUser, LServer, Plain, Passwords, Mod) + end, {error, not_allowed}, auth_modules(LServer)) of + ok -> + ejabberd_hooks:run( + register_user, LServer, [LUser, LServer]); + {error, _} = Err -> + Err + end; false -> {error, not_allowed} end; @@ -356,32 +421,27 @@ count_users(Server, Opts) -> auth_modules(LServer))) end. --spec get_password(binary(), binary()) -> false | password(). +-spec get_password(binary(), binary()) -> false | [password()]. get_password(User, Server) -> - case validate_credentials(User, Server) of - {ok, LUser, LServer} -> - case lists:foldl( - fun(M, error) -> db_get_password(LUser, LServer, M); - (_M, Acc) -> Acc - end, error, auth_modules(LServer)) of - {ok, Password} -> - Password; - error -> - false - end; - _ -> - false + case get_password_with_authmodule(User, Server) of + {Passwords, _} -> Passwords end. -spec get_password_s(binary(), binary()) -> password(). get_password_s(User, Server) -> case get_password(User, Server) of false -> <<"">>; - Password -> Password + Passwords -> + {_, Pass} = lists:foldl( + fun(Plain, _) when is_binary(Plain) -> {true, Plain}; + (Pass, {false, _}) -> {true, Pass}; + (_, Acc) -> Acc + end, {false, <<"">>}, Passwords), + Pass end. -spec get_password_with_authmodule(binary(), binary()) -> - {false | {false, atom(), binary()} | password(), module()}. + {false | {false, atom(), binary()} | [password()], module()}. get_password_with_authmodule(User, Server) -> case validate_credentials(User, Server) of {ok, LUser, LServer} -> @@ -395,8 +455,10 @@ get_password_with_authmodule(User, Server) -> (_M, Acc) -> Acc end, {error, undefined}, auth_modules(LServer)) of - {{ok, Password}, Module} -> + {{ok, Password}, Module} when is_list(Password) -> {Password, Module}; + {{ok, Password}, Module} -> + {[Password], Module}; {error, Module} -> {false, Module} end @@ -455,6 +517,30 @@ user_exists_in_other_modules_loop([AuthModule | AuthModules], User, Server) -> maybe_exists end. +drop_password_type(LServer, Type) -> + Hash = case Type of + plain -> plain; + scram_sha1 -> sha; + scram_sha256 -> sha256; + scram_sha512 -> sha512 + end, + lists:foreach( + fun(M) -> + case erlang:function_exported(M, drop_password_type, 2) of + true -> + M:drop_password_type(LServer, Hash), + case use_cache(M, LServer) of + true -> + ets_cache:clear(cache_tab(M), + cache_nodes(M, LServer)); + false -> + ok + end; + _ -> + ok + end + end, auth_modules(LServer)). + -spec which_users_exists(list({binary(), binary()})) -> list({binary(), binary()}). which_users_exists(USPairs) -> ByServer = lists:foldl( @@ -592,54 +678,86 @@ get_is_banned(User, Server) -> %%%---------------------------------------------------------------------- %%% Backend calls %%%---------------------------------------------------------------------- --spec db_try_register(binary(), binary(), password(), module()) -> ok | {error, exists | db_failure | not_allowed}. -db_try_register(User, Server, Password, Mod) -> - case erlang:function_exported(Mod, try_register, 3) of +-spec db_try_register(binary(), binary(), binary(), [password()], module()) -> ok | {error, exists | db_failure | not_allowed}. +db_try_register(User, Server, PlainPassword, Passwords, Mod) -> + Ret = case erlang:function_exported(Mod, try_register_multiple, 3) of true -> - Password1 = case Mod:store_type(Server) of - scram -> password_to_scram(Server, Password); - _ -> Password - end, - Ret = case use_cache(Mod, Server) of - true -> - ets_cache:update( - cache_tab(Mod), {User, Server}, {ok, Password}, - fun() -> Mod:try_register(User, Server, Password1) end, - cache_nodes(Mod, Server)); - false -> - ets_cache:untag(Mod:try_register(User, Server, Password1)) - end, - case Ret of - {ok, _} -> ok; - {error, _} = Err -> Err + case use_cache(Mod, Server) of + true -> + ets_cache:update( + cache_tab(Mod), {User, Server}, {ok, Passwords}, + fun() -> Mod:try_register_multiple(User, Server, Passwords) end, + cache_nodes(Mod, Server)); + false -> + ets_cache:untag(Mod:try_register_multiple(User, Server, Passwords)) end; - false -> - {error, not_allowed} + _ -> + case erlang:function_exported(Mod, try_register, 3) of + true -> + case use_cache(Mod, Server) of + true -> + ets_cache:update( + cache_tab(Mod), {User, Server}, {ok, [PlainPassword]}, + fun() -> + case Mod:try_register(User, Server, PlainPassword) of + {Tag, {ok, Pass}} -> {Tag, {ok, [Pass]}}; + Other -> Other + end + end, cache_nodes(Mod, Server)); + false -> + case Mod:try_register(User, Server, PlainPassword) of + {_, {ok, Pass}} -> {ok, [Pass]}; + V -> ets_cache:untag(V) + end + end; + false -> + {error, not_allowed} + end + end, + case Ret of + {ok, _} -> ok; + {error, _} = Err -> Err end. --spec db_set_password(binary(), binary(), password(), module()) -> ok | {error, db_failure | not_allowed}. -db_set_password(User, Server, Password, Mod) -> - case erlang:function_exported(Mod, set_password, 3) of - true -> - Password1 = case Mod:store_type(Server) of - scram -> password_to_scram(Server, Password); - _ -> Password - end, - Ret = case use_cache(Mod, Server) of +-spec db_set_password(binary(), binary(), binary(), [password()], module()) -> ok | {error, db_failure | not_allowed}. +db_set_password(User, Server, PlainPassword, Passwords, Mod) -> + Ret = case erlang:function_exported(Mod, set_password_multiple, 3) of + true -> + case use_cache(Mod, Server) of true -> ets_cache:update( - cache_tab(Mod), {User, Server}, {ok, Password}, - fun() -> Mod:set_password(User, Server, Password1) end, - cache_nodes(Mod, Server)); + cache_tab(Mod), {User, Server}, {ok, Passwords}, + fun() -> Mod:set_password_multiple(User, Server, Passwords) end, + cache_nodes(Mod, Server)); false -> - ets_cache:untag(Mod:set_password(User, Server, Password1)) - end, - case Ret of - {ok, _} -> ok; - {error, _} = Err -> Err - end; - false -> - {error, not_allowed} + ets_cache:untag(Mod:set_password_multiple(User, Server, Passwords)) + end; + _ -> + case erlang:function_exported(Mod, set_password, 3) of + true -> + case use_cache(Mod, Server) of + true -> + ets_cache:update( + cache_tab(Mod), {User, Server}, {ok, [PlainPassword]}, + fun() -> + case Mod:set_password(User, Server, PlainPassword) of + {Tag, {ok, Pass}} -> {Tag, {ok, [Pass]}}; + Other -> Other + end + end, cache_nodes(Mod, Server)); + false -> + case Mod:set_password(User, Server, PlainPassword) of + {_, {ok, Pass}} -> {ok, [Pass]}; + V -> ets_cache:untag(V) + end + end; + false -> + {error, not_allowed} + end + end, + case Ret of + {ok, _} -> ok; + {error, _} = Err -> Err end. db_get_password(User, Server, Mod) -> @@ -655,10 +773,20 @@ db_get_password(User, Server, Mod) -> error; true when UseCache -> ets_cache:lookup( - cache_tab(Mod), {User, Server}, - fun() -> Mod:get_password(User, Server) end); + cache_tab(Mod), {User, Server}, + fun() -> + case Mod:get_password(User, Server) of + {_, {ok, List}} = V when is_list(List) -> V; + {Tag, {ok, Single}} -> {Tag, {ok, [Single]}}; + Other -> Other + end + end); true -> - ets_cache:untag(Mod:get_password(User, Server)) + case Mod:get_password(User, Server) of + {_, {ok, List}} when is_list(List) -> {ok, List}; + {_, {ok, Single}} -> {ok, [Single]}; + Other -> ets_cache:untag(Other) + end end. db_user_exists(User, Server, Mod) -> @@ -703,8 +831,8 @@ db_user_exists(User, Server, Mod) -> db_check_password(User, AuthzId, Server, ProvidedPassword, Digest, DigestFun, Mod) -> case db_get_password(User, Server, Mod) of - {ok, ValidPassword} -> - match_passwords(ProvidedPassword, ValidPassword, Digest, DigestFun); + {ok, ValidPasswords} -> + match_passwords(ProvidedPassword, ValidPasswords, Digest, DigestFun); error -> case {Mod:store_type(Server), use_cache(Mod, Server)} of {external, true} -> @@ -809,7 +937,9 @@ password_to_scram(Host, Password) -> password_to_scram(_Host, #scram{} = Password, _IterationCount) -> Password; password_to_scram(Host, Password, IterationCount) -> - Hash = ejabberd_option:auth_scram_hash(Host), + password_to_scram(Host, Password, ejabberd_option:auth_scram_hash(Host), IterationCount). + +password_to_scram(_Host, Password, Hash, IterationCount) -> Salt = p1_rand:bytes(?SALT_LENGTH), SaltedPassword = scram:salted_password(Hash, Password, Salt, IterationCount), StoredKey = scram:stored_key(Hash, scram:client_key(Hash, SaltedPassword)), @@ -897,11 +1027,19 @@ auth_modules(Server) -> misc:atom_to_binary(M)]) || M <- Methods]. --spec match_passwords(password(), password(), +-spec match_passwords(password(), [password()], binary(), digest_fun() | undefined) -> boolean(). -match_passwords(Password, #scram{} = Scram, <<"">>, undefined) -> +match_passwords(Provided, Passwords, Digest, DigestFun) -> + lists:any( + fun(Pass) -> + match_password(Provided, Pass, Digest, DigestFun) + end, Passwords). + +-spec match_password(password(), password(), + binary(), digest_fun() | undefined) -> boolean(). +match_password(Password, #scram{} = Scram, <<"">>, undefined) -> is_password_scram_valid(Password, Scram); -match_passwords(Password, #scram{} = Scram, Digest, DigestFun) -> +match_password(Password, #scram{} = Scram, Digest, DigestFun) -> StoredKey = base64:decode(Scram#scram.storedkey), DigRes = if Digest /= <<"">> -> Digest == DigestFun(StoredKey); @@ -912,9 +1050,9 @@ match_passwords(Password, #scram{} = Scram, Digest, DigestFun) -> true -> StoredKey == Password andalso Password /= <<"">> end; -match_passwords(ProvidedPassword, ValidPassword, <<"">>, undefined) -> +match_password(ProvidedPassword, ValidPassword, <<"">>, undefined) -> ProvidedPassword == ValidPassword andalso ProvidedPassword /= <<"">>; -match_passwords(ProvidedPassword, ValidPassword, Digest, DigestFun) -> +match_password(ProvidedPassword, ValidPassword, Digest, DigestFun) -> DigRes = if Digest /= <<"">> -> Digest == DigestFun(ValidPassword); true -> false @@ -983,7 +1121,7 @@ convert_to_scram(Server) -> lists:foreach( fun({U, S}) -> case get_password(U, S) of - Pass when is_binary(Pass) -> + [Pass] when is_binary(Pass) -> SPass = password_to_scram(Server, Pass), set_password(U, S, SPass); _ -> diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl index 6ed303fae69..1fe57aca176 100644 --- a/src/ejabberd_auth_mnesia.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -29,11 +29,11 @@ -behaviour(ejabberd_auth). --export([start/1, stop/1, set_password/3, try_register/3, +-export([start/1, stop/1, set_password_multiple/3, try_register_multiple/3, get_users/2, init_db/0, count_users/2, get_password/2, remove_user/2, store_type/1, import/2, - plain_password_required/1, use_cache/1]). + plain_password_required/1, use_cache/1, drop_password_type/2, set_password_instance/3]). -export([need_transform/1, transform/1]). -include("logger.hrl"). @@ -86,30 +86,58 @@ plain_password_required(Server) -> store_type(Server) -> ejabberd_auth:password_format(Server). -set_password(User, Server, Password) -> - US = {User, Server}, - F = fun () -> - mnesia:write(#passwd{us = US, password = Password}) +set_password_multiple(User, Server, Passwords) -> + F = fun() -> + lists:foreach( + fun(#scram{hash = Hash} = Password) -> + mnesia:write(#passwd{us = {User, Server, Hash}, password = Password}); + (Plain) -> + mnesia:write(#passwd{us = {User, Server, plain}, password = Plain}) + end, Passwords) end, case mnesia:transaction(F) of {atomic, ok} -> - {cache, {ok, Password}}; + {cache, {ok, Passwords}}; {aborted, Reason} -> ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]), {nocache, {error, db_failure}} end. -try_register(User, Server, Password) -> - US = {User, Server}, - F = fun () -> - case mnesia:read({passwd, US}) of - [] -> - mnesia:write(#passwd{us = US, password = Password}), - mnesia:dirty_update_counter(reg_users_counter, Server, 1), - {ok, Password}; - [_] -> - {error, exists} - end +set_password_instance(User, Server, Password) -> + F = fun() -> + case Password of + #scram{hash = Hash} = Password -> + mnesia:write(#passwd{us = {User, Server, Hash}, password = Password}); + Plain -> + mnesia:write(#passwd{us = {User, Server, plain}, password = Plain}) + end + end, + case mnesia:transaction(F) of + {atomic, ok} -> + ok; + {aborted, Reason} -> + ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]), + {error, db_failure} + end. + +try_register_multiple(User, Server, Passwords) -> + F = fun() -> + case mnesia:select(passwd, [{{'_', {'$1', '$2', '_'}, '$3'}, + [{'==', '$1', User}, + {'==', '$2', Server}], + ['$3']}]) of + [] -> + lists:foreach( + fun(#scram{hash = Hash} = Password) -> + mnesia:write(#passwd{us = {User, Server, Hash}, password = Password}); + (Plain) -> + mnesia:write(#passwd{us = {User, Server, plain}, password = Plain}) + end, Passwords), + mnesia:dirty_update_counter(reg_users_counter, Server, 1), + {ok, Passwords}; + [_] -> + {error, exists} + end end, case mnesia:transaction(F) of {atomic, Res} -> @@ -120,9 +148,10 @@ try_register(User, Server, Password) -> end. get_users(Server, []) -> - mnesia:dirty_select(passwd, + Users = mnesia:dirty_select(passwd, [{#passwd{us = '$1', _ = '_'}, - [{'==', {element, 2, '$1'}, Server}], ['$1']}]); + [{'==', {element, 2, '$1'}, Server}], ['$1']}]), + lists:uniq(lists:map(fun({U, S, _}) -> {U, S} end, Users)); get_users(Server, [{from, Start}, {to, End}]) when is_integer(Start) and is_integer(End) -> get_users(Server, [{limit, End - Start + 1}, {offset, Start}]); @@ -179,22 +208,48 @@ count_users(Server, _) -> count_users(Server, []). get_password(User, Server) -> - case mnesia:dirty_read(passwd, {User, Server}) of - [{passwd, _, {scram, SK, SEK, Salt, IC}}] -> - {cache, {ok, #scram{storedkey = SK, serverkey = SEK, - salt = Salt, hash = sha, iterationcount = IC}}}; - [#passwd{password = Password}] -> - {cache, {ok, Password}}; + case mnesia:dirty_select(passwd, [{{'_', {'$1', '$2', '_'}, '$3'}, + [{'==', '$1', User}, + {'==', '$2', Server}], + ['$3']}]) of + [_|_] = List -> + List2 = lists:map( + fun({scram, SK, SEK, Salt, IC}) -> + #scram{storedkey = SK, serverkey = SEK, + salt = Salt, hash = sha, iterationcount = IC}; + (Other) -> Other + end, List), + {cache, {ok, List2}}; _ -> {cache, error} end. +drop_password_type(Server, Hash) -> + F = fun() -> + Keys = mnesia:select(passwd, [{{'_', '$1', '_'}, + [{'==', {element, 3, '$1'}, Hash}, + {'==', {element, 2, '$1'}, Server}], + ['$1']}]), + lists:foreach(fun(Key) -> mnesia:delete({passwd, Key}) end, Keys), + ok + end, + case mnesia:transaction(F) of + {atomic, ok} -> + ok; + {aborted, Reason} -> + ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]), + {error, db_failure} + end. + remove_user(User, Server) -> - US = {User, Server}, F = fun () -> - mnesia:delete({passwd, US}), - mnesia:dirty_update_counter(reg_users_counter, Server, -1), - ok + Keys = mnesia:select(passwd, [{{'_', '$1', '_'}, + [{'==', {element, 1, '$1'}, User}, + {'==', {element, 2, '$1'}, Server}], + ['$1']}]), + lists:foreach(fun(Key) -> mnesia:delete({passwd, Key}) end, Keys), + mnesia:dirty_update_counter(reg_users_counter, Server, -1), + ok end, case mnesia:transaction(F) of {atomic, ok} -> @@ -206,45 +261,10 @@ remove_user(User, Server) -> need_transform(#reg_users_counter{}) -> false; -need_transform({passwd, {U, S}, Pass}) -> - case Pass of - _ when is_binary(Pass) -> - case store_type(S) of - scram -> - ?INFO_MSG("Passwords in Mnesia table 'passwd' " - "will be SCRAM'ed", []), - true; - plain -> - false - end; - {scram, _, _, _, _} -> - case store_type(S) of - scram -> - false; - plain -> - ?WARNING_MSG("Some passwords were stored in the database " - "as SCRAM, but 'auth_password_format' " - "is not configured as 'scram': some " - "authentication mechanisms such as DIGEST-MD5 " - "would *fail*", []), - false - end; - #scram{} -> - case store_type(S) of - scram -> - false; - plain -> - ?WARNING_MSG("Some passwords were stored in the database " - "as SCRAM, but 'auth_password_format' " - "is not configured as 'scram': some " - "authentication mechanisms such as DIGEST-MD5 " - "would *fail*", []), - false - end; - _ when is_list(U) orelse is_list(S) orelse is_list(Pass) -> - ?INFO_MSG("Mnesia table 'passwd' will be converted to binary", []), - true - end. +need_transform({passwd, {_U, _S, _T}, _Pass}) -> + false; +need_transform({passwd, {_U, _S}, _Pass}) -> + true. transform({passwd, {U, S}, Pass}) when is_list(U) orelse is_list(S) orelse is_list(Pass) -> @@ -263,24 +283,14 @@ transform({passwd, {U, S}, Pass}) transform(#passwd{us = NewUS, password = NewPass}); transform(#passwd{us = {U, S}, password = Password} = P) when is_binary(Password) -> - case store_type(S) of - scram -> - case jid:resourceprep(Password) of - error -> - ?ERROR_MSG("SASLprep failed for password of user ~ts@~ts", - [U, S]), - P; - _ -> - Scram = ejabberd_auth:password_to_scram(S, Password), - P#passwd{password = Scram} - end; - plain -> - P - end; -transform({passwd, _, {scram, _, _, _, _}} = P) -> - P; -transform(#passwd{password = #scram{}} = P) -> - P. + P#passwd{us = {U, S, plain}, password = Password}; +transform({passwd, {U, S}, {scram, SK, SEK, Salt, IC}}) -> + #passwd{us = {U, S, sha}, + password = #scram{storedkey = SK, serverkey = SEK, + salt = Salt, hash = sha, iterationcount = IC}}; +transform(#passwd{us = {U, S}, password = #scram{hash = Hash}} = P) -> + P#passwd{us = {U, S, Hash}}; +transform(Other) -> Other. import(LServer, [LUser, Password, _TimeStamp]) -> mnesia:dirty_write( diff --git a/src/ejabberd_auth_sql.erl b/src/ejabberd_auth_sql.erl index fefabdf76d1..b8ff9861547 100644 --- a/src/ejabberd_auth_sql.erl +++ b/src/ejabberd_auth_sql.erl @@ -30,10 +30,10 @@ -behaviour(ejabberd_auth). --export([start/1, stop/1, set_password/3, try_register/3, +-export([start/1, stop/1, set_password_multiple/3, try_register_multiple/3, get_users/2, count_users/2, get_password/2, remove_user/2, store_type/1, plain_password_required/1, - export/1, which_users_exists/2]). + export/1, which_users_exists/2, drop_password_type/2, set_password_instance/3]). -export([sql_schemas/0]). -include_lib("xmpp/include/scram.hrl"). @@ -49,7 +49,34 @@ start(Host) -> ok. sql_schemas() -> - [#sql_schema{ + [ + #sql_schema{ + version = 2, + tables = + [#sql_table{ + name = <<"users">>, + columns = + [#sql_column{name = <<"username">>, type = text}, + #sql_column{name = <<"server_host">>, type = text}, + #sql_column{name = <<"type">>, type = smallint}, + #sql_column{name = <<"password">>, type = text}, + #sql_column{name = <<"serverkey">>, type = {text, 128}, + default = true}, + #sql_column{name = <<"salt">>, type = {text, 128}, + default = true}, + #sql_column{name = <<"iterationcount">>, type = integer, + default = true}, + #sql_column{name = <<"created_at">>, type = timestamp, + default = true}], + indices = [#sql_index{ + columns = [<<"server_host">>, <<"username">>, <<"type">>], + unique = true}]}], + update = [ + {add_column, <<"users">>, <<"type">>}, + {update_primary_key,<<"users">>, + [<<"server_host">>, <<"username">>, <<"type">>]} + ]}, + #sql_schema{ version = 1, tables = [#sql_table{ @@ -78,42 +105,87 @@ plain_password_required(Server) -> store_type(Server) -> ejabberd_auth:password_format(Server). -set_password(User, Server, Password) -> +hash_to_num(plain) -> 1; +hash_to_num(sha) -> 2; +hash_to_num(sha256) -> 3; +hash_to_num(sha512) -> 4. + +num_to_hash(2) -> sha; +num_to_hash(3) -> sha256; +num_to_hash(4) -> sha512. + +set_password_instance(User, Server, #scram{hash = Hash, storedkey = SK, serverkey = SEK, + salt = Salt, iterationcount = IC}) -> + F = fun() -> + set_password_scram_t(User, Server, Hash, + SK, SEK, Salt, IC) + end, + case ejabberd_sql:sql_transaction(Server, F) of + {atomic, _} -> + ok; + {aborted, _} -> + {error, db_failure} + end; +set_password_instance(User, Server, Plain) -> + F = fun() -> + set_password_t(User, Server, Plain) + end, + case ejabberd_sql:sql_transaction(Server, F) of + {atomic, _} -> + ok; + {aborted, _} -> + {error, db_failure} + end. + +set_password_multiple(User, Server, Passwords) -> F = fun() -> - case Password of - #scram{hash = Hash, storedkey = SK, serverkey = SEK, - salt = Salt, iterationcount = IC} -> - SK2 = scram_hash_encode(Hash, SK), + ejabberd_sql:sql_query_t( + ?SQL("delete from users where username=%(User)s and %(Server)H")), + lists:foreach( + fun(#scram{hash = Hash, storedkey = SK, serverkey = SEK, + salt = Salt, iterationcount = IC}) -> set_password_scram_t( - User, Server, - SK2, SEK, Salt, IC); - _ -> - set_password_t(User, Server, Password) - end + User, Server, Hash, + SK, SEK, Salt, IC); + (Plain) -> + set_password_t(User, Server, Plain) + end, Passwords) end, case ejabberd_sql:sql_transaction(Server, F) of {atomic, _} -> - {cache, {ok, Password}}; + {cache, {ok, Passwords}}; {aborted, _} -> {nocache, {error, db_failure}} end. -try_register(User, Server, Password) -> - Res = - case Password of - #scram{hash = Hash, storedkey = SK, serverkey = SEK, - salt = Salt, iterationcount = IC} -> - SK2 = scram_hash_encode(Hash, SK), - add_user_scram( - Server, User, - SK2, SEK, Salt, IC); - _ -> - add_user(Server, User, Password) - end, - case Res of - {updated, 1} -> {cache, {ok, Password}}; - _ -> {nocache, {error, exists}} +try_register_multiple(User, Server, Passwords) -> + F = + fun() -> + case ejabberd_sql:sql_query_t( + ?SQL("select @(count(*))d from users where username=%(User)s and %(Server)H")) of + {selected, [{0}]} -> + lists:foreach( + fun(#scram{hash = Hash, storedkey = SK, serverkey = SEK, + salt = Salt, iterationcount = IC}) -> + set_password_scram_t( + User, Server, Hash, + SK, SEK, Salt, IC); + (Plain) -> + set_password_t(User, Server, Plain) + end, Passwords), + {cache, {ok, Passwords}}; + {selected, _} -> + {nocache, {error, exists}}; + _ -> + {nocache, {error, db_failure}} + end + end, + case ejabberd_sql:sql_transaction(Server, F) of + {atomic, Res} -> + Res; + {aborted, _} -> + {nocache, {error, db_failure}} end. get_users(Server, Opts) -> @@ -132,21 +204,41 @@ count_users(Server, Opts) -> get_password(User, Server) -> case get_password_scram(Server, User) of - {selected, [{Password, <<>>, <<>>, 0}]} -> - {cache, {ok, Password}}; - {selected, [{StoredKey, ServerKey, Salt, IterationCount}]} -> - {Hash, SK} = case StoredKey of - <<"sha256:", Rest/binary>> -> {sha256, Rest}; - <<"sha512:", Rest/binary>> -> {sha512, Rest}; - Other -> {sha, Other} - end, - {cache, {ok, #scram{storedkey = SK, - serverkey = ServerKey, - salt = Salt, - hash = Hash, - iterationcount = IterationCount}}}; {selected, []} -> {cache, error}; + {selected, Passwords} -> + Converted = lists:map( + fun({0, Password, <<>>, <<>>, 0}) -> + update_password_type(User, Server, 1), + Password; + ({_, Password, <<>>, <<>>, 0}) -> + Password; + ({0, StoredKey, ServerKey, Salt, IterationCount}) -> + {Hash, SK} = case StoredKey of + <<"sha256:", Rest/binary>> -> + update_password_type(User, Server, 3, Rest), + {sha256, Rest}; + <<"sha512:", Rest/binary>> -> + update_password_type(User, Server, 4, Rest), + {sha512, Rest}; + Other -> + update_password_type(User, Server, 2), + {sha, Other} + end, + #scram{storedkey = SK, + serverkey = ServerKey, + salt = Salt, + hash = Hash, + iterationcount = IterationCount}; + ({Type, StoredKey, ServerKey, Salt, IterationCount}) -> + Hash = num_to_hash(Type), + #scram{storedkey = StoredKey, + serverkey = ServerKey, + salt = Salt, + hash = Hash, + iterationcount = IterationCount} + end, Passwords), + {cache, {ok, Converted}}; _ -> {nocache, error} end. @@ -159,6 +251,13 @@ remove_user(User, Server) -> {error, db_failure} end. +drop_password_type(LServer, Hash) -> + Type = hash_to_num(Hash), + ejabberd_sql:sql_query( + LServer, + ?SQL("delete from users" + " where type=%(Type)d and %(LServer)H")). + scram_hash_encode(Hash, StoreKey) -> case Hash of sha -> StoreKey; @@ -166,12 +265,14 @@ scram_hash_encode(Hash, StoreKey) -> sha512 -> <<"sha512:", StoreKey/binary>> end. -set_password_scram_t(LUser, LServer, +set_password_scram_t(LUser, LServer, Hash, StoredKey, ServerKey, Salt, IterationCount) -> + Type = hash_to_num(Hash), ?SQL_UPSERT_T( "users", ["!username=%(LUser)s", "!server_host=%(LServer)s", + "!type=%(Type)d", "password=%(StoredKey)s", "serverkey=%(ServerKey)s", "salt=%(Salt)s", @@ -182,39 +283,30 @@ set_password_t(LUser, LServer, Password) -> "users", ["!username=%(LUser)s", "!server_host=%(LServer)s", + "!type=1", "password=%(Password)s", "serverkey=''", "salt=''", "iterationcount=0"]). -get_password_scram(LServer, LUser) -> +update_password_type(LUser, LServer, Type, Password) -> ejabberd_sql:sql_query( - LServer, - ?SQL("select @(password)s, @(serverkey)s, @(salt)s, @(iterationcount)d" - " from users" - " where username=%(LUser)s and %(LServer)H")). + LServer, + ?SQL("update users set type=%(Type)d, password=%(Password)s" + " where username=%(LUser)s and type=0 and %(LServer)H")). -add_user_scram(LServer, LUser, - StoredKey, ServerKey, Salt, IterationCount) -> +update_password_type(LUser, LServer, Type) -> ejabberd_sql:sql_query( - LServer, - ?SQL_INSERT( - "users", - ["username=%(LUser)s", - "server_host=%(LServer)s", - "password=%(StoredKey)s", - "serverkey=%(ServerKey)s", - "salt=%(Salt)s", - "iterationcount=%(IterationCount)d"])). - -add_user(LServer, LUser, Password) -> + LServer, + ?SQL("update users set type=%(Type)d" + " where username=%(LUser)s and type=0 and %(LServer)H")). + +get_password_scram(LServer, LUser) -> ejabberd_sql:sql_query( LServer, - ?SQL_INSERT( - "users", - ["username=%(LUser)s", - "server_host=%(LServer)s", - "password=%(Password)s"])). + ?SQL("select @(type)d, @(password)s, @(serverkey)s, @(salt)s, @(iterationcount)d" + " from users" + " where username=%(LUser)s and %(LServer)H")). del_user(LServer, LUser) -> ejabberd_sql:sql_query( @@ -224,7 +316,7 @@ del_user(LServer, LUser) -> list_users(LServer, []) -> ejabberd_sql:sql_query( LServer, - ?SQL("select @(username)s from users where %(LServer)H")); + ?SQL("select @(distinct username)s from users where %(LServer)H")); list_users(LServer, [{from, Start}, {to, End}]) when is_integer(Start) and is_integer(End) -> list_users(LServer, @@ -240,7 +332,7 @@ list_users(LServer, [{limit, Limit}, {offset, Offset}]) when is_integer(Limit) and is_integer(Offset) -> ejabberd_sql:sql_query( LServer, - ?SQL("select @(username)s from users " + ?SQL("select @(distinct username)s from users " "where %(LServer)H " "order by username " "limit %(Limit)d offset %(Offset)d")); @@ -252,7 +344,7 @@ list_users(LServer, SPrefix2 = <>, ejabberd_sql:sql_query( LServer, - ?SQL("select @(username)s from users " + ?SQL("select @(distinct username)s from users " "where username like %(SPrefix2)s %ESCAPE and %(LServer)H " "order by username " "limit %(Limit)d offset %(Offset)d")). @@ -269,11 +361,11 @@ users_number(LServer) -> " where oid = 'users'::regclass::oid")); _ -> ejabberd_sql:sql_query_t( - ?SQL("select @(count(*))d from users where %(LServer)H")) + ?SQL("select @(count(distinct username))d from users where %(LServer)H")) end; (_Type, _) -> ejabberd_sql:sql_query_t( - ?SQL("select @(count(*))d from users where %(LServer)H")) + ?SQL("select @(count(distinct username))d from users where %(LServer)H")) end). users_number(LServer, [{prefix, Prefix}]) @@ -282,7 +374,7 @@ users_number(LServer, [{prefix, Prefix}]) SPrefix2 = <>, ejabberd_sql:sql_query( LServer, - ?SQL("select @(count(*))d from users " + ?SQL("select @(count(distinct username))d from users " "where username like %(SPrefix2)s %ESCAPE and %(LServer)H")); users_number(LServer, []) -> users_number(LServer). @@ -290,7 +382,7 @@ users_number(LServer, []) -> which_users_exists(LServer, LUsers) when length(LUsers) =< 100 -> try ejabberd_sql:sql_query( LServer, - ?SQL("select @(username)s from users where username in %(LUsers)ls")) of + ?SQL("select @(distinct username)s from users where username in %(LUsers)ls")) of {selected, Matching} -> [U || {U} <- Matching]; {error, _} = E -> diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index f00755625bf..1852dde3281 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -423,16 +423,27 @@ sasl_mechanisms(Mechs, #{lserver := LServer, stream_encrypted := Encrypted} = St Type = ejabberd_auth:store_type(LServer), Mechs1 = ejabberd_option:disable_sasl_mechanisms(LServer), - ScramHash = ejabberd_option:auth_scram_hash(LServer), - ShaAv = Type == plain orelse (Type == scram andalso ScramHash == sha), - Sha256Av = Type == plain orelse (Type == scram andalso ScramHash == sha256), - Sha512Av = Type == plain orelse (Type == scram andalso ScramHash == sha512), + {Digest, ShaAv, Sha256Av, Sha512Av} = + case ejabberd_option:auth_stored_password_types(LServer) of + [] -> + ScramHash = ejabberd_option:auth_scram_hash(LServer), + {Type == plain, + Type == plain orelse (Type == scram andalso ScramHash == sha), + Type == plain orelse (Type == scram andalso ScramHash == sha256), + Type == plain orelse (Type == scram andalso ScramHash == sha512)}; + Methods -> + HasPlain = lists:member(plain, Methods), + {HasPlain, + HasPlain orelse lists:member(scram_sha1, Methods), + HasPlain orelse lists:member(scram_sha256, Methods), + HasPlain orelse lists:member(scram_sha512, Methods)} + end, %% I re-created it from cyrsasl ets magic, but I think it's wrong %% TODO: need to check before 18.09 release lists:filter( fun(<<"ANONYMOUS">>) -> ejabberd_auth_anonymous:is_sasl_anonymous_enabled(LServer); - (<<"DIGEST-MD5">>) -> Type == plain; + (<<"DIGEST-MD5">>) -> Digest; (<<"SCRAM-SHA-1">>) -> ShaAv; (<<"SCRAM-SHA-1-PLUS">>) -> ShaAv andalso Encrypted; (<<"SCRAM-SHA-256">>) -> Sha256Av; diff --git a/src/ejabberd_option.erl b/src/ejabberd_option.erl index cb3765b585a..2a5c369637d 100644 --- a/src/ejabberd_option.erl +++ b/src/ejabberd_option.erl @@ -19,6 +19,7 @@ -export([auth_opts/0, auth_opts/1]). -export([auth_password_format/0, auth_password_format/1]). -export([auth_scram_hash/0, auth_scram_hash/1]). +-export([auth_stored_password_types/0, auth_stored_password_types/1]). -export([auth_use_cache/0, auth_use_cache/1]). -export([c2s_cafile/0, c2s_cafile/1]). -export([c2s_ciphers/0, c2s_ciphers/1]). @@ -264,6 +265,13 @@ auth_scram_hash() -> auth_scram_hash(Host) -> ejabberd_config:get_option({auth_scram_hash, Host}). +-spec auth_stored_password_types() -> ['plain' | 'scram_sha1' | 'scram_sha256' | 'scram_sha512']. +auth_stored_password_types() -> + auth_stored_password_types(global). +-spec auth_stored_password_types(global | binary()) -> ['plain' | 'scram_sha1' | 'scram_sha256' | 'scram_sha512']. +auth_stored_password_types(Host) -> + ejabberd_config:get_option({auth_stored_password_types, Host}). + -spec auth_use_cache() -> boolean(). auth_use_cache() -> auth_use_cache(global). diff --git a/src/ejabberd_options.erl b/src/ejabberd_options.erl index 0e471059eb4..8dc88cd2398 100644 --- a/src/ejabberd_options.erl +++ b/src/ejabberd_options.erl @@ -77,6 +77,8 @@ opt_type(auth_opts) -> {path_prefix, V} end, L) end; +opt_type(auth_stored_password_types) -> + econf:list(econf:enum([plain, scram_sha1, scram_sha256, scram_sha512])); opt_type(auth_password_format) -> econf:enum([plain, scram]); opt_type(auth_scram_hash) -> @@ -546,6 +548,7 @@ options() -> {auth_opts, []}, {auth_password_format, plain}, {auth_scram_hash, sha}, + {auth_stored_password_types, []}, {auth_external_user_exists_check, true}, {auth_use_cache, fun(Host) -> ejabberd_config:get_option({use_cache, Host}) end}, diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 312e00f0e23..0359b2dbfd7 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -399,6 +399,14 @@ doc() -> "You shouldn't change this if you already have passwords generated with " "a different algorithm - users that have such passwords will not be able " "to authenticate. The default value is 'sha'.")}}, + {auth_stored_password_types, + #{value => "[plain | scram_sha1 | scram_sha256 | scram_sha512]", + desc => + ?T("List with password types that should be stored concurently for each user in database. " + "Each time user set it password, database will be updated to store passwords in format " + "compatible with each format listed here. This can be used to migrate user passwords " + "to more secure format. This options if set, will override values set in 'auth_scream_hash' " + "and 'auth_password_format'. By default this value is not set.")}}, {auth_external_user_exists_check, #{value => "true | false", note => "added in 23.10", diff --git a/src/mod_scram_upgrade.erl b/src/mod_scram_upgrade.erl index e0ffabc703a..f08c2863158 100644 --- a/src/mod_scram_upgrade.erl +++ b/src/mod_scram_upgrade.erl @@ -107,7 +107,7 @@ c2s_handle_sasl2_task_data({_, #{user := User, server := Server, #scram_upgrade_hash{data = SaltedPassword} -> StoredKey = scram:stored_key(Algo, scram:client_key(Algo, SaltedPassword)), ServerKey = scram:server_key(Algo, SaltedPassword), - ejabberd_auth:set_password(User, Server, + ejabberd_auth:set_password_instance(User, Server, #scram{hash = Algo, iterationcount = Iter, salt = Salt, serverkey = ServerKey, storedkey = StoredKey}), State2 = maps:remove(scram_upgrade, State), diff --git a/test/webadmin_tests.erl b/test/webadmin_tests.erl index 6a4ff7cacc5..fa12fd6f86f 100644 --- a/test/webadmin_tests.erl +++ b/test/webadmin_tests.erl @@ -78,7 +78,7 @@ adduser(Config) -> "server/" ++ binary_to_list(Server) ++ "/users/", <<"register/user=", (mue(User))/binary, "®ister/password=", (mue(Password))/binary, "®ister=Register">>), - Password = ejabberd_auth:get_password(User, Server), + Password = ejabberd_auth:get_password_s(User, Server), ?match({_, _}, binary:match(Body, <<"User ", User/binary, "@", Server/binary, " successfully registered">>)). @@ -92,7 +92,7 @@ changepassword(Config) -> ++ "/user/" ++ binary_to_list(mue(User)) ++ "/", <<"change_password/newpass=", (mue(Password))/binary, "&change_password=Change+Password">>), - ?match(Password, ejabberd_auth:get_password(User, Server)), + ?match(Password, ejabberd_auth:get_password_s(User, Server)), ?match({_, _}, binary:match(Body, <<"
ok
">>)). removeuser(Config) -> From 968fbc94246e25e6c0e7e8121059557f5b183dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 26 Mar 2025 11:29:59 +0100 Subject: [PATCH 151/170] Fix compilation on Users = mnesia:dirty_select(passwd, [{#passwd{us = '$1', _ = '_'}, [{'==', {element, 2, '$1'}, Server}], ['$1']}]), - lists:uniq(lists:map(fun({U, S, _}) -> {U, S} end, Users)); + {_, Res} = lists:foldl( + fun({U, S, _}, {{U2, S2}, _} = Acc) when U == U2 andalso S == S2 -> + Acc; + ({U, S, _}, {_, Res}) -> + {{U, S}, [{U, S} | Res]} + end, {{none, none}, []}, Users), + Res; get_users(Server, [{from, Start}, {to, End}]) when is_integer(Start) and is_integer(End) -> get_users(Server, [{limit, End - Start + 1}, {offset, Start}]); From 6f9f4b36354c85664a5a137177e8d8a5879bf754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 26 Mar 2025 12:52:03 +0100 Subject: [PATCH 152/170] Fix issues with ldap authentication --- src/ejabberd_auth.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index aadbcf6315c..53b5e0f217a 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -767,7 +767,8 @@ db_get_password(User, Server, Mod) -> case ets_cache:lookup(cache_tab(Mod), {User, Server}) of {ok, exists} -> error; not_found -> error; - Other -> Other + {ok, List} = V when is_list(List) -> V; + {ok, Single} -> {ok, [Single]}; end; false -> error; From 9c92fcc92d96142f984e671a16ce1b5265690c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Wed, 26 Mar 2025 13:03:41 +0100 Subject: [PATCH 153/170] Fix last commit --- src/ejabberd_auth.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 53b5e0f217a..419aad54de3 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -769,6 +769,7 @@ db_get_password(User, Server, Mod) -> not_found -> error; {ok, List} = V when is_list(List) -> V; {ok, Single} -> {ok, [Single]}; + Other -> Other end; false -> error; From 90a200be25d65ffdf2aef5b9c9273b4a8360d81e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 27 Mar 2025 16:25:12 +0100 Subject: [PATCH 154/170] Tag deps --- mix.exs | 6 +++--- mix.lock | 14 +++++++------- rebar.config | 36 ++++++++++++++++++------------------ rebar.lock | 48 +++++++++++++++++++++++------------------------- 4 files changed, 51 insertions(+), 53 deletions(-) diff --git a/mix.exs b/mix.exs index dc42f28d4fa..69f4a745515 100644 --- a/mix.exs +++ b/mix.exs @@ -130,8 +130,8 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp", ref: "be24923968261c2661a9e116650dce5ac95c9d23", override: true}, - {:yconf, git: "https://github.com/processone/yconf", ref: "9682a6025ed543eedf34637e4cfcc66837074af6", override: true}] + {:xmpp, "~> 1.10.0"}, + {:yconf, ">= 1.0.18"}] ++ cond_deps() end @@ -161,7 +161,7 @@ defmodule Ejabberd.MixProject do {if_version_below(~c"22", true), {:lager, "~> 3.9.1"}}, {config(:lua), {:luerl, "~> 1.2.0"}}, {config(:mysql), {:p1_mysql, ">= 1.0.24"}}, - {config(:pgsql), {:p1_pgsql, ">= 1.1.26"}}, + {config(:pgsql), {:p1_pgsql, ">= 1.1.32"}}, {config(:sqlite), {:sqlite3, "~> 1.1"}}, {config(:stun), {:stun, "~> 1.0"}}], do: dep diff --git a/mix.lock b/mix.lock index e8ef48a9c8c..c0c7f254fe3 100644 --- a/mix.lock +++ b/mix.lock @@ -3,11 +3,11 @@ "cache_tab": {:hex, :cache_tab, "1.0.31", "e4097b50a6f373ab1e0a5f01bab0bef6626771a4cd6c93404ed6d54810e11fbc", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8582b60a4a09b247ef86355ba9e07fce9e11edc0345a775c9171f971c72b6351"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "eimp": {:hex, :eimp, "1.0.23", "aaf32efab061143403dadbaa63e699ef8e81702fbfa96fd436d5e9be4d6a8d3a", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "907c780023cb2893e4fc4bdbe6a4f02c355913862ac67f0ecc26605e816b628a"}, + "eimp": {:hex, :eimp, "1.0.24", "853db317ba394d479d2f1181e0b0135a3cd3c2c7eb48ff6cfb035a28dd354b14", [:rebar3], [{:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "7d61432eb8a45659c0be475f44e75eeb651743aa64a1de8adf785cdad81961ad"}, "epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"}, "eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, - "esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"}, + "esip": {:hex, :esip, "1.0.57", "4b14e4832d08b9ffc10d855b5d10b3083232b1d53deb4c046679496ce85569c4", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.17", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "19c357e1817b1e04792ef359bf900400f3e6d0e5ade929fd72f88ea9b44af2ed"}, "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, "exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"}, "ezlib": {:hex, :ezlib, "1.0.13", "3c7f62862850a241159c10b218ecf580bce54d0890601b65144dacc2633be2b0", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "9ee62ab3f8ed55a0fd11a9569fcb8e458683f95575417272192b069f092abfbb"}, @@ -25,15 +25,15 @@ "mqtree": {:hex, :mqtree, "1.0.17", "82f54b8f2d22b4445db1d6cccb7fe9ead049d61410c29e32475f3ceb3ee62a89", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "5fe8b7cf8fbc4783d0fceb94654ac2bbf3242a58cd0397d249ded8ae021be2a3"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "p1_acme": {:hex, :p1_acme, "1.0.25", "db91f0d6c193cd1d5c0b0fa3939a898dbf56a6075db4347cde26e802715de50c", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.17", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "a7b55b47495ddb4f98a15e65451ec3ad43f4637b955c74cd695d98e6a645d08c"}, - "p1_mysql": {:hex, :p1_mysql, "1.0.25", "875d4cbdc7c9990270df3292cce2514e4c18a9fdfd19bef258cb4d0c45b4f243", [:rebar3], [], "hexpm", "e6187ffae95b726098e88f3ee6f2344ac259ce2c26e0ee403b05feef341ae434"}, + "p1_mysql": {:hex, :p1_mysql, "1.0.26", "574d07c9936c53b1ec3556db3cf064cc14a6c39039835b3d940471bfa5ac8e2b", [:rebar3], [], "hexpm", "ea138083f2c54719b9cf549dbf5802a288b0019ea3e5449b354c74cc03fafdec"}, "p1_oauth2": {:hex, :p1_oauth2, "0.6.14", "1c5f82535574de87e2059695ac4b91f8f9aebacbc1c80287dae6f02552d47aea", [:rebar3], [], "hexpm", "1fd3ac474e43722d9d5a87c6df8d36f698ed87af7bb81cbbb66361451d99ae8f"}, - "p1_pgsql": {:hex, :p1_pgsql, "1.1.31", "8339beac1f0f4a45f476ff5306be5135020f02979a61df0d8cf7b1c67e85e2fd", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "b7fc45dfb2549187347871b7fd0573638ad5ea337f6263fba1b3840efab2ff49"}, + "p1_pgsql": {:hex, :p1_pgsql, "1.1.32", "3f95d7e3413fc8f0be80abb4be1a0d7f67066a36905085cd5a423145598b0cb0", [:rebar3], [{:xmpp, "~> 1.10.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "268b01e8f4eb75c211a31495a25c2815c549aecce2f0df1a161c6e0a2cde061e"}, "p1_utils": {:hex, :p1_utils, "1.0.26", "67b0c4ac9fa3ba3ef563b31aa111b0a004439a37fac85e027f1c3617e1c7ec6c", [:rebar3], [], "hexpm", "d0379e8c1156b98bd64f8129c1de022fcca4f2fdb7486ce73bf0ed2c3376b04c"}, "pkix": {:hex, :pkix, "1.0.10", "d3bfadf7b7cfe2a3636f1b256c9cce5f646a07ce31e57ee527668502850765a0", [:rebar3], [], "hexpm", "e02164f83094cb124c41b1ab28988a615d54b9adc38575f00f19a597a3ac5d0e"}, "sqlite3": {:hex, :sqlite3, "1.1.15", "e819defd280145c328457d7af897d2e45e8e5270e18812ee30b607c99cdd21af", [:rebar3], [], "hexpm", "3c0ba4e13322c2ad49de4e2ddd28311366adde54beae8dba9d9e3888f69d2857"}, "stringprep": {:hex, :stringprep, "1.0.31", "fa1688c156dd271722aa18c423a4163e710d2f4f475ad0bc220910df669b53af", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e9699c88e8db16b3a41f0e45ac6874a4da81a6e4854a77d76ede6d09b08e3530"}, - "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, + "stun": {:hex, :stun, "1.2.17", "c54614a592812ea125a2e6827aac5a438571b591616426ec1419ba9b48252f54", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "6b318244c21e8524a9aae3ac9a05cd8234ee994c1c2c815de68d306086ad768d"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:git, "https://github.com/processone/xmpp", "be24923968261c2661a9e116650dce5ac95c9d23", [ref: "be24923968261c2661a9e116650dce5ac95c9d23"]}, - "yconf": {:git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6", [ref: "9682a6025ed543eedf34637e4cfcc66837074af6"]}, + "xmpp": {:hex, :xmpp, "1.10.0", "68a6dff8db8987c4592b2d5dd71d3f947b4ebd15209c9acaca5909a642670630", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "ceeae43b8fe97649d8f8546b3f7f2b38ecfc931c0cdd5c7445ffb3f80fcb7d85"}, + "yconf": {:hex, :yconf, "1.0.18", "e565edc8aabb8164c3bebc86969095d296ad315dcbb46af65dccbc6c71eae0f6", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "fa950ec6503f92d6417fb8cc1d982403f041697e8e1bbf4d4588fb919b9562ea"}, } diff --git a/rebar.config b/rebar.config index f4795584147..1abf4bab498 100644 --- a/rebar.config +++ b/rebar.config @@ -26,8 +26,8 @@ {if_version_below, "24", {base64url, "~> 1.0", {git, "https://github.com/dvv/base64url", {tag, "1.0.1"}}} }}, - {cache_tab, "~> 1.0.30", {git, "https://github.com/processone/cache_tab", {tag, "1.0.31"}}}, - {eimp, "~> 1.0.22", {git, "https://github.com/processone/eimp", {tag, "1.0.23"}}}, + {cache_tab, "~> 1.0.31", {git, "https://github.com/processone/cache_tab", {tag, "1.0.31"}}}, + {eimp, "~> 1.0.24", {git, "https://github.com/processone/eimp", {tag, "1.0.24"}}}, {if_var_true, pam, {epam, "~> 1.0.14", {git, "https://github.com/processone/epam", {tag, "1.0.14"}}}}, {if_var_true, redis, @@ -41,12 +41,12 @@ {eredis, "~> 1.7.1", {git, "https://github.com/Nordix/eredis/", {tag, "v1.7.1"}}} }}}, {if_var_true, sip, - {esip, "~> 1.0.52", {git, "https://github.com/processone/esip", {tag, "1.0.56"}}}}, + {esip, "~> 1.0.57", {git, "https://github.com/processone/esip", {tag, "1.0.57"}}}}, {if_var_true, zlib, - {ezlib, "~> 1.0.12", {git, "https://github.com/processone/ezlib", {tag, "1.0.13"}}}}, - {fast_tls, "~> 1.1.19", {git, "https://github.com/processone/fast_tls", {tag, "1.1.22"}}}, - {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.55"}}}, - {fast_yaml, "~> 1.0.36", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.37"}}}, + {ezlib, "~> 1.0.13", {git, "https://github.com/processone/ezlib", {tag, "1.0.13"}}}}, + {fast_tls, "~> 1.1.22", {git, "https://github.com/processone/fast_tls", {tag, "1.1.22"}}}, + {fast_xml, "~> 1.1.55", {git, "https://github.com/processone/fast_xml", {tag, "1.1.55"}}}, + {fast_yaml, "~> 1.0.37", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.37"}}}, {idna, "~> 6.0", {git, "https://github.com/benoitc/erlang-idna", {tag, "6.0.0"}}}, {if_version_below, "27", {jiffy, "~> 1.1.1", {git, "https://github.com/davisp/jiffy", {tag, "1.1.1"}}} @@ -63,22 +63,22 @@ {luerl, "1.0.0", {git, "https://github.com/rvirding/luerl", {tag, "1.0"}}}, {luerl, "~> 1.2.0", {git, "https://github.com/rvirding/luerl", {tag, "1.2"}}} }}, - {mqtree, "~> 1.0.16", {git, "https://github.com/processone/mqtree", {tag, "1.0.17"}}}, - {p1_acme, "~> 1.0.23", {git, "https://github.com/processone/p1_acme", {tag, "1.0.25"}}}, + {mqtree, "~> 1.0.17", {git, "https://github.com/processone/mqtree", {tag, "1.0.17"}}}, + {p1_acme, "~> 1.0.25", {git, "https://github.com/processone/p1_acme", {tag, "1.0.25"}}}, {if_var_true, mysql, - {p1_mysql, "~> 1.0.24", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.25"}}}}, + {p1_mysql, "~> 1.0.26", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.26"}}}}, {p1_oauth2, "~> 0.6.14", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.14"}}}, {if_var_true, pgsql, - {p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.31"}}}}, - {p1_utils, "~> 1.0.25", {git, "https://github.com/processone/p1_utils", {tag, "1.0.26"}}}, + {p1_pgsql, "~> 1.1.32", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.32"}}}}, + {p1_utils, "~> 1.0.27", {git, "https://github.com/processone/p1_utils", {tag, "1.0.27"}}}, {pkix, "~> 1.0.10", {git, "https://github.com/processone/pkix", {tag, "1.0.10"}}}, {if_var_true, sqlite, - {sqlite3, "~> 1.1.14", {git, "https://github.com/processone/erlang-sqlite3", {tag, "1.1.15"}}}}, - {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, + {sqlite3, "~> 1.1.15", {git, "https://github.com/processone/erlang-sqlite3", {tag, "1.1.15"}}}}, + {stringprep, "~> 1.0.31", {git, "https://github.com/processone/stringprep", {tag, "1.0.31"}}}, {if_var_true, stun, - {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}}, - {xmpp, "~> 1.9.2", {git, "https://github.com/processone/xmpp", "8929be60aa0c56653b13f5fcada1e460337a016b"}}, - {yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", "9682a6025ed543eedf34637e4cfcc66837074af6"}} + {stun, "~> 1.2.17", {git, "https://github.com/processone/stun", {tag, "1.2.17"}}}}, + {xmpp, "~> 1.10.0", {git, "https://github.com/processone/xmpp", {tag, "1.10.0"}}}, + {yconf, "~> 1.0.18", {git, "https://github.com/processone/yconf", {tag, "1.0.18"}}} ]}. {gitonly_deps, [ejabberd_po]}. @@ -222,7 +222,7 @@ {dialyzer, [{get_warnings, false}, % Show warnings of dependencies {if_version_above, "25", {plt_extra_apps, - [asn1, odbc, public_key, stdlib, syntax_tools, + [asn1, public_key, stdlib, syntax_tools, idna, jose, cache_tab, eimp, fast_tls, fast_xml, fast_yaml, mqtree, p1_acme, p1_oauth2, p1_utils, pkix, diff --git a/rebar.lock b/rebar.lock index 68e7d5ae721..2c212b3309a 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,10 +1,10 @@ {"1.2.0", [{<<"base64url">>,{pkg,<<"base64url">>,<<"1.0.1">>},1}, {<<"cache_tab">>,{pkg,<<"cache_tab">>,<<"1.0.31">>},0}, - {<<"eimp">>,{pkg,<<"eimp">>,<<"1.0.23">>},0}, + {<<"eimp">>,{pkg,<<"eimp">>,<<"1.0.24">>},0}, {<<"epam">>,{pkg,<<"epam">>,<<"1.0.14">>},0}, {<<"eredis">>,{pkg,<<"eredis">>,<<"1.7.1">>},0}, - {<<"esip">>,{pkg,<<"esip">>,<<"1.0.56">>},0}, + {<<"esip">>,{pkg,<<"esip">>,<<"1.0.57">>},0}, {<<"ezlib">>,{pkg,<<"ezlib">>,<<"1.0.13">>},0}, {<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.22">>},0}, {<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.55">>},0}, @@ -15,31 +15,25 @@ {<<"luerl">>,{pkg,<<"luerl">>,<<"1.2.3">>},0}, {<<"mqtree">>,{pkg,<<"mqtree">>,<<"1.0.17">>},0}, {<<"p1_acme">>,{pkg,<<"p1_acme">>,<<"1.0.25">>},0}, - {<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.25">>},0}, + {<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.26">>},0}, {<<"p1_oauth2">>,{pkg,<<"p1_oauth2">>,<<"0.6.14">>},0}, - {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.31">>},0}, + {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.32">>},0}, {<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.27">>},0}, {<<"pkix">>,{pkg,<<"pkix">>,<<"1.0.10">>},0}, {<<"sqlite3">>,{pkg,<<"sqlite3">>,<<"1.1.15">>},0}, {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.31">>},0}, - {<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0}, + {<<"stun">>,{pkg,<<"stun">>,<<"1.2.17">>},0}, {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, - {<<"xmpp">>, - {git,"https://github.com/processone/xmpp", - {ref,"8929be60aa0c56653b13f5fcada1e460337a016b"}}, - 0}, - {<<"yconf">>, - {git,"https://github.com/processone/yconf", - {ref,"9682a6025ed543eedf34637e4cfcc66837074af6"}}, - 0}]}. + {<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.10.0">>},0}, + {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.18">>},0}]}. [ {pkg_hash,[ {<<"base64url">>, <<"F8C7F2DA04CA9A5D0F5F50258F055E1D699F0E8BF4CFDB30B750865368403CF6">>}, {<<"cache_tab">>, <<"E4097B50A6F373AB1E0A5F01BAB0BEF6626771A4CD6C93404ED6D54810E11FBC">>}, - {<<"eimp">>, <<"AAF32EFAB061143403DADBAA63E699EF8E81702FBFA96FD436D5E9BE4D6A8D3A">>}, + {<<"eimp">>, <<"853DB317BA394D479D2F1181E0B0135A3CD3C2C7EB48FF6CFB035A28DD354B14">>}, {<<"epam">>, <<"AA0B85D27F4EF3A756AE995179DF952A0721237E83C6B79D644347B75016681A">>}, {<<"eredis">>, <<"39E31AA02ADCD651C657F39AAFD4D31A9B2F63C6C700DC9CECE98D4BC3C897AB">>}, - {<<"esip">>, <<"63C0FDC667BE751714E1E5C14621A9334F21B60AC1BB68BE889454CA9CA021B7">>}, + {<<"esip">>, <<"4B14E4832D08B9FFC10D855B5D10B3083232B1D53DEB4C046679496CE85569C4">>}, {<<"ezlib">>, <<"3C7F62862850A241159C10B218ECF580BCE54D0890601B65144DACC2633BE2B0">>}, {<<"fast_tls">>, <<"44356B256AFAD4399C2FC5059A3066669DAFD8BD4E4E796C9C1CF8910DDD265E">>}, {<<"fast_xml">>, <<"ACE020F2521F2A484AC8467D2822AF85534A346E2AAE03FFCBC34F29318BEFAF">>}, @@ -50,22 +44,24 @@ {<<"luerl">>, <<"DF25F41944E57A7C4D9EF09D238BC3E850276C46039CFC12B8BB42ECCF36FCB1">>}, {<<"mqtree">>, <<"82F54B8F2D22B4445DB1D6CCCB7FE9EAD049D61410C29E32475F3CEB3EE62A89">>}, {<<"p1_acme">>, <<"DB91F0D6C193CD1D5C0B0FA3939A898DBF56A6075DB4347CDE26E802715DE50C">>}, - {<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>}, + {<<"p1_mysql">>, <<"574D07C9936C53B1EC3556DB3CF064CC14A6C39039835B3D940471BFA5AC8E2B">>}, {<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>}, - {<<"p1_pgsql">>, <<"8339BEAC1F0F4A45F476FF5306BE5135020F02979A61DF0D8CF7B1C67E85E2FD">>}, + {<<"p1_pgsql">>, <<"3F95D7E3413FC8F0BE80ABB4BE1A0D7F67066A36905085CD5A423145598B0CB0">>}, {<<"p1_utils">>, <<"F468D84C6FFA6E4B12A6160826DCF2D015527189D57865568A78B49C5ED972A1">>}, {<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>}, {<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>}, {<<"stringprep">>, <<"FA1688C156DD271722AA18C423A4163E710D2F4F475AD0BC220910DF669B53AF">>}, - {<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>}, - {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]}, + {<<"stun">>, <<"C54614A592812EA125A2E6827AAC5A438571B591616426EC1419BA9B48252F54">>}, + {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, + {<<"xmpp">>, <<"68A6DFF8DB8987C4592B2D5DD71D3F947B4EBD15209C9ACACA5909A642670630">>}, + {<<"yconf">>, <<"E565EDC8AABB8164C3BEBC86969095D296AD315DCBB46AF65DCCBC6C71EAE0F6">>}]}, {pkg_hash_ext,[ {<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>}, {<<"cache_tab">>, <<"8582B60A4A09B247EF86355BA9E07FCE9E11EDC0345A775C9171F971C72B6351">>}, - {<<"eimp">>, <<"907C780023CB2893E4FC4BDBE6A4F02C355913862AC67F0ECC26605E816B628A">>}, + {<<"eimp">>, <<"7D61432EB8A45659C0BE475F44E75EEB651743AA64A1DE8ADF785CDAD81961AD">>}, {<<"epam">>, <<"2F3449E72885A72A6C2A843F561ADD0FC2F70D7A21F61456930A547473D4D989">>}, {<<"eredis">>, <<"7C2B54C566FED55FEEF3341CA79B0100A6348FD3F162184B7ED5118D258C3CC1">>}, - {<<"esip">>, <<"9EF3660CEF93B623F7368DCD5C79F4E704358631909E6DD464E335378815DA1F">>}, + {<<"esip">>, <<"19C357E1817B1E04792EF359BF900400F3E6D0E5ADE929FD72F88EA9B44AF2ED">>}, {<<"ezlib">>, <<"9EE62AB3F8ED55A0FD11A9569FCB8E458683F95575417272192B069F092ABFBB">>}, {<<"fast_tls">>, <<"E65779AEFB7AB15C4755230FEF8077E687D20CC5A3984A5974F9F657E8E2485B">>}, {<<"fast_xml">>, <<"83F3E23A780ED5F567CDEC73953F06C95B838D709DBFA86B59A98A8D23C99F85">>}, @@ -76,13 +72,15 @@ {<<"luerl">>, <<"1B4B9D0CA5D7D280D1D2787A6A5EE9F5A212641B62BFF91556BAA53805DF3AED">>}, {<<"mqtree">>, <<"5FE8B7CF8FBC4783D0FCEB94654AC2BBF3242A58CD0397D249DED8AE021BE2A3">>}, {<<"p1_acme">>, <<"A7B55B47495DDB4F98A15E65451EC3AD43F4637B955C74CD695D98E6A645D08C">>}, - {<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>}, + {<<"p1_mysql">>, <<"EA138083F2C54719B9CF549DBF5802A288B0019EA3E5449B354C74CC03FAFDEC">>}, {<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>}, - {<<"p1_pgsql">>, <<"B7FC45DFB2549187347871B7FD0573638AD5EA337F6263FBA1B3840EFAB2FF49">>}, + {<<"p1_pgsql">>, <<"268B01E8F4EB75C211A31495A25C2815C549AECCE2F0DF1A161C6E0A2CDE061E">>}, {<<"p1_utils">>, <<"F1AF942B0A62BCFA0D59FBE30679BE4FFEB5E241A0C49ED5F094DB2F5B80F5E0">>}, {<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>}, {<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>}, {<<"stringprep">>, <<"E9699C88E8DB16B3A41F0E45AC6874A4DA81A6E4854A77D76EDE6D09B08E3530">>}, - {<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>}, - {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]} + {<<"stun">>, <<"6B318244C21E8524A9AAE3AC9A05CD8234EE994C1C2C815DE68D306086AD768D">>}, + {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, + {<<"xmpp">>, <<"CEEAE43B8FE97649D8F8546B3F7F2B38ECFC931C0CDD5C7445FFB3F80FCB7D85">>}, + {<<"yconf">>, <<"FA950EC6503F92D6417FB8CC1D982403F041697E8E1BBF4D4588FB919B9562EA">>}]} ]. From 01a71dc1892c0f946f92ea2c8e9eb247f3f9436a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Thu, 27 Mar 2025 18:29:54 +0100 Subject: [PATCH 155/170] Restore odbc in dialyzer apps --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index 1abf4bab498..0d09d7f2259 100644 --- a/rebar.config +++ b/rebar.config @@ -222,7 +222,7 @@ {dialyzer, [{get_warnings, false}, % Show warnings of dependencies {if_version_above, "25", {plt_extra_apps, - [asn1, public_key, stdlib, syntax_tools, + [asn1, odbc, public_key, stdlib, syntax_tools, idna, jose, cache_tab, eimp, fast_tls, fast_xml, fast_yaml, mqtree, p1_acme, p1_oauth2, p1_utils, pkix, From a4fc448a52fa095f6aeebf68f3763e2c794bd4c0 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 24 Mar 2025 17:37:52 +0100 Subject: [PATCH 156/170] Container: Bump versions to Erlang/OTP 27.3 and Elixir 1.18.3 --- .github/container/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile index 8aa35694902..2a271215d2f 100644 --- a/.github/container/Dockerfile +++ b/.github/container/Dockerfile @@ -1,6 +1,6 @@ #' Define default build variables -ARG OTP_VSN='27.2' -ARG ELIXIR_VSN='1.18.1' +ARG OTP_VSN='27.3' +ARG ELIXIR_VSN='1.18.3' ARG UID='9000' ARG USER='ejabberd' ARG HOME="opt/$USER" From 78650f827e04d99ed1efb90e4e60555f52dfde46 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 16:58:44 +0100 Subject: [PATCH 157/170] Rephrase auth_stored_password_types documentation --- src/ejabberd_options_doc.erl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 0359b2dbfd7..7c35f96facf 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -401,12 +401,13 @@ doc() -> "to authenticate. The default value is 'sha'.")}}, {auth_stored_password_types, #{value => "[plain | scram_sha1 | scram_sha256 | scram_sha512]", + note => "added in 25.03", desc => - ?T("List with password types that should be stored concurently for each user in database. " - "Each time user set it password, database will be updated to store passwords in format " - "compatible with each format listed here. This can be used to migrate user passwords " - "to more secure format. This options if set, will override values set in 'auth_scream_hash' " - "and 'auth_password_format'. By default this value is not set.")}}, + ?T("List of password types that should be stored simultaneously for each user in database. " + "When the user sets the account password, database will be updated to store the password in formats " + "compatible with each type listed here. This can be used to migrate user passwords " + "to a more secure format. If this option if set, it will override values set in _`auth_scram_hash`_ " + "and _`auth_password_format`_ options. The default value is `[]`.")}}, {auth_external_user_exists_check, #{value => "true | false", note => "added in 23.10", From 4fe5ee034ce8c6d8a7b970bb5eac2dc1e8ae3cdc Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 09:33:06 +0100 Subject: [PATCH 158/170] Update version number in documentation to 25.03 --- CONTAINER.md | 2 +- ejabberd.doap | 2 +- src/ejabberd.erl | 2 +- src/ejabberd_admin.erl | 4 ++-- src/ejabberd_options_doc.erl | 2 ++ src/mod_adhoc_api.erl | 2 +- src/mod_configure.erl | 2 +- src/mod_matrix_gw.erl | 7 ++++--- src/mod_muc.erl | 2 +- src/mod_muc_admin.erl | 2 +- src/mod_muc_room.erl | 2 +- 11 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CONTAINER.md b/CONTAINER.md index ea29c2f4fb4..3afe913b322 100644 --- a/CONTAINER.md +++ b/CONTAINER.md @@ -910,7 +910,7 @@ Images Comparison Let's summarize the differences between both container images. Legend: - :sparkle: is the recommended alternative -- :orange_circle: added in the latest release (ejabberd 25.xx) +- :orange_circle: added in the latest release (ejabberd 25.03) - :high_brightness: added in the previous release (ejabberd 24.12) - :low_brightness: added in the pre-previous release (ejabberd 24.10) diff --git a/ejabberd.doap b/ejabberd.doap index c17c89ca7ff..00e17190529 100644 --- a/ejabberd.doap +++ b/ejabberd.doap @@ -770,7 +770,7 @@ 0.4.0 24.02 complete - , 0.4.0 since 25.xx + , 0.4.0 since 25.03
diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 89cbd229c3e..5b6fea3aa02 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -42,7 +42,7 @@ -protocol({xep, 388, '0.4.0', '24.02', "complete", ""}). -protocol({xep, 424, '0.4.0', '24.02', "complete", ""}). -protocol({xep, 440, '0.4.0', '24.02', "complete", ""}). --protocol({xep, 474, '0.4.0', '24.02', "complete", "0.4.0 since 25.xx"}). +-protocol({xep, 474, '0.4.0', '24.02', "complete", "0.4.0 since 25.03"}). -protocol({xep, 485, '0.2.0', '24.02', "complete", "mod_pubsub_serverinfo in ejabberd-contrib.git"}). -export([start/0, stop/0, halt/0, start_app/1, start_app/2, diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 9f2cc84b816..4e7dfe739fc 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -600,7 +600,7 @@ get_commands_spec() -> #ejabberd_commands{name = mnesia_list_tables, tags = [mnesia], desc = "List of Mnesia tables", - note = "added in 25.xx", + note = "added in 25.03", module = ?MODULE, function = mnesia_list_tables, result = {tables, {list, {table, {tuple, [{name, atom}, {storage_type, binary}, @@ -618,7 +618,7 @@ get_commands_spec() -> #ejabberd_commands{name = mnesia_table_change_storage, tags = [mnesia], desc = "Change storage type of a Mnesia table", - note = "added in 25.xx", + note = "added in 25.03", longdesc = "Storage type can be: `ram_copies`, `disc_copies`, `disc_only_copies`, `remote_copy`.", module = ?MODULE, function = mnesia_table_change_storage, args = [{table, binary}, {storage_type, binary}], diff --git a/src/ejabberd_options_doc.erl b/src/ejabberd_options_doc.erl index 7c35f96facf..36bebcd5ce3 100644 --- a/src/ejabberd_options_doc.erl +++ b/src/ejabberd_options_doc.erl @@ -545,6 +545,7 @@ doc() -> "and sophisticated setups. The default value is an empty list.")}}, {define_keyword, #{value => "{NAME: Value}", + note => "added in 25.03", desc => ?T("Allows to define configuration " "_`../configuration/file-format.md#macros-and-keywords|keywords`_. "), @@ -560,6 +561,7 @@ doc() -> "sql_username: \"prefix.@SQL_USERNAME@\""]}}, {define_macro, #{value => "{NAME: Value}", + note => "improved in 25.03", desc => ?T("Allows to define configuration " "_`../configuration/file-format.md#macros-and-keywords|macros`_. "), diff --git a/src/mod_adhoc_api.erl b/src/mod_adhoc_api.erl index 397f9be6c1b..d8a16b50488 100644 --- a/src/mod_adhoc_api.erl +++ b/src/mod_adhoc_api.erl @@ -95,7 +95,7 @@ mod_doc() -> "https://xmpp.org/extensions/xep-0050.html[XEP-0050:%20Ad-Hoc%20Commands]." "This module requires _`mod_adhoc`_ (to execute the commands), " "and recommends _`mod_disco`_ (to discover the commands)."), - note => "added in 25.xx", + note => "added in 25.03", opts => [{default_version, #{value => "integer() | string()", diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 8e4c8840573..81e7d5e7b52 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1592,7 +1592,7 @@ mod_doc() -> opts => [{access, #{value => ?T("AccessName"), - note => "added in 25.xx", + note => "added in 25.03", desc => ?T("This option defines which access rule will be used to " "control who is allowed to access the features provided by this module. " diff --git a/src/mod_matrix_gw.erl b/src/mod_matrix_gw.erl index 3088a40d476..3eeaa47dc78 100644 --- a/src/mod_matrix_gw.erl +++ b/src/mod_matrix_gw.erl @@ -955,9 +955,10 @@ mod_options(Host) -> mod_doc() -> #{desc => - [?T("https://matrix.org/[Matrix]%20gateway." - "Erlang/OTP 25 or higher is required to use this module.")], - note => "added in 24.02", + [?T("https://matrix.org/[Matrix]%20gateway."), + ?T("Erlang/OTP 25 or higher is required to use this module."), + ?T("This module is available since ejabberd 24.02.")], + note => "improved in 25.03", example => ["listen:", " -", diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 42be73a9391..ac87fec68cb 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -1766,7 +1766,7 @@ mod_doc() -> "The default value is an empty string.")}}, {enable_hats, #{value => "true | false", - note => "improved in 25.xx", + note => "improved in 25.03", desc => ?T("Allow extended roles as defined in XEP-0317 Hats. " "Check the _`../../tutorials/muc-hats.md|MUC Hats`_ tutorial. " diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 59c5a0e9382..1eadea68496 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -196,7 +196,7 @@ get_commands_spec() -> "Each subscriber can have one or more nodes. " "In summary, `affiliations` is like `Type1=JID1;Type2=JID2` " "and `subscribers` is like `JID1=Nick1=Node1A=Node1B=Node1C;JID2=Nick2=Node2`.", - note = "modified in 25.xx", + note = "modified in 25.03", module = ?MODULE, function = create_room_with_opts, args_desc = ["Room name", "MUC service", "Server host", "List of options"], args_example = ["room1", "conference.example.com", "localhost", diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 81254ec9147..64e7e0a2d31 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -27,7 +27,7 @@ -author('alexey@process-one.net'). --protocol({xep, 317, '0.2.0', '25.xx', "complete", ""}). +-protocol({xep, 317, '0.2.0', '21.12', "complete", "0.2.0 since 25.03"}). -protocol({xep, 410, '1.1.0', '18.12', "complete", ""}). -behaviour(p1_fsm). From 9c29457ee2db576f9ff484b547455eb5566bf85c Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 17:19:16 +0100 Subject: [PATCH 159/170] mod_adhoc_api: Fix warning when running "make translations" --- src/mod_adhoc_api.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_adhoc_api.erl b/src/mod_adhoc_api.erl index d8a16b50488..2e478333ce1 100644 --- a/src/mod_adhoc_api.erl +++ b/src/mod_adhoc_api.erl @@ -504,7 +504,7 @@ set_form_api_command(From, Host, CommandNameBin, XData, _Lang) -> var = <<"error">>}] end, FieldsResultWithHeads = - [#xdata_field{type = fixed, label = ?T("")}, + [#xdata_field{type = fixed, label = <<"">>}, #xdata_field{type = fixed, label = ?T("Result")} | FieldsResult2], From 113e5a322e2b59e6fe113485dfa38d74e444e216 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 17:45:50 +0100 Subject: [PATCH 160/170] New Tamil translation (thanks to TamilNeram) --- priv/msgs/ta.msg | 625 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 625 insertions(+) create mode 100644 priv/msgs/ta.msg diff --git a/priv/msgs/ta.msg b/priv/msgs/ta.msg new file mode 100644 index 00000000000..fceafe5c0e8 --- /dev/null +++ b/priv/msgs/ta.msg @@ -0,0 +1,625 @@ +%% Generated automatically +%% DO NOT EDIT: run `make translations` instead +%% To improve translations please read: +%% https://docs.ejabberd.im/developer/extending-ejabberd/localization/ + +{" (Add * to the end of field to match substring)"," (அடி மூலக்கூறுடன் பொருந்தக்கூடிய புலத்தின் முடிவில் * சேர்க்கவும்)"}. +{" has set the subject to: "," இதற்கு பொருள் அமைத்துள்ளது: "}. +{"# participants","# பங்கேற்பாளர்கள்"}. +{"A description of the node","முனையின் விளக்கம்"}. +{"A friendly name for the node","முனைக்கு ஒரு நட்பு பெயர்"}. +{"A password is required to enter this room","இந்த அறைக்குள் நுழைய கடவுச்சொல் தேவை"}. +{"A Web Page","ஒரு வலைப்பக்கம்"}. +{"Accept","ஏற்றுக்கொள்"}. +{"Access denied by service policy","பணி கொள்கையால் மறுக்கப்பட்டது"}. +{"Access model","அணுகல் மாதிரி"}. +{"Account doesn't exist","கணக்கு இல்லை"}. +{"Action on user","பயனரின் செயல்"}. +{"Add a hat to a user","ஒரு பயனருக்கு ஒரு தொப்பியைச் சேர்க்கவும்"}. +{"Add User","பயனரைச் சேர்க்கவும்"}. +{"Administration of ","நிர்வாகம் "}. +{"Administration","நிர்வாகம்"}. +{"Administrator privileges required","நிர்வாகி சலுகைகள் தேவை"}. +{"All activity","அனைத்து செயல்பாடுகளும்"}. +{"All Users","அனைத்து பயனர்களும்"}. +{"Allow subscription","சந்தாவை அனுமதிக்கவும்"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","இந்த பப்சப் முனைக்கு குழுசேர இந்த சாபர் ஐடியை அனுமதிக்கவா?"}. +{"Allow this person to register with the room?","இந்த நபரை அறையில் பதிவு செய்ய அனுமதிக்கவா?"}. +{"Allow users to change the subject","இந்த விசயத்தை மாற்ற பயனர்களை அனுமதிக்கவும்"}. +{"Allow users to query other users","பயனர்களை மற்ற பயனர்களை வினவ அனுமதிக்கவும்"}. +{"Allow users to send invites","அழைப்புகளை அனுப்ப பயனர்களை அனுமதிக்கவும்"}. +{"Allow users to send private messages","தனிப்பட்ட செய்திகளை அனுப்ப பயனர்களை அனுமதிக்கவும்"}. +{"Allow visitors to change nickname","பார்வையாளர்களை புனைப்பெயரை மாற்ற அனுமதிக்கவும்"}. +{"Allow visitors to send private messages to","தனிப்பட்ட செய்திகளை அனுப்ப பார்வையாளர்களை அனுமதிக்கவும்"}. +{"Allow visitors to send status text in presence updates","முன்னிலையில் புதுப்பிப்புகளில் நிலை உரையை அனுப்ப பார்வையாளர்களை அனுமதிக்கவும்"}. +{"Allow visitors to send voice requests","குரல் கோரிக்கைகளை அனுப்ப பார்வையாளர்களை அனுமதிக்கவும்"}. +{"An associated LDAP group that defines room membership; this should be an LDAP Distinguished Name according to an implementation-specific or deployment-specific definition of a group.","அறை உறுப்பினர்களை வரையறுக்கும் தொடர்புடைய எல்.டி.ஏ.பி குழு; இது ஒரு குழுவின் செயல்படுத்தல்-குறிப்பிட்ட அல்லது வரிசைப்படுத்தல்-குறிப்பிட்ட வரையறையின்படி எல்.டி.ஏ.பி புகழ்பெற்ற பெயராக இருக்க வேண்டும்."}. +{"Announcements","அறிவிப்புகள்"}. +{"Answer associated with a picture","ஒரு படத்துடன் தொடர்புடைய பதில்"}. +{"Answer associated with a video","வீடியோவுடன் தொடர்புடைய பதில்"}. +{"Answer associated with speech","பேச்சுடன் தொடர்புடைய பதில்"}. +{"Answer to a question","ஒரு கேள்விக்கு பதில்"}. +{"Anyone in the specified roster group(s) may subscribe and retrieve items","குறிப்பிட்ட ரோச்டர் குழு (கள்) இல் உள்ள எவரும் உருப்படிகளை குழுசேரலாம் மற்றும் மீட்டெடுக்கலாம்"}. +{"Anyone may associate leaf nodes with the collection","எவரும் இலை முனைகளை சேகரிப்புடன் தொடர்புபடுத்தலாம்"}. +{"Anyone may publish","எவரும் வெளியிடலாம்"}. +{"Anyone may subscribe and retrieve items","எவரும் பொருட்களை குழுசேர் மற்றும் மீட்டெடுக்கலாம்"}. +{"Anyone with a presence subscription of both or from may subscribe and retrieve items","அல்லது இரண்டின் இருப்பு சந்தா உள்ள எவரும் உருப்படிகளை குழுசேர் மற்றும் மீட்டெடுக்கலாம்"}. +{"Anyone with Voice","குரல் உள்ள எவரும்"}. +{"Anyone","யாரும்"}. +{"April","ப-சித்திரை"}. +{"Attribute 'channel' is required for this request","இந்த கோரிக்கைக்கு 'சேனல்' என்ற பண்புக்கூறு தேவை"}. +{"Attribute 'id' is mandatory for MIX messages","கலவை செய்திகளுக்கு 'ஐடி' கட்டாயமாகும்"}. +{"Attribute 'jid' is not allowed here","'சிட்' என்ற பண்புக்கூறு இங்கே அனுமதிக்கப்படவில்லை"}. +{"Attribute 'node' is not allowed here","'முனை' என்ற பண்புக்கூறு இங்கே அனுமதிக்கப்படவில்லை"}. +{"Attribute 'to' of stanza that triggered challenge","சவாலைத் தூண்டும் சரணத்தின் '' 'என்ற பண்புக்கூறு"}. +{"August","ஆ-ஆவணி"}. +{"Automatic node creation is not enabled","தானியங்கி முனை உருவாக்கம் இயக்கப்படவில்லை"}. +{"Backup Management","காப்பு மேலாண்மை"}. +{"Backup of ~p","~p இன் காப்புப்பிரதி"}. +{"Backup to File at ","தாக்கல் செய்ய காப்புப்பிரதி "}. +{"Backup","காப்புப்பிரதி"}. +{"Bad format","மோசமான வடிவம்"}. +{"Birthday","பிறந்த நாள்"}. +{"Both the username and the resource are required","பயனர்பெயர் மற்றும் சான்று இரண்டும் தேவை"}. +{"Bytestream already activated","பைட்டெச்ட்ரீம் ஏற்கனவே செயல்படுத்தப்பட்டது"}. +{"Cannot remove active list","செயலில் உள்ள பட்டியலை அகற்ற முடியாது"}. +{"Cannot remove default list","இயல்புநிலை பட்டியலை அகற்ற முடியாது"}. +{"CAPTCHA web page","கேப்ட்சா வலைப்பக்கம்"}. +{"Challenge ID","அறைகூவல் ஐடி"}. +{"Change Password","கடவுச்சொல்லை மாற்றவும்"}. +{"Change User Password","பயனர் கடவுச்சொல்லை மாற்றவும்"}. +{"Changing password is not allowed","கடவுச்சொல்லை மாற்ற அனுமதிக்கப்படவில்லை"}. +{"Changing role/affiliation is not allowed","பங்கு/இணைப்பை மாற்ற அனுமதிக்கப்படவில்லை"}. +{"Channel already exists","சேனல் ஏற்கனவே உள்ளது"}. +{"Channel does not exist","சேனல் இல்லை"}. +{"Channel JID","சேனல் சிட்"}. +{"Channels","சேனல்கள்"}. +{"Characters not allowed:","எழுத்துக்கள் அனுமதிக்கப்படவில்லை:"}. +{"Chatroom configuration modified","அரட்டை உள்ளமைவு மாற்றப்பட்டது"}. +{"Chatroom is created","அரட்டை அறை உருவாக்கப்பட்டது"}. +{"Chatroom is destroyed","அரட்டை அறை அழிக்கப்படுகிறது"}. +{"Chatroom is started","அரட்டை அறை தொடங்கப்பட்டது"}. +{"Chatroom is stopped","அரட்டை அறை நிறுத்தப்பட்டது"}. +{"Chatrooms","அரட்டை அறைகள்"}. +{"Choose a username and password to register with this server","இந்த சேவையகத்துடன் பதிவு செய்ய பயனர்பெயர் மற்றும் கடவுச்சொல்லைத் தேர்வுசெய்க"}. +{"Choose storage type of tables","அட்டவணைகளின் சேமிப்பக வகை என்பதைத் தேர்வுசெய்க"}. +{"Choose whether to approve this entity's subscription.","இந்த நிறுவனத்தின் சந்தாவை அங்கீகரிக்க வேண்டுமா என்பதைத் தேர்வுசெய்க."}. +{"City","நகரம்"}. +{"Client acknowledged more stanzas than sent by server","சேவையகத்தால் அனுப்பப்பட்டதை விட கிளையன்ட் அதிக சரணத்தை ஒப்புக் கொண்டார்"}. +{"Commands","கட்டளைகள்"}. +{"Conference room does not exist","மாநாட்டு அறை இல்லை"}. +{"Configuration of room ~s","அறையின் உள்ளமைவு ~s"}. +{"Configuration","உள்ளமைவு"}. +{"Contact Addresses (normally, room owner or owners)","தொடர்பு முகவரிகள் (பொதுவாக, அறை உரிமையாளர் அல்லது உரிமையாளர்கள்)"}. +{"Country","நாடு"}. +{"Current Discussion Topic","தற்போதைய கலந்துரையாடல் தலைப்பு"}. +{"Database failure","தரவுத்தள தோல்வி"}. +{"Database Tables Configuration at ","தரவுத்தள அட்டவணைகள் உள்ளமைவு "}. +{"Database","தரவுத்தளம்"}. +{"December","கா-மார்கழி"}. +{"Default users as participants","பங்கேற்பாளர்களாக இயல்புநிலை பயனர்கள்"}. +{"Delete message of the day on all hosts","அனைத்து புரவலர்களிலும் அன்றைய செய்தியை நீக்கு"}. +{"Delete message of the day","அன்றைய செய்தியை நீக்கு"}. +{"Delete User","பயனரை நீக்கு"}. +{"Deliver event notifications","நிகழ்வு அறிவிப்புகளை வழங்கவும்"}. +{"Deliver payloads with event notifications","நிகழ்வு அறிவிப்புகளுடன் பேலோடுகளை வழங்கவும்"}. +{"Disc only copy","வட்டு மட்டுமே நகலெடுக்கவும்"}. +{"Don't tell your password to anybody, not even the administrators of the XMPP server.","உங்கள் கடவுச்சொல்லை யாரிடமும் சொல்லாதீர்கள், எக்ச்எம்பி.பி சேவையகத்தின் நிர்வாகிகள் கூட இல்லை."}. +{"Dump Backup to Text File at ","உரை கோப்பில் காப்புப்பிரதியை டம்ப் செய்யுங்கள் "}. +{"Dump to Text File","உரை கோப்பில் டம்ப் செய்யுங்கள்"}. +{"Duplicated groups are not allowed by RFC6121","நகல் குழுக்கள் RFC6121 ஆல் அனுமதிக்கப்படவில்லை"}. +{"Dynamically specify a replyto of the item publisher","உருப்படி வெளியீட்டாளரின் பதிலை மாறும் வகையில் குறிப்பிடவும்"}. +{"Edit Properties","பண்புகளைத் திருத்து"}. +{"Either approve or decline the voice request.","குரல் கோரிக்கையை அங்கீகரிக்கவும் அல்லது நிராகரிக்கவும்."}. +{"ejabberd HTTP Upload service","EJABBERD HTTP பதிவேற்ற பணி"}. +{"ejabberd MUC module","EJABBERD MUC தொகுதி"}. +{"ejabberd Multicast service","எசாபர்ட் மல்டிகாச்ட் பணி"}. +{"ejabberd Publish-Subscribe module","EJABBERD வெளியீட்டு-சந்தா தொகுதி"}. +{"ejabberd SOCKS5 Bytestreams module","EJABBERD SOCKS5 BYTESTREAMS தொகுதி"}. +{"ejabberd vCard module","EJABBERD VCARD தொகுதி"}. +{"ejabberd Web Admin","எசாபர்ட் வலை நிர்வாகி"}. +{"ejabberd","எசாபர்ட்"}. +{"Email Address","மின்னஞ்சல் முகவரி"}. +{"Email","மின்னஞ்சல்"}. +{"Enable hats","தொப்பிகளை இயக்கவும்"}. +{"Enable logging","பதிவை இயக்கவும்"}. +{"Enable message archiving","செய்தி காப்பகத்தை இயக்கவும்"}. +{"Enabling push without 'node' attribute is not supported","'முனை' பண்புக்கூறு இல்லாமல் உந்துதலை இயக்குவது ஆதரிக்கப்படவில்லை"}. +{"End User Session","இறுதி பயனர் அமர்வு"}. +{"Enter nickname you want to register","நீங்கள் பதிவு செய்ய விரும்பும் புனைப்பெயரை உள்ளிடவும்"}. +{"Enter path to backup file","காப்புப்பிரதி கோப்பிற்கு பாதையை உள்ளிடவும்"}. +{"Enter path to jabberd14 spool dir","Jabberd14 Spool அடைவு க்கு பாதையை உள்ளிடவும்"}. +{"Enter path to jabberd14 spool file","சாபர்ட் 14 ச்பூல் கோப்புக்கு பாதையை உள்ளிடவும்"}. +{"Enter path to text file","உரை கோப்புக்கு பாதையை உள்ளிடவும்"}. +{"Enter the text you see","நீங்கள் பார்க்கும் உரையை உள்ளிடவும்"}. +{"Erlang XMPP Server","எர்லாங் எக்ச்எம்பிபி சேவையகம்"}. +{"Exclude Jabber IDs from CAPTCHA challenge","கேப்ட்சா சேலஞ்சில் இருந்து சாபர் ஐடிகளை விலக்குங்கள்"}. +{"Export all tables as SQL queries to a file:","அனைத்து அட்டவணைகளையும் கவிமொ வினவல்களாக ஒரு கோப்பில் ஏற்றுமதி செய்யுங்கள்:"}. +{"Export data of all users in the server to PIEFXIS files (XEP-0227):","சேவையகத்தில் உள்ள அனைத்து பயனர்களின் தரவை Piefxis கோப்புகளுக்கு (XEP-0227) ஏற்றுமதி செய்யுங்கள்:"}. +{"Export data of users in a host to PIEFXIS files (XEP-0227):","ஓச்டில் பயனர்களின் தரவை Piefxis கோப்புகளுக்கு ஏற்றுமதி செய்யுங்கள் (XEP-0227):"}. +{"External component failure","வெளிப்புற கூறு தோல்வி"}. +{"External component timeout","வெளிப்புற கூறு நேரம் முடிந்தது"}. +{"Failed to activate bytestream","பைட்டெச்ட்ரீமை செயல்படுத்தத் தவறிவிட்டது"}. +{"Failed to extract JID from your voice request approval","உங்கள் குரல் கோரிக்கை ஒப்புதலிலிருந்து சிட் பிரித்தெடுப்பதில் தோல்வி"}. +{"Failed to map delegated namespace to external component","வெளிப்புற கூறுகளுக்கு பிரதிநிதித்துவ பெயர்வெளியை வரைபடமாக்குவதில் தோல்வி"}. +{"Failed to parse HTTP response","HTTP பதிலை அலசத் தவறிவிட்டது"}. +{"Failed to process option '~s'","விருப்பத்தை '~s' செயலாக்குவதில் தோல்வி"}. +{"Family Name","குடும்ப பெயர்"}. +{"FAQ Entry","கேள்விகள் நுழைவு"}. +{"February","தை-மாசி"}. +{"File larger than ~w bytes","~w பைட்டுகளை விட பெரியது"}. +{"Fill in the form to search for any matching XMPP User","பொருந்தக்கூடிய எக்ச்எம்பிபி பயனரைத் தேட படிவத்தை நிரப்பவும்"}. +{"Friday","வெள்ளிக்கிழமை"}. +{"From ~ts","~ts இலிருந்து"}. +{"Full List of Room Admins","அறை நிர்வாகிகளின் முழு பட்டியல்"}. +{"Full List of Room Owners","அறை உரிமையாளர்களின் முழு பட்டியல்"}. +{"Full Name","முழு பெயர்"}. +{"Get List of Online Users","நிகழ்நிலை பயனர்களின் பட்டியலைப் பெறுங்கள்"}. +{"Get List of Registered Users","பதிவுசெய்யப்பட்ட பயனர்களின் பட்டியலைப் பெறுங்கள்"}. +{"Get Number of Online Users","நிகழ்நிலை பயனர்களின் எண்ணிக்கையைப் பெறுங்கள்"}. +{"Get Number of Registered Users","பதிவுசெய்யப்பட்ட பயனர்களின் எண்ணிக்கையைப் பெறுங்கள்"}. +{"Get Pending","நிலுவையில் செல்லுங்கள்"}. +{"Get User Last Login Time","பயனர் கடைசி உள்நுழைவு நேரத்தைப் பெறுங்கள்"}. +{"Get User Statistics","பயனர் புள்ளிவிவரங்களைப் பெறுங்கள்"}. +{"Given Name","கொடுக்கப்பட்ட பெயர்"}. +{"Grant voice to this person?","இந்த நபருக்கு குரல் கொடுக்கவா?"}. +{"has been banned","தடைசெய்யப்பட்டுள்ளது"}. +{"has been kicked because of a system shutdown","கணினி பணிநிறுத்தம் காரணமாக உதைக்கப்பட்டுள்ளது"}. +{"has been kicked because of an affiliation change","இணைப்பு மாற்றம் காரணமாக உதைக்கப்பட்டுள்ளது"}. +{"has been kicked because the room has been changed to members-only","அறை உறுப்பினர்களுக்கு மட்டுமே மாற்றப்பட்டதால் உதைக்கப்பட்டுள்ளது"}. +{"has been kicked","உதைக்கப்பட்டுள்ளது"}. +{"Hash of the vCard-temp avatar of this room","இந்த அறையின் vcard-temp அவதாரத்தின் ஆச்"}. +{"Hat title","தொப்பி தலைப்பு"}. +{"Hat URI","தொப்பி யூரி"}. +{"Hats limit exceeded","தொப்பிகள் வரம்பு மீறியது"}. +{"Host unknown","புரவலன் தெரியவில்லை"}. +{"HTTP File Upload","HTTP கோப்பு பதிவேற்றம்"}. +{"Idle connection","செயலற்ற இணைப்பு"}. +{"If you don't see the CAPTCHA image here, visit the web page.","நீங்கள் இங்கே கேப்ட்சா படத்தைக் காணவில்லை என்றால், வலைப்பக்கத்தைப் பார்வையிடவும்."}. +{"Import Directory","இறக்குமதி அடைவு"}. +{"Import File","கோப்பு இறக்குமதி"}. +{"Import user data from jabberd14 spool file:","சாபர்ட் 14 ச்பூல் கோப்பிலிருந்து பயனர் தரவை இறக்குமதி செய்யுங்கள்:"}. +{"Import User from File at ","கோப்பிலிருந்து பயனரை இறக்குமதி செய்யுங்கள் "}. +{"Import users data from a PIEFXIS file (XEP-0227):","PIEFXIS கோப்பிலிருந்து (XEP-0227) பயனர்களின் தரவை இறக்குமதி செய்யுங்கள்:"}. +{"Import users data from jabberd14 spool directory:","சாபர்ட் 14 ச்பூல் கோப்பகத்திலிருந்து பயனர்களின் தரவை இறக்குமதி செய்யுங்கள்:"}. +{"Import Users from Dir at ","அடைவு இலிருந்து பயனர்களை இறக்குமதி செய்யுங்கள் "}. +{"Import Users From jabberd14 Spool Files","சாபர்ட் 14 ச்பூல் கோப்புகளிலிருந்து பயனர்களை இறக்குமதி செய்யுங்கள்"}. +{"Improper domain part of 'from' attribute","'ஃப்ரம்' பண்புக்கூறின் முறையற்ற டொமைன் பகுதி"}. +{"Improper message type","முறையற்ற செய்தி வகை"}. +{"Incorrect CAPTCHA submit","தவறான கேப்ட்சா சமர்ப்பிக்கவும்"}. +{"Incorrect data form","தவறான தரவு வடிவம்"}. +{"Incorrect password","தவறான கடவுச்சொல்"}. +{"Incorrect value of 'action' attribute","'செயல்' பண்புக்கூறின் தவறான மதிப்பு"}. +{"Incorrect value of 'action' in data form","தரவு வடிவத்தில் 'செயல்' இன் தவறான மதிப்பு"}. +{"Incorrect value of 'path' in data form","தரவு வடிவத்தில் 'பாதை' இன் தவறான மதிப்பு"}. +{"Installed Modules:","நிறுவப்பட்ட தொகுதிகள்:"}. +{"Install","நிறுவவும்"}. +{"Insufficient privilege","போதிய சலுகை"}. +{"Internal server error","உள் சேவையக பிழை"}. +{"Invalid 'from' attribute in forwarded message","அனுப்பப்பட்ட செய்தியில் 'இலிருந்து' பண்புக்கூறு"}. +{"Invalid node name","தவறான முனை பெயர்"}. +{"Invalid 'previd' value","தவறான 'முந்தைய' மதிப்பு"}. +{"Invitations are not allowed in this conference","இந்த மாநாட்டில் அழைப்புகள் அனுமதிக்கப்படவில்லை"}. +{"IP addresses","ஐபி முகவரிகள்"}. +{"is now known as","இப்போது அழைக்கப்படுகிறது"}. +{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","பிழை செய்திகளை அறைக்கு அனுப்ப அனுமதிக்கப்படவில்லை. பங்கேற்பாளர் (~s) ஒரு பிழை செய்தியை (~s) அனுப்பி அறையிலிருந்து உதைத்துள்ளார்"}. +{"It is not allowed to send private messages of type \"groupchat\"","\"குரூப்சாட்\" என்ற வகை தனிப்பட்ட செய்திகளை அனுப்ப அனுமதிக்கப்படவில்லை"}. +{"It is not allowed to send private messages to the conference","தனிப்பட்ட செய்திகளை மாநாட்டிற்கு அனுப்ப அனுமதிக்கப்படவில்லை"}. +{"Jabber ID","சாபர் ஐடி"}. +{"January","மா-தை"}. +{"JID normalization denied by service policy","பணி கொள்கையால் மறுக்கப்பட்ட சிட் இயல்பாக்கம்"}. +{"JID normalization failed","சிட் இயல்பாக்கம் தோல்வியடைந்தது"}. +{"Joined MIX channels of ~ts","~ts இன் கலவை சேனல்களில் சேர்ந்தது"}. +{"Joined MIX channels:","இணைந்த கலவை சேனல்கள்:"}. +{"joins the room","அறையில் இணைகிறது"}. +{"July","ஆ-ஆடி"}. +{"June","வை-ஆனி"}. +{"Just created","இப்போது உருவாக்கப்பட்டது"}. +{"Last Activity","கடைசி செயல்பாடு"}. +{"Last login","கடைசி உள்நுழைவு"}. +{"Last message","கடைசி செய்தி"}. +{"Last month","கடந்த மாதம்"}. +{"Last year","கடந்த ஆண்டு"}. +{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","உரையின் SHA-256 ஆசின் குறைந்த குறிப்பிடத்தக்க பிட்கள் எக்சாடெசிமல் சிட்டை சமமாக இருக்க வேண்டும்"}. +{"leaves the room","அறையை விட்டு வெளியேறுகிறது"}. +{"List of users with hats","தொப்பிகளைக் கொண்ட பயனர்களின் பட்டியல்"}. +{"List users with hats","தொப்பிகளுடன் பயனர்களை பட்டியலிடுங்கள்"}. +{"Logged Out","வெளியேறியது"}. +{"Logging","பதிவு"}. +{"Make participants list public","பங்கேற்பாளர்கள் பட்டியலிடுங்கள்"}. +{"Make room CAPTCHA protected","அறை கேப்ட்சா பாதுகாக்கவும்"}. +{"Make room members-only","அறை உறுப்பினர்களை மட்டும் செய்யுங்கள்"}. +{"Make room moderated","அறை மிதமானதாக்குங்கள்"}. +{"Make room password protected","அறை கடவுச்சொல்லைப் பாதுகாக்கவும்"}. +{"Make room persistent","அறையை தொடர்ந்து செய்யுங்கள்"}. +{"Make room public searchable","அறையை பொதுவில் தேடலாம்"}. +{"Malformed username","தவறான பயனர்பெயர்"}. +{"MAM preference modification denied by service policy","பணி கொள்கையால் மறுக்கப்பட்ட மாம் விருப்பத்தேர்வு மாற்றம்"}. +{"March","மா-பங்குனி"}. +{"Max # of items to persist, or `max` for no specific limit other than a server imposed maximum","அதிகபட்சம் # தொடர்ச்சியாக இருக்க வேண்டும், அல்லது அதிகபட்சமாக விதிக்கப்பட்ட சேவையகத்தைத் தவிர வேறு எந்த குறிப்பிட்ட வரம்பும் இல்லாமல் `அதிகபட்சம்"}. +{"Max payload size in bytes","பைட்டுகளில் அதிகபட்ச பேலோட் அளவு"}. +{"Maximum file size","அதிகபட்ச கோப்பு அளவு"}. +{"Maximum Number of History Messages Returned by Room","அறையால் திரும்பிய அதிகபட்ச வரலாற்று செய்திகளின் எண்ணிக்கை"}. +{"Maximum number of items to persist","தொடர்ந்து அதிகபட்ச உருப்படிகளின் எண்ணிக்கை"}. +{"Maximum Number of Occupants","அதிகபட்ச குடியிருப்பாளர்களின் எண்ணிக்கை"}. +{"May","சி-வைகாசி"}. +{"Membership is required to enter this room","இந்த அறைக்குள் நுழைய உறுப்பினர் தேவை"}. +{"Memorize your password, or write it in a paper placed in a safe place. In XMPP there isn't an automated way to recover your password if you forget it.","உங்கள் கடவுச்சொல்லை மனப்பாடம் செய்யுங்கள், அல்லது பாதுகாப்பான இடத்தில் வைக்கப்பட்டுள்ள ஒரு காகிதத்தில் எழுதுங்கள். உங்கள் கடவுச்சொல்லை மறந்துவிட்டால் அதை மீட்டெடுக்க எக்ச்எம்பிபியில் தானியங்கு வழி இல்லை."}. +{"Mere Availability in XMPP (No Show Value)","எக்ச்எம்பிபியில் வெறும் கிடைக்கும் (காட்சி மதிப்பு இல்லை)"}. +{"Message body","செய்தி உடல்"}. +{"Message not found in forwarded payload","அனுப்பப்பட்ட பேலோடில் செய்தி காணப்படவில்லை"}. +{"Messages from strangers are rejected","அந்நியர்களிடமிருந்து செய்திகள் நிராகரிக்கப்படுகின்றன"}. +{"Messages of type headline","வகை தலைப்பின் செய்திகள்"}. +{"Messages of type normal","வகை இயல்பான செய்திகள்"}. +{"Middle Name","நடுத்தர பெயர்"}. +{"Minimum interval between voice requests (in seconds)","குரல் கோரிக்கைகளுக்கு இடையில் குறைந்தபட்ச இடைவெளி (நொடிகளில்)"}. +{"Moderator privileges required","மதிப்பீட்டாளர் சலுகைகள் தேவை"}. +{"Moderators Only","மதிப்பீட்டாளர்கள் மட்டுமே"}. +{"Moderator","மதிப்பீட்டாளர்"}. +{"Module failed to handle the query","தொகுதி வினவலைக் கையாளத் தவறிவிட்டது"}. +{"Monday","திங்கள்"}. +{"Multicast","மல்டிகாச்ட்"}. +{"Multiple elements are not allowed by RFC6121","பல <உருப்படி/> கூறுகள் RFC6121 ஆல் அனுமதிக்கப்படாது"}. +{"Multi-User Chat","பல பயனர் அரட்டை"}. +{"Name","பெயர்"}. +{"Natural Language for Room Discussions","அறை விவாதங்களுக்கு இயற்கை மொழி"}. +{"Natural-Language Room Name","இயற்கை மொழி அறை பெயர்"}. +{"Neither 'jid' nor 'nick' attribute found","'சிட்' அல்லது 'நிக்' பண்புக்கூறு இல்லை"}. +{"Neither 'role' nor 'affiliation' attribute found","'பங்கு' அல்லது 'இணைப்பு' பண்புக்கூறு இல்லை"}. +{"Never","ஒருபோதும்"}. +{"New Password:","புதிய கடவுச்சொல்:"}. +{"Nickname can't be empty","புனைப்பெயர் காலியாக இருக்க முடியாது"}. +{"Nickname Registration at ","இல் புனைப்பெயர் பதிவு "}. +{"Nickname ~s does not exist in the room","அறையில் ~s புனைப்பெயர் இல்லை"}. +{"Nickname","புனைப்பெயர்"}. +{"No address elements found","முகவரி கூறுகள் எதுவும் கிடைக்கவில்லை"}. +{"No addresses element found","முகவரிகள் உறுப்பு இல்லை"}. +{"No 'affiliation' attribute found","'இணைப்பு' பண்புக்கூறு இல்லை"}. +{"No available resource found","கிடைக்கக்கூடிய வளங்கள் எதுவும் கிடைக்கவில்லை"}. +{"No body provided for announce message","அறிவிப்பு செய்திக்கு எந்த உடலும் வழங்கப்படவில்லை"}. +{"No child elements found","குழந்தை கூறுகள் எதுவும் கிடைக்கவில்லை"}. +{"No data form found","தரவு படிவம் எதுவும் கிடைக்கவில்லை"}. +{"No Data","தரவு இல்லை"}. +{"No features available","நற்பொருத்தங்கள் எதுவும் கிடைக்கவில்லை"}. +{"No element found","இல்லை <முன்னோக்கி/> உறுப்பு காணப்பட்டது"}. +{"No hook has processed this command","இந்த கட்டளையை எந்த ஊக்கும் செயலாக்கவில்லை"}. +{"No info about last activity found","கடைசி செயல்பாட்டைப் பற்றிய எந்த தகவலும் கிடைக்கவில்லை"}. +{"No 'item' element found","'உருப்படி' உறுப்பு இல்லை"}. +{"No items found in this query","இந்த வினவலில் எந்த உருப்படிகளும் காணப்படவில்லை"}. +{"No limit","வரம்பு இல்லை"}. +{"No module is handling this query","இந்த வினவலை எந்த தொகுதியும் கையாளவில்லை"}. +{"No node specified","எந்த முனையும் குறிப்பிடப்படவில்லை"}. +{"No 'password' found in data form","தரவு வடிவத்தில் 'கடவுச்சொல்' காணப்படவில்லை"}. +{"No 'password' found in this query","இந்த வினவலில் 'கடவுச்சொல்' இல்லை"}. +{"No 'path' found in data form","தரவு வடிவத்தில் 'பாதை' இல்லை"}. +{"No pending subscriptions found","நிலுவையில் உள்ள சந்தாக்கள் எதுவும் கிடைக்கவில்லை"}. +{"No privacy list with this name found","இந்த பெயருடன் தனியுரிமை பட்டியல் எதுவும் இல்லை"}. +{"No private data found in this query","இந்த வினவலில் தனிப்பட்ட தரவு எதுவும் காணப்படவில்லை"}. +{"No running node found","இயங்கும் முனை எதுவும் கிடைக்கவில்லை"}. +{"No services available","சேவைகள் எதுவும் கிடைக்கவில்லை"}. +{"No statistics found for this item","இந்த உருப்படிக்கு புள்ளிவிவரங்கள் எதுவும் கிடைக்கவில்லை"}. +{"No 'to' attribute found in the invitation","அழைப்பில் காணப்படும் 'to' பண்புக்கூறு"}. +{"Nobody","யாரும்"}. +{"Node already exists","முனை ஏற்கனவே உள்ளது"}. +{"Node ID","முனை ஐடி"}. +{"Node index not found","முனை குறியீடு கிடைக்கவில்லை"}. +{"Node not found","முனை கிடைக்கவில்லை"}. +{"Node ~p","முனை ~p"}. +{"Nodeprep has failed","நோடெப்ரெப் தோல்வியுற்றது"}. +{"Nodes","முனைகள்"}. +{"Node","கணு"}. +{"None","எதுவுமில்லை"}. +{"Not allowed","அனுமதிக்கப்படவில்லை"}. +{"Not Found","கண்டுபிடிக்கப்படவில்லை"}. +{"Not subscribed","குழுசேரவில்லை"}. +{"Notify subscribers when items are removed from the node","முனையிலிருந்து உருப்படிகள் அகற்றப்படும்போது சந்தாதாரர்களுக்கு அறிவிக்கவும்"}. +{"Notify subscribers when the node configuration changes","முனை உள்ளமைவு மாறும்போது சந்தாதாரர்களுக்கு அறிவிக்கவும்"}. +{"Notify subscribers when the node is deleted","முனை நீக்கப்படும் போது சந்தாதாரர்களுக்கு அறிவிக்கவும்"}. +{"November","ஐ-கார்த்திகை"}. +{"Number of answers required","தேவையான பதில்களின் எண்ணிக்கை"}. +{"Number of occupants","குடியிருப்பாளர்களின் எண்ணிக்கை"}. +{"Number of Offline Messages","இணைப்பில்லாத செய்திகளின் எண்ணிக்கை"}. +{"Number of online users","நிகழ்நிலை பயனர்களின் எண்ணிக்கை"}. +{"Number of registered users","பதிவுசெய்யப்பட்ட பயனர்களின் எண்ணிக்கை"}. +{"Number of seconds after which to automatically purge items, or `max` for no specific limit other than a server imposed maximum","உருப்படிகளை தானாக தூய்மைப்படுத்துவதற்கான விநாடிகளின் எண்ணிக்கை, அல்லது அதிகபட்சம் விதிக்கப்பட்ட சேவையகத்தைத் தவிர வேறு எந்த குறிப்பிட்ட வரம்பையும் `அதிகபட்சம்`"}. +{"Occupants are allowed to invite others","குடியிருப்பாளர்கள் மற்றவர்களை அழைக்க அனுமதிக்கப்படுகிறார்கள்"}. +{"Occupants are allowed to query others","குடியிருப்பாளர்கள் மற்றவர்களை வினவ அனுமதிக்கப்படுகிறார்கள்"}. +{"Occupants May Change the Subject","குடியிருப்பாளர்கள் இந்த விசயத்தை மாற்றலாம்"}. +{"October","பு-ஐப்பசி"}. +{"OK","சரி"}. +{"Old Password:","பழைய கடவுச்சொல்:"}. +{"Online Users","நிகழ்நிலை பயனர்கள்"}. +{"Online","ஆன்லைனில்"}. +{"Only collection node owners may associate leaf nodes with the collection","சேகரிப்பு முனை உரிமையாளர்கள் மட்டுமே இலை முனைகளை சேகரிப்புடன் தொடர்புபடுத்தலாம்"}. +{"Only deliver notifications to available users","கிடைக்கக்கூடிய பயனர்களுக்கு மட்டுமே அறிவிப்புகளை வழங்கவும்"}. +{"Only or tags are allowed"," அல்லது <முடக்கு/> குறிச்சொற்கள் மட்டுமே அனுமதிக்கப்படுகின்றன"}. +{"Only element is allowed in this query","இந்த வினவலில் <பட்டியல்/> உறுப்பு மட்டுமே அனுமதிக்கப்படுகிறது"}. +{"Only members may query archives of this room","உறுப்பினர்கள் மட்டுமே இந்த அறையின் காப்பகங்களை வினவலாம்"}. +{"Only moderators and participants are allowed to change the subject in this room","இந்த அறையில் உள்ள விசயத்தை மாற்ற மதிப்பீட்டாளர்கள் மற்றும் பங்கேற்பாளர்கள் மட்டுமே அனுமதிக்கப்படுகிறார்கள்"}. +{"Only moderators are allowed to change the subject in this room","இந்த அறையில் உள்ள விசயத்தை மாற்ற மதிப்பீட்டாளர்கள் மட்டுமே அனுமதிக்கப்படுகிறார்கள்"}. +{"Only moderators are allowed to retract messages","மதிப்பீட்டாளர்கள் மட்டுமே செய்திகளைத் திரும்பப் பெற அனுமதிக்கப்படுகிறார்கள்"}. +{"Only moderators can approve voice requests","மதிப்பீட்டாளர்கள் மட்டுமே குரல் கோரிக்கைகளை அங்கீகரிக்க முடியும்"}. +{"Only occupants are allowed to send messages to the conference","குடியிருப்பாளர்கள் மட்டுமே மாநாட்டிற்கு செய்திகளை அனுப்ப அனுமதிக்கப்படுகிறார்கள்"}. +{"Only occupants are allowed to send queries to the conference","மாநாட்டிற்கு வினவல்களை அனுப்ப குடியிருப்பாளர்கள் மட்டுமே அனுமதிக்கப்படுகிறார்கள்"}. +{"Only publishers may publish","வெளியீட்டாளர்கள் மட்டுமே வெளியிடலாம்"}. +{"Only service administrators are allowed to send service messages","பணி செய்திகளை அனுப்ப பணி நிர்வாகிகள் மட்டுமே அனுமதிக்கப்படுகிறார்கள்"}. +{"Only those on a whitelist may associate leaf nodes with the collection","அனுமதிப்பட்டியலில் இருப்பவர்கள் மட்டுமே இலை முனைகளை சேகரிப்புடன் தொடர்புபடுத்தலாம்"}. +{"Only those on a whitelist may subscribe and retrieve items","அனுமதிப்பட்டியலில் இருப்பவர்கள் மட்டுமே உருப்படிகளை குழுசேரலாம் மற்றும் மீட்டெடுக்கலாம்"}. +{"Organization Name","அமைப்பு பெயர்"}. +{"Organization Unit","அமைப்பு பிரிவு"}. +{"Other Modules Available:","பிற தொகுதிகள் கிடைக்கின்றன:"}. +{"Outgoing s2s Connections","வெளிச்செல்லும் எச் 2 எச் இணைப்புகள்"}. +{"Owner privileges required","உரிமையாளர் சலுகைகள் தேவை"}. +{"Packet relay is denied by service policy","பணி கொள்கையால் பாக்கெட் ரிலே மறுக்கப்படுகிறது"}. +{"Participant ID","பங்கேற்பாளர் ஐடி"}. +{"Participant","பங்கேற்பாளர்"}. +{"Password Verification","கடவுச்சொல் சரிபார்ப்பு"}. +{"Password Verification:","கடவுச்சொல் சரிபார்ப்பு:"}. +{"Password","கடவுச்சொல்"}. +{"Password:","கடவுச்சொல்:"}. +{"Path to Dir","அடைவு க்கு பாதை"}. +{"Path to File","தாக்கல் செய்வதற்கான பாதை"}. +{"Payload semantic type information","பேலோட் சொற்பொருள் வகை செய்தி"}. +{"Period: ","காலம்: "}. +{"Persist items to storage","சேமிப்பகத்திற்கு உருப்படிகளைத் தொடருங்கள்"}. +{"Persistent","விடாமுயற்சி"}. +{"Ping query is incorrect","பிங் வினவல் தவறானது"}. +{"Ping","பிங்"}. +{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","இந்த விருப்பங்கள் பில்டின் மென்சியா தரவுத்தளத்தை மட்டுமே காப்புப் பிரதி எடுக்கும் என்பதை நினைவில் கொள்க. நீங்கள் ODBC தொகுதியைப் பயன்படுத்துகிறீர்கள் என்றால், உங்கள் கவிமொ தரவுத்தளத்தையும் தனித்தனியாக காப்புப் பிரதி எடுக்க வேண்டும்."}. +{"Please, wait for a while before sending new voice request","தயவுசெய்து, புதிய குரல் கோரிக்கையை அனுப்புவதற்கு முன் சிறிது நேரம் காத்திருங்கள்"}. +{"Pong","பாங்"}. +{"Possessing 'ask' attribute is not allowed by RFC6121","'கேளுங்கள்' பண்புக்கூறு வைத்திருப்பது RFC6121 ஆல் அனுமதிக்கப்படவில்லை"}. +{"Present real Jabber IDs to","உண்மையான சாபர் ஐடிகளை வழங்கவும்"}. +{"Previous session not found","முந்தைய அமர்வு காணப்படவில்லை"}. +{"Previous session PID has been killed","முந்தைய அமர்வு பிஐடி கொல்லப்பட்டுள்ளது"}. +{"Previous session PID has exited","முந்தைய அமர்வு பிஐடி வெளியேறியது"}. +{"Previous session PID is dead","முந்தைய அமர்வு பிஐடி இறந்துவிட்டது"}. +{"Previous session timed out","முந்தைய அமர்வு நேரம் முடிந்தது"}. +{"private, ","தனிப்பட்ட, "}. +{"Public","பொது"}. +{"Publish model","மாதிரி வெளியிடு"}. +{"Publish-Subscribe","வெளியீட்டு-சந்தா"}. +{"PubSub subscriber request","பப்சப் சந்தாதாரர் கோரிக்கை"}. +{"Purge all items when the relevant publisher goes offline","தொடர்புடைய வெளியீட்டாளர் ஆஃப்லைனில் செல்லும்போது எல்லா பொருட்களையும் தூய்மைப்படுத்துங்கள்"}. +{"Push record not found","புச் பதிவு கிடைக்கவில்லை"}. +{"Queries to the conference members are not allowed in this room","இந்த அறையில் மாநாட்டு உறுப்பினர்களுக்கு வினவல்கள் அனுமதிக்கப்படவில்லை"}. +{"Query to another users is forbidden","மற்றொரு பயனர்களுக்கு வினவல் தடைசெய்யப்பட்டுள்ளது"}. +{"RAM and disc copy","ராம் மற்றும் வட்டு நகல்"}. +{"RAM copy","ரேம் நகல்"}. +{"Really delete message of the day?","அன்றைய செய்தியை உண்மையில் நீக்கவா?"}. +{"Receive notification from all descendent nodes","அனைத்து வழித்தோன்றல்களிலிருந்தும் அறிவிப்பைப் பெறுங்கள்"}. +{"Receive notification from direct child nodes only","நேரடி குழந்தை முனைகளிலிருந்து மட்டுமே அறிவிப்பைப் பெறுங்கள்"}. +{"Receive notification of new items only","புதிய பொருட்களின் அறிவிப்பைப் பெறுங்கள்"}. +{"Receive notification of new nodes only","புதிய முனைகளின் அறிவிப்பைப் பெறுங்கள்"}. +{"Recipient is not in the conference room","பெறுநர் மாநாட்டு அறையில் இல்லை"}. +{"Register an XMPP account","எக்ச்எம்பி.பி கணக்கை பதிவு செய்யுங்கள்"}. +{"Register","பதிவு செய்யுங்கள்"}. +{"Remote copy","தொலை நகல்"}. +{"Remove a hat from a user","ஒரு பயனரிடமிருந்து ஒரு தொப்பியை அகற்றவும்"}. +{"Remove User","பயனரை அகற்று"}. +{"Replaced by new connection","புதிய இணைப்பு மூலம் மாற்றப்பட்டது"}. +{"Request has timed out","கோரிக்கை நேரம் முடிந்துவிட்டது"}. +{"Request is ignored","கோரிக்கை புறக்கணிக்கப்படுகிறது"}. +{"Requested role","கோரப்பட்ட பங்கு"}. +{"Resources","வளங்கள்"}. +{"Restart Service","சேவையை மறுதொடக்கம் செய்யுங்கள்"}. +{"Restore Backup from File at ","கோப்பிலிருந்து காப்புப்பிரதியை மீட்டெடுக்கவும் "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","அடுத்த EJABBERD மறுதொடக்கத்திற்குப் பிறகு பைனரி காப்புப்பிரதியை மீட்டமைக்கவும் (குறைவான நினைவகம் தேவை):"}. +{"Restore binary backup immediately:","பைனரி காப்புப்பிரதியை உடனடியாக மீட்டமைக்கவும்:"}. +{"Restore plain text backup immediately:","எளிய உரை காப்புப்பிரதியை உடனடியாக மீட்டெடுக்கவும்:"}. +{"Restore","மீட்டமை"}. +{"Roles and Affiliations that May Retrieve Member List","உறுப்பினர் பட்டியலை மீட்டெடுக்கக்கூடிய பாத்திரங்கள் மற்றும் இணைப்புகள்"}. +{"Roles for which Presence is Broadcasted","இருப்பு ஒளிபரப்பப்படும் பாத்திரங்கள்"}. +{"Roles that May Send Private Messages","தனிப்பட்ட செய்திகளை அனுப்பக்கூடிய பாத்திரங்கள்"}. +{"Room Configuration","அறை உள்ளமைவு"}. +{"Room creation is denied by service policy","பணி கொள்கையால் அறை உருவாக்கம் மறுக்கப்படுகிறது"}. +{"Room description","அறை விளக்கம்"}. +{"Room Occupants","அறை குடியிருப்பாளர்கள்"}. +{"Room terminates","அறை முடிவடைகிறது"}. +{"Room title","அறை தலைப்பு"}. +{"Roster groups allowed to subscribe","பட்டியல் குழுக்கள் குழுசேர அனுமதிக்கப்பட்டன"}. +{"Roster size","பட்டியல் அளவு"}. +{"Running Nodes","இயங்கும் முனைகள்"}. +{"~s invites you to the room ~s","~s எச் உங்களை அறைக்கு அழைக்கிறது ~s கள்"}. +{"Saturday","காரிக்கிழமை"}. +{"Search from the date","தேதியிலிருந்து தேடுங்கள்"}. +{"Search Results for ","தேடல் முடிவுகள் "}. +{"Search the text","உரையைத் தேடுங்கள்"}. +{"Search until the date","தேதி வரை தேடுங்கள்"}. +{"Search users in ","பயனர்களைத் தேடுங்கள் "}. +{"Send announcement to all online users on all hosts","அனைத்து ஓச்ட்களிலும் அனைத்து நிகழ்நிலை பயனர்களுக்கும் அறிவிப்பை அனுப்பவும்"}. +{"Send announcement to all online users","அனைத்து நிகழ்நிலை பயனர்களுக்கும் அறிவிப்பை அனுப்பவும்"}. +{"Send announcement to all users on all hosts","அனைத்து ஓச்ட்களிலும் உள்ள அனைத்து பயனர்களுக்கும் அறிவிப்பை அனுப்பவும்"}. +{"Send announcement to all users","அனைத்து பயனர்களுக்கும் அறிவிப்பை அனுப்பவும்"}. +{"September","ஆ-புரட்டாசி"}. +{"Server:","சேவையகம்:"}. +{"Service list retrieval timed out","பணி பட்டியல் மீட்டெடுப்பு நேரம் முடிந்தது"}. +{"Session state copying timed out","அமர்வு நிலை நகலெடுக்கும் நேரம் முடிந்தது"}. +{"Set message of the day and send to online users","அன்றைய செய்தியை அமைத்து நிகழ்நிலை பயனர்களுக்கு அனுப்பவும்"}. +{"Set message of the day on all hosts and send to online users","அனைத்து ஓச்ட்களிலும் அன்றைய செய்தியை அமைத்து நிகழ்நிலை பயனர்களுக்கு அனுப்பவும்"}. +{"Shared Roster Groups","பகிரப்பட்ட பட்டியல் குழுக்கள்"}. +{"Show Integral Table","ஒருங்கிணைந்த அட்டவணையைக் காட்டு"}. +{"Show Occupants Join/Leave","காட்டு குடியிருப்பாளர்கள் சேர/விடுகிறார்கள்"}. +{"Show Ordinary Table","சாதாரண அட்டவணையைக் காட்டு"}. +{"Shut Down Service","சேவையை மூடு"}. +{"SOCKS5 Bytestreams","SOCKS5 BYTESTREAMS"}. +{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","சில எக்ச்எம்பிபி வாடிக்கையாளர்கள் உங்கள் கடவுச்சொல்லை கணினியில் சேமிக்க முடியும், ஆனால் பாதுகாப்பு காரணங்களுக்காக இதை உங்கள் தனிப்பட்ட கணினியில் மட்டுமே செய்ய வேண்டும்."}. +{"Sources Specs:","ஆதார விவரக்குறிப்புகள்:"}. +{"Specify the access model","அணுகல் மாதிரியைக் குறிப்பிடவும்"}. +{"Specify the event message type","நிகழ்வு செய்தி வகையைக் குறிப்பிடவும்"}. +{"Specify the publisher model","வெளியீட்டாளர் மாதிரியைக் குறிப்பிடவும்"}. +{"Stanza id is not valid","முடிப்பு ஐடி செல்லுபடியாகாது"}. +{"Stanza ID","முடிப்பு"}. +{"Statically specify a replyto of the node owner(s)","முனை உரிமையாளரின் (கள்) ஒரு பதிலை நிலையான முறையில் குறிப்பிடவும்"}. +{"Stopped Nodes","நிறுத்தப்பட்ட முனைகள்"}. +{"Store binary backup:","பைனரி காப்புப்பிரதியை சேமிக்கவும்:"}. +{"Store plain text backup:","எளிய உரை காப்புப்பிரதியை சேமிக்கவும்:"}. +{"Stream management is already enabled","ச்ட்ரீம் மேலாண்மை ஏற்கனவே இயக்கப்பட்டது"}. +{"Stream management is not enabled","ச்ட்ரீம் மேலாண்மை இயக்கப்படவில்லை"}. +{"Subject","பொருள்"}. +{"Submitted","சமர்ப்பிக்கப்பட்டது"}. +{"Subscriber Address","சந்தாதாரர் முகவரி"}. +{"Subscribers may publish","சந்தாதாரர்கள் வெளியிடலாம்"}. +{"Subscription requests must be approved and only subscribers may retrieve items","சந்தா கோரிக்கைகள் அங்கீகரிக்கப்பட வேண்டும் மற்றும் சந்தாதாரர்கள் மட்டுமே உருப்படிகளை மீட்டெடுக்க முடியும்"}. +{"Subscriptions are not allowed","சந்தாக்கள் அனுமதிக்கப்படவில்லை"}. +{"Sunday","ஞாயிற்றுக்கிழமை"}. +{"Text associated with a picture","ஒரு படத்துடன் தொடர்புடைய உரை"}. +{"Text associated with a sound","ஒலி ஒரு ஒலியுடன் தொடர்புடையது"}. +{"Text associated with a video","வீடியோவுடன் தொடர்புடைய உரை"}. +{"Text associated with speech","பேச்சுடன் தொடர்புடைய உரை"}. +{"That nickname is already in use by another occupant","அந்த புனைப்பெயர் ஏற்கனவே மற்றொரு குடியிருப்பாளரால் பயன்பாட்டில் உள்ளது"}. +{"That nickname is registered by another person","அந்த புனைப்பெயர் மற்றொரு நபரால் பதிவு செய்யப்பட்டுள்ளது"}. +{"The account already exists","கணக்கு ஏற்கனவே உள்ளது"}. +{"The account was not unregistered","கணக்கு பதிவு செய்யப்படவில்லை"}. +{"The body text of the last received message","கடைசியாக பெறப்பட்ட செய்தியின் உடல் உரை"}. +{"The CAPTCHA is valid.","கேப்ட்சா செல்லுபடியாகும்."}. +{"The CAPTCHA verification has failed","கேப்ட்சா சரிபார்ப்பு தோல்வியுற்றது"}. +{"The captcha you entered is wrong","நீங்கள் உள்ளிட்ட கேப்ட்சா தவறு"}. +{"The child nodes (leaf or collection) associated with a collection","சேகரிப்புடன் தொடர்புடைய குழந்தை முனைகள் (இலை அல்லது சேகரிப்பு)"}. +{"The collections with which a node is affiliated","ஒரு முனை இணைக்கப்பட்ட தொகுப்புகள்"}. +{"The DateTime at which a leased subscription will end or has ended","குத்தகைக்கு விடப்பட்ட சந்தா முடிவடையும் அல்லது முடிவடைந்த தேதிநேரம்"}. +{"The datetime when the node was created","முனை உருவாக்கப்பட்ட தேதிநேரம்"}. +{"The default language of the node","முனையின் இயல்புநிலை மொழி"}. +{"The feature requested is not supported by the conference","கோரப்பட்ட நற்பொருத்தம் மாநாட்டால் ஆதரிக்கப்படவில்லை"}. +{"The JID of the node creator","முனை படைப்பாளரின் சிட்"}. +{"The JIDs of those to contact with questions","கேள்விகளுடன் தொடர்பு கொள்ளுபவர்களின் குழந்தைகள்"}. +{"The JIDs of those with an affiliation of owner","உரிமையாளரின் இணைப்பு உள்ளவர்களின் குழந்தைகள்"}. +{"The JIDs of those with an affiliation of publisher","வெளியீட்டாளரின் இணைப்பு உள்ளவர்களின் குழந்தைகள்"}. +{"The list of all online users","அனைத்து நிகழ்நிலை பயனர்களின் பட்டியல்"}. +{"The list of all users","அனைத்து பயனர்களின் பட்டியல்"}. +{"The list of JIDs that may associate leaf nodes with a collection","இலை முனைகளை ஒரு தொகுப்போடு தொடர்புபடுத்தக்கூடிய JIDS இன் பட்டியல்"}. +{"The maximum number of child nodes that can be associated with a collection, or `max` for no specific limit other than a server imposed maximum","ஒரு சேகரிப்புடன் தொடர்புடைய அதிகபட்ச குழந்தை முனைகளின் எண்ணிக்கை, அல்லது அதிகபட்சமாக விதிக்கப்பட்ட சேவையகத்தைத் தவிர வேறு எந்த குறிப்பிட்ட வரம்பும் இல்லாமல் `அதிகபட்சம் '"}. +{"The minimum number of milliseconds between sending any two notification digests","இரண்டு அறிவிப்பு செரிமானங்களையும் அனுப்புவதற்கு இடையில் குறைந்தபட்ச மில்லி விநாடிகளின் எண்ணிக்கை"}. +{"The name of the node","முனையின் பெயர்"}. +{"The node is a collection node","முனை ஒரு சேகரிப்பு முனை"}. +{"The node is a leaf node (default)","முனை ஒரு இலை முனை (இயல்புநிலை)"}. +{"The NodeID of the relevant node","தொடர்புடைய முனையின் நோடிட்"}. +{"The number of pending incoming presence subscription requests","நிலுவையில் உள்ள உள்வரும் இருப்பு சந்தா கோரிக்கைகளின் எண்ணிக்கை"}. +{"The number of subscribers to the node","முனைக்கு சந்தாதாரர்களின் எண்ணிக்கை"}. +{"The number of unread or undelivered messages","படிக்காத அல்லது வழங்கப்படாத செய்திகளின் எண்ணிக்கை"}. +{"The password contains unacceptable characters","கடவுச்சொல்லில் ஏற்றுக்கொள்ள முடியாத எழுத்துக்கள் உள்ளன"}. +{"The password is too weak","கடவுச்சொல் மிகவும் பலவீனமாக உள்ளது"}. +{"the password is","கடவுச்சொல்"}. +{"The password of your XMPP account was successfully changed.","உங்கள் எக்ச்எம்பிபி கணக்கின் கடவுச்சொல் வெற்றிகரமாக மாற்றப்பட்டது."}. +{"The password was not changed","கடவுச்சொல் மாற்றப்படவில்லை"}. +{"The passwords are different","கடவுச்சொற்கள் வேறுபட்டவை"}. +{"The presence states for which an entity wants to receive notifications","ஒரு நிறுவனம் அறிவிப்புகளைப் பெற விரும்பும் இருப்பு நிலைகள்"}. +{"The query is only allowed from local users","வினவல் உள்ளக பயனர்களிடமிருந்து மட்டுமே அனுமதிக்கப்படுகிறது"}. +{"The query must not contain elements","வினவலில் <பொருள்/> கூறுகள் இருக்கக்கூடாது"}. +{"The room subject can be modified by participants","அறை பொருள் பங்கேற்பாளர்களால் மாற்றப்படலாம்"}. +{"The semantic type information of data in the node, usually specified by the namespace of the payload (if any)","முனையில் உள்ள தரவின் சொற்பொருள் வகை செய்தி, பொதுவாக பேலோடின் பெயர்வெளியால் குறிப்பிடப்படுகிறது (ஏதேனும் இருந்தால்)"}. +{"The sender of the last received message","கடைசியாக பெறப்பட்ட செய்தியை அனுப்பு"}. +{"The stanza MUST contain only one element, one element, or one element","ச்டான்சாவில் ஒரே <செயலில்/> உறுப்பு, ஒரு <இயல்புநிலை/> உறுப்பு அல்லது ஒரு <பட்டியல்/> உறுப்பு மட்டுமே இருக்க வேண்டும்"}. +{"The subscription identifier associated with the subscription request","சந்தா கோரிக்கையுடன் தொடர்புடைய சந்தா அடையாளங்காட்டி"}. +{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","பொருத்தமான செய்தி உடல் உறுப்பை உருவாக்குவதற்காக பேலோடுகளுக்கு பயன்படுத்தக்கூடிய எக்ச்எச்எல் மாற்றத்தின் முகவரி."}. +{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","செல்லுபடியாகும் தரவு படிவங்களை உருவாக்குவதற்காக பேலோட் வடிவத்தில் பயன்படுத்தக்கூடிய ஒரு எக்ச்எச்எல் உருமாற்றத்தின் முகவரி, கிளையன்ட் பொதுவான தரவு படிவங்கள் வழங்குதல் எஞ்சின் பயன்படுத்தி காண்பிக்க முடியும்"}. +{"There was an error changing the password: ","கடவுச்சொல்லை மாற்றுவதில் பிழை ஏற்பட்டது: "}. +{"There was an error creating the account: ","கணக்கை உருவாக்கும் பிழை இருந்தது: "}. +{"There was an error deleting the account: ","கணக்கை நீக்குவதில் பிழை ஏற்பட்டது: "}. +{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","இது வழக்கு உணர்வற்றது: மாக்பெத் மற்றும் மாக்பெத் தான்."}. +{"This page allows to register an XMPP account in this XMPP server. Your JID (Jabber ID) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","இந்த XMPP சேவையகத்தில் ஒரு XMPP கணக்கை பதிவு செய்ய இந்த பக்கம் அனுமதிக்கிறது. உங்கள் சிட் (சாபர் ஐடி) படிவமாக இருக்கும்: பயனர்பெயர்@சேவையகம். புலங்களை சரியாக நிரப்ப வழிமுறைகளை கவனமாகப் படியுங்கள்."}. +{"This page allows to unregister an XMPP account in this XMPP server.","இந்த எக்ச்எம்பி.பி சேவையகத்தில் எக்ச்எம்பி.பி கணக்கை பதிவு செய்ய இந்த பக்கம் அனுமதிக்கிறது."}. +{"This room is not anonymous","இந்த அறை அநாமதேயமானது அல்ல"}. +{"This service can not process the address: ~s","இந்த பணி முகவரியை செயலாக்க முடியாது: ~s"}. +{"Thursday","வியாழக்கிழமை"}. +{"Time delay","நேர நேரந்தவறுகை"}. +{"Timed out waiting for stream resumption","ச்ட்ரீம் மறுதொடக்கத்திற்காக காத்திருக்கும் நேரம்"}. +{"To register, visit ~s","பதிவு செய்ய, ~s பார்வையிடவும்"}. +{"To ~ts","~ts K"}. +{"Token TTL","கிள்ளாக்கு டி.டி.எல்"}. +{"Too many active bytestreams","பல செயலில் உள்ள பைட்டிரீம்கள்"}. +{"Too many CAPTCHA requests","பல கேப்ட்சா கோரிக்கைகள்"}. +{"Too many child elements","பல குழந்தை கூறுகள்"}. +{"Too many elements","பல <உருப்படி/> கூறுகள்"}. +{"Too many elements","பல <பட்டியல்/> கூறுகள்"}. +{"Too many (~p) failed authentications from this IP address (~s). The address will be unblocked at ~s UTC","இந்த ஐபி முகவரியிலிருந்து (~p) பல (~s) தோல்வியுற்ற அங்கீகாரங்கள் ~s. முகவரி UTC இல் தடைசெய்யப்படும்"}. +{"Too many receiver fields were specified","அதிகமான ரிசீவர் புலங்கள் குறிப்பிடப்பட்டன"}. +{"Too many unacked stanzas","பல அறியப்படாத சரணங்கள்"}. +{"Too many users in this conference","இந்த மாநாட்டில் அதிகமான பயனர்கள்"}. +{"Traffic rate limit is exceeded","போக்குவரத்து வீத வரம்பு மீறப்பட்டது"}. +{"~ts's MAM Archive","~ts இன் மாம் காப்பகம்"}. +{"~ts's Offline Messages Queue","~ts இன் இணைப்பில்லாத செய்திகள் வரிசை"}. +{"Tuesday","செவ்வாய்க்கிழமை"}. +{"Unable to generate a CAPTCHA","கேப்ட்சாவை உருவாக்க முடியவில்லை"}. +{"Unable to register route on existing local domain","தற்போதுள்ள உள்ளக களத்தில் வழியை பதிவு செய்ய முடியவில்லை"}. +{"Unauthorized","அங்கீகரிக்கப்படாதது"}. +{"Unexpected action","எதிர்பாராத நடவடிக்கை"}. +{"Unexpected error condition: ~p","எதிர்பாராத பிழை நிலை: ~p"}. +{"Uninstall","நிறுவல் நீக்க"}. +{"Unregister an XMPP account","ஒரு எக்ச்எம்பிபி கணக்கை பதிவு செய்யவும்"}. +{"Unregister","பதிவு செய்யப்படாதது"}. +{"Unsupported element","ஆதரிக்கப்படாத <குறியீட்டு/> உறுப்பு"}. +{"Unsupported version","ஆதரிக்கப்படாத பதிப்பு"}. +{"Update message of the day (don't send)","அன்றைய செய்தியைப் புதுப்பிக்கவும் (அனுப்ப வேண்டாம்)"}. +{"Update message of the day on all hosts (don't send)","எல்லா ஓச்ட்களிலும் அன்றைய செய்தியைப் புதுப்பிக்கவும் (அனுப்ப வேண்டாம்)"}. +{"Update specs to get modules source, then install desired ones.","தொகுதிகள் மூலத்தைப் பெற விவரக்குறிப்புகளைப் புதுப்பிக்கவும், பின்னர் விரும்பியவற்றை நிறுவவும்."}. +{"Update Specs","விவரக்குறிப்புகளைப் புதுப்பிக்கவும்"}. +{"Updating the vCard is not supported by the vCard storage backend","VCARD ஐப் புதுப்பிப்பது VCARD சேமிப்பக பின்தளத்தில் ஆதரிக்கப்படவில்லை"}. +{"Upgrade","மேம்படுத்தல்"}. +{"URL for Archived Discussion Logs","காப்பகப்படுத்தப்பட்ட கலந்துரையாடல் பதிவுகளுக்கான முகவரி"}. +{"User already exists","பயனர் ஏற்கனவே உள்ளது"}. +{"User (jid)","பயனர் (சிட்)"}. +{"User JID","பயனர் சிட்"}. +{"User Management","பயனர் மேலாண்மை"}. +{"User not allowed to perform an IQ set on another user's vCard.","மற்றொரு பயனரின் VCARD இல் IQ தொகுப்பை செய்ய பயனர் அனுமதிக்கப்படவில்லை."}. +{"User removed","பயனர் அகற்றப்பட்டார்"}. +{"User session not found","பயனர் அமர்வு காணப்படவில்லை"}. +{"User session terminated","பயனர் அமர்வு நிறுத்தப்பட்டது"}. +{"User ~ts","பயனர் ~ts"}. +{"Username:","பயனர்பெயர்:"}. +{"Users are not allowed to register accounts so quickly","பயனர்கள் கணக்குகளை விரைவாக பதிவு செய்ய அனுமதிக்கப்படுவதில்லை"}. +{"Users Last Activity","பயனர்கள் கடைசி செயல்பாடு"}. +{"Users","பயனர்கள்"}. +{"User","பயனர்"}. +{"Value 'get' of 'type' attribute is not allowed","'வகை' பண்புக்கூறின் மதிப்பு 'பெறுதல்' அனுமதிக்கப்படவில்லை"}. +{"Value of '~s' should be boolean","'~s' மதிப்பு பூலியனாக இருக்க வேண்டும்"}. +{"Value of '~s' should be datetime string","'~s' இன் மதிப்பு தேதிநேர சரமாக இருக்க வேண்டும்"}. +{"Value of '~s' should be integer","'~s' இன் மதிப்பு முழு எண்ணாக இருக்க வேண்டும்"}. +{"Value 'set' of 'type' attribute is not allowed","'வகை' பண்புக்கூறின் 'தொகுப்பு' மதிப்பு அனுமதிக்கப்படவில்லை"}. +{"vCard User Search","VCARD பயனர் தேடல்"}. +{"View joined MIX channels","கலப்பு சேனல்களில் சேர்ந்தார்"}. +{"Virtual Hosts","மெய்நிகர் ஓச்ட்கள்"}. +{"Visitors are not allowed to change their nicknames in this room","இந்த அறையில் பார்வையாளர்கள் தங்கள் புனைப்பெயர்களை மாற்ற அனுமதிக்கப்படுவதில்லை"}. +{"Visitors are not allowed to send messages to all occupants","பார்வையாளர்கள் அனைத்து குடியிருப்பாளர்களுக்கும் செய்திகளை அனுப்ப அனுமதிக்கப்படுவதில்லை"}. +{"Visitor","பார்வையாளர்"}. +{"Voice requests are disabled in this conference","இந்த மாநாட்டில் குரல் கோரிக்கைகள் முடக்கப்பட்டுள்ளன"}. +{"Voice request","குரல் கோரிக்கை"}. +{"Wednesday","புதன்கிழமை"}. +{"When a new subscription is processed and whenever a subscriber comes online","புதிய சந்தா செயலாக்கப்படும் போது, சந்தாதாரர் ஆன்லைனில் வரும்போதெல்லாம்"}. +{"When a new subscription is processed","புதிய சந்தா செயலாக்கப்படும் போது"}. +{"When to send the last published item","கடைசியாக வெளியிடப்பட்ட உருப்படியை எப்போது அனுப்ப வேண்டும்"}. +{"Whether an entity wants to receive an XMPP message body in addition to the payload format","ஒரு நிறுவனம் பேலோட் வடிவமைப்பிற்கு கூடுதலாக ஒரு எக்ச்எம்பிபி செய்தி உடலைப் பெற விரும்புகிறதா என்பதை"}. +{"Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually","ஒரு நிறுவனம் அறிவிப்புகளின் செரிமானங்களை (திரட்டல்கள்) பெற விரும்புகிறதா அல்லது அனைத்து அறிவிப்புகளையும் தனித்தனியாகப் பெற விரும்புகிறதா"}. +{"Whether an entity wants to receive or disable notifications","ஒரு நிறுவனம் அறிவிப்புகளைப் பெற விரும்புகிறதா அல்லது முடக்க விரும்புகிறதா"}. +{"Whether owners or publisher should receive replies to items","உரிமையாளர்கள் அல்லது வெளியீட்டாளர் உருப்படிகளுக்கான பதில்களைப் பெற வேண்டுமா"}. +{"Whether the node is a leaf (default) or a collection","முனை ஒரு இலை (இயல்புநிலை) அல்லது தொகுப்பாக இருந்தாலும் சரி"}. +{"Whether to allow subscriptions","சந்தாக்களை அனுமதிக்க வேண்டுமா"}. +{"Whether to make all subscriptions temporary, based on subscriber presence","அனைத்து சந்தாக்களையும் தற்காலிகமாக மாற்றலாமா, சந்தாதாரர் இருப்பின் அடிப்படையில்"}. +{"Whether to notify owners about new subscribers and unsubscribes","புதிய சந்தாதாரர்கள் மற்றும் குழுவிலகங்களைப் பற்றி உரிமையாளர்களுக்கு அறிவிக்க வேண்டுமா"}. +{"Who can send private messages","தனிப்பட்ட செய்திகளை யார் அனுப்ப முடியும்"}. +{"Who may associate leaf nodes with a collection","இலை முனைகளை யார் சேகரிப்புடன் தொடர்புபடுத்தலாம்"}. +{"Wrong parameters in the web formulary","வலை சூத்திரத்தில் தவறான அளவுருக்கள்"}. +{"Wrong xmlns","தவறான xmlns"}. +{"XMPP Account Registration","எக்ச்எம்பிபி கணக்கு பதிவு"}. +{"XMPP Domains","எக்ச்எம்பிபி களங்கள்"}. +{"XMPP Show Value of Away","எக்ச்எம்பிபி சோ மதிப்பைக் காட்டுகிறது"}. +{"XMPP Show Value of Chat","எக்ச்எம்பிபி அரட்டையின் மதிப்பைக் காட்டுகிறது"}. +{"XMPP Show Value of DND (Do Not Disturb)","எக்ச்எம்பிபி டி.என்.டி யின் மதிப்பைக் காட்டுகிறது (தொந்தரவு செய்யாதீர்கள்)"}. +{"XMPP Show Value of XA (Extended Away)","XMPP XA இன் மதிப்பைக் காட்டுகிறது (நீட்டிக்கப்பட்டது)"}. +{"XMPP URI of Associated Publish-Subscribe Node","அசோசியேட்டட் பப்ளிச்-சப்ச்கிரிப்ட் முனையின் எக்ச்எம்பிபி யுஆர்ஐ"}. +{"You are being removed from the room because of a system shutdown","கணினி பணிநிறுத்தம் காரணமாக நீங்கள் அறையிலிருந்து அகற்றப்படுகிறீர்கள்"}. +{"You are not allowed to send private messages","தனிப்பட்ட செய்திகளை அனுப்ப உங்களுக்கு இசைவு இல்லை"}. +{"You are not joined to the channel","நீங்கள் சேனலுடன் சேரவில்லை"}. +{"You can later change your password using an XMPP client.","எக்ச்எம்பிபி கிளையண்டைப் பயன்படுத்தி உங்கள் கடவுச்சொல்லை பின்னர் மாற்றலாம்."}. +{"You have been banned from this room","இந்த அறையிலிருந்து நீங்கள் தடை செய்யப்பட்டுள்ளீர்கள்"}. +{"You have joined too many conferences","நீங்கள் பல மாநாடுகளில் சேர்ந்துள்ளீர்கள்"}. +{"You must fill in field \"Nickname\" in the form","நீங்கள் வடிவத்தில் புலம் \"புனைப்பெயரை\" நிரப்ப வேண்டும்"}. +{"You need a client that supports x:data and CAPTCHA to register","எக்ச்: தரவு மற்றும் கேப்ட்சா பதிவு செய்ய உங்களுக்கு ஒரு வாங்கி தேவை"}. +{"You need a client that supports x:data to register the nickname","புனைப்பெயரை பதிவு செய்ய எக்ச்: தரவை ஆதரிக்கும் வாங்கி உங்களுக்குத் தேவை"}. +{"You need an x:data capable client to search","தேட உங்களுக்கு ஒரு ஃச் தேவை: தேட தரவு திறன் கொண்ட வாங்கி"}. +{"Your active privacy list has denied the routing of this stanza.","உங்கள் செயலில் உள்ள தனியுரிமை பட்டியல் இந்த சரணத்தை வழிநடத்துவதை மறுத்துள்ளது."}. +{"Your contact offline message queue is full. The message has been discarded.","உங்கள் தொடர்பு இணைப்பில்லாத செய்தி வரிசை நிரம்பியுள்ளது. செய்தி நிராகரிக்கப்பட்டுள்ளது."}. +{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","உங்கள் சந்தா கோரிக்கை மற்றும்/அல்லது செய்திகளுக்கான செய்திகள் தடுக்கப்பட்டுள்ளன ~s. உங்கள் சந்தா கோரிக்கையைத் தடுக்க, ~s கள் பார்வையிடவும்"}. +{"Your XMPP account was successfully registered.","உங்கள் எக்ச்எம்பிபி கணக்கு வெற்றிகரமாக பதிவு செய்யப்பட்டது."}. +{"Your XMPP account was successfully unregistered.","உங்கள் எக்ச்எம்பிபி கணக்கு வெற்றிகரமாக பதிவு செய்யப்படவில்லை."}. +{"You're not allowed to create nodes","முனைகளை உருவாக்க உங்களுக்கு இசைவு இல்லை"}. From 4967acaec939a2eb121811c5d5377e2a5303be1a Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 17:47:29 +0100 Subject: [PATCH 161/170] =?UTF-8?q?Update=20Ukrainian=20translation=20(tha?= =?UTF-8?q?nks=20to=20=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=93=D0=BE?= =?UTF-8?q?=D1=80=D0=BF=D0=B8=D0=BD=D1=96=D1=87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- priv/msgs/uk.msg | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/priv/msgs/uk.msg b/priv/msgs/uk.msg index 5992bfdf1ba..48f98b60dc6 100644 --- a/priv/msgs/uk.msg +++ b/priv/msgs/uk.msg @@ -108,6 +108,7 @@ {"Dump Backup to Text File at ","Копіювання в текстовий файл на "}. {"Dump to Text File","Копіювання в текстовий файл"}. {"Duplicated groups are not allowed by RFC6121","RFC6121 забороняє дублювати групи"}. +{"Dynamically specify a replyto of the item publisher","Динамічно вказуйте відповідь видавця елемента"}. {"Edit Properties","Змінити параметри"}. {"Either approve or decline the voice request.","Підтвердіть або відхиліть голосовий запит."}. {"ejabberd HTTP Upload service","Служба відвантаження по HTTP для ejabberd"}. @@ -123,6 +124,7 @@ {"Enable hats","Увімкнути капелюхи"}. {"Enable logging","Увімкнути журнал роботи"}. {"Enable message archiving","Ввімкнути архівацію повідомлень"}. +{"Enabling push without 'node' attribute is not supported","Увімкнення push без атрибута node не підтримується"}. {"End User Session","Закінчити Сеанс Користувача"}. {"Enter nickname you want to register","Введіть псевдонім, який ви хочете зареєструвати"}. {"Enter path to backup file","Введіть шлях до резервного файла"}. @@ -166,6 +168,7 @@ {"has been kicked because of an affiliation change","вигнано з кімнати внаслідок зміни рангу"}. {"has been kicked because the room has been changed to members-only","вигнано з кімнати тому, що вона стала тільки для учасників"}. {"has been kicked","вигнали з кімнати"}. +{"Hash of the vCard-temp avatar of this room","Хеш тимчасового аватара vCard цієї кімнати"}. {"Hat title","Назва кімнати"}. {"Hat URI","Назва URI"}. {"Hats limit exceeded","Перевищено швидкість передачі інформації"}. @@ -206,6 +209,8 @@ {"January","січня"}. {"JID normalization denied by service policy","Створювати конференцію заборонено політикою служби"}. {"JID normalization failed","Помилка нормалізації JID"}. +{"Joined MIX channels of ~ts","Приєднався до каналів MIX ~ts"}. +{"Joined MIX channels:","Приєднався до каналів MIX:"}. {"joins the room","увійшов(ла) в кімнату"}. {"July","липня"}. {"June","червня"}. @@ -219,6 +224,7 @@ {"leaves the room","вийшов(ла) з кімнати"}. {"List of users with hats","Список користувачів із капелюхами"}. {"List users with hats","Список користувачів із капелюхами"}. +{"Logged Out","Вийшов із системи"}. {"Logging","Журналювання"}. {"Make participants list public","Зробити список учасників видимим всім"}. {"Make room CAPTCHA protected","Зробити кімнату захищеною капчею"}. @@ -382,12 +388,19 @@ {"RAM copy","Копія оперативної пам'яті"}. {"Really delete message of the day?","Дійсно видалити повідомлення дня?"}. {"Receive notification from all descendent nodes","Отримувати сповіщення від усіх підпорядкованих вузлів"}. +{"Receive notification from direct child nodes only","Отримувати сповіщення лише від прямих дочірніх вузлів"}. +{"Receive notification of new items only","Отримувати сповіщення лише про нові товари"}. +{"Receive notification of new nodes only","Отримувати сповіщення лише про нові вузли"}. {"Recipient is not in the conference room","Адресата немає в конференції"}. {"Register an XMPP account","Зареєструвати XMPP-запис"}. {"Register","Реєстрація"}. {"Remote copy","не зберігаеться локально"}. +{"Remove a hat from a user","Зняти шапку з користувача"}. {"Remove User","Видалити користувача"}. {"Replaced by new connection","Замінено новим з'єднанням"}. +{"Request has timed out","Час очікування запиту минув"}. +{"Request is ignored","Запит ігнорується"}. +{"Requested role","Запитана роль"}. {"Resources","Ресурси"}. {"Restart Service","Перезапустити Сервіс"}. {"Restore Backup from File at ","Відновлення з резервної копії на "}. @@ -395,6 +408,7 @@ {"Restore binary backup immediately:","Відновити з бінарної резервної копії негайно:"}. {"Restore plain text backup immediately:","Відновити з текстової резервної копії негайно:"}. {"Restore","Відновлення з резервної копії"}. +{"Roles and Affiliations that May Retrieve Member List","Ролі та зв’язки, які можуть отримати список учасників"}. {"Roles for which Presence is Broadcasted","Ролі для яких поширюється наявність"}. {"Roles that May Send Private Messages","Ролі, що можуть надсилати приватні повідомлення"}. {"Room Configuration","Конфігурація кімнати"}. @@ -408,7 +422,10 @@ {"Running Nodes","Працюючі вузли"}. {"~s invites you to the room ~s","~s запрошує вас до кімнати ~s"}. {"Saturday","Субота"}. +{"Search from the date","Пошук від дати"}. {"Search Results for ","Результати пошуку в "}. +{"Search the text","Знайдіть текст"}. +{"Search until the date","Пошук до дати"}. {"Search users in ","Пошук користувачів в "}. {"Send announcement to all online users on all hosts","Надіслати сповіщення всім підключеним користувачам на всіх віртуальних серверах"}. {"Send announcement to all online users","Надіслати сповіщення всім підключеним користувачам"}. @@ -416,42 +433,94 @@ {"Send announcement to all users","Надіслати сповіщення всім користувачам"}. {"September","вересня"}. {"Server:","Сервер:"}. +{"Service list retrieval timed out","Час очікування отримання списку послуг минув"}. +{"Session state copying timed out","Час очікування копіювання стану сеансу минув"}. {"Set message of the day and send to online users","Встановити повідомлення дня та надіслати його підключеним користувачам"}. {"Set message of the day on all hosts and send to online users","Встановити повідомлення дня на всіх хостах та надійслати його підключеним користувачам"}. {"Shared Roster Groups","Спільні групи контактів"}. {"Show Integral Table","Показати інтегральну таблицю"}. +{"Show Occupants Join/Leave","Показати мешканцям приєднатися/вийти"}. {"Show Ordinary Table","Показати звичайну таблицю"}. {"Shut Down Service","Вимкнути Сервіс"}. +{"SOCKS5 Bytestreams","Потоки байтів SOCKS5"}. +{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","Деякі клієнти XMPP можуть зберігати ваш пароль на комп’ютері, але ви повинні робити це лише на своєму персональному комп’ютері з міркувань безпеки."}. +{"Sources Specs:","Специфікації джерел:"}. {"Specify the access model","Визначити модель доступу"}. {"Specify the event message type","Вкажіть тип повідомлень зі сповіщеннями про події"}. {"Specify the publisher model","Умови публікації"}. +{"Stanza id is not valid","Ідентифікатор строфи недійсний"}. +{"Stanza ID","ID кімнати"}. +{"Statically specify a replyto of the node owner(s)","Статично вкажіть відповідь власника(ів) вузла"}. {"Stopped Nodes","Зупинені вузли"}. {"Store binary backup:","Зберегти бінарну резервну копію:"}. {"Store plain text backup:","Зберегти текстову резервну копію:"}. +{"Stream management is already enabled","Керування потоком уже ввімкнено"}. +{"Stream management is not enabled","Керування потоком не ввімкнено"}. {"Subject","Тема"}. {"Submitted","Відправлено"}. {"Subscriber Address","Адреса абонента"}. +{"Subscribers may publish","Підписники можуть публікувати"}. +{"Subscription requests must be approved and only subscribers may retrieve items","Запити на підписку мають бути схвалені, і лише передплатники можуть отримувати елементи"}. +{"Subscriptions are not allowed","Підписка заборонена"}. {"Sunday","Неділя"}. +{"Text associated with a picture","Текст, пов'язаний із зображенням"}. +{"Text associated with a sound","Текст, пов'язаний зі звуком"}. +{"Text associated with a video","Текст, пов’язаний із відео"}. +{"Text associated with speech","Текст, пов'язаний з мовленням"}. {"That nickname is already in use by another occupant","Псевдонім зайнято кимось з присутніх"}. {"That nickname is registered by another person","Псевдонім зареєстровано кимось іншим"}. +{"The account already exists","Обліковий запис уже існує"}. {"The account was not unregistered","Обліковий запис не було видалено"}. +{"The body text of the last received message","Основний текст останнього отриманого повідомлення"}. {"The CAPTCHA is valid.","Перевірку CAPTCHA успішно завершено."}. {"The CAPTCHA verification has failed","Перевірку капчею не пройдено"}. +{"The captcha you entered is wrong","Captcha, яку ви ввели, неправильна"}. +{"The child nodes (leaf or collection) associated with a collection","Дочірні вузли (лист або колекція), пов’язані з колекцією"}. {"The collections with which a node is affiliated","Колекція, до якої входить вузол"}. +{"The DateTime at which a leased subscription will end or has ended","DateTime, коли орендована підписка закінчиться або закінчилася"}. +{"The datetime when the node was created","Дата і час створення вузла"}. +{"The default language of the node","Мова вузла за замовчуванням"}. +{"The feature requested is not supported by the conference","Запитана функція не підтримується конференцією"}. +{"The JID of the node creator","JID творця вузла"}. +{"The JIDs of those to contact with questions","JID тих, до кого можна звернутися із запитаннями"}. +{"The JIDs of those with an affiliation of owner","JID тих, хто є афілійованим власником"}. +{"The JIDs of those with an affiliation of publisher","JID тих, хто пов’язаний із видавцем"}. +{"The list of all online users","Список усіх онлайн-користувачів"}. +{"The list of all users","Список усіх користувачів"}. +{"The list of JIDs that may associate leaf nodes with a collection","Список JID, які можуть пов’язувати листові вузли з колекцією"}. +{"The maximum number of child nodes that can be associated with a collection, or `max` for no specific limit other than a server imposed maximum","Максимальна кількість дочірніх вузлів, які можна пов’язати з колекцією, або `max` для відсутності конкретного обмеження, окрім максимального накладеного сервером"}. +{"The minimum number of milliseconds between sending any two notification digests","Мінімальна кількість мілісекунд між надсиланням будь-яких двох дайджестів сповіщень"}. +{"The name of the node","Ім'я вузла"}. +{"The node is a collection node","Вузол є вузлом колекції"}. +{"The node is a leaf node (default)","Вузол є листовим вузлом (за замовчуванням)"}. +{"The NodeID of the relevant node","NodeID відповідного вузла"}. +{"The number of pending incoming presence subscription requests","Кількість вхідних запитів на підписку про присутність, що очікують на розгляд"}. +{"The number of subscribers to the node","Кількість передплатників вузла"}. +{"The number of unread or undelivered messages","Кількість непрочитаних або недоставлених повідомлень"}. +{"The password contains unacceptable characters","Пароль містить неприйнятні символи"}. {"The password is too weak","Пароль надто простий"}. {"the password is","паролем є"}. +{"The password of your XMPP account was successfully changed.","Пароль вашого облікового запису XMPP успішно змінено."}. +{"The password was not changed","Пароль не змінено"}. +{"The passwords are different","Паролі різні"}. {"The presence states for which an entity wants to receive notifications","Стан присутності, для якого сутність хоче отримувати сповіщення"}. {"The query is only allowed from local users","Запит дозволено лише від локальних користувачів"}. {"The query must not contain elements","Запит не повинен містити елементів "}. {"The room subject can be modified by participants","Тема кімнати може бути змінена учасниками"}. +{"The semantic type information of data in the node, usually specified by the namespace of the payload (if any)","Інформація про семантичний тип даних у вузлі, зазвичай визначена простором імен корисного навантаження (якщо є)"}. {"The sender of the last received message","Відправник останнього отриманого повідомлення"}. {"The stanza MUST contain only one element, one element, or one element","Строфа ПОВИННА містити лише один елемент , один елемент або один елемент "}. {"The subscription identifier associated with the subscription request","Ідентифікатор підписки, пов’язаний із запитом на підписку"}. +{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","URL-адреса перетворення XSL, яке можна застосувати до корисних даних, щоб створити відповідний елемент тіла повідомлення."}. +{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","URL-адреса трансформації XSL, яку можна застосувати до формату корисного навантаження, щоб створити дійсний результат форм даних, який клієнт міг би відобразити за допомогою загального механізму візуалізації форм даних"}. {"There was an error changing the password: ","Помилка при зміні пароля: "}. {"There was an error creating the account: ","Помилка при створенні облікового запису: "}. {"There was an error deleting the account: ","Помилка при видаленні акаунту: "}. +{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Тут не враховується регістр: Макбет – це те саме, що Макбет і Макбет."}. +{"This page allows to register an XMPP account in this XMPP server. Your JID (Jabber ID) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Ця сторінка дозволяє зареєструвати обліковий запис XMPP на цьому сервері XMPP. Ваш JID (Jabber ID) матиме такий вигляд: ім’я користувача@сервер. Уважно прочитайте інструкції, щоб правильно заповнити поля."}. {"This page allows to unregister an XMPP account in this XMPP server.","Ця сторінка дозволяє видалити свій обліковий запис з XMPP-сервера."}. {"This room is not anonymous","Ця кімната не анонімна"}. +{"This service can not process the address: ~s","Ця служба не може обробити адресу: ~s"}. {"Thursday","Четвер"}. {"Time delay","Час затримки"}. {"Timed out waiting for stream resumption","Час очікування на відновлення потоку закінчився"}. @@ -468,6 +537,7 @@ {"Too many unacked stanzas","Занадто багато пакетів без відповідей"}. {"Too many users in this conference","Надто багато користувачів у цій конференції"}. {"Traffic rate limit is exceeded","Швидкість передачі інформації було перевищено"}. +{"~ts's MAM Archive","Архів МАМ ~ts"}. {"~ts's Offline Messages Queue","Черга автономних повідомлень ~ts"}. {"Tuesday","Вівторок"}. {"Unable to generate a CAPTCHA","Нема можливості згенерувати капчу"}. @@ -475,17 +545,23 @@ {"Unauthorized","Не авторизовано"}. {"Unexpected action","Несподівана дія"}. {"Unexpected error condition: ~p","Умова несподіваної помилки: ~p"}. +{"Uninstall","Видалити"}. {"Unregister an XMPP account","Видалити обліковий запис XMPP"}. {"Unregister","Видалити"}. {"Unsupported element","Непідтримуваний елемент "}. {"Unsupported version","Непідтримувана версія"}. {"Update message of the day (don't send)","Оновити повідомлення дня (не надсилати)"}. {"Update message of the day on all hosts (don't send)","Оновити повідомлення дня на всіх хостах (не надсилати)"}. +{"Update specs to get modules source, then install desired ones.","Оновіть специфікації, щоб отримати джерело модулів, а потім встановіть потрібні."}. +{"Update Specs","Оновити характеристики"}. +{"Updating the vCard is not supported by the vCard storage backend","Оновлення vCard не підтримується системою зберігання vCard"}. +{"Upgrade","Оновлення"}. {"URL for Archived Discussion Logs","URL-адреса для журналів архівних обговорень"}. {"User already exists","Користувач уже існує"}. {"User JID","JID Користувача"}. {"User (jid)","Користувач (jid)"}. {"User Management","Управління Користувачами"}. +{"User not allowed to perform an IQ set on another user's vCard.","Користувачеві заборонено виконувати тест IQ на vCard іншого користувача."}. {"User removed","Користувача видалено"}. {"User session not found","Сеанс користувача не знайдено"}. {"User session terminated","Сеанс користувача припинено"}. @@ -495,10 +571,13 @@ {"Users Last Activity","Статистика останнього підключення користувачів"}. {"Users","Користувачі"}. {"User","Користувач"}. +{"Value 'get' of 'type' attribute is not allowed","Значення 'get' атрибута 'type' не дозволене"}. {"Value of '~s' should be boolean","Значення \"~s\" має бути логічним"}. {"Value of '~s' should be datetime string","Значення \"~s\" має бути рядком дати і часу"}. {"Value of '~s' should be integer","Значення \"~s\" має бути цілим числом"}. +{"Value 'set' of 'type' attribute is not allowed","Значення 'set' атрибута 'type' не допускається"}. {"vCard User Search","Пошук користувачів по vCard"}. +{"View joined MIX channels","Перегляд приєднаних каналів MIX"}. {"Virtual Hosts","віртуальні хости"}. {"Visitors are not allowed to change their nicknames in this room","Відвідувачам не дозволяється змінювати псевдонім в цій кімнаті"}. {"Visitors are not allowed to send messages to all occupants","Відвідувачам не дозволяється надсилати повідомлення всім присутнім"}. @@ -506,20 +585,30 @@ {"Voice requests are disabled in this conference","Голосові запити відключені в цій конференції"}. {"Voice request","Голосовий запит"}. {"Wednesday","Середа"}. +{"When a new subscription is processed and whenever a subscriber comes online","Коли обробляється нова підписка та щоразу, коли абонент виходить в Інтернет"}. {"When a new subscription is processed","Під час обробки нової підписки"}. {"When to send the last published item","Коли надсилати останній опублікований елемент"}. +{"Whether an entity wants to receive an XMPP message body in addition to the payload format","Чи бажає суб’єкт отримувати тіло повідомлення XMPP на додаток до формату корисного навантаження"}. +{"Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually","Чи бажає організація отримувати дайджести (агрегації) сповіщень чи всі сповіщення окремо"}. +{"Whether an entity wants to receive or disable notifications","Чи бажає суб’єкт отримувати або вимикати сповіщення"}. {"Whether owners or publisher should receive replies to items","Чи повинні власники або видавець отримувати відповіді на елементи"}. {"Whether the node is a leaf (default) or a collection","Чи є вузол листом (типово) чи колекцією"}. {"Whether to allow subscriptions","Дозволяти підписку"}. {"Whether to make all subscriptions temporary, based on subscriber presence","Чи робити всі підписки тимчасовими, залежно від присутності читача"}. {"Whether to notify owners about new subscribers and unsubscribes","Чи повідомляти власників про нових читачів та їх втрату"}. +{"Who can send private messages","Хто може надсилати приватні повідомлення"}. {"Who may associate leaf nodes with a collection","Хто може пов’язувати листові вузли з колекцією"}. {"Wrong parameters in the web formulary","Неправильні параметри у веб-формі"}. {"Wrong xmlns","Неправильний xmlns"}. {"XMPP Account Registration","Реєстрація облікового запису XMPP"}. {"XMPP Domains","Домени XMPP"}. +{"XMPP Show Value of Away","XMPP Показати значення Away"}. +{"XMPP Show Value of Chat","XMPP Показати значення чату"}. +{"XMPP Show Value of DND (Do Not Disturb)","XMPP Показати значення DND (Не турбувати)"}. +{"XMPP Show Value of XA (Extended Away)","XMPP Показати значення XA (розширено)"}. {"XMPP URI of Associated Publish-Subscribe Node","XMPP URI-адреса асоційованого вузла публікацій-підписок"}. {"You are being removed from the room because of a system shutdown","Ви будете видалені з кімнати через завершення роботи системи"}. +{"You are not allowed to send private messages","Ви не можете надсилати приватні повідомлення"}. {"You are not joined to the channel","Ви не приєднані до каналу"}. {"You can later change your password using an XMPP client.","Пізніше ви можете змінити пароль за допомогою XMPP-клієнта."}. {"You have been banned from this room","Вам заборонено входити в цю конференцію"}. From 322e642f194669a5c2d0e0f11d966e7e004a7853 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 17:48:27 +0100 Subject: [PATCH 162/170] Update Chinese (Simplified) translation (thanks to Sketch6580) --- priv/msgs/zh.msg | 301 +++++++++++++++++++++++------------------------ 1 file changed, 150 insertions(+), 151 deletions(-) diff --git a/priv/msgs/zh.msg b/priv/msgs/zh.msg index c1bfd98b271..ab7053b82c6 100644 --- a/priv/msgs/zh.msg +++ b/priv/msgs/zh.msg @@ -8,7 +8,7 @@ {"# participants","# 参与者"}. {"A description of the node","节点的描述"}. {"A friendly name for the node","节点的易记名称"}. -{"A password is required to enter this room","进入此群聊需要密码"}. +{"A password is required to enter this room","需要密码才能进入此房间"}. {"A Web Page","网页"}. {"Accept","接受"}. {"Access denied by service policy","服务策略拒绝访问"}. @@ -23,26 +23,26 @@ {"All activity","所有活动"}. {"All Users","所有用户"}. {"Allow subscription","允许订阅"}. -{"Allow this Jabber ID to subscribe to this pubsub node?","允许此 Jabber ID 订阅此 pubsub 节点?"}. -{"Allow this person to register with the room?","允许此用户注册此群聊?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","是否允许此 Jabber ID 订阅此 pubsub 节点?"}. +{"Allow this person to register with the room?","是否允许此用户在房间注册?"}. {"Allow users to change the subject","允许用户更改话题"}. {"Allow users to query other users","允许用户查询其他用户"}. {"Allow users to send invites","允许用户发送邀请"}. {"Allow users to send private messages","允许用户发送私信"}. -{"Allow visitors to change nickname","允许访客更改昵称"}. -{"Allow visitors to send private messages to","允许访客发送私信至"}. -{"Allow visitors to send status text in presence updates","允许访客在在线状态更新中发送状态文本"}. -{"Allow visitors to send voice requests","允许访客发送发言请求"}. -{"An associated LDAP group that defines room membership; this should be an LDAP Distinguished Name according to an implementation-specific or deployment-specific definition of a group.","与定义群聊成员资格相关联的 LDAP 组;根据组的特定实施或特定部署的定义,使用 LDAP 专有名称。"}. +{"Allow visitors to change nickname","允许参观者更改昵称"}. +{"Allow visitors to send private messages to","允许参观者发送私信至"}. +{"Allow visitors to send status text in presence updates","允许参观者在在线状态更新中发送状态文本"}. +{"Allow visitors to send voice requests","允许参观者发送发言权请求"}. +{"An associated LDAP group that defines room membership; this should be an LDAP Distinguished Name according to an implementation-specific or deployment-specific definition of a group.","与定义房间成员资格相关联的 LDAP 组;根据组的特定实施或特定部署的定义,使用 LDAP 专有名称。"}. {"Announcements","公告"}. {"Answer associated with a picture","与图片相关的答案"}. {"Answer associated with a video","与视频相关的答案"}. {"Answer associated with speech","与讲话相关的答案"}. {"Answer to a question","问题的答案"}. -{"Anyone in the specified roster group(s) may subscribe and retrieve items","指定花名册组中的任何人都可以订阅和检索项目"}. +{"Anyone in the specified roster group(s) may subscribe and retrieve items","指定名册组中的任何人都可以订阅和检索项目"}. {"Anyone may associate leaf nodes with the collection","任何人都可以将叶节点与集合关联"}. {"Anyone may publish","任何人都可以发布"}. -{"Anyone may subscribe and retrieve items","任何人都可以订阅和检索内容项"}. +{"Anyone may subscribe and retrieve items","任何人都可以订阅和检索项目"}. {"Anyone with a presence subscription of both or from may subscribe and retrieve items","任何拥有 both 或 from 的在线状态订阅的用户都可以订阅和检索项目"}. {"Anyone with Voice","任何有发言权的人"}. {"Anyone","任何人"}. @@ -75,22 +75,22 @@ {"Channel JID","频道 JID"}. {"Channels","频道"}. {"Characters not allowed:","不允许字符:"}. -{"Chatroom configuration modified","群聊配置已修改"}. -{"Chatroom is created","群聊已创建"}. -{"Chatroom is destroyed","群聊已解散"}. -{"Chatroom is started","群聊已开始"}. -{"Chatroom is stopped","群聊已停止"}. -{"Chatrooms","群聊"}. +{"Chatroom configuration modified","聊天室配置已修改"}. +{"Chatroom is created","已创建聊天室"}. +{"Chatroom is destroyed","已解散聊天室"}. +{"Chatroom is started","已启动聊天室"}. +{"Chatroom is stopped","已停止聊天室"}. +{"Chatrooms","聊天室"}. {"Choose a username and password to register with this server","请选择要在此服务器中注册的用户名和密码"}. {"Choose storage type of tables","选择表的存储类型"}. {"Choose whether to approve this entity's subscription.","选择是否批准此实体的订阅。"}. {"City","城市"}. {"Client acknowledged more stanzas than sent by server","客户端确认的节数多于服务器发送的节数"}. {"Commands","命令"}. -{"Conference room does not exist","群聊不存在"}. -{"Configuration of room ~s","群聊 ~s 的配置"}. +{"Conference room does not exist","会议室不存在"}. +{"Configuration of room ~s","房间 ~s 的配置"}. {"Configuration","配置"}. -{"Contact Addresses (normally, room owner or owners)","联系人地址(通常为群聊所有者)"}. +{"Contact Addresses (normally, room owner or owners)","联系地址(通常为房间所有者)"}. {"Country","国家/地区"}. {"Current Discussion Topic","当前讨论话题"}. {"Database failure","数据库失败"}. @@ -104,16 +104,16 @@ {"Deliver event notifications","传递事件通知"}. {"Deliver payloads with event notifications","用事件通知传递有效负载"}. {"Disc only copy","仅磁盘副本"}. -{"Don't tell your password to anybody, not even the administrators of the XMPP server.","不要将密码告诉任何人,甚至是 XMPP 服务的管理员。"}. +{"Don't tell your password to anybody, not even the administrators of the XMPP server.","不要将您的密码告诉任何人,甚至是 XMPP 服务器的管理员。"}. {"Dump Backup to Text File at ","将备份转储到位于以下位置的文本文件 "}. {"Dump to Text File","转储到文本文件"}. {"Duplicated groups are not allowed by RFC6121","按照 RFC6121 的规则,不允许重复的组"}. {"Dynamically specify a replyto of the item publisher","动态指定项目发布者的 replyto"}. {"Edit Properties","编辑属性"}. -{"Either approve or decline the voice request.","批准或拒绝发言请求。"}. +{"Either approve or decline the voice request.","批准或拒绝发言权请求。"}. {"ejabberd HTTP Upload service","ejabberd HTTP 上传服务"}. {"ejabberd MUC module","ejabberd MUC 模块"}. -{"ejabberd Multicast service","ejabberd 多重映射服务"}. +{"ejabberd Multicast service","ejabberd 多播服务"}. {"ejabberd Publish-Subscribe module","ejabberd 发布–订阅模块"}. {"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 字节流模块"}. {"ejabberd vCard module","ejabberd vCard 模块"}. @@ -123,7 +123,7 @@ {"Email","电子邮件"}. {"Enable hats","启用头衔"}. {"Enable logging","启用日志记录"}. -{"Enable message archiving","启用消息存档"}. +{"Enable message archiving","启用消息归档"}. {"Enabling push without 'node' attribute is not supported","不支持没有“node”属性就启用推送"}. {"End User Session","结束用户会话"}. {"Enter nickname you want to register","请输入要注册的昵称"}. @@ -133,26 +133,26 @@ {"Enter path to text file","请输入文本文件的路径"}. {"Enter the text you see","请输入您看到的文本"}. {"Erlang XMPP Server","Erlang XMPP 服务器"}. -{"Exclude Jabber IDs from CAPTCHA challenge","从验证码挑战中排除 Jabber ID"}. +{"Exclude Jabber IDs from CAPTCHA challenge","从验证码挑战中排除的 Jabber ID"}. {"Export all tables as SQL queries to a file:","将所有表以 SQL 查询导出到文件:"}. {"Export data of all users in the server to PIEFXIS files (XEP-0227):","将服务器中所有用户的数据导出到 PIEFXIS 文件(XEP-0227):"}. {"Export data of users in a host to PIEFXIS files (XEP-0227):","将主机中用户的数据导出到 PIEFXIS 文件(XEP-0227):"}. {"External component failure","外部组件故障"}. {"External component timeout","外部组件超时"}. -{"Failed to activate bytestream","激活字节流失败"}. -{"Failed to extract JID from your voice request approval","无法从发言请求批准中提取 JID"}. -{"Failed to map delegated namespace to external component","未能将委托命名空间映射到外部组件"}. -{"Failed to parse HTTP response","HTTP 响应解析失败"}. +{"Failed to activate bytestream","无法激活字节流"}. +{"Failed to extract JID from your voice request approval","无法从您的发言权请求批准中提取 JID"}. +{"Failed to map delegated namespace to external component","无法将委托命名空间映射到外部组件"}. +{"Failed to parse HTTP response","无法解析 HTTP 响应"}. {"Failed to process option '~s'","无法处理选项“~s”"}. {"Family Name","姓氏"}. -{"FAQ Entry","常见问题解答"}. +{"FAQ Entry","常见问题条目"}. {"February","二月"}. {"File larger than ~w bytes","文件大于 ~w 字节"}. {"Fill in the form to search for any matching XMPP User","填写表单以搜索任何匹配的 XMPP 用户"}. {"Friday","周五"}. {"From ~ts","来自 ~ts"}. -{"Full List of Room Admins","群聊管理员完整列表"}. -{"Full List of Room Owners","群聊所有者完整列表"}. +{"Full List of Room Admins","房间管理员的完整列表"}. +{"Full List of Room Owners","房间所有者的完整列表"}. {"Full Name","全名"}. {"Get List of Online Users","获取在线用户列表"}. {"Get List of Registered Users","获取注册用户列表"}. @@ -161,14 +161,14 @@ {"Get Pending","获取待处理"}. {"Get User Last Login Time","获取用户上次登录时间"}. {"Get User Statistics","获取用户统计数据"}. -{"Given Name","中间名"}. -{"Grant voice to this person?","授予此用户发言权?"}. +{"Given Name","名字"}. +{"Grant voice to this person?","是否授予此用户发言权?"}. {"has been banned","已被封禁"}. {"has been kicked because of a system shutdown","因系统关闭而被踢出"}. {"has been kicked because of an affiliation change","由于从属关系的更改而被踢出"}. -{"has been kicked because the room has been changed to members-only","被踢出,因为群聊已更改为仅成员进入"}. +{"has been kicked because the room has been changed to members-only","被踢出,因为房间已更改为仅成员"}. {"has been kicked","已被踢出"}. -{"Hash of the vCard-temp avatar of this room","此群聊 vCard-temp 头像的散列值"}. +{"Hash of the vCard-temp avatar of this room","此房间的 vCard-temp 头像的散列"}. {"Hat title","头衔标题"}. {"Hat URI","头衔 URI"}. {"Hats limit exceeded","已超过头衔限制"}. @@ -197,135 +197,134 @@ {"Insufficient privilege","权限不足"}. {"Internal server error","内部服务器错误"}. {"Invalid 'from' attribute in forwarded message","转发消息中的“from”属性无效"}. -{"Invalid node name","无效的节点名称"}. +{"Invalid node name","节点名称无效"}. {"Invalid 'previd' value","“previd”值无效"}. -{"Invitations are not allowed in this conference","此群聊不允许邀请"}. +{"Invitations are not allowed in this conference","此会议不允许邀请"}. {"IP addresses","IP 地址"}. {"is now known as","现在昵称为"}. -{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","不允许向此群聊发送错误消息。参与者(~s)发送了错误消息(~s),被踢出了群聊"}. +{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","不允许向此房间发送错误消息。参与者(~s)发送了错误消息(~s),被踢出了房间"}. {"It is not allowed to send private messages of type \"groupchat\"","不允许发送“groupchat”类型的私信"}. -{"It is not allowed to send private messages to the conference","不允许向群聊发送私信"}. +{"It is not allowed to send private messages to the conference","不允许向会议发送私信"}. {"Jabber ID","Jabber ID"}. {"January","一月"}. {"JID normalization denied by service policy","服务策略拒绝 JID 规范化"}. {"JID normalization failed","JID 规范化失败"}. {"Joined MIX channels of ~ts","加入了 ~ts 的 MIX 频道"}. {"Joined MIX channels:","加入了 MIX 频道:"}. -{"joins the room","加入群聊"}. +{"joins the room","加入房间"}. {"July","七月"}. {"June","六月"}. {"Just created","刚刚创建"}. {"Last Activity","上次活动"}. {"Last login","上次登录"}. -{"Last message","最近消息"}. +{"Last message","最后一条消息"}. {"Last month","上个月"}. {"Last year","去年"}. -{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","文本的 SHA-256 哈希的最低有效位应等于十六进制标签"}. -{"leaves the room","离开群聊"}. -{"List of users with hats","有头衔用户的列表"}. -{"List users with hats","有头衔用户列表"}. +{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","文本的 SHA-256 散列的最低有效位应等于十六进制标签"}. +{"leaves the room","离开房间"}. +{"List of users with hats","有头衔的用户列表"}. +{"List users with hats","列出有头衔的用户"}. {"Logged Out","已登出"}. {"Logging","日志记录"}. {"Make participants list public","公开参与者列表"}. -{"Make room CAPTCHA protected","开启群聊验证码保护"}. -{"Make room members-only","仅成员进入的群聊"}. -{"Make room moderated","开启群聊发言审核"}. -{"Make room password protected","开启群聊密码保护"}. -{"Make room persistent","持续存在的群聊"}. -{"Make room public searchable","可公开搜索的群聊"}. +{"Make room CAPTCHA protected","开启房间验证码保护"}. +{"Make room members-only","将房间设为仅成员"}. +{"Make room moderated","开启房间发言审核"}. +{"Make room password protected","开启房间密码保护"}. +{"Make room persistent","将房间设为持久"}. +{"Make room public searchable","将房间设为公开可搜索"}. {"Malformed username","用户名格式不正确"}. {"MAM preference modification denied by service policy","服务策略拒绝修改 MAM 首选项"}. {"March","三月"}. -{"Max # of items to persist, or `max` for no specific limit other than a server imposed maximum","要持久化的最大项目数 #,或“max”表示除服务器施加的最大值之外没有特定限制"}. +{"Max # of items to persist, or `max` for no specific limit other than a server imposed maximum","要保留的最大项目数 #,或 `max` 表示除服务器强制规定的最大值外无其他特定限制"}. {"Max payload size in bytes","最大有效负载大小(字节)"}. {"Maximum file size","最大文件大小"}. -{"Maximum Number of History Messages Returned by Room","群聊返回的聊天记录消息的最大值"}. -{"Maximum number of items to persist","要持久化的最大项目数"}. -{"Maximum Number of Occupants","最大参与者人数"}. +{"Maximum Number of History Messages Returned by Room","房间返回的最大历史消息数"}. +{"Maximum number of items to persist","要保留的最大项目数"}. +{"Maximum Number of Occupants","最大使用者数"}. {"May","五月"}. -{"Membership is required to enter this room","进入此群聊需要成员资格"}. -{"Memorize your password, or write it in a paper placed in a safe place. In XMPP there isn't an automated way to recover your password if you forget it.","请记住密码,或将密码写在纸上,放在安全的地方。在 XMPP 中,如果您忘记密码,没有自动恢复密码的方法。"}. +{"Membership is required to enter this room","进入此房间需要成员资格"}. +{"Memorize your password, or write it in a paper placed in a safe place. In XMPP there isn't an automated way to recover your password if you forget it.","请记住您的密码,或写在放在安全地方的纸上。在 XMPP 中,如果您忘记密码,没有自动恢复密码的方法。"}. {"Mere Availability in XMPP (No Show Value)","XMPP 中的可用性(无显示值)"}. {"Message body","消息正文"}. -{"Message not found in forwarded payload","在转发的有效负载中找不到消息"}. +{"Message not found in forwarded payload","在转发的有效负载中未找到消息"}. {"Messages from strangers are rejected","拒绝来自陌生人的消息"}. {"Messages of type headline","标题类型的消息"}. {"Messages of type normal","普通类型的消息"}. {"Middle Name","中间名"}. -{"Minimum interval between voice requests (in seconds)","发言请求之间的最短间隔时间(秒)"}. +{"Minimum interval between voice requests (in seconds)","发言权请求的最短间隔时间(秒)"}. {"Moderator privileges required","需要主持人权限"}. {"Moderators Only","仅主持人"}. {"Moderator","主持人"}. {"Module failed to handle the query","模块无法处理查询"}. {"Monday","周一"}. -{"Multicast","多重映射"}. +{"Multicast","多播"}. {"Multiple elements are not allowed by RFC6121","按照 RFC6121,多个 元素是不允许的"}. {"Multi-User Chat","多用户聊天"}. {"Name","名称"}. -{"Natural Language for Room Discussions","群聊讨论的自然语言"}. -{"Natural-Language Room Name","自然语言群聊名称"}. +{"Natural Language for Room Discussions","房间讨论的自然语言"}. +{"Natural-Language Room Name","自然语言房间名称"}. {"Neither 'jid' nor 'nick' attribute found","未找到“jid”和“nick”属性"}. {"Neither 'role' nor 'affiliation' attribute found","未找到“role”或“affiliation”属性"}. {"Never","从不"}. {"New Password:","新密码:"}. {"Nickname can't be empty","昵称不能为空"}. {"Nickname Registration at ","昵称注册于 "}. -{"Nickname ~s does not exist in the room","昵称 ~s 不在此群聊"}. +{"Nickname ~s does not exist in the room","昵称 ~s 在房间中不存在"}. {"Nickname","昵称"}. -{"No address elements found","找不到地址元素"}. -{"No addresses element found","找不到地址元素"}. +{"No address elements found","未找到地址元素"}. +{"No addresses element found","未找到地址元素"}. {"No 'affiliation' attribute found","未找到“affiliation”属性"}. -{"No available resource found","找不到可用资源"}. -{"No body provided for announce message","没有为公告消息提供正文"}. -{"No child elements found","没有找到子元素"}. -{"No data form found","没有找到数据表单"}. -{"No Data","没有数据"}. -{"No features available","没有可用功能"}. +{"No available resource found","未找到可用资源"}. +{"No body provided for announce message","未提供公告消息正文"}. +{"No child elements found","未找到子元素"}. +{"No data form found","未找到数据表单"}. +{"No Data","无数据"}. +{"No features available","无可用功能"}. {"No element found","未找到 元素"}. {"No hook has processed this command","没有钩子处理此命令"}. {"No info about last activity found","未找到有关上次活动的信息"}. {"No 'item' element found","未找到“item”元素"}. -{"No items found in this query","在此查询中找不到任何项目"}. -{"No limit","没有限制"}. +{"No items found in this query","在此查询中未找到任何项目"}. +{"No limit","无限制"}. {"No module is handling this query","没有模块正在处理此查询"}. {"No node specified","未指定节点"}. -{"No 'password' found in data form","在数据表单中找不到“password”"}. -{"No 'password' found in this query","在此查询中找不到“password”"}. -{"No 'path' found in data form","在数据表单中找不到“path”"}. +{"No 'password' found in data form","在数据表单中未找到“password”"}. +{"No 'password' found in this query","在此查询中未找到“password”"}. +{"No 'path' found in data form","在数据表单中未找到“path”"}. {"No pending subscriptions found","未找到待处理的订阅"}. {"No privacy list with this name found","未找到具有此名称的隐私列表"}. -{"No private data found in this query","在此查询中找不到专用数据"}. -{"No element found","未找到 元素"}. -{"No running node found","找不到正在运行的节点"}. +{"No private data found in this query","在此查询中未找到专用数据"}. +{"No running node found","未找到正在运行的节点"}. {"No services available","无可用服务"}. {"No statistics found for this item","未找到此项目的统计数据"}. {"No 'to' attribute found in the invitation","邀请中未找到“to”属性"}. {"Nobody","没有人"}. {"Node already exists","节点已存在"}. {"Node ID","节点 ID"}. -{"Node index not found","没有找到节点索引"}. -{"Node not found","没有找到节点"}. +{"Node index not found","未找到节点索引"}. +{"Node not found","未找到节点"}. {"Node ~p","节点 ~p"}. -{"Nodeprep has failed","Nodeprep 已失效"}. +{"Nodeprep has failed","Nodeprep 失败了"}. {"Nodes","节点"}. {"Node","节点"}. {"None","无"}. {"Not allowed","不允许"}. -{"Not Found","没有找到"}. +{"Not Found","未找到"}. {"Not subscribed","未订阅"}. {"Notify subscribers when items are removed from the node","从节点中移除项目时通知订阅者"}. {"Notify subscribers when the node configuration changes","节点配置更改时通知订阅者"}. {"Notify subscribers when the node is deleted","删除节点时通知订阅者"}. {"November","十一月"}. -{"Number of answers required","所需答案数量"}. -{"Number of occupants","参与者人数"}. -{"Number of Offline Messages","离线消息数量"}. +{"Number of answers required","所需答案数"}. +{"Number of occupants","使用者数"}. +{"Number of Offline Messages","离线消息数"}. {"Number of online users","在线用户数"}. {"Number of registered users","注册用户数"}. -{"Number of seconds after which to automatically purge items, or `max` for no specific limit other than a server imposed maximum","等待多少秒后自动清除项目,“max”表示除服务器施加的最大值外没有特定限制"}. -{"Occupants are allowed to invite others","允许参与者邀请别人"}. -{"Occupants are allowed to query others","允许参与者查询别人"}. -{"Occupants May Change the Subject","参与者可以更改话题"}. +{"Number of seconds after which to automatically purge items, or `max` for no specific limit other than a server imposed maximum","自动清除项目前的秒数,`max` 表示除服务器强制规定的最大值外无其他特定限制"}. +{"Occupants are allowed to invite others","允许使用者邀请他人"}. +{"Occupants are allowed to query others","允许使用者查询他人"}. +{"Occupants May Change the Subject","使用者可以更改话题"}. {"October","十月"}. {"OK","确定"}. {"Old Password:","旧密码:"}. @@ -335,13 +334,13 @@ {"Only deliver notifications to available users","仅向在线用户发送通知"}. {"Only or tags are allowed","仅允许 标签"}. {"Only element is allowed in this query","此查询中只允许 元素"}. -{"Only members may query archives of this room","只有成员才能查询此群聊的存档"}. -{"Only moderators and participants are allowed to change the subject in this room","只允许主持人和参与者在此群聊更改话题"}. -{"Only moderators are allowed to change the subject in this room","只允许主持人在此群聊更改话题"}. +{"Only members may query archives of this room","只有成员才能查询此房间的归档"}. +{"Only moderators and participants are allowed to change the subject in this room","只允许主持人和参与者更改此房间的话题"}. +{"Only moderators are allowed to change the subject in this room","只允许主持人更改此房间的话题"}. {"Only moderators are allowed to retract messages","只允许主持人撤回消息"}. -{"Only moderators can approve voice requests","只有主持人才能批准发言请求"}. -{"Only occupants are allowed to send messages to the conference","只允许参与者向群聊发送消息"}. -{"Only occupants are allowed to send queries to the conference","只允许参与者向群聊发送查询"}. +{"Only moderators can approve voice requests","只有主持人可以批准发言权请求"}. +{"Only occupants are allowed to send messages to the conference","只允许使用者向会议发送消息"}. +{"Only occupants are allowed to send queries to the conference","只允许使用者向会议发送查询"}. {"Only publishers may publish","只有发布者才能发布"}. {"Only service administrators are allowed to send service messages","只允许服务管理员发送服务消息"}. {"Only those on a whitelist may associate leaf nodes with the collection","只有白名单上的那些可以将叶节点与集合关联"}. @@ -361,17 +360,17 @@ {"Path to Dir","目录路径"}. {"Path to File","文件路径"}. {"Payload semantic type information","有效负载语义类型信息"}. -{"Period: ","持续时间: "}. -{"Persist items to storage","将项目持久化到存储"}. +{"Period: ","时段: "}. +{"Persist items to storage","将项目保留到存储"}. {"Persistent","持久"}. {"Ping query is incorrect","Ping 查询不正确"}. {"Ping","Ping"}. {"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","注意:这些选项只会备份内置的 Mnesia 数据库。如果使用 ODBC 模块,还需要单独备份 SQL 数据库。"}. -{"Please, wait for a while before sending new voice request","请稍候,然后再发送新的发言请求"}. +{"Please, wait for a while before sending new voice request","请稍候再发送新的发言权请求"}. {"Pong","Pong"}. {"Possessing 'ask' attribute is not allowed by RFC6121","按照 RFC6121, 不允许有“ask”属性"}. -{"Present real Jabber IDs to","将用户真实 JID 显示给"}. -{"Previous session not found","上一个会话未找到"}. +{"Present real Jabber IDs to","将真实 Jabber ID 显示给"}. +{"Previous session not found","未找到上一个会话"}. {"Previous session PID has been killed","上一个会话 PID 已终止"}. {"Previous session PID has exited","上一个会话 PID 已退出"}. {"Previous session PID is dead","上一个会话 PID 已失效"}. @@ -382,8 +381,8 @@ {"Publish-Subscribe","发布–订阅"}. {"PubSub subscriber request","PubSub 订阅者请求"}. {"Purge all items when the relevant publisher goes offline","相关发布者离线后清除所有项目"}. -{"Push record not found","推送记录未找到"}. -{"Queries to the conference members are not allowed in this room","不允许在此群聊中查询群聊成员"}. +{"Push record not found","未找到推送记录"}. +{"Queries to the conference members are not allowed in this room","此房间不允许向会议成员查询"}. {"Query to another users is forbidden","禁止查询其他用户"}. {"RAM and disc copy","RAM 和磁盘副本"}. {"RAM copy","RAM 副本"}. @@ -392,7 +391,7 @@ {"Receive notification from direct child nodes only","仅接收直接子节点的通知"}. {"Receive notification of new items only","仅接收新项目的通知"}. {"Receive notification of new nodes only","仅接收新节点的通知"}. -{"Recipient is not in the conference room","接收者不在群聊"}. +{"Recipient is not in the conference room","接收者不在会议室"}. {"Register an XMPP account","注册 XMPP 账号"}. {"Register","注册"}. {"Remote copy","远程副本"}. @@ -407,21 +406,21 @@ {"Restore Backup from File at ","从以下位置的文件恢复备份 "}. {"Restore binary backup after next ejabberd restart (requires less memory):","在下次 ejabberd 重启后恢复二进制备份(所需内存较少):"}. {"Restore binary backup immediately:","立即恢复二进制备份:"}. -{"Restore plain text backup immediately:","立即恢复明文备份:"}. +{"Restore plain text backup immediately:","立即恢复纯文本备份:"}. {"Restore","恢复"}. {"Roles and Affiliations that May Retrieve Member List","可以检索成员列表的角色和从属关系"}. {"Roles for which Presence is Broadcasted","广播在线状态的角色"}. {"Roles that May Send Private Messages","可以发送私信的角色"}. -{"Room Configuration","群聊配置"}. -{"Room creation is denied by service policy","服务策略拒绝群聊创建"}. -{"Room description","群聊描述"}. -{"Room Occupants","群聊参与者"}. -{"Room terminates","群聊终止"}. -{"Room title","群聊标题"}. -{"Roster groups allowed to subscribe","允许订阅的花名册组"}. -{"Roster size","花名册大小"}. +{"Room Configuration","房间配置"}. +{"Room creation is denied by service policy","服务策略拒绝创建房间"}. +{"Room description","房间描述"}. +{"Room Occupants","房间使用者"}. +{"Room terminates","房间终止"}. +{"Room title","房间标题"}. +{"Roster groups allowed to subscribe","允许订阅的名册组"}. +{"Roster size","名册大小"}. {"Running Nodes","正在运行的节点"}. -{"~s invites you to the room ~s","~s 邀请您加入群聊 ~s"}. +{"~s invites you to the room ~s","~s 邀请您加入房间 ~s"}. {"Saturday","周六"}. {"Search from the date","从日期搜索"}. {"Search Results for ","搜索结果 "}. @@ -438,9 +437,9 @@ {"Session state copying timed out","会话状态复制超时"}. {"Set message of the day and send to online users","设置每日消息并发送给在线用户"}. {"Set message of the day on all hosts and send to online users","在所有主机上设置每日消息并发送给在线用户"}. -{"Shared Roster Groups","共享的花名册组"}. +{"Shared Roster Groups","共享名册组"}. {"Show Integral Table","显示完整表"}. -{"Show Occupants Join/Leave","显示参与者加入/离开"}. +{"Show Occupants Join/Leave","显示使用者加入/离开"}. {"Show Ordinary Table","显示普通表"}. {"Shut Down Service","关闭服务"}. {"SOCKS5 Bytestreams","SOCKS5 字节流"}. @@ -454,9 +453,9 @@ {"Statically specify a replyto of the node owner(s)","静态指定节点所有者的 replyto"}. {"Stopped Nodes","已停止的节点"}. {"Store binary backup:","存储二进制备份:"}. -{"Store plain text backup:","存储明文备份:"}. -{"Stream management is already enabled","流管理已启用"}. -{"Stream management is not enabled","流管理未启用"}. +{"Store plain text backup:","存储纯文本备份:"}. +{"Stream management is already enabled","已启用流管理"}. +{"Stream management is not enabled","未启用流管理"}. {"Subject","话题"}. {"Submitted","已提交"}. {"Subscriber Address","订阅者地址"}. @@ -468,35 +467,35 @@ {"Text associated with a sound","与声音相关的文字"}. {"Text associated with a video","与视频相关的文字"}. {"Text associated with speech","与语音相关的文字"}. -{"That nickname is already in use by another occupant","该昵称已被另一参与者使用了"}. +{"That nickname is already in use by another occupant","该昵称已被其他使用者使用"}. {"That nickname is registered by another person","该昵称已被另一用户注册了"}. {"The account already exists","此账号已存在"}. {"The account was not unregistered","此账号未注销"}. {"The body text of the last received message","最后收到的消息的正文"}. {"The CAPTCHA is valid.","验证码有效。"}. -{"The CAPTCHA verification has failed","验证码检查失败"}. +{"The CAPTCHA verification has failed","验证码验证失败"}. {"The captcha you entered is wrong","您输入的验证码错误"}. {"The child nodes (leaf or collection) associated with a collection","与集合关联的子节点(叶或集合)"}. {"The collections with which a node is affiliated","节点所属的集合"}. {"The DateTime at which a leased subscription will end or has ended","租赁订阅将结束或已结束的日期时间"}. {"The datetime when the node was created","创建节点的日期时间"}. {"The default language of the node","节点的默认语言"}. -{"The feature requested is not supported by the conference","群聊不支持请求的功能"}. +{"The feature requested is not supported by the conference","会议不支持所请求的功能"}. {"The JID of the node creator","节点创建者的 JID"}. -{"The JIDs of those to contact with questions","有问题要联系的人的 JID"}. -{"The JIDs of those with an affiliation of owner","与所有者的从属关系有关的用户 JID"}. -{"The JIDs of those with an affiliation of publisher","与发布者的从属关系有关的用户 JID"}. +{"The JIDs of those to contact with questions","有疑问时需联系的人员的 JID"}. +{"The JIDs of those with an affiliation of owner","有所有者从属关系的人员的 JID"}. +{"The JIDs of those with an affiliation of publisher","有发布者从属关系的人员的 JID"}. {"The list of all online users","所有在线用户的列表"}. {"The list of all users","所有用户的列表"}. {"The list of JIDs that may associate leaf nodes with a collection","可以将叶节点与集合关联的 JID 列表"}. -{"The maximum number of child nodes that can be associated with a collection, or `max` for no specific limit other than a server imposed maximum","可以与集合关联的子节点的最大数量,或“max”表示除服务器施加的最大值外没有特定限制"}. +{"The maximum number of child nodes that can be associated with a collection, or `max` for no specific limit other than a server imposed maximum","可以与集合关联的子节点的最大数量,或 `max` 表示除服务器强制规定的最大值外无其他特定限制"}. {"The minimum number of milliseconds between sending any two notification digests","发送任意两个通知摘要之间的最小毫秒数"}. {"The name of the node","节点的名称"}. {"The node is a collection node","节点是集合节点"}. {"The node is a leaf node (default)","节点是叶节点(默认)"}. {"The NodeID of the relevant node","相关节点的 NodeID"}. {"The number of pending incoming presence subscription requests","待处理的传入在线状态订阅请求数"}. -{"The number of subscribers to the node","节点的订阅者数量"}. +{"The number of subscribers to the node","节点的订阅者数"}. {"The number of unread or undelivered messages","未读或未传递的消息数"}. {"The password contains unacceptable characters","密码包含不可接受的字符"}. {"The password is too weak","密码太弱"}. @@ -505,9 +504,9 @@ {"The password was not changed","密码未更改"}. {"The passwords are different","密码不同"}. {"The presence states for which an entity wants to receive notifications","实体要接收通知的在线状态"}. -{"The query is only allowed from local users","仅允许本地用户查询"}. +{"The query is only allowed from local users","仅允许来自本地用户的查询"}. {"The query must not contain elements","查询不能包含 元素"}. -{"The room subject can be modified by participants","群聊话题可由参与者修改"}. +{"The room subject can be modified by participants","参与者可以修改房间话题"}. {"The semantic type information of data in the node, usually specified by the namespace of the payload (if any)","节点中数据的语义类型信息,通常由有效负载的命名空间指定(如果有)"}. {"The sender of the last received message","最后收到的消息的发送者"}. {"The stanza MUST contain only one element, one element, or one element","节必须仅包含一个 元素、一个 元素或一个 元素"}. @@ -520,7 +519,7 @@ {"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","此处不区分大小写:MacBeth 和 Macbeth 都是 macbeth。"}. {"This page allows to register an XMPP account in this XMPP server. Your JID (Jabber ID) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","本页面允许在此服务器中注册 XMPP 账号,您的 JID(Jabber ID)的格式为:用户名@服务器。请仔细阅读说明以正确填写字段。"}. {"This page allows to unregister an XMPP account in this XMPP server.","本页面允许在此 XMPP 服务器中注销 XMPP 账号。"}. -{"This room is not anonymous","此群聊是非匿名的"}. +{"This room is not anonymous","此房间是非匿名的"}. {"This service can not process the address: ~s","此服务无法处理地址:~s"}. {"Thursday","周四"}. {"Time delay","时间延迟"}. @@ -530,21 +529,21 @@ {"Token TTL","令牌 TTL"}. {"Too many active bytestreams","活动字节流太多"}. {"Too many CAPTCHA requests","验证码请求太多"}. -{"Too many child elements","太多子元素"}. -{"Too many elements","太多 元素"}. -{"Too many elements","太多 元素"}. -{"Too many (~p) failed authentications from this IP address (~s). The address will be unblocked at ~s UTC","有太多 (~p) 失败的身份验证来自此 IP 地址 (~s),将在 UTC 时间 ~s 解除对该地址的屏蔽"}. +{"Too many child elements","子元素太多"}. +{"Too many elements"," 元素太多"}. +{"Too many elements"," 元素太多"}. +{"Too many (~p) failed authentications from this IP address (~s). The address will be unblocked at ~s UTC","有太多(~p)失败的身份验证来自此 IP 地址(~s),将在 UTC 时间 ~s 取消对该地址的屏蔽"}. {"Too many receiver fields were specified","指定的接收者字段太多"}. -{"Too many unacked stanzas","太多未确认的节"}. -{"Too many users in this conference","此群聊中的用户太多"}. +{"Too many unacked stanzas","未确认的节太多"}. +{"Too many users in this conference","此会议中的用户太多"}. {"Traffic rate limit is exceeded","超过流量速率限制"}. -{"~ts's MAM Archive","~ts 的 MAM 存档"}. +{"~ts's MAM Archive","~ts 的 MAM 归档"}. {"~ts's Offline Messages Queue","~ts 的离线消息队列"}. {"Tuesday","周二"}. {"Unable to generate a CAPTCHA","无法生成验证码"}. {"Unable to register route on existing local domain","无法在现有本地域上注册路由"}. {"Unauthorized","未经授权"}. -{"Unexpected action","意外的操作"}. +{"Unexpected action","意外操作"}. {"Unexpected error condition: ~p","意外错误条件:~p"}. {"Uninstall","卸载"}. {"Unregister an XMPP account","注销 XMPP 账号"}. @@ -557,14 +556,14 @@ {"Update Specs","更新规格"}. {"Updating the vCard is not supported by the vCard storage backend","vCard 存储后端不支持更新 vCard"}. {"Upgrade","升级"}. -{"URL for Archived Discussion Logs","存档讨论日志的 URL"}. +{"URL for Archived Discussion Logs","已归档的讨论日志 URL"}. {"User already exists","用户已存在"}. -{"User (jid)","用户 (jid)"}. {"User JID","用户 JID"}. +{"User (jid)","用户(JID)"}. {"User Management","用户管理"}. {"User not allowed to perform an IQ set on another user's vCard.","不允许用户在其他用户的 vCard 上执行 IQ 设置。"}. {"User removed","用户已移除"}. -{"User session not found","用户会话未找到"}. +{"User session not found","未找到用户会话"}. {"User session terminated","用户会话已终止"}. {"User ~ts","用户 ~ts"}. {"Username:","用户名:"}. @@ -580,11 +579,11 @@ {"vCard User Search","vCard 用户搜索"}. {"View joined MIX channels","查看已加入的 MIX 频道"}. {"Virtual Hosts","虚拟主机"}. -{"Visitors are not allowed to change their nicknames in this room","不允许访客在此群聊中更改其昵称"}. -{"Visitors are not allowed to send messages to all occupants","不允许访客向所有参与者发送消息"}. -{"Visitor","访客"}. -{"Voice requests are disabled in this conference","此群聊中禁用发言请求"}. -{"Voice request","发言请求"}. +{"Visitors are not allowed to change their nicknames in this room","不允许参观者在此房间中更改其昵称"}. +{"Visitors are not allowed to send messages to all occupants","不允许参观者向所有使用者发送消息"}. +{"Visitor","参观者"}. +{"Voice requests are disabled in this conference","此会议中禁用了发言权请求"}. +{"Voice request","发言权请求"}. {"Wednesday","周三"}. {"When a new subscription is processed and whenever a subscriber comes online","处理新订阅时和订阅者上线时"}. {"When a new subscription is processed","处理新订阅时"}. @@ -599,7 +598,7 @@ {"Whether to notify owners about new subscribers and unsubscribes","是否通知所有者新的订阅者和退订者"}. {"Who can send private messages","谁可以发送私信"}. {"Who may associate leaf nodes with a collection","谁可以将叶节点与集合关联"}. -{"Wrong parameters in the web formulary","web 公式中的参数错误"}. +{"Wrong parameters in the web formulary","Web 表单集中的参数错误"}. {"Wrong xmlns","错误的 xmlns"}. {"XMPP Account Registration","XMPP 账号注册"}. {"XMPP Domains","XMPP 域"}. @@ -608,19 +607,19 @@ {"XMPP Show Value of DND (Do Not Disturb)","XMPP 的 DND(请勿打扰)显示值"}. {"XMPP Show Value of XA (Extended Away)","XMPP 的 XA(延长离开)显示值"}. {"XMPP URI of Associated Publish-Subscribe Node","关联发布–订阅节点的 XMPP URI"}. -{"You are being removed from the room because of a system shutdown","由于系统关闭,您将会从群聊中移除"}. +{"You are being removed from the room because of a system shutdown","由于系统关闭,您将被移出房间"}. {"You are not allowed to send private messages","不允许您发送私信"}. {"You are not joined to the channel","您未加入频道"}. {"You can later change your password using an XMPP client.","您之后可以使用 XMPP 客户端更改密码。"}. -{"You have been banned from this room","禁止您进入此群聊"}. -{"You have joined too many conferences","您加入了太多群聊"}. +{"You have been banned from this room","禁止您进入此房间"}. +{"You have joined too many conferences","您加入了太多会议"}. {"You must fill in field \"Nickname\" in the form","您必须在表单中填写“昵称”字段"}. {"You need a client that supports x:data and CAPTCHA to register","您需要支持 x:data 和验证码的客户端来注册"}. {"You need a client that supports x:data to register the nickname","您需要支持 x:data 的客户端来注册昵称"}. {"You need an x:data capable client to search","您需要支持 x:data 的客户端来搜索"}. {"Your active privacy list has denied the routing of this stanza.","您的活动隐私列表已拒绝路由此节。"}. {"Your contact offline message queue is full. The message has been discarded.","您的联系人离线消息队列已满。消息已被丢弃。"}. -{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","您对 ~s 的订阅请求和/或消息已被屏蔽。若要解除屏蔽您的订阅请求,请访问 ~s"}. +{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","您发给 ~s 的订阅请求和/或消息已被屏蔽。若要取消屏蔽您的订阅请求,请访问 ~s"}. {"Your XMPP account was successfully registered.","您的 XMPP 账号注册成功。"}. {"Your XMPP account was successfully unregistered.","您的 XMPP 账号注销成功。"}. {"You're not allowed to create nodes","不允许您创建节点"}. From d831fd4789d4fda3284a91fa871478d34002c413 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 17:49:08 +0100 Subject: [PATCH 163/170] Result of runing "make translations" --- priv/msgs/bg.msg | 1 - priv/msgs/ca.msg | 5 ++--- priv/msgs/de.msg | 1 - priv/msgs/es.msg | 1 - priv/msgs/it.msg | 1 - priv/msgs/pt-br.msg | 1 - priv/msgs/sq.msg | 1 - 7 files changed, 2 insertions(+), 9 deletions(-) diff --git a/priv/msgs/bg.msg b/priv/msgs/bg.msg index 128de867384..bf0b8eca07d 100644 --- a/priv/msgs/bg.msg +++ b/priv/msgs/bg.msg @@ -295,7 +295,6 @@ {"No pending subscriptions found","Не са намерени чакащи абонаменти"}. {"No privacy list with this name found","Не е намерен списък за поверителност с това име"}. {"No private data found in this query","Няма открити лични данни в тази заявка"}. -{"No element found","Елементът не е намерен"}. {"No running node found","Не е намерен работещ нод"}. {"No services available","Няма налични услуги"}. {"No statistics found for this item","Не е налична статистика за този елемент"}. diff --git a/priv/msgs/ca.msg b/priv/msgs/ca.msg index 10da4600784..2982b121114 100644 --- a/priv/msgs/ca.msg +++ b/priv/msgs/ca.msg @@ -22,7 +22,7 @@ {"Administrator privileges required","Es necessita tenir privilegis d'administrador"}. {"All activity","Tota l'activitat"}. {"All Users","Tots els usuaris"}. -{"Allow subscription","Permetre subscripcions"}. +{"Allow subscription","Permetre subscripció"}. {"Allow this Jabber ID to subscribe to this pubsub node?","Permetre que aquesta Jabber ID es puga subscriure a aquest node pubsub?"}. {"Allow this person to register with the room?","Permetre a esta persona registrar-se a la sala?"}. {"Allow users to change the subject","Permetre que els usuaris canviïn el tema"}. @@ -295,7 +295,6 @@ {"No pending subscriptions found","No s'han trobat subscripcions pendents"}. {"No privacy list with this name found","No s'ha trobat cap llista de privacitat amb aquest nom"}. {"No private data found in this query","No s'ha trobat dades privades en esta petició"}. -{"No element found","No s'ha trobat cap element "}. {"No running node found","No s'ha trobat node en marxa"}. {"No services available","No n'hi ha serveis disponibles"}. {"No statistics found for this item","No n'hi ha estadístiques disponibles per a aquest element"}. @@ -594,7 +593,7 @@ {"Whether an entity wants to receive or disable notifications","Si una entitat vol rebre notificacions o no"}. {"Whether owners or publisher should receive replies to items","Si el propietaris o publicadors deurien de rebre respostes als elements"}. {"Whether the node is a leaf (default) or a collection","Si el node es fulla (per defecte) o es una col·lecció"}. -{"Whether to allow subscriptions","Permetre subscripcions"}. +{"Whether to allow subscriptions","Si s'hauria de permetre subscripcions"}. {"Whether to make all subscriptions temporary, based on subscriber presence","Si fer totes les subscripcions temporals, basat en la presencia del subscriptor"}. {"Whether to notify owners about new subscribers and unsubscribes","Si notificar als propietaris sobre noves subscripcions i desubscripcions"}. {"Who can send private messages","Qui pot enviar missatges privats"}. diff --git a/priv/msgs/de.msg b/priv/msgs/de.msg index 4e4bc0b3a1d..8c97e427d87 100644 --- a/priv/msgs/de.msg +++ b/priv/msgs/de.msg @@ -294,7 +294,6 @@ {"No pending subscriptions found","Keine ausstehenden Abonnements gefunden"}. {"No privacy list with this name found","Keine Privacy-Liste mit diesem Namen gefunden"}. {"No private data found in this query","Keine privaten Daten in dieser Anfrage gefunden"}. -{"No element found","Kein -Element gefunden"}. {"No running node found","Kein laufender Knoten gefunden"}. {"No services available","Keine Dienste verfügbar"}. {"No statistics found for this item","Keine Statistiken für dieses Item gefunden"}. diff --git a/priv/msgs/es.msg b/priv/msgs/es.msg index 607b9599721..a810915661e 100644 --- a/priv/msgs/es.msg +++ b/priv/msgs/es.msg @@ -295,7 +295,6 @@ {"No pending subscriptions found","No se han encontrado suscripciones pendientes"}. {"No privacy list with this name found","No se ha encontrado una lista de privacidad con este nombre"}. {"No private data found in this query","No se ha encontrado ningún elemento de dato privado en esta petición"}. -{"No element found","No se encontró ningún elemento "}. {"No running node found","No se ha encontrado ningún nodo activo"}. {"No services available","No hay servicios disponibles"}. {"No statistics found for this item","No se han encontrado estadísticas para este elemento"}. diff --git a/priv/msgs/it.msg b/priv/msgs/it.msg index f7b5c545183..926d166871d 100644 --- a/priv/msgs/it.msg +++ b/priv/msgs/it.msg @@ -295,7 +295,6 @@ {"No pending subscriptions found","Nessuna sottoscrizione in attesa trovata"}. {"No privacy list with this name found","Nessun elenco di privacy con questo nome trovato"}. {"No private data found in this query","Non sono stati trovati dati privati in questa query"}. -{"No element found","Nessun elemento trovato"}. {"No running node found","Nessun nodo in esecuzione trovato"}. {"No services available","Nessun servizio disponibile"}. {"No statistics found for this item","Nessuna statistica trovata per questa voce"}. diff --git a/priv/msgs/pt-br.msg b/priv/msgs/pt-br.msg index 882c03ec2d5..244138db534 100644 --- a/priv/msgs/pt-br.msg +++ b/priv/msgs/pt-br.msg @@ -295,7 +295,6 @@ {"No pending subscriptions found","Não foram encontradas subscrições"}. {"No privacy list with this name found","Nenhuma lista de privacidade encontrada com este nome"}. {"No private data found in this query","Nenhum dado privado encontrado nesta consulta"}. -{"No element found","Nenhum elemento foi encontrado"}. {"No running node found","Nenhum nó em execução foi encontrado"}. {"No services available","Não há serviços disponíveis"}. {"No statistics found for this item","Não foram encontradas estatísticas para este item"}. diff --git a/priv/msgs/sq.msg b/priv/msgs/sq.msg index 4469cea98d5..2cc43274dcd 100644 --- a/priv/msgs/sq.msg +++ b/priv/msgs/sq.msg @@ -186,7 +186,6 @@ {"No node specified","S’u përcaktua nyjë"}. {"No pending subscriptions found","S’u gjetën pajtime pezull"}. {"No privacy list with this name found","S’u gjet listë privatësie me atë emër"}. -{"No element found","S’u gjetën elementë "}. {"No running node found","S’u gjet nyjë në funksionim"}. {"No services available","S’ka shërbime të gatshme"}. {"No statistics found for this item","S’u gjetën statistika për këtë objekt"}. From 91fb02d62e42c59bfebde8e3c288cf704404f5de Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 18:08:57 +0100 Subject: [PATCH 164/170] Result of running "make doap" --- ejabberd.doap | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/ejabberd.doap b/ejabberd.doap index 00e17190529..b1df5efc73a 100644 --- a/ejabberd.doap +++ b/ejabberd.doap @@ -134,6 +134,15 @@ mod_muc + + + + 1.2 + 0.5.0 + complete + mod_pubsub + + @@ -476,6 +485,15 @@ mod_s2s_dialback + + + + 1.1.1 + 2.0.0 + complete + mod_pubsub + + @@ -512,6 +530,15 @@ mod_pubsub + + + + 1.2 + 0.5.0 + complete + mod_muc + + @@ -524,7 +551,7 @@ - 0.13.2 + 1.0.1 13.06 complete mod_carboncopy @@ -551,10 +578,10 @@ - 0.1 + 0.2.0 21.12 complete - mod_muc_room, conversejs/prosody compatible + mod_muc_room, 0.2.0 since 25.03 From f58a0cdbfdbbf74fdb2f4f7e7a7baa22997e9a5d Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 20:16:02 +0100 Subject: [PATCH 165/170] Add some apps to rebar2 OTP releases --- rel/reltool.config.script | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rel/reltool.config.script b/rel/reltool.config.script index 0a87ce73540..4f142efe22e 100644 --- a/rel/reltool.config.script +++ b/rel/reltool.config.script @@ -38,11 +38,12 @@ Vars = case file:consult(filename:join([TopDir, "vars.config"])) of RequiredOTPApps = [sasl, crypto, public_key, ssl, mnesia, inets, compiler, asn1, + observer, tools, syntax_tools, os_mon, xmerl], ConfiguredOTPApps = lists:flatmap( fun({tools, true}) -> - [tools, runtime_tools]; + [runtime_tools]; ({odbc, true}) -> [odbc]; (_) -> From 9087867631126abe8cca2809b6f1bd1b837836f2 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 22:46:31 +0100 Subject: [PATCH 166/170] Container: Document the used Erlang and Elixir versions --- CONTAINER.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTAINER.md b/CONTAINER.md index 3afe913b322..8badba85205 100644 --- a/CONTAINER.md +++ b/CONTAINER.md @@ -920,7 +920,7 @@ Let's summarize the differences between both container images. Legend: | Generated by | [container.yml](https://github.com/processone/ejabberd/blob/master/.github/workflows/container.yml) | [tests.yml](https://github.com/processone/docker-ejabberd/blob/master/.github/workflows/tests.yml) | | Built for | stable releases
`master` branch | stable releases
[`master` branch zip](https://github.com/processone/docker-ejabberd/actions/workflows/tests.yml) | | Architectures | `linux/amd64`
`linux/arm64` | `linux/amd64` | -| Software | Erlang/OTP 27.2-alpine
Elixir 1.18.1 | Alpine 3.19
Erlang/OTP 26.2
Elixir 1.15.7 | +| Software | Erlang/OTP 27.3-alpine
Elixir 1.18.3 | Alpine 3.19
Erlang/OTP 26.2
Elixir 1.15.7 | | Published in | [ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd) | [docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/)
[ghcr.io/processone/ecs](https://github.com/processone/docker-ejabberd/pkgs/container/ecs) | | :black_square_button: **Additional content** | | [ejabberd-contrib](https://docs.ejabberd.im/admin/guide/modules/#ejabberd-contrib) | included | not included | From 2ed7ce49a22e6f5041b7f2498820793a25c91bca Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 27 Mar 2025 23:11:29 +0100 Subject: [PATCH 167/170] Update documentation about XEP-0424 support and move to proper file (#3340) --- ejabberd.doap | 6 +++--- src/ejabberd.erl | 1 - src/mod_mam.erl | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ejabberd.doap b/ejabberd.doap index b1df5efc73a..1fc7df52ef4 100644 --- a/ejabberd.doap +++ b/ejabberd.doap @@ -758,10 +758,10 @@ - 0.4.0 + 0.4.2 24.02 - complete - + partial + mod_mam, Tombstones not implemented diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 5b6fea3aa02..b49d11f7f74 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -40,7 +40,6 @@ -protocol({xep, 368, '1.1.0', '17.09', "complete", ""}). -protocol({xep, 386, '0.3.0', '24.02', "complete", ""}). -protocol({xep, 388, '0.4.0', '24.02', "complete", ""}). --protocol({xep, 424, '0.4.0', '24.02', "complete", ""}). -protocol({xep, 440, '0.4.0', '24.02', "complete", ""}). -protocol({xep, 474, '0.4.0', '24.02', "complete", "0.4.0 since 25.03"}). -protocol({xep, 485, '0.2.0', '24.02', "complete", "mod_pubsub_serverinfo in ejabberd-contrib.git"}). diff --git a/src/mod_mam.erl b/src/mod_mam.erl index a7b47fe91e3..8df6900ee27 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -28,6 +28,7 @@ -protocol({xep, 313, '0.6.1', '15.06', "complete", ""}). -protocol({xep, 334, '0.2', '16.01', "complete", ""}). -protocol({xep, 359, '0.5.0', '15.09', "complete", ""}). +-protocol({xep, 424, '0.4.2', '24.02', "partial", "Tombstones not implemented"}). -protocol({xep, 425, '0.3.0', '24.06', "complete", ""}). -protocol({xep, 441, '0.2.0', '15.06', "complete", ""}). From 05f8992e3ea73f5a24dd0ccbb37b474364385792 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 28 Mar 2025 10:25:59 +0100 Subject: [PATCH 168/170] Update man page to 25.03 --- man/ejabberd.yml.5 | 403 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 345 insertions(+), 58 deletions(-) diff --git a/man/ejabberd.yml.5 b/man/ejabberd.yml.5 index 493aaee19b0..90cffcc9aab 100644 --- a/man/ejabberd.yml.5 +++ b/man/ejabberd.yml.5 @@ -2,12 +2,12 @@ .\" Title: ejabberd.yml .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 12/17/2024 +.\" Date: 03/28/2025 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "EJABBERD\&.YML" "5" "12/17/2024" "\ \&" "\ \&" +.TH "EJABBERD\&.YML" "5" "03/28/2025" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -82,14 +82,14 @@ All options can be changed in runtime by running \fIejabberdctl reload\-config\f .sp Some options can be specified for particular virtual host(s) only using \fIhost_config\fR or \fIappend_host_config\fR options\&. Such options are called \fIlocal\fR\&. Examples are \fImodules\fR, \fIauth_method\fR and \fIdefault_db\fR\&. The options that cannot be defined per virtual host are called \fIglobal\fR\&. Examples are \fIloglevel\fR, \fIcertfiles\fR and \fIlisten\fR\&. It is a configuration mistake to put \fIglobal\fR options under \fIhost_config\fR or \fIappend_host_config\fR section \- ejabberd will refuse to load such configuration\&. .sp -It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/24\&.12/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&. +It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/25\&.03/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&. .sp Note that this document is intended to provide comprehensive description of all configuration options that can be consulted to understand the meaning of a particular option, its format and possible values\&. It will be quite hard to understand how to configure ejabberd by reading this document only \- for this purpose the reader is recommended to read online Configuration Guide available at https://docs\&.ejabberd\&.im/admin/configuration\&. .SH "TOP LEVEL OPTIONS" .sp -This section describes top level options of ejabberd 24\&.12\&. The options that changed in this version are marked with 🟤\&. +This section describes top level options of ejabberd 25\&.03\&. The options that changed in this version are marked with 🟤\&. .PP -\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLRules|ACLName}}\fR +\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLName|ACLDefinition}}\fR .RS 4 This option defines \fIbasic\&.md#access\-rules|Access Rules\fR\&. Each access rule is assigned a name that can be referenced from other parts of the configuration file (mostly from @@ -305,7 +305,7 @@ acme: \fBallow_contrib_modules\fR: \fItrue | false\fR .RS 4 Whether to allow installation of third\-party modules or not\&. See -\fI\&.\&./\&.\&./developer/extending\-ejabberd/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR +\fI\&.\&./\&.\&./admin/guide/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR documentation section\&. The default value is \fItrue\fR\&. .RE @@ -423,7 +423,7 @@ methods to use\&. If several methods are defined, authentication is considered s This is used by the contributed module \fIejabberd_auth_http\fR that can be installed from the -ejabberd\-contrib +\fI\&.\&./\&.\&./admin/guide/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR Git repository\&. Please refer to that module\(cqs README file for details\&. .RE .PP @@ -469,6 +469,17 @@ format\&. You shouldn\(cqt change this if you already have passwords generated w \fIsha\fR\&. .RE .PP +\fBauth_stored_password_types 🟤\fR: \fI[plain | scram_sha1 | scram_sha256 | scram_sha512]\fR +.RS 4 +\fINote\fR +about this option: added in 25\&.03\&. List of password types that should be stored simultaneously for each user in database\&. When the user sets the account password, database will be updated to store the password in formats compatible with each type listed here\&. This can be used to migrate user passwords to a more secure format\&. If this option if set, it will override values set in +\fIauth_scram_hash\fR +and +\fIauth_password_format\fR +options\&. The default value is +[]\&. +.RE +.PP \fBauth_use_cache\fR: \fItrue | false\fR .RS 4 Same as @@ -587,11 +598,11 @@ A maximum number of items (not memory!) in cache\&. The rule of thumb, for all t \fINote\fR about this option: improved in 23\&.01\&. Full path to a script that generates \fIbasic\&.md#captcha|CAPTCHA\fR -images\&. +images\&. The keyword \fI@VERSION@\fR is replaced with ejabberd version number in \fIXX\&.YY\fR -format\&. +format\&. The keyword \fI@SEMVER@\fR is replaced with ejabberd version number in semver format when compiled with Elixir\(cqs mix, or XX\&.YY format otherwise\&. Alternatively, it can be the name of a module that implements ejabberd CAPTCHA support\&. There is no default value: when this option is not set, CAPTCHA functionality is completely disabled\&. .sp @@ -696,14 +707,38 @@ Default volatile (in\-memory) storage for ejabberd\&. Modules and other componen \fImnesia\fR\&. .RE .PP -\fBdefine_macro\fR: \fI{MacroName: MacroValue}\fR +\fBdefine_keyword 🟤\fR: \fI{NAME: Value}\fR .RS 4 -Defines a -\fI\&.\&./configuration/file\-format\&.md#macros\-in\-configuration\-file|macro\fR\&. The value can be any valid arbitrary YAML value\&. For convenience, it\(cqs recommended to define a -\fIMacroName\fR -in capital letters\&. Duplicated macros are not allowed\&. Macros are processed after additional configuration files have been included, so it is possible to use macros that are defined in configuration files included before the usage\&. It is possible to use a -\fIMacroValue\fR -in the definition of another macro\&. +\fINote\fR +about this option: added in 25\&.03\&. Allows to define configuration +\fI\&.\&./configuration/file\-format\&.md#macros\-and\-keywords|keywords\fR\&. +.sp +\fBExample\fR: +.sp +.if n \{\ +.RS 4 +.\} +.nf +define_keyword: + SQL_USERNAME: "eja\&.global" + +host_config: + localhost: + define_keyword: + SQL_USERNAME: "eja\&.localhost" + +sql_username: "prefix\&.@SQL_USERNAME@" +.fi +.if n \{\ +.RE +.\} +.RE +.PP +\fBdefine_macro 🟤\fR: \fI{NAME: Value}\fR +.RS 4 +\fINote\fR +about this option: improved in 25\&.03\&. Allows to define configuration +\fI\&.\&./configuration/file\-format\&.md#macros\-and\-keywords|macros\fR\&. .sp \fBExample\fR: .sp @@ -911,9 +946,7 @@ host_config: .RS 4 List of one or more \fI\&.\&./configuration/basic\&.md#host\-names|host names\fR -(or domains) that -\fIejabberd\fR -will serve\&. This is a +(or domains) that ejabberd will serve\&. This is a \fBmandatory\fR option\&. .RE @@ -946,7 +979,7 @@ Disallows the usage of those options in the included file .RS 4 \fINote\fR about this option: added in 23\&.10\&. Modules to install from -\fI\&.\&./\&.\&./developer/extending\-ejabberd/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR +\fI\&.\&./\&.\&./admin/guide/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR at start time\&. The default value is an empty list of modules: \fI[]\fR\&. .RE @@ -1008,10 +1041,23 @@ Whether to dereference aliases or not\&. The default value is \fBldap_dn_filter\fR: \fI{Filter: FilterAttrs}\fR .RS 4 This filter is applied on the results returned by the main filter\&. The filter performs an additional LDAP lookup to make the complete result\&. This is useful when you are unable to define all filter rules in -\fIldap_filter\fR\&. You can define "%u", "%d", "%s" and "%D" pattern variables in -\fIFilter\fR: "%u" is replaced by a user\(cqs part of the JID, "%d" is replaced by the corresponding domain (virtual host), all "%s" variables are consecutively replaced by values from the attributes in +\fIldap_filter\fR\&. You can define +\fI"%u"\fR, +\fI"%d"\fR, +\fI"%s"\fR +and +\fI"%D"\fR +pattern variables in +\fIFilter: "%u"\fR +is replaced by a user\(cqs part of the JID, +\fI"%d"\fR +is replaced by the corresponding domain (virtual host), all +\fI"%s"\fR +variables are consecutively replaced by values from the attributes in \fIFilterAttrs\fR -and "%D" is replaced by Distinguished Name from the result set\&. There is no default value, which means the result is not filtered\&. WARNING: Since this filter makes additional LDAP lookups, use it only as the last resort: try to define all filter rules in +and +\fI"%D"\fR +is replaced by Distinguished Name from the result set\&. There is no default value, which means the result is not filtered\&. WARNING: Since this filter makes additional LDAP lookups, use it only as the last resort: try to define all filter rules in \fIldap_filter\fR option if possible\&. .sp @@ -1038,7 +1084,10 @@ Whether to encrypt LDAP connection using TLS or not\&. The default value is \fBldap_filter\fR: \fIFilter\fR .RS 4 An LDAP filter as defined in -RFC4515\&. There is no default value\&. Example: "(&(objectClass=shadowAccount)(memberOf=XMPP Users))"\&. NOTE: don\(cqt forget to close brackets and don\(cqt use superfluous whitespaces\&. Also you must not use "uid" attribute in the filter because this attribute will be appended to the filter automatically\&. +RFC4515\&. There is no default value\&. Example: +\fI"(&(objectClass=shadowAccount)(memberOf=XMPP Users))"\fR\&. NOTE: don\(cqt forget to close brackets and don\(cqt use superfluous whitespaces\&. Also you must not use +\fI"uid"\fR +attribute in the filter because this attribute will be appended to the filter automatically\&. .RE .PP \fBldap_password\fR: \fIPassword\fR @@ -1101,11 +1150,15 @@ LDAP attributes which hold a list of attributes to use as alternatives for getti \fIAttr\fR is an LDAP attribute which holds the user\(cqs part of the JID and \fIAttrFormat\fR -must contain one and only one pattern variable "%u" which will be replaced by the user\(cqs part of the JID\&. For example, "%u@example\&.org"\&. If the value is in the form of +must contain one and only one pattern variable +\fI"%u"\fR +which will be replaced by the user\(cqs part of the JID\&. For example, +\fI"%\fR\fIu@example\fR\fI\&.org"\fR\&. If the value is in the form of \fI[Attr]\fR then \fIAttrFormat\fR -is assumed to be "%u"\&. +is assumed to be +\fI"%u"\fR\&. .RE .PP \fBlisten\fR: \fI[Options, \&.\&.\&.]\fR @@ -1193,7 +1246,7 @@ This option can be used to tune tick time parameter of .RS 4 Whether to use the \fIdatabase\&.md#default\-and\-new\-schemas|new SQL schema\fR\&. All schemas are located at -https://github\&.com/processone/ejabberd/tree/24\&.12/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The +https://github\&.com/processone/ejabberd/tree/25\&.03/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The \fInew\fR schema can handle several XMPP domains in a single ejabberd database\&. Using this \fInew\fR @@ -1434,7 +1487,7 @@ or if the latter is not set\&. .RE .PP -\fBredis_server 🟤\fR: \fIHost | IP Address | Unix Socket Path\fR +\fBredis_server\fR: \fIHost | IP Address | Unix Socket Path\fR .RS 4 \fINote\fR about this option: improved in 24\&.12\&. A hostname, IP address or unix domain socket file of the @@ -1675,7 +1728,7 @@ shaper: .\} .RE .PP -\fBshaper_rules\fR: \fI{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}\fR +\fBshaper_rules\fR: \fI{ShaperRuleName: {Number|ShaperName: ACLName|ACLDefinition}}\fR .RS 4 This option defines \fI\&.\&./configuration/basic\&.md#shaper\-rules|shaper rules\fR @@ -1990,7 +2043,7 @@ seconds\&. .RE .SH "MODULES" .sp -This section describes modules options of ejabberd 24\&.12\&. The modules that changed in this version are marked with 🟤\&. +This section describes modules options of ejabberd 25\&.03\&. The modules that changed in this version are marked with 🟤\&. .SS "mod_adhoc" .sp This module implements XEP\-0050: Ad\-Hoc Commands\&. It\(cqs an auxiliary module and is only needed by some of the other modules\&. @@ -2009,6 +2062,63 @@ Provide the Commands item in the Service Discovery\&. Default value: \fIfalse\fR\&. .RE .RE +.SS "mod_adhoc_api 🟤" +.sp +\fINote\fR about this option: added in 25\&.03\&. +.sp +Execute API Commands in a XMPP client using XEP\-0050: Ad\-Hoc Commands\&. This module requires \fImod_adhoc\fR (to execute the commands), and recommends \fImod_disco\fR (to discover the commands)\&. +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBAvailable options:\fR +.RS 4 +.PP +\fBdefault_version\fR: \fIinteger() | string()\fR +.RS 4 +What API version to use\&. If setting an ejabberd version, it will use the latest API version that was available in that ejabberd version\&. For example, setting +\fI"24\&.06"\fR +in this option implies +\fI2\fR\&. The default value is the latest version\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBExample:\fR +.RS 4 +.sp +.if n \{\ +.RS 4 +.\} +.nf +acl: + admin: + user: jan@localhost + +api_permissions: + "adhoc commands": + from: mod_adhoc_api + who: admin + what: + \- "[tag:roster]" + \- "[tag:session]" + \- stats + \- status + +modules: + mod_adhoc_api: + default_version: 2 +.fi +.if n \{\ +.RE +.\} +.RE .SS "mod_admin_extra" .sp This module provides additional administrative commands\&. @@ -2097,13 +2207,27 @@ This module can be used to update existing SQL database from the default to the The module has no options\&. .SS "mod_announce" .sp -This module enables configured users to broadcast announcements and to set the message of the day (MOTD)\&. Configured users can perform these actions with an XMPP client either using Ad\-hoc Commands or sending messages to specific JIDs\&. +This module enables configured users to broadcast announcements and to set the message of the day (MOTD)\&. Configured users can perform these actions with an XMPP client either using Ad\-Hoc Commands or sending messages to specific JIDs\&. +.if n \{\ .sp -Note that this module can be resource intensive on large deployments as it may broadcast a lot of messages\&. This module should be disabled for instances of ejabberd with hundreds of thousands users\&. +.\} +.RS 4 +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBNote\fR +.ps -1 +.br +.sp +This module can be resource intensive on large deployments as it may broadcast a lot of messages\&. This module should be disabled for instances of ejabberd with hundreds of thousands users\&. +.sp .5v +.RE .sp -The Ad\-hoc Commands are listed in the Server Discovery\&. For this feature to work, \fImod_adhoc\fR must be enabled\&. +To send announcements using XEP\-0050: Ad\-Hoc Commands, this module requires \fImod_adhoc\fR (to execute the commands), and recommends \fImod_disco\fR (to discover the commands)\&. .sp -The specific JIDs where messages can be sent are listed below\&. The first JID in each entry will apply only to the specified virtual host example\&.org, while the JID between brackets will apply to all virtual hosts in ejabberd: +To send announcements by sending messages to specific JIDs, these are the destination JIDs: .sp .RS 4 .ie n \{\ @@ -2113,7 +2237,7 @@ The specific JIDs where messages can be sent are listed below\&. The first JID i .sp -1 .IP \(bu 2.3 .\} -example\&.org/announce/all (example\&.org/announce/all\-hosts/all):: The message is sent to all registered users\&. If the user is online and connected to several resources, only the resource with the highest priority will receive the message\&. If the registered user is not connected, the message will be stored offline in assumption that offline storage (see +\fIexample\&.org/announce/all\fR: Send the message to all registered users in that vhost\&. If the user is online and connected to several resources, only the resource with the highest priority will receive the message\&. If the registered user is not connected, the message is stored offline in assumption that offline storage (see \fImod_offline\fR) is enabled\&. .RE .sp @@ -2125,7 +2249,7 @@ example\&.org/announce/all (example\&.org/announce/all\-hosts/all):: The message .sp -1 .IP \(bu 2.3 .\} -example\&.org/announce/online (example\&.org/announce/all\-hosts/online):: The message is sent to all connected users\&. If the user is online and connected to several resources, all resources will receive the message\&. +\fIexample\&.org/announce/online\fR: Send the message to all connected users\&. If the user is online and connected to several resources, all resources will receive the message\&. .RE .sp .RS 4 @@ -2136,7 +2260,43 @@ example\&.org/announce/online (example\&.org/announce/all\-hosts/online):: The m .sp -1 .IP \(bu 2.3 .\} -example\&.org/announce/motd (example\&.org/announce/all\-hosts/motd):: The message is set as the message of the day (MOTD) and is sent to users when they login\&. In addition the message is sent to all connected users (similar to announce/online)\&. +\fIexample\&.org/announce/motd\fR: Set the message of the day (MOTD) that is sent to users when they login\&. Also sends the message to all connected users (similar to +\fIannounce/online\fR)\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fIexample\&.org/announce/motd/update\fR: Set the message of the day (MOTD) that is sent to users when they login\&. This does not send the message to any currently connected user\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fIexample\&.org/announce/motd/delete\fR: Remove the existing message of the day (MOTD) by sending a message to this JID\&. +.RE +.sp +There are similar destination JIDs to apply to all virtual hosts in ejabberd: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fIexample\&.org/announce/all\-hosts/all\fR: send to all registered accounts .RE .sp .RS 4 @@ -2147,7 +2307,7 @@ example\&.org/announce/motd (example\&.org/announce/all\-hosts/motd):: The messa .sp -1 .IP \(bu 2.3 .\} -example\&.org/announce/motd/update (example\&.org/announce/all\-hosts/motd/update):: The message is set as message of the day (MOTD) and is sent to users when they login\&. The message is not sent to any currently connected user\&. +\fIexample\&.org/announce/all\-hosts/online\fR: send to online sessions .RE .sp .RS 4 @@ -2158,7 +2318,29 @@ example\&.org/announce/motd/update (example\&.org/announce/all\-hosts/motd/updat .sp -1 .IP \(bu 2.3 .\} -example\&.org/announce/motd/delete (example\&.org/announce/all\-hosts/motd/delete):: Any message sent to this JID removes the existing message of the day (MOTD)\&. +\fIexample\&.org/announce/all\-hosts/motd\fR: set MOTD and send to online +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fIexample\&.org/announce/all\-hosts/motd/update\fR: update MOTD +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fIexample\&.org/announce/all\-hosts/motd/delete\fR: delete MOTD .RE .sp .it 1 an-trap @@ -2211,11 +2393,11 @@ Same as top\-level option, but applied to this module only\&. .RE .RE -.SS "mod_auth_fast 🟤" +.SS "mod_auth_fast" .sp \fINote\fR about this option: added in 24\&.12\&. .sp -The module adds support for XEP\-0480: Fast Authentication Streamlining Tokens that allows users to authenticate using self managed tokens\&. +The module adds support for XEP\-0484: Fast Authentication Streamlining Tokens that allows users to authenticate using self\-managed tokens\&. .sp .it 1 an-trap .nr an-no-space-flag 1 @@ -2225,7 +2407,7 @@ The module adds support for XEP\-0480: Fast Authentication Streamlining Tokens t \fBAvailable options:\fR .RS 4 .PP -\fBdb_type\fR: \fImnesia | sql\fR +\fBdb_type\fR: \fImnesia\fR .RS 4 Same as top\-level \fIdefault_db\fR @@ -2234,7 +2416,7 @@ option, but applied to this module only\&. .PP \fBtoken_lifetime\fR: \fItimeout()\fR .RS 4 -Time that tokens will be keept, measured from it\(cqs creation time\&. Default value set to 30 days +Time that tokens will be kept, measured from it\(cqs creation time\&. Default value set to 30 days .RE .PP \fBtoken_refresh_age\fR: \fItimeout()\fR @@ -2257,7 +2439,7 @@ This time determines age of token, that qualifies for automatic refresh\&. Defau .nf modules: mod_auth_fast: - token_timeout: 14days + token_lifetime: 14days .fi .if n \{\ .RE @@ -2578,9 +2760,90 @@ While a client is inactive, queue presence stanzas that indicate (un)availabilit .RE .SS "mod_configure" .sp -The module provides server configuration functionality via XEP\-0050: Ad\-Hoc Commands\&. Implements many commands as defined in XEP\-0133: Service Administration\&. This module requires \fImod_adhoc\fR to be loaded\&. +The module provides server configuration functionalities using XEP\-0030: Service Discovery and XEP\-0050: Ad\-Hoc Commands: .sp -The module has no options\&. +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +List and discover outgoing s2s, online client sessions and all registered accounts +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Most of the ad\-hoc commands defined in +XEP\-0133: Service Administration +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Additional custom ad\-hoc commands specific to ejabberd +.RE +.sp +This module requires \fImod_adhoc\fR (to execute the commands), and recommends \fImod_disco\fR (to discover the commands)\&. +.sp +Please notice that all the ad\-hoc commands implemented by this module have an equivalent API Command that you can execute using \fImod_adhoc_api\fR or any other API frontend\&. +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBAvailable options:\fR +.RS 4 +.PP +\fBaccess 🟤\fR: \fIAccessName\fR +.RS 4 +\fINote\fR +about this option: added in 25\&.03\&. This option defines which access rule will be used to control who is allowed to access the features provided by this module\&. The default value is +\fIconfigure\fR\&. +.RE +.RE +.sp +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBExample:\fR +.RS 4 +.sp +.if n \{\ +.RS 4 +.\} +.nf +acl: + admin: + user: sun@localhost + +access_rules: + configure: + allow: admin + +modules: + mod_configure: + access: configure +.fi +.if n \{\ +.RE +.\} +.RE .SS "mod_conversejs" .sp \fINote\fR about this option: added in 21\&.12 and improved in 22\&.05\&. @@ -3060,7 +3323,8 @@ To run a command, send a POST request to the corresponding URL: \fIhttp://localh .PP \fBdefault_version\fR: \fIinteger() | string()\fR .RS 4 -What API version to use when none is specified in the URL path\&. If setting an ejabberd version, it will use the latest API version that was available in that ejabberd version\&. For example, setting +\fINote\fR +about this option: added in 24\&.12\&. What API version to use when none is specified in the URL path\&. If setting an ejabberd version, it will use the latest API version that was available in that ejabberd version\&. For example, setting \fI"24\&.06"\fR in this option implies \fI2\fR\&. The default value is the latest version\&. @@ -3578,6 +3842,22 @@ The module has no options\&. .SS "mod_mam" .sp This module implements XEP\-0313: Message Archive Management and XEP\-0441: Message Archive Management Preferences\&. Compatible XMPP clients can use it to store their chat history on the server\&. +.if n \{\ +.sp +.\} +.RS 4 +.it 1 an-trap +.nr an-no-space-flag 1 +.nr an-break-flag 1 +.br +.ps +1 +\fBNote\fR +.ps -1 +.br +.sp +Mnesia backend for mod_mam is not recommended: it\(cqs limited to 2GB and often gets corrupted when reaching this limit\&. SQL backend is recommended\&. Namely, for small servers SQLite is a preferred choice because it\(cqs very easy to configure\&. +.sp .5v +.RE .sp .it 1 an-trap .nr an-no-space-flag 1 @@ -3676,11 +3956,11 @@ When this option is disabled, for each individual subscriber a separate mucsub m \fIfalse\fR\&. .RE .RE -.SS "mod_matrix_gw" +.SS "mod_matrix_gw 🟤" .sp -\fINote\fR about this option: added in 24\&.02\&. +\fINote\fR about this option: improved in 25\&.03\&. .sp -Matrix gateway\&. Erlang/OTP 25 or higher is required to use this module\&. +Matrix gateway\&. Erlang/OTP 25 or higher is required to use this module\&. This module is available since ejabberd 24\&.02\&. .sp .it 1 an-trap .nr an-no-space-flag 1 @@ -4349,9 +4629,12 @@ in order to accept their join in the room\&. The default value is Short description of the room\&. The default value is an empty string\&. .RE .PP -\fBenable_hats\fR: \fItrue | false\fR +\fBenable_hats 🟤\fR: \fItrue | false\fR .RS 4 -Allow extended roles as defined in XEP\-0317 Hats\&. The default value is +\fINote\fR +about this option: improved in 25\&.03\&. Allow extended roles as defined in XEP\-0317 Hats\&. Check the +\fI\&.\&./\&.\&./tutorials/muc\-hats\&.md|MUC Hats\fR +tutorial\&. The default value is \fIfalse\fR\&. .RE .PP @@ -4467,6 +4750,12 @@ A human\-readable title of the room\&. There is no default value A custom vCard for the room\&. See the equivalent mod_muc option\&.The default value is an empty string\&. .RE .PP +\fBvcard_xupdate\fR: \fIundefined | external | AvatarHash\fR +.RS 4 +Set the hash of the avatar image\&. The default value is +\fIundefined\fR\&. +.RE +.PP \fBvoice_request_min_interval\fR: \fINumber\fR .RS 4 Minimum interval between voice requests, in seconds\&. The default value is @@ -6308,9 +6597,7 @@ is .PP \fBaccess_from\fR: \fIAccessName\fR .RS 4 -By default, -\fIejabberd\fR -doesn\(cqt allow the client to register new accounts from s2s or existing c2s sessions\&. You can change it by defining access rule in this option\&. Use with care: allowing registration from s2s leads to uncontrolled massive accounts creation by rogue users\&. +By default, ejabberd doesn\(cqt allow the client to register new accounts from s2s or existing c2s sessions\&. You can change it by defining access rule in this option\&. Use with care: allowing registration from s2s leads to uncontrolled massive accounts creation by rogue users\&. .RE .PP \fBaccess_remove\fR: \fIAccessName\fR @@ -8085,7 +8372,7 @@ Should the operating system be revealed or not\&. The default value is .RE .SH "LISTENERS" .sp -This section describes listeners options of ejabberd 24\&.12\&. +This section describes listeners options of ejabberd 25\&.03\&. .sp TODO .SH "AUTHOR" @@ -8093,13 +8380,13 @@ TODO ProcessOne\&. .SH "VERSION" .sp -This document describes the configuration file of ejabberd 24\&.12\&. Configuration options of other ejabberd versions may differ significantly\&. +This document describes the configuration file of ejabberd 25\&.03\&. Configuration options of other ejabberd versions may differ significantly\&. .SH "REPORTING BUGS" .sp Report bugs to https://github\&.com/processone/ejabberd/issues .SH "SEE ALSO" .sp -Default configuration file: https://github\&.com/processone/ejabberd/blob/24\&.12/ejabberd\&.yml\&.example +Default configuration file: https://github\&.com/processone/ejabberd/blob/25\&.03/ejabberd\&.yml\&.example .sp Main site: https://ejabberd\&.im .sp From f67743643701cfdf645d954fbd8187caf496cb20 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 28 Mar 2025 10:34:17 +0100 Subject: [PATCH 169/170] Update changelog to 25.03 --- CHANGELOG.md | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e1fc3bece0..7c536367770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,117 @@ +## Version 25.03 + +#### Commands API +- `ejabberdctl`: New option `CTL_OVER_HTTP` ([#4340](https://github.com/processone/ejabberd/issues/4340)) +- `ejabberd_web_admin`: Support commands with tuple arguments +- `mod_adhoc_api`: New module to execute API Commands using Ad-Hoc Commands ([#4357](https://github.com/processone/ejabberd/issues/4357)) +- `mod_http_api`: Sort list elements in a command result +- Show warning when registering command with an existing name +- Fix commands unregistration +- `change_room_option`: Add forgotten support to set `enable_hats` room option +- `change_room_option`: Verify room option value before setting it ([#4337](https://github.com/processone/ejabberd/issues/4337)) +- `create_room_with_opts`: Recommend using `;` and `=` separators +- `list_cluster_detailed`: Fix crash when a node is down +- `mnesia_list_tables`: Allow using this internal command +- `mnesia_table_change_storage`: Allow using this internal command +- `status`: Separate command result with newline +- `update_sql`: Fix updating tables created by ejabberd internally +- `update_sql`: Fix MySQL support + +#### Configuration +- `acl`: Fix bug matching the acl `shared_group: NAME` +- `define_keyword`: New option to define keywords ([#4350](https://github.com/processone/ejabberd/issues/4350)) +- `define_macro`: Add option to `globals()` because it's useless inside `host_config` +- `ejabberd.yml.example`: Enable `mod_muc_occupantid` by default +- Add support to use keywords in toplevel, listener and modules +- Show warning also when deprecated listener option is set as disabled ([#4345](https://github.com/processone/ejabberd/issues/4345)) + +#### Container +- Bump versions to Erlang/OTP 27.3 and Elixir 1.18.3 +- Add `ERL_FLAGS` to compile elixir on qemu cross-platform +- Copy files to stable path, add ecs backwards compatibility +- Fix warning about relative workdir +- Improve entrypoint script: register account, or set random +- Link path to Mnesia spool dir for backwards compatibility +- Place `sockets/` outside `database/` +- Use again direct METHOD, qemu got fixed ([#4280](https://github.com/processone/ejabberd/issues/4280)) +- `ejabberd.yml.example`: Copy main example configuration file +- `ejabberd.yml.example`: Define and use macros in the default configuration file +- `ejabberd.yml.example`: Enable `CTL_OVER_HTTP` by default +- `ejabberd.yml.example`: Listen for webadmin in a port number lower than any other +- `ejabberdapi`: Compile during build +- `CONTAINER.md`: Include documentation for ecs container image + +#### Core and Modules +- `ejabberd_auth`: Add support for `auth_stored_password_types` +- `ejabberd_router`: Don't rewrite "self-addressed" privileged IQs as results ([#4348](https://github.com/processone/ejabberd/issues/4348)) +- `misc`: Fix json version of `json_encode_with_kv_list` for nested kv lists ([#4338](https://github.com/processone/ejabberd/issues/4338)) +- OAuth: Fix crashes when oauth is feed with invalid jid ([#4355](https://github.com/processone/ejabberd/issues/4355)) +- PubSub: Bubble up db errors in `nodetree_tree_sql:set_node` +- `mod_configure`: Add option `access` to let configure the access name +- `mod_mix_pam`: Remove `Channels` roster group of mix channels ([#4297](https://github.com/processone/ejabberd/issues/4297)) +- `mod_muc`: Document MUC room option vcard_xupdate +- `mod_privilege`: Accept non-privileged IQs from privileged components ([#4341](https://github.com/processone/ejabberd/issues/4341)) +- `mod_private`: Improve exception handling +- `mod_private`: Don't warn on conversion errors +- `mod_private`: Handle invalid PEP-native bookmarks +- `mod_private`: Don't crash on invalid bookmarks +- `mod_s2s_bidi`: Stop processing other handlers in s2s_in_handle_info ([#4344](https://github.com/processone/ejabberd/issues/4344)) +- `mod_s2s_bidi`: Fix issue with wrong namespace + +#### Dependencies +- `ex_doc`: Bump to 0.37.2 +- `stringprep`: Bump to 1.0.31 +- `provider_asn1`: Bump to 0.4.1 +- `xmpp` Bump to bring fix for ssdp hash calculation +- `xmpp` Bump to get support for webchat_url ([#3041](https://github.com/processone/ejabberd/issues/3041)) +- `xmpp` Bump to get XEP-0317 Hats namespaces version 0.2.0 +- `xmpp` Bump to bring SSDP to XEP version 0.4 +- `yconf` Bump to support macro inside string + +#### Development and Testing +- `mix.exs`: Keep debug info when building `dev` release +- `mix.exs`: The `ex_doc` dependency is only relevant for the `edoc` Mix environment +- `ext_mod`: add `$libdir/include` to include path +- `ext_mod`: fix greedy include path ([#4359](https://github.com/processone/ejabberd/issues/4359)) +- `gen_mod`: Support registering commands and `hook_subscribe` in `start/2` result +- `c2s_handle_bind`: New event in `ejabberd_c2s` ([#4356](https://github.com/processone/ejabberd/issues/4356)) +- `muc_disco_info_extras`: New event `mod_muc_room` useful for `mod_muc_webchat_url` ([#3041](https://github.com/processone/ejabberd/issues/3041)) +- VSCode: Fix compiling support +- Add tests for config features `define_macro` and `define_keyword` +- Allow test to run using `ct_run` +- Fixes to handle re-running test after `update_sql` +- Uninstall `mod_example` when the tests has finished + +#### Documentation +- Add XEPs that are indirectly supported and required by XEP-0479 +- Document that XEP-0474 0.4.0 was recently upgraded +- Don't use backtick quotes for ejabberd name +- Fix values allowed in db_type of mod_auth_fast documentation +- Reword explanation about ACL names and definitions +- Update moved or broken URLs in documentation + +#### Installers +- Bump Erlang/OTP 27.3 and Elixir 1.18.3 +- Bump OpenSSL 3.4.1 +- Bump crosstool-NG 1.27.0 +- Fix building Termcap and Linux-PAM + +#### Matrix Gateway +- Preserve XMPP message IDs in Matrix rooms +- Better Matrix room topic and room roles to MUC conversion, support room aliases in invites +- Add `muc#user` element to presences and an initial empty subject +- Fix `gen_iq_handler:remove_iq_handler` call +- Properly handle IQ requests +- Support Matrix room aliases +- Fix handling of 3PI events + +#### Unix Domain Socket +- Add support for socket relative path +- Use `/tmp` for temporary socket, as path is restricted to 107 chars +- Handle unix socket when logging remote client +- When stopping listener, delete Unix Domain Socket file +- `get_auto_url` option: Don't build auto URL if port is unix domain socket ([#4345](https://github.com/processone/ejabberd/issues/4345)) + ## Version 24.12 #### Miscelanea From 85d0e93af57ecce96eeb649dbca40944fd088095 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 28 Mar 2025 10:38:16 +0100 Subject: [PATCH 170/170] Set version to 25.03 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 9e68cd390fc..5d1d0d68dab 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 24.12` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd]) +AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 25.03` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd]) REQUIRE_ERLANG_MIN="9.0.5 (Erlang/OTP 20.0)" REQUIRE_ERLANG_MAX="100.0.0 (No Max)"