Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 601fcba4cb | |||
| cc3a9f7722 | |||
| 296ef8287f | |||
| b5dab24679 | |||
| 319414b985 | |||
| 6b0058c89c | |||
| 855c828d1f | |||
| c72ef537ee | |||
| 11e86811a0 | |||
| 2183f60917 | |||
| 05f0fbf195 | |||
| 853da159de | |||
| 643ae7e5f9 | |||
| 322e25d18e | |||
| bdd8ba115e | |||
| 71ad7c368d | |||
| 8be0f8a0b0 | |||
| e9e678a994 | |||
| a89152a3d7 | |||
| 46d5ab369f | |||
| 81906b74ed | |||
| 74b0f64645 | |||
| 50948d1619 | |||
| 38f1132192 | |||
| 50ef49d190 | |||
| 3669ac8aed | |||
| 7f8519c0af | |||
| 859ba3e0c2 | |||
| 94c2a115d5 | |||
| 634b646711 | |||
| 2a9dc2c7b2 | |||
| ef93a5359b | |||
| efb1fc9b3f | |||
| aa5faf1f36 | |||
| 4723283896 | |||
| 36187e07d0 | |||
| a9583b43c3 | |||
| ca54f81f58 | |||
| b4399291ef | |||
| a8df58f056 | |||
| 54a89b39fb | |||
| 4a931b42ab | |||
| 15d73b9d20 | |||
| c2d4f73893 | |||
| 31b85351f2 | |||
| c900f0ad83 | |||
| b2e6749fd2 | |||
| 2437dc4e06 | |||
| 115e7d08aa | |||
| d9ddbe0212 | |||
| 512285e48d | |||
| 642e7ecc29 | |||
| ce5a8acaf7 | |||
| 3d9a5a1635 | |||
| 3469a51f58 | |||
| d4b30957a3 | |||
| cc377bbebf | |||
| eec836239f | |||
| 941d51a6e7 | |||
| e3243fa35b | |||
| 70512c7116 | |||
| 3c896d1c6a | |||
| b455d93c69 | |||
| 017b2feac1 | |||
| 5f47860ee1 | |||
| 795498fa45 | |||
| aa1717ee77 | |||
| db6d3e63f2 | |||
| 0304428d95 | |||
| 74b80bfe08 | |||
| 90ce65e4dc | |||
| d4d9771a71 | |||
| 70ee294079 | |||
| 5f4d17621f | |||
| 8f4179050b | |||
| fddacd51a4 | |||
| e726ba9a8b | |||
| da1673e264 | |||
| 7cd34d3709 | |||
| ec7fd05987 | |||
| 34a58863e3 | |||
| 3237a955e5 | |||
| 8e7489c2be | |||
| df5202a2f0 | |||
| db3a5d8915 | |||
| 6110f213de | |||
| e99fe98db4 | |||
| b07e28be2c | |||
| 937d5fe495 | |||
| 01141e5f69 | |||
| 15569d0b13 | |||
| 918806006c | |||
| d5e030a638 | |||
| 47f1beca0c | |||
| a565b0e4c1 | |||
| 10d1704899 | |||
| bc7c8e3952 | |||
| 4e35515a8c | |||
| d2a3fe3ed2 |
@@ -68,8 +68,8 @@ jobs:
|
||||
|
||||
- name: Prepare databases
|
||||
run: |
|
||||
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
|
||||
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
|
||||
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
|
||||
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
|
||||
sudo systemctl start mysql.service
|
||||
sudo systemctl start postgresql.service
|
||||
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
- name: Remove syntax_tools from release
|
||||
run: sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
|
||||
|
||||
- name: Cache rebar
|
||||
- name: Cache Hex.pm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
@@ -133,6 +133,8 @@ jobs:
|
||||
- run: make xref
|
||||
- run: make dialyzer
|
||||
- run: make test-eunit
|
||||
- run: make elvis
|
||||
if: matrix.otp >= 23
|
||||
|
||||
- name: Check Production Release
|
||||
run: |
|
||||
@@ -145,12 +147,30 @@ jobs:
|
||||
cat $RE/logs/ejabberd.log
|
||||
grep -q "is stopped in" $RE/logs/ejabberd.log
|
||||
|
||||
- name: Check Development Release
|
||||
- name: Start Development Release
|
||||
run: |
|
||||
make dev
|
||||
RE=_build/dev/rel/ejabberd
|
||||
sed -i 's/starttls_required: true/starttls_required: false/g' $RE/conf/ejabberd.yml
|
||||
$RE/bin/ejabberdctl start
|
||||
$RE/bin/ejabberdctl started
|
||||
$RE/bin/ejabberdctl register admin localhost admin
|
||||
grep -q "is started in" $RE/logs/ejabberd.log
|
||||
|
||||
- name: Run XMPP Interoperability Tests against CI server.
|
||||
if: matrix.otp == '26'
|
||||
continue-on-error: true
|
||||
uses: XMPP-Interop-Testing/xmpp-interop-tests-action@v1.4.0
|
||||
with:
|
||||
domain: 'localhost'
|
||||
adminAccountUsername: 'admin'
|
||||
adminAccountPassword: 'admin'
|
||||
disabledSpecifications: RFC6121,XEP-0030,XEP-0045,XEP-0054,XEP-0060,XEP-0080,XEP-0115,XEP-0118,XEP-0215,XEP-0347,XEP-0363,XEP-0384
|
||||
|
||||
- name: Stop Development Release
|
||||
if: always()
|
||||
run: |
|
||||
RE=_build/dev/rel/ejabberd
|
||||
$RE/bin/ejabberdctl stop
|
||||
$RE/bin/ejabberdctl stopped
|
||||
cat $RE/logs/ejabberd.log
|
||||
@@ -256,12 +276,12 @@ jobs:
|
||||
run: |
|
||||
[[ -d logs ]] && rm -rf logs
|
||||
[[ -d _build/test/logs ]] && rm -rf _build/test/logs || true
|
||||
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
|
||||
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
|
||||
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
|
||||
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
|
||||
mysql -u root -proot -e "DROP DATABASE ejabberd_test;"
|
||||
sudo -u postgres psql -c "DROP DATABASE ejabberd_test;"
|
||||
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
|
||||
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
|
||||
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
|
||||
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
|
||||
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
|
||||
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
|
||||
TO 'ejabberd_test'@'localhost';"
|
||||
|
||||
@@ -61,6 +61,13 @@ jobs:
|
||||
apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
|
||||
libsqlite3-dev libwebp-dev libyaml-dev
|
||||
|
||||
- name: Cache Hex.pm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/rebar3/
|
||||
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -204,6 +211,13 @@ jobs:
|
||||
sed -i 's|^{deps, \[\(.*\)|{deps, [{decimal, ".*", {git, "https://github.com/ericmj/decimal", {branch, "main"}}},\n \1|g' rebar.config
|
||||
cat rebar.config
|
||||
|
||||
- name: Cache Hex.pm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/rebar3/
|
||||
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -347,6 +361,13 @@ jobs:
|
||||
run: |
|
||||
mix deps.unlock jose
|
||||
|
||||
- name: Cache Hex.pm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.hex/
|
||||
key: ${{matrix.otp}}-${{hashFiles('mix.exs')}}
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
|
||||
Vendored
+17
@@ -1,6 +1,23 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Relive (Vim)",
|
||||
"type": "erlang",
|
||||
"request": "launch",
|
||||
"runinterminal": [
|
||||
"./rebar3", "shell",
|
||||
"--apps", "ejabberd",
|
||||
"--config", "rel/relive.config",
|
||||
"--script", "rel/relive.escript",
|
||||
"--name", "ejabberd@localhost",
|
||||
"--setcookie", "COOKIE"
|
||||
],
|
||||
"projectnode": "ejabberd@localhost",
|
||||
"cookie": "COOKIE",
|
||||
"timeout": 900,
|
||||
"cwd": "."
|
||||
},
|
||||
{
|
||||
"name": "Relive",
|
||||
"type": "erlang",
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
[ ! -f Makefile ] \
|
||||
&& ./autogen.sh \
|
||||
&& ./configure --with-rebar=./rebar3 \
|
||||
&& ./configure --with-rebar=rebar3 \
|
||||
&& make deps
|
||||
|
||||
make relive
|
||||
|
||||
@@ -1,3 +1,83 @@
|
||||
## Version 24.10
|
||||
|
||||
#### Miscelanea
|
||||
|
||||
- `ejabberd_c2s`: Optionally allow unencrypted SASL2
|
||||
- `ejabberd_system_monitor`: Handle call by `gen_event:swap_handler` ([#4233](https://github.com/processone/ejabberd/issues/4233))
|
||||
- `ejabberd_http_ws`: Remove support for old websocket connection protocol
|
||||
- `ejabberd_stun`: Omit `auth_realm` log message
|
||||
- `ext_mod`: Handle `info` message when contrib module transfers table ownership
|
||||
- `mod_block_strangers`: Add feature announcement to disco-info ([#4039](https://github.com/processone/ejabberd/issues/4039))
|
||||
- `mod_mam`: Advertise XEP-0424 feature in server disco-info ([#3340](https://github.com/processone/ejabberd/issues/3340))
|
||||
- `mod_muc_admin`: Better handling of malformed jids in `send_direct_invitation` command
|
||||
- `mod_muc_rtbl`: Fix call to `gen_server:stop` ([#4260](https://github.com/processone/ejabberd/issues/4260))
|
||||
- `mod_privilege`: Support "IQ permission" from XEP-0356 0.4.1 ([#3889](https://github.com/processone/ejabberd/issues/3889))
|
||||
- `mod_pubsub`: Don't blindly echo PEP notification
|
||||
- `mod_pubsub`: Skip non-delivery errors for local pubsub generated notifications
|
||||
- `mod_pubsub`: Fall back to default plugin options
|
||||
- `mod_pubsub`: Fix choice of node config defaults
|
||||
- `mod_pubsub`: Fix merging of default node options
|
||||
- `mod_pubsub`: Fix default node config parsing
|
||||
- `mod_register`: Support to block IPs in a vhost using `append_host_config` ([#4038](https://github.com/processone/ejabberd/issues/4038))
|
||||
- `mod_s2s_bidi`: Add support for S2S Bidirectional
|
||||
- `mod_scram_upgrade`: Add support for SCRAM upgrade tasks
|
||||
- `mod_vcard`: Return error stanza when storage doesn't support vcard update ([#4266](https://github.com/processone/ejabberd/issues/4266))
|
||||
- `mod_vcard`: Return explicit error stanza when user attempts to modify other's vcard
|
||||
- Minor improvements to support `mod_tombstones` (#2456)
|
||||
- Update `fast_xml` to use `use_maps` and remove obsolete elixir files
|
||||
- Update `fast_tls` and `xmpp` to improve s2s fallback for invalid direct tls connections
|
||||
- `make-binaries`: Bump dependency versions: Elixir 1.17.2, OpenSSL 3.3.2, ...
|
||||
|
||||
#### Administration
|
||||
- `ejabberdctl`: If `ERLANG_NODE` lacks host, add hostname ([#4288](https://github.com/processone/ejabberd/issues/4288))
|
||||
- `ejabberd_app`: At server start, log Erlang and Elixir versions
|
||||
- MySQL: Fix column type in the schema update of `archive` table in schema update
|
||||
|
||||
#### Commands API
|
||||
- `get_mam_count`: New command to get number of archived messages for an account
|
||||
- `set_presence`: Return error when session not found
|
||||
- `update`: Fix command output
|
||||
- Add `mam` and `offline` tags to the related purge commands
|
||||
|
||||
#### Code Quality
|
||||
- Fix warnings about unused macro definitions reported by Erlang LS
|
||||
- Fix Elvis report: Fix dollar space syntax
|
||||
- Fix Elvis report: Remove spaces in weird places
|
||||
- Fix Elvis report: Don't use ignored variables
|
||||
- Fix Elvis report: Remove trailing whitespace characters
|
||||
- Define the types of options that `opt_type.sh` cannot derive automatically
|
||||
- `ejabberd_http_ws`: Fix dialyzer warnings
|
||||
- `mod_matrix_gw`: Remove useless option `persist`
|
||||
- `mod_privilege`: Replace `try...catch` with a clean alternative
|
||||
|
||||
#### Development Help
|
||||
- `elvis.config`: Fix file syntax, set vim mode, disable many tests
|
||||
- `erlang_ls.config`: Let it find paths, update to Erlang 26, enable crossref
|
||||
- `hooks_deps`: Hide false-positive warnings about `gen_mod`
|
||||
- `Makefile`: Add support for `make elvis` when using rebar3
|
||||
- `.vscode/launch.json`: Experimental support for debugging with Neovim
|
||||
- CI: Add Elvis tests
|
||||
- CI: Add XMPP Interop tests
|
||||
- Runtime: Cache hex.pm archive from rebar3 and mix
|
||||
|
||||
#### Documentation
|
||||
- Add links in top-level options documentation to their Docs website sections
|
||||
- Document which SQL servers can really use `update_sql_schema`
|
||||
- Improve documentation of `ldap_servers` and `ldap_backups` options ([#3977](https://github.com/processone/ejabberd/issues/3977))
|
||||
- `mod_register`: Document behavior when `access` is set to `none` ([#4078](https://github.com/processone/ejabberd/issues/4078))
|
||||
|
||||
#### Elixir
|
||||
- Handle case when elixir support is enabled but not available
|
||||
- Start ExSync manually to ensure it's started if (and only if) Relive
|
||||
- `mix.exs`: Fix `mix release` error: `logger` being regular and included application ([#4265](https://github.com/processone/ejabberd/issues/4265))
|
||||
- `mix.exs`: Remove from `extra_applications` the apps already defined in `deps` ([#4265](https://github.com/processone/ejabberd/issues/4265))
|
||||
|
||||
#### WebAdmin
|
||||
- Add links in user page to offline and roster pages
|
||||
- Add new "MAM Archive" page to webadmin
|
||||
- Improve many pages to handle when modules are disabled
|
||||
- `mod_admin_extra`: Move some webadmin pages to their modules
|
||||
|
||||
## Version 24.07
|
||||
|
||||
#### Core
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
|
||||
[](https://github.com/processone/ejabberd/tags)
|
||||
[](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
|
||||
|
||||
[](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
|
||||
[](https://hub.docker.com/r/ejabberd/ecs/)
|
||||
|
||||
`ejabberd` Container Image
|
||||
==========================
|
||||
|
||||
@@ -642,6 +642,13 @@ dialyzer: erlang_plt deps_plt ejabberd_plt
|
||||
endif
|
||||
endif
|
||||
|
||||
#.
|
||||
#' elvis
|
||||
#
|
||||
|
||||
elvis:
|
||||
$(REBAR) lint
|
||||
|
||||
#.
|
||||
#' test
|
||||
#
|
||||
@@ -699,6 +706,7 @@ help:
|
||||
@echo " indent Indent source code using erlang-mode [emacs]"
|
||||
@echo ""
|
||||
@echo " dialyzer Run Dialyzer static analyzer"
|
||||
@echo " elvis Run Elvis source code style reviewer [rebar3]"
|
||||
@echo " hooks Run hooks validator"
|
||||
@echo " test Run Common Tests suite [rebar3]"
|
||||
@echo " test-eunit Run EUnit suite [rebar3]"
|
||||
|
||||
+1
-1
@@ -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.07` | 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 24.10` | 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)"
|
||||
|
||||
|
||||
+20
-2
@@ -566,6 +566,15 @@
|
||||
<xmpp:note>mod_carboncopy</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0288.html"/>
|
||||
<xmpp:version>1.0.1</xmpp:version>
|
||||
<xmpp:since>24.10</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_s2s_bidi</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0313.html"/>
|
||||
@@ -623,8 +632,8 @@
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0356.html"/>
|
||||
<xmpp:version>0.2.1</xmpp:version>
|
||||
<xmpp:since>16.09</xmpp:since>
|
||||
<xmpp:version>0.4.1</xmpp:version>
|
||||
<xmpp:since>24.10</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note>mod_privilege</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
@@ -791,6 +800,15 @@
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0480.html"/>
|
||||
<xmpp:version>0.1</xmpp:version>
|
||||
<xmpp:since>24.10</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_scram_upgrade</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0485.html"/>
|
||||
|
||||
@@ -227,6 +227,7 @@ modules:
|
||||
ip_access: trusted_network
|
||||
mod_roster:
|
||||
versioning: true
|
||||
mod_s2s_bidi: {}
|
||||
mod_s2s_dialback: {}
|
||||
mod_shared_roster: {}
|
||||
mod_stream_mgmt:
|
||||
|
||||
@@ -66,6 +66,7 @@ done
|
||||
# shellcheck source=ejabberdctl.cfg.example
|
||||
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
|
||||
[ -n "$ERLANG_NODE_ARG" ] && ERLANG_NODE="$ERLANG_NODE_ARG"
|
||||
[ "$ERLANG_NODE" = "${ERLANG_NODE%@*}" ] && ERLANG_NODE="$ERLANG_NODE@$(hostname -s)"
|
||||
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
|
||||
: "${SPOOL_DIR:="{{spool_dir}}"}"
|
||||
: "${EJABBERD_LOG_PATH:="$LOGS_DIR/ejabberd.log"}"
|
||||
|
||||
+37
-21
@@ -5,38 +5,54 @@
|
||||
{config,
|
||||
[#{dirs => ["src"],
|
||||
filter => "*.erl",
|
||||
ignore => ['ELDAPv3', eldap_filter_yecc],
|
||||
ruleset => erl_files,
|
||||
rules => [{elvis_style, line_length, #{limit => 100,
|
||||
skip_comments => false}},
|
||||
rules => [{elvis_text_style, line_length, #{limit => 1000, skip_comments => false}},
|
||||
{elvis_text_style, no_tabs, disable},
|
||||
{elvis_style, no_debug_call, disable},
|
||||
{elvis_style, operator_spaces, disable},
|
||||
{elvis_style, atom_naming_convention, disable},
|
||||
{elvis_style, consistent_variable_casing, disable},
|
||||
{elvis_style, dont_repeat_yourself, #{min_complexity => 70}},
|
||||
{elvis_style, export_used_types, disable},
|
||||
{elvis_style, function_naming_convention, disable},
|
||||
{elvis_style, god_modules, #{limit => 300}},
|
||||
{elvis_style, invalid_dynamic_call, disable},
|
||||
{elvis_style, variable_naming_convention, #{ regex => ".*" }},
|
||||
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
|
||||
]
|
||||
{elvis_style, macro_module_names, disable},
|
||||
{elvis_style, macro_names, disable},
|
||||
{elvis_style, max_function_arity, disable}, % #{max_arity => 15}},
|
||||
{elvis_style, nesting_level, disable},
|
||||
{elvis_style, no_author, disable},
|
||||
{elvis_style, no_catch_expressions, disable},
|
||||
{elvis_style, no_debug_call, disable},
|
||||
{elvis_style, no_if_expression, disable},
|
||||
{elvis_style, no_import, disable},
|
||||
{elvis_style, no_match_in_condition, disable},
|
||||
{elvis_style, no_nested_try_catch, disable},
|
||||
{elvis_style, no_single_clause_case, disable},
|
||||
{elvis_style, no_spec_with_records, disable},
|
||||
{elvis_style, no_throw, disable},
|
||||
{elvis_style, operator_spaces, disable},
|
||||
{elvis_style, param_pattern_matching, disable},
|
||||
{elvis_style, private_data_types, disable},
|
||||
{elvis_style, variable_naming_convention, disable}
|
||||
]
|
||||
},
|
||||
|
||||
%#{dirs => ["include"],
|
||||
% filter => "*.hrl",
|
||||
% ruleset => hrl_files},
|
||||
|
||||
#{dirs => ["."],
|
||||
filter => "Makefile.in",
|
||||
ruleset => makefiles,
|
||||
rules => [{elvis_style, line_length, #{limit => 100,
|
||||
rules => [{elvis_text_style, line_length, #{limit => 400,
|
||||
skip_comments => false}},
|
||||
{elvis_style, no_tabs, disable},
|
||||
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
|
||||
]
|
||||
},
|
||||
#{dirs => ["."],
|
||||
filter => "rebar.config",
|
||||
ruleset => rebar_config,
|
||||
rules => [{elvis_style, line_length, #{limit => 100,
|
||||
skip_comments => false}},
|
||||
{elvis_style, no_tabs, disable},
|
||||
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
|
||||
]
|
||||
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
].
|
||||
|
||||
%% vim: set filetype=erlang tabstop=8:
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
otp_path: "/usr/lib/erlang"
|
||||
plt_path: "_build/default/rebar3_24.3.3_plt"
|
||||
#otp_path: "/usr/lib/erlang"
|
||||
#plt_path: "_build/default/rebar3_24.3.3_plt"
|
||||
#code_reload:
|
||||
# node: ejabberd@localhost
|
||||
apps_dirs:
|
||||
@@ -14,12 +14,12 @@ macros:
|
||||
- name: DEPRECATED_GET_STACKTRACE
|
||||
- name: HAVE_ERL_ERROR
|
||||
- name: HAVE_URI_STRING
|
||||
- name: OTP_BELOW_25
|
||||
- name: OTP_BELOW_27
|
||||
- name: SIP
|
||||
- name: STUN
|
||||
diagnostics:
|
||||
# enabled:
|
||||
# - crossref
|
||||
enabled:
|
||||
- crossref
|
||||
disabled:
|
||||
# - dialyzer
|
||||
- unused_includes # Otherwise it complains about unused logger.hrl
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
allow_visitor_nickchange = true :: boolean(),
|
||||
public = true :: boolean(),
|
||||
public_list = true :: boolean(),
|
||||
persistent = false :: boolean(),
|
||||
persistent = false :: boolean() | {destroying, boolean()},
|
||||
moderated = true :: boolean(),
|
||||
captcha_protected = false :: boolean(),
|
||||
members_by_default = true :: boolean(),
|
||||
|
||||
+206
-59
@@ -2,12 +2,12 @@
|
||||
.\" Title: ejabberd.yml
|
||||
.\" Author: [see the "AUTHOR" section]
|
||||
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
|
||||
.\" Date: 07/18/2024
|
||||
.\" Date: 10/28/2024
|
||||
.\" Manual: \ \&
|
||||
.\" Source: \ \&
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "EJABBERD\&.YML" "5" "07/18/2024" "\ \&" "\ \&"
|
||||
.TH "EJABBERD\&.YML" "5" "10/28/2024" "\ \&" "\ \&"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@@ -82,12 +82,12 @@ 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\&.07/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/24\&.10/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\&.07\&. The options that changed in this version are marked with 🟤\&.
|
||||
This section describes top level options of ejabberd 24\&.10\&. The options that changed in this version are marked with 🟤\&.
|
||||
.PP
|
||||
\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLRules|ACLName}}\fR
|
||||
.RS 4
|
||||
@@ -138,7 +138,8 @@ access_rules:
|
||||
.PP
|
||||
\fBacl\fR: \fI{ACLName: {ACLType: ACLValue}}\fR
|
||||
.RS 4
|
||||
The option defines access control lists: named sets of rules which are used to match against different targets (such as a JID or an IP address)\&. Every set of rules has name
|
||||
This option defines
|
||||
\fI\&.\&./configuration/basic\&.md#acl|access control lists\fR: named sets of rules which are used to match against different targets (such as a JID or an IP address)\&. Every set of rules has name
|
||||
\fIACLName\fR: it can be any string except
|
||||
\fIall\fR
|
||||
or
|
||||
@@ -319,7 +320,9 @@ means that the same username can be taken multiple times in anonymous login mode
|
||||
.PP
|
||||
\fBanonymous_protocol\fR: \fIlogin_anon | sasl_anon | both\fR
|
||||
.RS 4
|
||||
Define what anonymous protocol will be used:
|
||||
Define what
|
||||
\fIauthentication\&.md#anonymous\-login\-and\-sasl\-anonymous|anonymous\fR
|
||||
protocol will be used:
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
@@ -368,11 +371,8 @@ Define the permissions for API access\&. Please consult the ejabberd Docs web
|
||||
.PP
|
||||
\fBappend_host_config\fR: \fI{Host: Options}\fR
|
||||
.RS 4
|
||||
To define specific ejabberd modules in a virtual host, you can define the global
|
||||
\fImodules\fR
|
||||
option with the common modules, and later add specific modules to certain virtual hosts\&. To accomplish that,
|
||||
\fIappend_host_config\fR
|
||||
option can be used\&.
|
||||
Add a few specific options to a certain
|
||||
\fI\&.\&./configuration/basic\&.md#virtual\-hosting|virtual host\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBauth_cache_life_time\fR: \fItimeout()\fR
|
||||
@@ -412,7 +412,9 @@ and certificate based authentication)\&. This helps with processing offline mess
|
||||
.PP
|
||||
\fBauth_method\fR: \fI[mnesia | sql | anonymous | external | jwt | ldap | pam, \&.\&.\&.]\fR
|
||||
.RS 4
|
||||
A list of authentication methods to use\&. If several methods are defined, authentication is considered successful as long as authentication of at least one of the methods succeeds\&. The default value is
|
||||
A list of
|
||||
\fIauthentication\&.md|authentication\fR
|
||||
methods to use\&. If several methods are defined, authentication is considered successful as long as authentication of at least one of the methods succeeds\&. The default value is
|
||||
\fI[mnesia]\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -682,7 +684,8 @@ A list of Erlang nodes to connect on ejabberd startup\&. This option is mostly i
|
||||
.PP
|
||||
\fBdefault_db\fR: \fImnesia | sql\fR
|
||||
.RS 4
|
||||
Default persistent storage for ejabberd\&. Modules and other components (e\&.g\&. authentication) may have its own value\&. The default value is
|
||||
\fIdatabase\&.md#default\-database|Default database\fR
|
||||
to store persistent data in ejabberd\&. Modules and other components (e\&.g\&. authentication) may have its own value\&. The default value is
|
||||
\fImnesia\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -694,7 +697,8 @@ Default volatile (in\-memory) storage for ejabberd\&. Modules and other componen
|
||||
.PP
|
||||
\fBdefine_macro\fR: \fI{MacroName: MacroValue}\fR
|
||||
.RS 4
|
||||
Defines a macro\&. The value can be any valid arbitrary YAML value\&. For convenience, it\(cqs recommended to define a
|
||||
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
|
||||
@@ -742,7 +746,9 @@ which enables this extension\&.
|
||||
.PP
|
||||
\fBdomain_balancing\fR: \fI{Domain: Options}\fR
|
||||
.RS 4
|
||||
An algorithm to load balance the components that are plugged on an ejabberd cluster\&. It means that you can plug one or several instances of the same component on each ejabberd node and that the traffic will be automatically distributed\&. The algorithm to deliver messages to the component(s) can be specified by this option\&. For any component connected as
|
||||
An algorithm to
|
||||
\fI\&.\&./guide/clustering\&.md#service\-load\-balancing|load\-balance\fR
|
||||
the components that are plugged on an ejabberd cluster\&. It means that you can plug one or several instances of the same component on each ejabberd node and that the traffic will be automatically distributed\&. The algorithm to deliver messages to the component(s) can be specified by this option\&. For any component connected as
|
||||
\fIDomain\fR, available
|
||||
\fIOptions\fR
|
||||
are:
|
||||
@@ -821,18 +827,22 @@ Define the base URI when performing ReST requests\&. The default value is:
|
||||
.PP
|
||||
\fBextauth_pool_name\fR: \fIName\fR
|
||||
.RS 4
|
||||
Define the pool name appendix, so the full pool name will be
|
||||
Define the pool name appendix in
|
||||
\fIauthentication\&.md#external\-script|external auth\fR, so the full pool name will be
|
||||
\fIextauth_pool_Name\fR\&. The default value is the hostname\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBextauth_pool_size\fR: \fISize\fR
|
||||
.RS 4
|
||||
The option defines the number of instances of the same external program to start for better load balancing\&. The default is the number of available CPU cores\&.
|
||||
The option defines the number of instances of the same
|
||||
\fIauthentication\&.md#external\-script|external auth\fR
|
||||
program to start for better load balancing\&. The default is the number of available CPU cores\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBextauth_program\fR: \fIPath\fR
|
||||
.RS 4
|
||||
Indicate in this option the full path to the external authentication script\&. The script must be executable by ejabberd\&.
|
||||
Indicate in this option the full path to the
|
||||
\fIauthentication\&.md#external\-script|external authentication script\fR\&. The script must be executable by ejabberd\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBfqdn\fR: \fIDomain\fR
|
||||
@@ -851,7 +861,8 @@ for backward compatibility\&.
|
||||
.RS 4
|
||||
The option is used to redefine
|
||||
\fIOptions\fR
|
||||
for virtual host
|
||||
for
|
||||
\fI\&.\&./configuration/basic\&.md#virtual\-hosting|virtual host\fR
|
||||
\fIHost\fR\&. In the example below LDAP authentication method will be used on virtual host
|
||||
\fIdomain\&.tld\fR
|
||||
and SQL method will be used on virtual host
|
||||
@@ -882,7 +893,9 @@ host_config:
|
||||
.PP
|
||||
\fBhosts\fR: \fI[Domain1, Domain2, \&.\&.\&.]\fR
|
||||
.RS 4
|
||||
The option defines a list containing one or more domains that
|
||||
List of one or more
|
||||
\fI\&.\&./configuration/basic\&.md#host\-names|host names\fR
|
||||
(or domains) that
|
||||
\fIejabberd\fR
|
||||
will serve\&. This is a
|
||||
\fBmandatory\fR
|
||||
@@ -891,7 +904,9 @@ option\&.
|
||||
.PP
|
||||
\fBinclude_config_file\fR: \fI[Filename, \&.\&.\&.] | {Filename: Options}\fR
|
||||
.RS 4
|
||||
Read additional configuration from
|
||||
Read and
|
||||
\fI\&.\&./configuration/file\-format\&.md#include\-additional\-files|include additional file\fR
|
||||
from
|
||||
\fIFilename\fR\&. If the value is provided in
|
||||
\fI{Filename: Options}\fR
|
||||
format, the
|
||||
@@ -922,7 +937,9 @@ at start time\&. The default value is an empty list of modules:
|
||||
.PP
|
||||
\fBjwt_auth_only_rule\fR: \fIAccessName\fR
|
||||
.RS 4
|
||||
This ACL rule defines accounts that can use only this auth method, even if others are also defined in the ejabberd configuration file\&. In other words: if there are several auth methods enabled for this host (JWT, SQL, \&...), users that match this rule can only use JWT\&. The default value is
|
||||
This ACL rule defines accounts that can use only the
|
||||
\fIauthentication\&.md#jwt\-authentication|JWT\fR
|
||||
auth method, even if others are also defined in the ejabberd configuration file\&. In other words: if there are several auth methods enabled for this host (JWT, SQL, \&...), users that match this rule can only use JWT\&. The default value is
|
||||
\fInone\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -930,18 +947,24 @@ This ACL rule defines accounts that can use only this auth method, even if other
|
||||
.RS 4
|
||||
By default, the JID is defined in the
|
||||
\fI"jid"\fR
|
||||
JWT field\&. In this option you can specify other JWT field name where the JID is defined\&.
|
||||
JWT field\&. In this option you can specify other
|
||||
\fIauthentication\&.md#jwt\-authentication|JWT\fR
|
||||
field name where the JID is defined\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBjwt_key\fR: \fIFilePath\fR
|
||||
.RS 4
|
||||
Path to the file that contains the JWK Key\&. The default value is
|
||||
Path to the file that contains the
|
||||
\fIauthentication\&.md#jwt\-authentication|JWT\fR
|
||||
key\&. The default value is
|
||||
\fIundefined\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBlanguage\fR: \fILanguage\fR
|
||||
.RS 4
|
||||
The option defines the default language of server strings that can be seen by XMPP clients\&. If an XMPP client does not possess
|
||||
Define the
|
||||
\fI\&.\&./configuration/basic\&.md#default\-language|default language\fR
|
||||
of server strings that can be seen by XMPP clients\&. If an XMPP client does not possess
|
||||
\fIxml:lang\fR
|
||||
attribute, the specified language is used\&. The default value is
|
||||
\fI"en"\fR\&.
|
||||
@@ -949,9 +972,10 @@ attribute, the specified language is used\&. The default value is
|
||||
.PP
|
||||
\fBldap_backups\fR: \fI[Host, \&.\&.\&.]\fR
|
||||
.RS 4
|
||||
A list of IP addresses or DNS names of LDAP backup servers\&. When no servers listed in
|
||||
A list of IP addresses or DNS names of LDAP backup servers (see
|
||||
\fI\&.\&./configuration/ldap\&.md#ldap\-connection|LDAP connection\fR)\&. When no servers listed in
|
||||
\fIldap_servers\fR
|
||||
option are reachable, ejabberd will try to connect to these backup servers\&. The default is an empty list, i\&.e\&. no backup servers specified\&. WARNING: ejabberd doesn\(cqt try to reconnect back to the main servers when they become operational again, so the only way to restore these connections is to restart ejabberd\&. This limitation might be fixed in future releases\&.
|
||||
option are reachable, ejabberd connects to these backup servers\&. The default is an empty list, i\&.e\&. no backup servers specified\&. Please notice that ejabberd only connects to the next server when the existing connection is lost; it doesn\(cqt detect when a previously\-attempted server becomes available again\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBldap_base\fR: \fIBase\fR
|
||||
@@ -1022,7 +1046,8 @@ Bind Distinguished Name\&. The default value is an empty string, which means "an
|
||||
.PP
|
||||
\fBldap_servers\fR: \fI[Host, \&.\&.\&.]\fR
|
||||
.RS 4
|
||||
A list of IP addresses or DNS names of your LDAP servers\&. The default value is
|
||||
A list of IP addresses or DNS names of your LDAP servers (see
|
||||
\fI\&.\&./configuration/ldap\&.md#ldap\-connection|LDAP connection\fR)\&. ejabberd connects immediately to all of them, and reconnects infinitely if connection is lost\&. The default value is
|
||||
\fI[localhost]\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -1114,7 +1139,8 @@ The size (in bytes) of a log file to trigger rotation\&. If set to
|
||||
.PP
|
||||
\fBloglevel\fR: \fInone | emergency | alert | critical | error | warning | notice | info | debug\fR
|
||||
.RS 4
|
||||
Verbosity of log files generated by ejabberd\&. The default value is
|
||||
Verbosity of ejabberd
|
||||
\fI\&.\&./configuration/basic\&.md#logging|logging\fR\&. The default value is
|
||||
\fIinfo\fR\&. NOTE: previous versions of ejabberd had log levels defined in numeric format (\fI0\&.\&.5\fR)\&. The numeric values are still accepted for backward compatibility, but are not recommended\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -1126,9 +1152,9 @@ This option specifies the maximum number of elements in the queue of the FSM (Fi
|
||||
.PP
|
||||
\fBmodules\fR: \fI{Module: Options}\fR
|
||||
.RS 4
|
||||
The option for modules configuration\&. See
|
||||
\fImodules\&.md|Modules\fR
|
||||
section for details\&.
|
||||
Set all the
|
||||
\fImodules\&.md|modules\fR
|
||||
configuration options\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBnegotiation_timeout\fR: \fItimeout()\fR
|
||||
@@ -1147,10 +1173,9 @@ This option can be used to tune tick time parameter of
|
||||
.PP
|
||||
\fBnew_sql_schema\fR: \fItrue | false\fR
|
||||
.RS 4
|
||||
Whether to use
|
||||
\fInew\fR
|
||||
SQL schema\&. All schemas are located at
|
||||
https://github\&.com/processone/ejabberd/tree/24\&.07/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The
|
||||
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\&.10/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
|
||||
@@ -1296,13 +1321,17 @@ seconds\&.
|
||||
.PP
|
||||
\fBpam_service\fR: \fIName\fR
|
||||
.RS 4
|
||||
This option defines the PAM service name\&. Refer to the PAM documentation of your operation system for more information\&. The default value is
|
||||
This option defines the
|
||||
\fIauthentication\&.md#pam\-authentication|PAM\fR
|
||||
service name\&. Refer to the PAM documentation of your operation system for more information\&. The default value is
|
||||
\fIejabberd\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBpam_userinfotype\fR: \fIusername | jid\fR
|
||||
.RS 4
|
||||
This option defines what type of information about the user ejabberd provides to the PAM service: only the username, or the user\(cqs JID\&. Default is
|
||||
This option defines what type of information about the user ejabberd provides to the
|
||||
\fIauthentication\&.md#pam\-authentication|PAM\fR
|
||||
service: only the username, or the user\(cqs JID\&. Default is
|
||||
\fIusername\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -1336,36 +1365,47 @@ option where file queues will be placed\&. The default value is
|
||||
.PP
|
||||
\fBredis_connect_timeout\fR: \fItimeout()\fR
|
||||
.RS 4
|
||||
A timeout to wait for the connection to be re\-established to the Redis server\&. The default is
|
||||
A timeout to wait for the connection to be re\-established to the
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
server\&. The default is
|
||||
\fI1 second\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBredis_db\fR: \fINumber\fR
|
||||
.RS 4
|
||||
Redis database number\&. The default is
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
database number\&. The default is
|
||||
\fI0\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBredis_password\fR: \fIPassword\fR
|
||||
.RS 4
|
||||
The password to the Redis server\&. The default is an empty string, i\&.e\&. no password\&.
|
||||
The password to the
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
server\&. The default is an empty string, i\&.e\&. no password\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBredis_pool_size\fR: \fINumber\fR
|
||||
.RS 4
|
||||
The number of simultaneous connections to the Redis server\&. The default value is
|
||||
The number of simultaneous connections to the
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
server\&. The default value is
|
||||
\fI10\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBredis_port\fR: \fI1\&.\&.65535\fR
|
||||
.RS 4
|
||||
The port where the Redis server is accepting connections\&. The default is
|
||||
The port where the
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
server is accepting connections\&. The default is
|
||||
\fI6379\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBredis_queue_type\fR: \fIram | file\fR
|
||||
.RS 4
|
||||
The type of request queue for the Redis server\&. See description of
|
||||
The type of request queue for the
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
server\&. See description of
|
||||
\fIqueue_type\fR
|
||||
option for the explanation\&. The default value is the value defined in
|
||||
\fIqueue_type\fR
|
||||
@@ -1376,7 +1416,9 @@ if the latter is not set\&.
|
||||
.PP
|
||||
\fBredis_server\fR: \fIHostname\fR
|
||||
.RS 4
|
||||
A hostname or an IP address of the Redis server\&. The default is
|
||||
A hostname or an IP address of the
|
||||
\fIdatabase\&.md#redis|Redis\fR
|
||||
server\&.The default is
|
||||
\fIlocalhost\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
@@ -1579,7 +1621,8 @@ XEP\-0138) or not\&. The default value is
|
||||
.PP
|
||||
\fBshaper\fR: \fI{ShaperName: Rate}\fR
|
||||
.RS 4
|
||||
The option defines a set of shapers\&. Every shaper is assigned a name
|
||||
The option defines a set of
|
||||
\fI\&.\&./configuration/basic\&.md#shapers|shapers\fR\&. Every shaper is assigned a name
|
||||
\fIShaperName\fR
|
||||
that can be used in other parts of the configuration file, such as
|
||||
\fIshaper_rules\fR
|
||||
@@ -1611,7 +1654,9 @@ shaper:
|
||||
.PP
|
||||
\fBshaper_rules\fR: \fI{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}\fR
|
||||
.RS 4
|
||||
An entry allowing to declaring shaper to use for matching user/hosts\&. Semantics is similar to
|
||||
This option defines
|
||||
\fI\&.\&./configuration/basic\&.md#shaper\-rules|shaper rules\fR
|
||||
to use for matching user/hosts\&. Semantics is similar to
|
||||
\fIaccess_rules\fR
|
||||
option, the only difference is that instead using
|
||||
\fIallow\fR
|
||||
@@ -1858,11 +1903,11 @@ header if you enable this option as, otherwise, the client can set it itself and
|
||||
\fBupdate_sql_schema\fR: \fItrue | false\fR
|
||||
.RS 4
|
||||
\fINote\fR
|
||||
about this option: updated in 24\&.06\&. Allow ejabberd to update SQL schema\&. This option was added in ejabberd 23\&.10, and enabled by default since 24\&.06\&. The default value is
|
||||
about this option: updated in 24\&.06\&. Allow ejabberd to update SQL schema in MySQL, PostgreSQL and SQLite databases\&. This option was added in ejabberd 23\&.10, and enabled by default since 24\&.06\&. The default value is
|
||||
\fItrue\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBupdate_sql_schema_timeout 🟤\fR: \fItimeout()\fR
|
||||
\fBupdate_sql_schema_timeout\fR: \fItimeout()\fR
|
||||
.RS 4
|
||||
\fINote\fR
|
||||
about this option: added in 24\&.07\&. Time allocated to SQL schema update queries\&. The default value is set to 5 minutes\&.
|
||||
@@ -1919,12 +1964,7 @@ seconds\&.
|
||||
.RE
|
||||
.SH "MODULES"
|
||||
.sp
|
||||
This section describes modules options of ejabberd 24\&.07\&. The modules that changed in this version are marked with 🟤\&.
|
||||
.SS "Elixir\&.ModPresenceDemo"
|
||||
.sp
|
||||
This is just a demonstration\&.
|
||||
.sp
|
||||
The module has no options\&.
|
||||
This section describes modules options of ejabberd 24\&.10\&. 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\&.
|
||||
@@ -5367,6 +5407,8 @@ option, but applied to this module only\&.
|
||||
.RE
|
||||
.SS "mod_privilege"
|
||||
.sp
|
||||
\fINote\fR about this option: improved in 24\&.10\&.
|
||||
.sp
|
||||
This module is an implementation of XEP\-0356: Privileged Entity\&. This extension allows components to have privileged access to other entity data (send messages on behalf of the server or on behalf of a user, get/set user roster, access presence information, etc\&.)\&. This may be used to write powerful external components, for example implementing an external PEP or MAM service\&.
|
||||
.sp
|
||||
By default a component does not have any privileged access\&. It is worth noting that the permissions grant access to the component to a specific data type for all users of the virtual host on which \fImod_privilege\fR is loaded\&.
|
||||
@@ -5413,6 +5455,36 @@ This module is complementary to \fImod_delegation\fR, but can also be used separ
|
||||
\fBAvailable options:\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fBiq\fR: \fI{Namespace: Options}\fR
|
||||
.RS 4
|
||||
This option defines namespaces and their IQ permissions\&. By default no permissions are given\&. The
|
||||
\fIOptions\fR
|
||||
are:
|
||||
.PP
|
||||
\fBboth\fR: \fIAccessName\fR
|
||||
.RS 4
|
||||
Allows sending IQ stanzas of type
|
||||
\fIget\fR
|
||||
and
|
||||
\fIset\fR\&. The default value is
|
||||
\fInone\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBget\fR: \fIAccessName\fR
|
||||
.RS 4
|
||||
Allows sending IQ stanzas of type
|
||||
\fIget\fR\&. The default value is
|
||||
\fInone\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBset\fR: \fIAccessName\fR
|
||||
.RS 4
|
||||
Allows sending IQ stanzas of type
|
||||
\fIset\fR\&. The default value is
|
||||
\fInone\fR\&.
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
\fBmessage\fR: \fIOptions\fR
|
||||
.RS 4
|
||||
This option defines permissions for messages\&. By default no permissions are given\&. The
|
||||
@@ -5485,6 +5557,9 @@ Sets write access to a user\(cqs roster\&. The default value is
|
||||
.nf
|
||||
modules:
|
||||
mod_privilege:
|
||||
iq:
|
||||
http://jabber\&.org/protocol/pubsub:
|
||||
get: all
|
||||
roster:
|
||||
get: all
|
||||
presence:
|
||||
@@ -6120,7 +6195,10 @@ This module reads also the top\-level \fIregistration_timeout\fR option defined
|
||||
.RS 4
|
||||
Specify rules to restrict what usernames can be registered\&. If a rule returns
|
||||
\fIdeny\fR
|
||||
on the requested username, registration of that user name is denied\&. There are no restrictions by default\&.
|
||||
on the requested username, registration of that user name is denied\&. There are no restrictions by default\&. If
|
||||
\fIAccessName\fR
|
||||
is
|
||||
\fInone\fR, then registering new accounts using In\-Band Registration is disabled and the corresponding stream feature is not announced to clients\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBaccess_from\fR: \fIAccessName\fR
|
||||
@@ -6376,6 +6454,33 @@ modules:
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_s2s_bidi"
|
||||
.sp
|
||||
\fINote\fR about this option: added in 24\&.10\&.
|
||||
.sp
|
||||
The module adds support for XEP\-0288: Bidirectional Server\-to\-Server Connections that allows using single s2s connection to communicate in both directions\&.
|
||||
.sp
|
||||
The module has no options\&.
|
||||
.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
|
||||
modules:
|
||||
mod_s2s_bidi: {}
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_s2s_dialback"
|
||||
.sp
|
||||
The module adds support for XEP\-0220: Server Dialback to provide server identity verification based on DNS\&.
|
||||
@@ -6435,6 +6540,48 @@ modules:
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_scram_upgrade"
|
||||
.sp
|
||||
\fINote\fR about this option: added in 24\&.10\&.
|
||||
.sp
|
||||
The module adds support for XEP\-0480: SASL Upgrade Tasks that allows users to upgrade passwords to more secure representation\&.
|
||||
.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
|
||||
\fBoffered_upgrades\fR: \fIlist(sha256, sha512)\fR
|
||||
.RS 4
|
||||
List with upgrade types that should be offered
|
||||
.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
|
||||
modules:
|
||||
mod_scram_upgrade:
|
||||
offered_upgrades:
|
||||
\- sha256
|
||||
\- sha512
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_service_log"
|
||||
.sp
|
||||
This module forwards copies of all stanzas to remote XMPP servers or components\&. Every stanza is encapsulated into <forwarded/> element as described in XEP\-0297: Stanza Forwarding\&.
|
||||
@@ -7833,7 +7980,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\&.07\&.
|
||||
This section describes listeners options of ejabberd 24\&.10\&.
|
||||
.sp
|
||||
TODO
|
||||
.SH "AUTHOR"
|
||||
@@ -7841,13 +7988,13 @@ TODO
|
||||
ProcessOne\&.
|
||||
.SH "VERSION"
|
||||
.sp
|
||||
This document describes the configuration file of ejabberd 24\&.07\&. Configuration options of other ejabberd versions may differ significantly\&.
|
||||
This document describes the configuration file of ejabberd 24\&.10\&. 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\&.07/ejabberd\&.yml\&.example
|
||||
Default configuration file: https://github\&.com/processone/ejabberd/blob/24\&.10/ejabberd\&.yml\&.example
|
||||
.sp
|
||||
Main site: https://ejabberd\&.im
|
||||
.sp
|
||||
|
||||
@@ -43,11 +43,10 @@ defmodule Ejabberd.MixProject do
|
||||
|
||||
def application do
|
||||
[mod: {:ejabberd_app, []},
|
||||
applications: [:idna, :inets, :kernel, :sasl, :ssl, :stdlib, :mix,
|
||||
:fast_tls, :fast_xml, :fast_yaml, :jose,
|
||||
:p1_utils, :stringprep, :syntax_tools, :yconf, :xmpp]
|
||||
extra_applications: [:inets, :kernel, :sasl, :ssl, :stdlib, :syntax_tools,
|
||||
:logger, :mix]
|
||||
++ cond_apps(),
|
||||
included_applications: [:mnesia, :os_mon, :logger,
|
||||
included_applications: [:mnesia, :os_mon,
|
||||
:cache_tab, :eimp, :mqtree, :p1_acme,
|
||||
:p1_oauth2, :pkix]
|
||||
++ cond_included_apps()]
|
||||
@@ -135,8 +134,8 @@ defmodule Ejabberd.MixProject do
|
||||
{:dialyxir, "~> 1.2", only: [:test], runtime: false},
|
||||
{:eimp, "~> 1.0"},
|
||||
{:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false},
|
||||
{:fast_tls, ">= 1.1.18"},
|
||||
{:fast_xml, ">= 1.1.51"},
|
||||
{:fast_tls, "~> 1.1.22"},
|
||||
{:fast_xml, "~> 1.1.53"},
|
||||
{:fast_yaml, "~> 1.0"},
|
||||
{:idna, "~> 6.0"},
|
||||
{:mqtree, "~> 1.0"},
|
||||
@@ -145,7 +144,7 @@ defmodule Ejabberd.MixProject do
|
||||
{:p1_utils, "~> 1.0"},
|
||||
{:pkix, "~> 1.0"},
|
||||
{:stringprep, ">= 1.0.26"},
|
||||
{:xmpp, ">= 1.8.3"},
|
||||
{:xmpp, "~> 1.9"},
|
||||
{:yconf, "~> 1.0"}]
|
||||
++ cond_deps()
|
||||
end
|
||||
@@ -166,7 +165,7 @@ defmodule Ejabberd.MixProject do
|
||||
{Mix.env() == :translations,
|
||||
{:ejabberd_po, git: "https://github.com/processone/ejabberd-po.git"}},
|
||||
{Mix.env() == :dev,
|
||||
{:exsync, "~> 0.2"}},
|
||||
{:exsync, "~> 0.2", optional: true, runtime: false}},
|
||||
{config(:redis), {:eredis, "~> 1.2.0"}},
|
||||
{config(:sip), {:esip, "~> 1.0"}},
|
||||
{config(:zlib), {:ezlib, "~> 1.0"}},
|
||||
@@ -184,7 +183,6 @@ defmodule Ejabberd.MixProject do
|
||||
|
||||
defp cond_apps do
|
||||
for {:true, app} <- [{config(:stun), :stun},
|
||||
{Map.has_key?(System.get_env(), "RELIVE"), :exsync},
|
||||
{if_version_below(~c"27", true), :jiffy},
|
||||
{config(:tools), :observer}], do:
|
||||
app
|
||||
|
||||
@@ -1,40 +1,37 @@
|
||||
%{
|
||||
"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.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
|
||||
"dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
|
||||
"eimp": {:hex, :eimp, "1.0.23", "aaf32efab061143403dadbaa63e699ef8e81702fbfa96fd436d5e9be4d6a8d3a", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "907c780023cb2893e4fc4bdbe6a4f02c355913862ac67f0ecc26605e816b628a"},
|
||||
"ejabberd_po": {:git, "https://github.com/processone/ejabberd-po.git", "6ef974cbc28e1a52d7a35fd4d9081d175d0ac10d", []},
|
||||
"epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"},
|
||||
"eredis": {:hex, :eredis, "1.2.0", "0b8e9cfc2c00fa1374cd107ea63b49be08d933df2cf175e6a89b73dd9c380de4", [:rebar3], [], "hexpm", "d9b5abef2c2c8aba8f32aa018203e0b3dc8b1157773b254ab1d4c2002317f1e1"},
|
||||
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
|
||||
"esip": {:hex, :esip, "1.0.54", "dae8fb8278fd3b2c0d38c2e832c4b8d26700eb239b9a42c8ea574fee76f5e76a", [:rebar3], [{:fast_tls, "1.1.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.14", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "8187af819d7259cdaddaf69726c239ef604c9b0b0298a5f2d3e687bf5e2237ee"},
|
||||
"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.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [: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", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
|
||||
"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.21", "65d7d547a09eefb37a1c0d04d8601fac4f3e6e2c1ede859a7787081670f9648d", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "131542913937025e48cd80aa81f00359686d5501b75621e72026a87b5229505b"},
|
||||
"fast_xml": {:hex, :fast_xml, "1.1.52", "0289daafbf1190b0e53b444d4885cccf41e4b05768d4b3acc76dd8d143668e10", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "795192390e06d2b65016a6990bbfa5727f4a26d2914808b1c3c9a32eedcd1bfd"},
|
||||
"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.53", "1ef4f6e5995bcfa94800a46b460c3400c19c0a533948b12200a2e2fb1a2be427", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "5064336d6f363eee5097aa5dc5ced9b67f05152f2e6b8520fd50d268c2ab839c"},
|
||||
"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.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
|
||||
"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"},
|
||||
"luerl": {:hex, :luerl, "1.2.0", "60f05f4240f0e7c148ddb79b67b8ff972734aad237aa74c83d0748b8214c8ef0", [:rebar3], [], "hexpm", "9cafd4f6094ff0f5a9d278fd81d60d3e026c820bdfb6cacd4b1bd909f21b525d"},
|
||||
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [: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", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
|
||||
"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"},
|
||||
"p1_acme": {:hex, :p1_acme, "1.0.23", "791aef0f79dc7f768b228808250c349fa9ce585cd8779da50ca93106eb3394d0", [: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.15", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "8ce196f26e3d22ea10b7809122950465878c127f80767e325207aed7e8d0dd59"},
|
||||
"p1_mysql": {:hex, :p1_mysql, "1.0.24", "0ed1e098c5a4525032448c65a2715f30980aae725615a4d255fd25f26bb22507", [:rebar3], [], "hexpm", "f058865f64257f507a2c6a5aff369b1375dbcb30b3d4258dad4f1b3eaffb655f"},
|
||||
"p1_acme": {:hex, :p1_acme, "1.0.24", "e19876618eb0be22815aca99640cb88cd5c86e4239b8e8dc15b4e5d7854ef7e2", [: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.15", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "f1451d706595ef997ab1ca17162ddac58f874ac97e315a5fadbe3cfa26148002"},
|
||||
"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.27", "883e335d82ac062de0bde7981f8250a2e632258bb7a47df839a4cbdcb3e971e6", [:rebar3], [{:xmpp, "~> 1.8.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "8e4d1a7602cb68780e55d89dc5a9b2e1aaca3f4f1ee3d1a25f2f8c3d2364ffb9"},
|
||||
"p1_pgsql": {:hex, :p1_pgsql, "1.1.28", "08eca7d2afc81ba6d757b572f4a57ef3a2383b0c7b785fde38184bc368376d54", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "655bb75df036ace55ddce17ca741143c42e0667c6206ac27a4dcbc65f71ac9ef"},
|
||||
"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"},
|
||||
"stun": {:hex, :stun, "1.2.14", "6f538ac80c842131dbd149055570d116bfabc9b5ebff4bd6af2e7888958c660c", [:rebar3], [{:fast_tls, "1.1.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e134807b1b7a8dffd94e64eefee00e65c7b4042f3d14e16f8f43566d20371583"},
|
||||
"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.8.3", "acf39a8b70b066bb8f10b0862e031e8abcf92fe89d1c41d06c1e39ae5caf89c4", [: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", "ed70065f9a89a818dcff43b74c080c9e7f4f1414e1051beddb7280db809af711"},
|
||||
"xmpp": {:hex, :xmpp, "1.9.0", "d92446bf51d36adda02db63b963fe6d4a1ede33e59b38a43d9b90afd20c25b74", [: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", "c1b91be74a9a9503afa6766f756477516920ffbfeea0c260c2fa171355f53c27"},
|
||||
"yconf": {:hex, :yconf, "1.0.16", "d59521d66ff89f219411b6e9277cd6feec7cc6fce11554e67de02a8d0a470479", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "e947813273f38711c7b2e5a8e4acc9a51c7bbe854f744a345f60300b38586c89"},
|
||||
}
|
||||
|
||||
@@ -111,6 +111,11 @@
|
||||
{"Dynamically specify a replyto of the item publisher","Динамично задаване на отговор към публикувалия елемента"}.
|
||||
{"Edit Properties","Редактиране на свойства"}.
|
||||
{"Either approve or decline the voice request.","Одобрете или отхвърлете заявката за гласова връзка."}.
|
||||
{"ejabberd HTTP Upload service","ejabberd HTTP Upload услуга"}.
|
||||
{"ejabberd MUC module","ejabberd MUC модул"}.
|
||||
{"ejabberd Multicast service","ejabberd Multicast услуга"}.
|
||||
{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe модул"}.
|
||||
{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams модул"}.
|
||||
{"ejabberd vCard module","ejabberd vCard модул"}.
|
||||
{"ejabberd Web Admin","Уеб администрация на ejabberd"}.
|
||||
{"ejabberd","ejabberd"}.
|
||||
@@ -158,6 +163,12 @@
|
||||
{"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 аватар на тази стая"}.
|
||||
{"Hat title","Заглавие на шапката"}.
|
||||
{"Hat URI","URI адрес за шапка"}.
|
||||
{"Hats limit exceeded","Превишен е лимитът за шапка"}.
|
||||
@@ -190,6 +201,7 @@
|
||||
{"Invalid 'previd' value","Невалидна стойност на 'previd'"}.
|
||||
{"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 private messages of type \"groupchat\"","Изпращането на лични съобщения от тип \"групов чат\" не е разрешено"}.
|
||||
{"It is not allowed to send private messages to the conference","Изпращането на лични съобщения до конференцията не е разрешено"}.
|
||||
@@ -199,6 +211,7 @@
|
||||
{"JID normalization failed","Нормализирането на JID е неуспешно"}.
|
||||
{"Joined MIX channels of ~ts","Свързани MIX канали на ~ts"}.
|
||||
{"Joined MIX channels:","Свързани MIX канали:"}.
|
||||
{"joins the room","се присъединява към стаята"}.
|
||||
{"July","Юли"}.
|
||||
{"June","Юни"}.
|
||||
{"Just created","Току що създаден"}.
|
||||
@@ -208,8 +221,10 @@
|
||||
{"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","Защити стаята с CAPTCHA"}.
|
||||
@@ -360,6 +375,7 @@
|
||||
{"Previous session PID has exited","Предишният PID на сесията е излязъл"}.
|
||||
{"Previous session PID is dead","PID от предишната сесия не съществува"}.
|
||||
{"Previous session timed out","Времето на предишната сесия изтече"}.
|
||||
{"private, ","частна, "}.
|
||||
{"Public","Публичен"}.
|
||||
{"Publish model","Модел за публикуване"}.
|
||||
{"Publish-Subscribe","Публикуване-Абониране"}.
|
||||
@@ -423,6 +439,7 @@
|
||||
{"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 байтови потоци"}.
|
||||
@@ -482,6 +499,7 @@
|
||||
{"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","Паролите са различни"}.
|
||||
@@ -555,6 +573,7 @@
|
||||
{"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","Посетителите нямат право да променят псевдонимите си в тази стая"}.
|
||||
@@ -584,6 +603,7 @@
|
||||
{"XMPP Show Value of Chat","XMPP покажи стойност на Чат"}.
|
||||
{"XMPP Show Value of DND (Do Not Disturb)","XMPP покажи стойност на DND (Не ме безпокой)"}.
|
||||
{"XMPP Show Value of XA (Extended Away)","XMPP покажи стойност на Продължително отсъствие"}.
|
||||
{"XMPP URI of Associated Publish-Subscribe Node","XMPP URI на асоцииран Publish-Subscribe нод"}.
|
||||
{"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","Не сте присъединени към канала"}.
|
||||
@@ -594,6 +614,9 @@
|
||||
{"You need a client that supports x:data and CAPTCHA to register","За да се регистрирате Ви е нужен клиент, който поддържа x:data и CAPTCHA"}.
|
||||
{"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 XMPP account was successfully registered.","Вашият XMPP акаунт, беше регистриран успешно."}.
|
||||
{"Your XMPP account was successfully unregistered.","Вашият XMPP акаунт, беше успешно дерегистриран."}.
|
||||
{"You're not allowed to create nodes","Нямате право да създавате нодове"}.
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
{"has been kicked because of an affiliation change","ha sigut expulsat a causa d'un canvi d'afiliació"}.
|
||||
{"has been kicked because the room has been changed to members-only","ha sigut expulsat perquè la sala ara és només per a membres"}.
|
||||
{"has been kicked","ha sigut expulsat"}.
|
||||
{"Hash of the vCard-temp avatar of this room","Hash del avatar a vCard-temp d'esta sala"}.
|
||||
{"Hat title","Títol del barret"}.
|
||||
{"Hat URI","URI del barret"}.
|
||||
{"Hats limit exceeded","El límit de tràfic ha sigut sobrepassat"}.
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
{"has been kicked because of an affiliation change","ha sido expulsado por un cambio de su afiliación"}.
|
||||
{"has been kicked because the room has been changed to members-only","ha sido expulsado porque la sala es ahora solo para miembros"}.
|
||||
{"has been kicked","ha sido expulsado"}.
|
||||
{"Hash of the vCard-temp avatar of this room","Hash del avatar vCard-temp de esta sala"}.
|
||||
{"Hat title","Título del sombrero"}.
|
||||
{"Hat URI","Dirección del sombrero"}.
|
||||
{"Hats limit exceeded","Se ha excedido el límite de sombreros"}.
|
||||
|
||||
+4
-4
@@ -9,19 +9,19 @@
|
||||
{"A description of the node","Una descrizione del nodo"}.
|
||||
{"A friendly name for the node","Un nome comodo per il nodo"}.
|
||||
{"A password is required to enter this room","Per entrare in questa stanza è necessaria una password"}.
|
||||
{"A Web Page","Un Pagina Web"}.
|
||||
{"A Web Page","Una pagina web"}.
|
||||
{"Accept","Accettare"}.
|
||||
{"Access denied by service policy","Accesso impedito dalle politiche del servizio"}.
|
||||
{"Access denied by service policy","Accesso negato dalle politiche del servizio"}.
|
||||
{"Access model","Modello di accesso"}.
|
||||
{"Account doesn't exist","L'account non esiste"}.
|
||||
{"Action on user","Azione sull'utente"}.
|
||||
{"Add a hat to a user","Aggiungere un cappello a un utente"}.
|
||||
{"Add User","Aggiungere un Utente"}.
|
||||
{"Add User","Aggiungere un utente"}.
|
||||
{"Administration of ","Amministrazione di "}.
|
||||
{"Administration","Amministrazione"}.
|
||||
{"Administrator privileges required","Sono richiesti privilegi di amministratore"}.
|
||||
{"All activity","Tutta l'attività"}.
|
||||
{"All Users","Tutti gli Utenti"}.
|
||||
{"All Users","Tutti gli utenti"}.
|
||||
{"Allow subscription","Consenti iscrizione"}.
|
||||
{"Allow this Jabber ID to subscribe to this pubsub node?","Consentire a questo ID Jabber di iscriversi a questo nodo pubsub?"}.
|
||||
{"Allow this person to register with the room?","Permettere a questa persona di registrarsi con la stanza?"}.
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
{"has been kicked because of an affiliation change","foi desconectado porque por afiliação inválida"}.
|
||||
{"has been kicked because the room has been changed to members-only","foi desconectado porque a política da sala mudou, só membros são permitidos"}.
|
||||
{"has been kicked","foi removido"}.
|
||||
{"Hash of the vCard-temp avatar of this room","Hash do avatar do vCard-temp desta sala"}.
|
||||
{"Hat title","Título do chapéu"}.
|
||||
{"Hat URI","URI do chapéu"}.
|
||||
{"Hats limit exceeded","O limite dos chapéus foi excedido"}.
|
||||
|
||||
+7
-6
@@ -168,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-temp 头像的散列值"}.
|
||||
{"Hat title","头衔标题"}.
|
||||
{"Hat URI","头衔 URI"}.
|
||||
{"Hats limit exceeded","已超过头衔限制"}.
|
||||
@@ -226,12 +227,12 @@
|
||||
{"Logged Out","已登出"}.
|
||||
{"Logging","日志记录"}.
|
||||
{"Make participants list public","公开参与者列表"}.
|
||||
{"Make room CAPTCHA protected","让群聊受验证码保护"}.
|
||||
{"Make room members-only","让群聊仅成员进入"}.
|
||||
{"Make room CAPTCHA protected","开启群聊验证码保护"}.
|
||||
{"Make room members-only","仅成员进入的群聊"}.
|
||||
{"Make room moderated","开启群聊发言审核"}.
|
||||
{"Make room password protected","让群聊受密码保护"}.
|
||||
{"Make room persistent","让群聊持续存在"}.
|
||||
{"Make room public searchable","让群聊可公开搜索"}.
|
||||
{"Make room password protected","开启群聊密码保护"}.
|
||||
{"Make room persistent","持续存在的群聊"}.
|
||||
{"Make room public searchable","可公开搜索的群聊"}.
|
||||
{"Malformed username","用户名格式不正确"}.
|
||||
{"MAM preference modification denied by service policy","服务策略拒绝修改 MAM 首选项"}.
|
||||
{"March","三月"}.
|
||||
@@ -607,7 +608,7 @@
|
||||
{"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 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 和验证码的客户端来注册"}.
|
||||
|
||||
+10
-9
@@ -33,11 +33,11 @@
|
||||
{if_var_true, redis,
|
||||
{eredis, "~> 1.2.0", {git, "https://github.com/wooga/eredis", {tag, "v1.2.0"}}}},
|
||||
{if_var_true, sip,
|
||||
{esip, "~> 1.0.52", {git, "https://github.com/processone/esip", {tag, "1.0.54"}}}},
|
||||
{esip, "~> 1.0.52", {git, "https://github.com/processone/esip", {tag, "1.0.56"}}}},
|
||||
{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.21"}}},
|
||||
{fast_xml, "~> 1.1.51", {git, "https://github.com/processone/fast_xml", {tag, "1.1.52"}}},
|
||||
{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.53"}}},
|
||||
{fast_yaml, "~> 1.0.36", {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",
|
||||
@@ -56,20 +56,20 @@
|
||||
{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.23"}}},
|
||||
{p1_acme, "~> 1.0.23", {git, "https://github.com/processone/p1_acme", {tag, "1.0.24"}}},
|
||||
{if_var_true, mysql,
|
||||
{p1_mysql, "~> 1.0.24", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.24"}}}},
|
||||
{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.27"}}}},
|
||||
{p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.28"}}}},
|
||||
{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,
|
||||
{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"}}},
|
||||
{if_var_true, stun,
|
||||
{stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.14"}}}},
|
||||
{xmpp, "~> 1.8.3", {git, "https://github.com/processone/xmpp", {tag, "1.8.3"}}},
|
||||
{stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}},
|
||||
{xmpp, "~> 1.9.0", {git, "https://github.com/processone/xmpp", {tag, "1.9.0"}}},
|
||||
{yconf, "~> 1.0.15", {git, "https://github.com/processone/yconf", {tag, "1.0.16"}}}
|
||||
]}.
|
||||
|
||||
@@ -156,7 +156,8 @@
|
||||
{branch, "consolidation_fix"}}}
|
||||
}]}}.
|
||||
{if_rebar3, {project_plugins, [configure_deps,
|
||||
{if_var_true, tools, rebar3_format}
|
||||
{if_var_true, tools, rebar3_format},
|
||||
{if_var_true, tools, rebar3_lint}
|
||||
]}}.
|
||||
{if_not_rebar3, {plugins, [
|
||||
deps_erl_opts, override_deps_versions2, override_opts, configure_deps
|
||||
|
||||
+24
-24
@@ -4,27 +4,27 @@
|
||||
{<<"eimp">>,{pkg,<<"eimp">>,<<"1.0.23">>},0},
|
||||
{<<"epam">>,{pkg,<<"epam">>,<<"1.0.14">>},0},
|
||||
{<<"eredis">>,{pkg,<<"eredis">>,<<"1.2.0">>},0},
|
||||
{<<"esip">>,{pkg,<<"esip">>,<<"1.0.54">>},0},
|
||||
{<<"esip">>,{pkg,<<"esip">>,<<"1.0.56">>},0},
|
||||
{<<"ezlib">>,{pkg,<<"ezlib">>,<<"1.0.13">>},0},
|
||||
{<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.21">>},0},
|
||||
{<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.52">>},0},
|
||||
{<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.22">>},0},
|
||||
{<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.53">>},0},
|
||||
{<<"fast_yaml">>,{pkg,<<"fast_yaml">>,<<"1.0.37">>},0},
|
||||
{<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},0},
|
||||
{<<"jiffy">>,{pkg,<<"jiffy">>,<<"1.1.2">>},1},
|
||||
{<<"jose">>,{pkg,<<"jose">>,<<"1.11.10">>},0},
|
||||
{<<"luerl">>,{pkg,<<"luerl">>,<<"1.2.0">>},0},
|
||||
{<<"mqtree">>,{pkg,<<"mqtree">>,<<"1.0.17">>},0},
|
||||
{<<"p1_acme">>,{pkg,<<"p1_acme">>,<<"1.0.23">>},0},
|
||||
{<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.24">>},0},
|
||||
{<<"p1_acme">>,{pkg,<<"p1_acme">>,<<"1.0.24">>},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.27">>},0},
|
||||
{<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.28">>},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.14">>},0},
|
||||
{<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0},
|
||||
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1},
|
||||
{<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.8.3">>},0},
|
||||
{<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.0">>},0},
|
||||
{<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.16">>},0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
@@ -33,27 +33,27 @@
|
||||
{<<"eimp">>, <<"AAF32EFAB061143403DADBAA63E699EF8E81702FBFA96FD436D5E9BE4D6A8D3A">>},
|
||||
{<<"epam">>, <<"AA0B85D27F4EF3A756AE995179DF952A0721237E83C6B79D644347B75016681A">>},
|
||||
{<<"eredis">>, <<"0B8E9CFC2C00FA1374CD107EA63B49BE08D933DF2CF175E6A89B73DD9C380DE4">>},
|
||||
{<<"esip">>, <<"DAE8FB8278FD3B2C0D38C2E832C4B8D26700EB239B9A42C8EA574FEE76F5E76A">>},
|
||||
{<<"esip">>, <<"63C0FDC667BE751714E1E5C14621A9334F21B60AC1BB68BE889454CA9CA021B7">>},
|
||||
{<<"ezlib">>, <<"3C7F62862850A241159C10B218ECF580BCE54D0890601B65144DACC2633BE2B0">>},
|
||||
{<<"fast_tls">>, <<"65D7D547A09EEFB37A1C0D04D8601FAC4F3E6E2C1EDE859A7787081670F9648D">>},
|
||||
{<<"fast_xml">>, <<"0289DAAFBF1190B0E53B444D4885CCCF41E4B05768D4B3ACC76DD8D143668E10">>},
|
||||
{<<"fast_tls">>, <<"44356B256AFAD4399C2FC5059A3066669DAFD8BD4E4E796C9C1CF8910DDD265E">>},
|
||||
{<<"fast_xml">>, <<"1EF4F6E5995BCFA94800A46B460C3400C19C0A533948B12200A2E2FB1A2BE427">>},
|
||||
{<<"fast_yaml">>, <<"F71D472FBF787CCD161B914D1EB486116A0F4F2E835337A378FBD31B59D2E74B">>},
|
||||
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
|
||||
{<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>},
|
||||
{<<"jose">>, <<"A903F5227417BD2A08C8A00A0CBCC458118BE84480955E8D251297A425723F83">>},
|
||||
{<<"luerl">>, <<"60F05F4240F0E7C148DDB79B67B8FF972734AAD237AA74C83D0748B8214C8EF0">>},
|
||||
{<<"mqtree">>, <<"82F54B8F2D22B4445DB1D6CCCB7FE9EAD049D61410C29E32475F3CEB3EE62A89">>},
|
||||
{<<"p1_acme">>, <<"791AEF0F79DC7F768B228808250C349FA9CE585CD8779DA50CA93106EB3394D0">>},
|
||||
{<<"p1_mysql">>, <<"0ED1E098C5A4525032448C65A2715F30980AAE725615A4D255FD25F26BB22507">>},
|
||||
{<<"p1_acme">>, <<"E19876618EB0BE22815ACA99640CB88CD5C86E4239B8E8DC15B4E5D7854EF7E2">>},
|
||||
{<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>},
|
||||
{<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>},
|
||||
{<<"p1_pgsql">>, <<"883E335D82AC062DE0BDE7981F8250A2E632258BB7A47DF839A4CBDCB3E971E6">>},
|
||||
{<<"p1_pgsql">>, <<"08ECA7D2AFC81BA6D757B572F4A57EF3A2383B0C7B785FDE38184BC368376D54">>},
|
||||
{<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>},
|
||||
{<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>},
|
||||
{<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>},
|
||||
{<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>},
|
||||
{<<"stun">>, <<"6F538AC80C842131DBD149055570D116BFABC9B5EBFF4BD6AF2E7888958C660C">>},
|
||||
{<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>},
|
||||
{<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>},
|
||||
{<<"xmpp">>, <<"ACF39A8B70B066BB8F10B0862E031E8ABCF92FE89D1C41D06C1E39AE5CAF89C4">>},
|
||||
{<<"xmpp">>, <<"D92446BF51D36ADDA02DB63B963FE6D4A1EDE33E59B38A43D9B90AFD20C25B74">>},
|
||||
{<<"yconf">>, <<"D59521D66FF89F219411B6E9277CD6FEEC7CC6FCE11554E67DE02A8D0A470479">>}]},
|
||||
{pkg_hash_ext,[
|
||||
{<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>},
|
||||
@@ -61,26 +61,26 @@
|
||||
{<<"eimp">>, <<"907C780023CB2893E4FC4BDBE6A4F02C355913862AC67F0ECC26605E816B628A">>},
|
||||
{<<"epam">>, <<"2F3449E72885A72A6C2A843F561ADD0FC2F70D7A21F61456930A547473D4D989">>},
|
||||
{<<"eredis">>, <<"D9B5ABEF2C2C8ABA8F32AA018203E0B3DC8B1157773B254AB1D4C2002317F1E1">>},
|
||||
{<<"esip">>, <<"8187AF819D7259CDADDAF69726C239EF604C9B0B0298A5F2D3E687BF5E2237EE">>},
|
||||
{<<"esip">>, <<"9EF3660CEF93B623F7368DCD5C79F4E704358631909E6DD464E335378815DA1F">>},
|
||||
{<<"ezlib">>, <<"9EE62AB3F8ED55A0FD11A9569FCB8E458683F95575417272192B069F092ABFBB">>},
|
||||
{<<"fast_tls">>, <<"131542913937025E48CD80AA81F00359686D5501B75621E72026A87B5229505B">>},
|
||||
{<<"fast_xml">>, <<"795192390E06D2B65016A6990BBFA5727F4A26D2914808B1C3C9A32EEDCD1BFD">>},
|
||||
{<<"fast_tls">>, <<"E65779AEFB7AB15C4755230FEF8077E687D20CC5A3984A5974F9F657E8E2485B">>},
|
||||
{<<"fast_xml">>, <<"5064336D6F363EEE5097AA5DC5CED9B67F05152F2E6B8520FD50D268C2AB839C">>},
|
||||
{<<"fast_yaml">>, <<"8DE868721BF7E2172414F7D3148EDE0F3C922B496455CD625DD5C4429515A769">>},
|
||||
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
|
||||
{<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>},
|
||||
{<<"jose">>, <<"0D6CD36FF8BA174DB29148FC112B5842186B68A90CE9FC2B3EC3AFE76593E614">>},
|
||||
{<<"luerl">>, <<"9CAFD4F6094FF0F5A9D278FD81D60D3E026C820BDFB6CACD4B1BD909F21B525D">>},
|
||||
{<<"mqtree">>, <<"5FE8B7CF8FBC4783D0FCEB94654AC2BBF3242A58CD0397D249DED8AE021BE2A3">>},
|
||||
{<<"p1_acme">>, <<"8CE196F26E3D22EA10B7809122950465878C127F80767E325207AED7E8D0DD59">>},
|
||||
{<<"p1_mysql">>, <<"F058865F64257F507A2C6A5AFF369B1375DBCB30B3D4258DAD4F1B3EAFFB655F">>},
|
||||
{<<"p1_acme">>, <<"F1451D706595EF997AB1CA17162DDAC58F874AC97E315A5FADBE3CFA26148002">>},
|
||||
{<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>},
|
||||
{<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>},
|
||||
{<<"p1_pgsql">>, <<"8E4D1A7602CB68780E55D89DC5A9B2E1AACA3F4F1EE3D1A25F2F8C3D2364FFB9">>},
|
||||
{<<"p1_pgsql">>, <<"655BB75DF036ACE55DDCE17CA741143C42E0667C6206AC27A4DCBC65F71AC9EF">>},
|
||||
{<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>},
|
||||
{<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>},
|
||||
{<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>},
|
||||
{<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>},
|
||||
{<<"stun">>, <<"E134807B1B7A8DFFD94E64EEFEE00E65C7B4042F3D14E16F8F43566D20371583">>},
|
||||
{<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>},
|
||||
{<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>},
|
||||
{<<"xmpp">>, <<"ED70065F9A89A818DCFF43B74C080C9E7F4F1414E1051BEDDB7280DB809AF711">>},
|
||||
{<<"xmpp">>, <<"C1B91BE74A9A9503AFA6766F756477516920FFBFEEA0C260C2FA171355F53C27">>},
|
||||
{<<"yconf">>, <<"E947813273F38711C7B2E5A8E4ACC9A51C7BBE854F744A345F60300B38586C89">>}]}
|
||||
].
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ CREATE INDEX i_archive_sh_timestamp USING BTREE ON archive(server_host(191), tim
|
||||
CREATE INDEX i_archive_sh_username_origin_id USING BTREE ON archive(server_host(191), username(191), origin_id(191));
|
||||
|
||||
-- To update 'archive' from ejabberd <= 23.10:
|
||||
-- ALTER TABLE archive ADD COLUMN origin_id text NOT NULL DEFAULT '';
|
||||
-- ALTER TABLE archive ADD COLUMN origin_id varchar(191) NOT NULL DEFAULT '';
|
||||
-- ALTER TABLE archive ALTER COLUMN origin_id DROP DEFAULT;
|
||||
-- CREATE INDEX i_archive_sh_username_origin_id USING BTREE ON archive(server_host(191), username(191), origin_id(191));
|
||||
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ CREATE INDEX i_timestamp USING BTREE ON archive(timestamp);
|
||||
CREATE INDEX i_archive_username_origin_id USING BTREE ON archive(username(191), origin_id(191));
|
||||
|
||||
-- To update 'archive' from ejabberd <= 23.10:
|
||||
-- ALTER TABLE archive ADD COLUMN origin_id origin_id(191) NOT NULL DEFAULT '';
|
||||
-- ALTER TABLE archive ADD COLUMN origin_id varchar(191) NOT NULL DEFAULT '';
|
||||
-- ALTER TABLE archive ALTER COLUMN origin_id DROP DEFAULT;
|
||||
-- CREATE INDEX i_archive_username_origin_id USING BTREE ON archive(username(191), origin_id(191));
|
||||
|
||||
|
||||
@@ -203,6 +203,7 @@ get_commands_spec() ->
|
||||
#ejabberd_commands{name = update, tags = [server],
|
||||
desc = "Update the given module",
|
||||
longdesc = "To update all the possible modules, use `all`.",
|
||||
note = "improved in 24.10",
|
||||
module = ?MODULE, function = update,
|
||||
args_example = ["all"],
|
||||
args = [{module, string}],
|
||||
@@ -370,17 +371,17 @@ get_commands_spec() ->
|
||||
args = [{out, string}],
|
||||
result = {res, rescode}},
|
||||
|
||||
#ejabberd_commands{name = delete_expired_messages, tags = [purge],
|
||||
#ejabberd_commands{name = delete_expired_messages, tags = [offline, purge],
|
||||
desc = "Delete expired offline messages from database",
|
||||
module = ?MODULE, function = delete_expired_messages,
|
||||
args = [], result = {res, rescode}},
|
||||
#ejabberd_commands{name = delete_old_messages, tags = [purge],
|
||||
#ejabberd_commands{name = delete_old_messages, tags = [offline, purge],
|
||||
desc = "Delete offline messages older than DAYS",
|
||||
module = ?MODULE, function = delete_old_messages,
|
||||
args_desc = ["Number of days"],
|
||||
args_example = [31],
|
||||
args = [{days, integer}], result = {res, rescode}},
|
||||
#ejabberd_commands{name = delete_old_messages_batch, tags = [purge],
|
||||
#ejabberd_commands{name = delete_old_messages_batch, tags = [offline, purge],
|
||||
desc = "Delete offline messages older than DAYS",
|
||||
note = "added in 22.05",
|
||||
module = ?MODULE, function = delete_old_messages_batch,
|
||||
@@ -393,7 +394,7 @@ get_commands_spec() ->
|
||||
result = {res, restuple},
|
||||
result_desc = "Result tuple",
|
||||
result_example = {ok, <<"Removal of 5000 messages in progress">>}},
|
||||
#ejabberd_commands{name = delete_old_messages_status, tags = [purge],
|
||||
#ejabberd_commands{name = delete_old_messages_status, tags = [offline, purge],
|
||||
desc = "Status of delete old offline messages operation",
|
||||
note = "added in 22.05",
|
||||
module = ?MODULE, function = delete_old_messages_status,
|
||||
@@ -403,7 +404,7 @@ get_commands_spec() ->
|
||||
result = {status, string},
|
||||
result_desc = "Status test",
|
||||
result_example = "Operation in progress, delete 5000 messages"},
|
||||
#ejabberd_commands{name = abort_delete_old_messages, tags = [purge],
|
||||
#ejabberd_commands{name = abort_delete_old_messages, tags = [offline, purge],
|
||||
desc = "Abort currently running delete old offline messages operation",
|
||||
note = "added in 22.05",
|
||||
module = ?MODULE, function = delete_old_messages_abort,
|
||||
@@ -528,7 +529,7 @@ get_commands_spec() ->
|
||||
module = ejabberd_doc, function = man,
|
||||
args = [], result = {res, restuple}},
|
||||
|
||||
#ejabberd_commands{name = webadmin_host_user_queue, tags = [internal],
|
||||
#ejabberd_commands{name = webadmin_host_user_queue, tags = [offline, internal],
|
||||
desc = "Generate WebAdmin offline queue HTML",
|
||||
module = mod_offline, function = webadmin_host_user_queue,
|
||||
args = [{user, binary}, {host, binary}, {query, any}, {lang, binary}],
|
||||
@@ -746,7 +747,7 @@ update_module(ModuleNameString) ->
|
||||
case ejabberd_update:update([ModuleName]) of
|
||||
{ok, []} ->
|
||||
{ok, "Not updated: "++ModuleNameString};
|
||||
{ok, [{ModuleName, _}]} ->
|
||||
{ok, [ModuleName]} ->
|
||||
{ok, "Updated: "++ModuleNameString};
|
||||
{error, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
+20
-1
@@ -59,10 +59,14 @@ start(normal, _Args) ->
|
||||
ejabberd_hooks:run(ejabberd_started, []),
|
||||
ejabberd:check_apps(),
|
||||
ejabberd_systemd:ready(),
|
||||
maybe_start_exsync(),
|
||||
{T2, _} = statistics(wall_clock),
|
||||
?INFO_MSG("ejabberd ~ts is started in the node ~p in ~.2fs",
|
||||
[ejabberd_option:version(),
|
||||
node(), (T2-T1)/1000]),
|
||||
maybe_print_elixir_version(),
|
||||
?INFO_MSG("~ts",
|
||||
[erlang:system_info(system_version)]),
|
||||
{ok, SupPid};
|
||||
Err ->
|
||||
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Err]),
|
||||
@@ -175,7 +179,11 @@ file_queue_init() ->
|
||||
-ifdef(ELIXIR_ENABLED).
|
||||
is_using_elixir_config() ->
|
||||
Config = ejabberd_config:path(),
|
||||
'Elixir.Ejabberd.ConfigUtil':is_elixir_config(Config).
|
||||
try 'Elixir.Ejabberd.ConfigUtil':is_elixir_config(Config) of
|
||||
B when is_boolean(B) -> B
|
||||
catch
|
||||
_:_ -> false
|
||||
end.
|
||||
|
||||
setup_if_elixir_conf_used() ->
|
||||
case is_using_elixir_config() of
|
||||
@@ -194,8 +202,19 @@ start_elixir_application() ->
|
||||
ok -> ok;
|
||||
{error, _Msg} -> ?ERROR_MSG("Elixir application not started.", [])
|
||||
end.
|
||||
|
||||
maybe_start_exsync() ->
|
||||
case os:getenv("RELIVE") of
|
||||
"true" -> rpc:call(node(), 'Elixir.ExSync.Application', start, []);
|
||||
_ -> ok
|
||||
end.
|
||||
|
||||
maybe_print_elixir_version() ->
|
||||
?INFO_MSG("Elixir ~ts", [maps:get(build, 'Elixir.System':build_info())]).
|
||||
-else.
|
||||
setup_if_elixir_conf_used() -> ok.
|
||||
register_elixir_config_hooks() -> ok.
|
||||
start_elixir_application() -> ok.
|
||||
maybe_start_exsync() -> ok.
|
||||
maybe_print_elixir_version() -> ok.
|
||||
-endif.
|
||||
|
||||
@@ -293,6 +293,8 @@ 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
|
||||
true ->
|
||||
case lists:foldl(
|
||||
fun(_, ok) ->
|
||||
ok;
|
||||
@@ -307,6 +309,9 @@ try_register(User, Server, Password) ->
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end;
|
||||
false ->
|
||||
{error, not_allowed}
|
||||
end;
|
||||
false ->
|
||||
{error, not_allowed}
|
||||
end
|
||||
|
||||
@@ -44,9 +44,9 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
start(Host) ->
|
||||
%% We add our default JWT verifier with hook priority 100.
|
||||
%% So if you need to check or verify your custom JWT before the
|
||||
%% default verifier, It's better to use this hook with priority
|
||||
%% little than 100 and return bool() or {stop, bool()} in your own
|
||||
%% So if you need to check or verify your custom JWT before the
|
||||
%% default verifier, It's better to use this hook with priority
|
||||
%% little than 100 and return bool() or {stop, bool()} in your own
|
||||
%% callback function.
|
||||
ejabberd_hooks:add(check_decoded_jwt, Host, ?MODULE, check_decoded_jwt, 100),
|
||||
case ejabberd_option:jwt_key(Host) of
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
-include("ejabberd_auth.hrl").
|
||||
|
||||
-define(SALT_LENGTH, 16).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
@@ -161,8 +159,6 @@ remove_user(User, Server) ->
|
||||
{error, db_failure}
|
||||
end.
|
||||
|
||||
-define(BATCH_SIZE, 1000).
|
||||
|
||||
scram_hash_encode(Hash, StoreKey) ->
|
||||
case Hash of
|
||||
sha -> StoreKey;
|
||||
|
||||
+14
-14
@@ -308,9 +308,9 @@ init([#body{attrs = Attrs}, IP, SID]) ->
|
||||
ignore
|
||||
end.
|
||||
|
||||
wait_for_session(_Event, State) ->
|
||||
wait_for_session(Event, State) ->
|
||||
?ERROR_MSG("Unexpected event in 'wait_for_session': ~p",
|
||||
[_Event]),
|
||||
[Event]),
|
||||
{next_state, wait_for_session, State}.
|
||||
|
||||
wait_for_session(#body{attrs = Attrs} = Req, From,
|
||||
@@ -367,16 +367,16 @@ wait_for_session(#body{attrs = Attrs} = Req, From,
|
||||
reply_next_state(State4, Resp#body{els = RespEls}, RID,
|
||||
From)
|
||||
end;
|
||||
wait_for_session(_Event, _From, State) ->
|
||||
wait_for_session(Event, _From, State) ->
|
||||
?ERROR_MSG("Unexpected sync event in 'wait_for_session': ~p",
|
||||
[_Event]),
|
||||
[Event]),
|
||||
{reply, {error, badarg}, wait_for_session, State}.
|
||||
|
||||
active({#body{} = Body, From}, State) ->
|
||||
active1(Body, From, State);
|
||||
active(_Event, State) ->
|
||||
active(Event, State) ->
|
||||
?ERROR_MSG("Unexpected event in 'active': ~p",
|
||||
[_Event]),
|
||||
[Event]),
|
||||
{next_state, active, State}.
|
||||
|
||||
active(#body{attrs = Attrs, size = Size} = Req, From,
|
||||
@@ -408,9 +408,9 @@ active(#body{attrs = Attrs, size = Size} = Req, From,
|
||||
end;
|
||||
true -> active1(Req, From, State1)
|
||||
end;
|
||||
active(_Event, _From, State) ->
|
||||
active(Event, _From, State) ->
|
||||
?ERROR_MSG("Unexpected sync event in 'active': ~p",
|
||||
[_Event]),
|
||||
[Event]),
|
||||
{reply, {error, badarg}, active, State}.
|
||||
|
||||
active1(#body{attrs = Attrs} = Req, From, State) ->
|
||||
@@ -517,9 +517,9 @@ handle_event({activate, C2SPid}, StateName,
|
||||
handle_event({change_shaper, Shaper}, StateName,
|
||||
State) ->
|
||||
{next_state, StateName, State#state{shaper_state = Shaper}};
|
||||
handle_event(_Event, StateName, State) ->
|
||||
handle_event(Event, StateName, State) ->
|
||||
?ERROR_MSG("Unexpected event in '~ts': ~p",
|
||||
[StateName, _Event]),
|
||||
[StateName, Event]),
|
||||
{next_state, StateName, State}.
|
||||
|
||||
handle_sync_event({send_xml,
|
||||
@@ -557,9 +557,9 @@ handle_sync_event(deactivate_socket, _From, StateName,
|
||||
StateData) ->
|
||||
{reply, ok, StateName,
|
||||
StateData#state{c2s_pid = undefined}};
|
||||
handle_sync_event(_Event, _From, StateName, State) ->
|
||||
handle_sync_event(Event, _From, StateName, State) ->
|
||||
?ERROR_MSG("Unexpected sync event in '~ts': ~p",
|
||||
[StateName, _Event]),
|
||||
[StateName, Event]),
|
||||
{reply, {error, badarg}, StateName, State}.
|
||||
|
||||
handle_info({timeout, TRef, wait_timeout}, StateName,
|
||||
@@ -583,9 +583,9 @@ handle_info({timeout, TRef, shaper_timeout}, StateName,
|
||||
{stop, normal, State};
|
||||
_ -> {next_state, StateName, State}
|
||||
end;
|
||||
handle_info(_Info, StateName, State) ->
|
||||
handle_info(Info, StateName, State) ->
|
||||
?ERROR_MSG("Unexpected info:~n** Msg: ~p~n** StateName: ~p",
|
||||
[_Info, StateName]),
|
||||
[Info, StateName]),
|
||||
{next_state, StateName, State}.
|
||||
|
||||
terminate(_Reason, _StateName, State) ->
|
||||
|
||||
+29
-12
@@ -35,16 +35,17 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
handle_info/2, terminate/2, code_change/3]).
|
||||
-export([tls_options/1, tls_required/1, tls_enabled/1,
|
||||
compress_methods/1, bind/2, sasl_mechanisms/2,
|
||||
get_password_fun/2, check_password_fun/2, check_password_digest_fun/2,
|
||||
unauthenticated_stream_features/1, authenticated_stream_features/1,
|
||||
handle_stream_start/2, handle_stream_end/2,
|
||||
handle_unauthenticated_packet/2, handle_authenticated_packet/2,
|
||||
handle_auth_success/4, handle_auth_failure/4, handle_send/3,
|
||||
handle_recv/3, handle_cdata/2, handle_unbinded_packet/2,
|
||||
inline_stream_features/1, handle_sasl2_inline/2,
|
||||
handle_sasl2_inline_post/3, handle_bind2_inline/2,
|
||||
handle_bind2_inline_post/3, sasl_options/1]).
|
||||
allow_unencrypted_sasl2/1, compress_methods/1, bind/2,
|
||||
sasl_mechanisms/2, get_password_fun/2, check_password_fun/2,
|
||||
check_password_digest_fun/2, unauthenticated_stream_features/1,
|
||||
authenticated_stream_features/1, handle_stream_start/2,
|
||||
handle_stream_end/2, handle_unauthenticated_packet/2,
|
||||
handle_authenticated_packet/2, handle_auth_success/4,
|
||||
handle_auth_failure/4, handle_send/3, handle_recv/3, handle_cdata/2,
|
||||
handle_unbinded_packet/2, inline_stream_features/1,
|
||||
handle_sasl2_inline/2, handle_sasl2_inline_post/3,
|
||||
handle_bind2_inline/2, handle_bind2_inline_post/3, sasl_options/1,
|
||||
handle_sasl2_task_next/4, handle_sasl2_task_data/3]).
|
||||
%% Hooks
|
||||
-export([handle_unexpected_cast/2, handle_unexpected_call/3,
|
||||
process_auth_result/3, reject_unauthenticated_packet/2,
|
||||
@@ -392,6 +393,9 @@ tls_enabled(#{tls_enabled := TLSEnabled,
|
||||
tls_verify := TLSVerify}) ->
|
||||
TLSEnabled or TLSRequired or TLSVerify.
|
||||
|
||||
allow_unencrypted_sasl2(#{allow_unencrypted_sasl2 := AllowUnencryptedSasl2}) ->
|
||||
AllowUnencryptedSasl2.
|
||||
|
||||
compress_methods(#{zlib := true}) ->
|
||||
[<<"zlib">>];
|
||||
compress_methods(_) ->
|
||||
@@ -404,7 +408,7 @@ authenticated_stream_features(#{lserver := LServer}) ->
|
||||
ejabberd_hooks:run_fold(c2s_post_auth_features, LServer, [], [LServer]).
|
||||
|
||||
inline_stream_features(#{lserver := LServer}) ->
|
||||
ejabberd_hooks:run_fold(c2s_inline_features, LServer, {[], []}, [LServer]).
|
||||
ejabberd_hooks:run_fold(c2s_inline_features, LServer, {[], [], []}, [LServer]).
|
||||
|
||||
sasl_mechanisms(Mechs, #{lserver := LServer, stream_encrypted := Encrypted} = State) ->
|
||||
Type = ejabberd_auth:store_type(LServer),
|
||||
@@ -580,6 +584,14 @@ handle_bind2_inline_post(Els, Results, #{lserver := LServer} = State) ->
|
||||
ejabberd_hooks:run_fold(c2s_handle_bind2_inline_post, LServer,
|
||||
State, [Els, Results]).
|
||||
|
||||
handle_sasl2_task_next(Task, Els, InlineEls, #{lserver := LServer} = State) ->
|
||||
ejabberd_hooks:run_fold(c2s_handle_sasl2_task_next, LServer,
|
||||
{abort, State}, [Task, Els, InlineEls]).
|
||||
|
||||
handle_sasl2_task_data(Els, InlineEls, #{lserver := LServer} = State) ->
|
||||
ejabberd_hooks:run_fold(c2s_handle_sasl2_task_data, LServer,
|
||||
{abort, State}, [Els, InlineEls]).
|
||||
|
||||
handle_recv(El, Pkt, #{lserver := LServer} = State) ->
|
||||
ejabberd_hooks:run_fold(c2s_handle_recv, LServer, State, [El, Pkt]).
|
||||
|
||||
@@ -604,12 +616,14 @@ init([State, Opts]) ->
|
||||
TLSEnabled = proplists:get_bool(starttls, Opts),
|
||||
TLSRequired = proplists:get_bool(starttls_required, Opts),
|
||||
TLSVerify = proplists:get_bool(tls_verify, Opts),
|
||||
AllowUnencryptedSasl2 = proplists:get_bool(allow_unencrypted_sasl2, Opts),
|
||||
Zlib = proplists:get_bool(zlib, Opts),
|
||||
Timeout = ejabberd_option:negotiation_timeout(),
|
||||
State1 = State#{tls_options => TLSOpts2,
|
||||
tls_required => TLSRequired,
|
||||
tls_enabled => TLSEnabled,
|
||||
tls_verify => TLSVerify,
|
||||
allow_unencrypted_sasl2 => AllowUnencryptedSasl2,
|
||||
pres_a => ?SETS:new(),
|
||||
zlib => Zlib,
|
||||
lang => ejabberd_option:language(),
|
||||
@@ -1002,7 +1016,7 @@ get_conn_type(State) ->
|
||||
websocket -> websocket
|
||||
end.
|
||||
|
||||
-spec fix_from_to(xmpp_element(), state()) -> stanza().
|
||||
-spec fix_from_to(xmpp_element(), state()) -> stanza() | xmpp_element().
|
||||
fix_from_to(Pkt, #{jid := JID}) when ?is_stanza(Pkt) ->
|
||||
#jid{luser = U, lserver = S, lresource = R} = JID,
|
||||
case xmpp:get_from(Pkt) of
|
||||
@@ -1047,6 +1061,8 @@ listen_opt_type(starttls) ->
|
||||
econf:bool();
|
||||
listen_opt_type(starttls_required) ->
|
||||
econf:bool();
|
||||
listen_opt_type(allow_unencrypted_sasl2) ->
|
||||
econf:bool();
|
||||
listen_opt_type(tls_verify) ->
|
||||
econf:bool();
|
||||
listen_opt_type(zlib) ->
|
||||
@@ -1069,6 +1085,7 @@ listen_options() ->
|
||||
{tls_compression, false},
|
||||
{starttls, false},
|
||||
{starttls_required, false},
|
||||
{allow_unencrypted_sasl2, false},
|
||||
{tls_verify, false},
|
||||
{zlib, false},
|
||||
{max_stanza_size, infinity},
|
||||
|
||||
@@ -616,8 +616,7 @@ return(Port, TRef, Result) ->
|
||||
|
||||
is_feature_available() ->
|
||||
case get_prog_name() of
|
||||
Prog when is_binary(Prog) -> true;
|
||||
MF when is_list(MF) -> true;
|
||||
PathOrModule when is_binary(PathOrModule) -> true;
|
||||
false -> false
|
||||
end.
|
||||
|
||||
|
||||
@@ -56,8 +56,6 @@
|
||||
-include("logger.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
-define(POLICY_ACCESS, '$policy').
|
||||
|
||||
-type auth() :: {binary(), binary(), binary() | {oauth, binary()}, boolean()} | map().
|
||||
|
||||
-record(state, {}).
|
||||
|
||||
@@ -80,7 +80,7 @@ start_link() ->
|
||||
add(Hook, Function, Seq) when is_function(Function) ->
|
||||
add(Hook, global, undefined, Function, Seq).
|
||||
|
||||
-spec add(atom(), HostOrModule :: binary() | atom(), fun() | atom() , integer()) -> ok.
|
||||
-spec add(atom(), HostOrModule :: binary() | atom(), fun() | atom(), integer()) -> ok.
|
||||
add(Hook, Host, Function, Seq) when is_function(Function) ->
|
||||
add(Hook, Host, undefined, Function, Seq);
|
||||
|
||||
|
||||
+50
-100
@@ -50,8 +50,7 @@
|
||||
input = [] :: list(),
|
||||
active = false :: boolean(),
|
||||
c2s_pid :: pid(),
|
||||
ws :: {#ws{}, pid()},
|
||||
rfc_compliant = undefined :: boolean() | undefined}).
|
||||
ws :: {#ws{}, pid()}}).
|
||||
|
||||
%-define(DBGFSM, true).
|
||||
|
||||
@@ -166,57 +165,38 @@ handle_event({new_shaper, Shaper}, StateName, #state{ws = {_, WsPid}} = StateDat
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
handle_sync_event({send_xml, Packet}, _From, StateName,
|
||||
#state{ws = {_, WsPid}, rfc_compliant = R} = StateData) ->
|
||||
Packet2 = case {case R of undefined -> true; V -> V end, Packet} of
|
||||
{true, {xmlstreamstart, _, Attrs}} ->
|
||||
Attrs2 = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>} |
|
||||
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
|
||||
{xmlstreamelement, #xmlel{name = <<"open">>, attrs = Attrs2}};
|
||||
{true, {xmlstreamend, _}} ->
|
||||
{xmlstreamelement, #xmlel{name = <<"close">>,
|
||||
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>}]}};
|
||||
{true, {xmlstreamraw, <<"\r\n\r\n">>}} -> % cdata ping
|
||||
skip;
|
||||
{true, {xmlstreamelement, #xmlel{name=Name2} = El2}} ->
|
||||
El3 = case Name2 of
|
||||
<<"stream:", _/binary>> ->
|
||||
fxml:replace_tag_attr(<<"xmlns:stream">>, ?NS_STREAM, El2);
|
||||
_ ->
|
||||
case fxml:get_tag_attr_s(<<"xmlns">>, El2) of
|
||||
<<"">> ->
|
||||
fxml:replace_tag_attr(<<"xmlns">>, <<"jabber:client">>, El2);
|
||||
_ ->
|
||||
El2
|
||||
end
|
||||
end,
|
||||
{xmlstreamelement , El3};
|
||||
_ ->
|
||||
Packet
|
||||
end,
|
||||
case Packet2 of
|
||||
{xmlstreamstart, Name, Attrs3} ->
|
||||
B = fxml:element_to_binary(#xmlel{name = Name, attrs = Attrs3}),
|
||||
route_text(WsPid, <<(binary:part(B, 0, byte_size(B)-2))/binary, ">">>);
|
||||
{xmlstreamend, Name} ->
|
||||
route_text(WsPid, <<"</", Name/binary, ">">>);
|
||||
{xmlstreamelement, El} ->
|
||||
route_text(WsPid, fxml:element_to_binary(El));
|
||||
{xmlstreamraw, Bin} ->
|
||||
route_text(WsPid, Bin);
|
||||
{xmlstreamcdata, Bin2} ->
|
||||
route_text(WsPid, Bin2);
|
||||
skip ->
|
||||
ok
|
||||
end,
|
||||
SN2 = case Packet2 of
|
||||
{xmlstreamelement, #xmlel{name = <<"close">>}} ->
|
||||
stream_end_sent;
|
||||
_ ->
|
||||
StateName
|
||||
end,
|
||||
#state{ws = {_, WsPid}} = StateData) ->
|
||||
SN2 = case Packet of
|
||||
{xmlstreamstart, _, Attrs} ->
|
||||
Attrs2 = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>} |
|
||||
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
|
||||
route_el(WsPid, #xmlel{name = <<"open">>, attrs = Attrs2}),
|
||||
StateName;
|
||||
{xmlstreamend, _} ->
|
||||
route_el(WsPid, #xmlel{name = <<"close">>,
|
||||
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>}]}),
|
||||
stream_end_sent;
|
||||
{xmlstreamraw, <<"\r\n\r\n">>} ->
|
||||
% cdata ping
|
||||
StateName;
|
||||
{xmlstreamelement, #xmlel{name = Name2} = El2} ->
|
||||
El3 = case Name2 of
|
||||
<<"stream:", _/binary>> ->
|
||||
fxml:replace_tag_attr(<<"xmlns:stream">>, ?NS_STREAM, El2);
|
||||
_ ->
|
||||
case fxml:get_tag_attr_s(<<"xmlns">>, El2) of
|
||||
<<"">> ->
|
||||
fxml:replace_tag_attr(<<"xmlns">>, <<"jabber:client">>, El2);
|
||||
_ ->
|
||||
El2
|
||||
end
|
||||
end,
|
||||
route_el(WsPid, El3),
|
||||
StateName
|
||||
end,
|
||||
{reply, ok, SN2, StateData};
|
||||
handle_sync_event(close, _From, StateName, #state{ws = {_, WsPid}, rfc_compliant = true} = StateData)
|
||||
when StateName /= stream_end_sent ->
|
||||
handle_sync_event(close, _From, StateName, #state{ws = {_, WsPid}} = StateData)
|
||||
when StateName /= stream_end_sent ->
|
||||
Close = #xmlel{name = <<"close">>,
|
||||
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>}]},
|
||||
route_text(WsPid, fxml:element_to_binary(Close)),
|
||||
@@ -230,7 +210,7 @@ handle_info({received, Packet}, StateName, StateDataI) ->
|
||||
{StateData, Parsed} = parse(StateDataI, Packet),
|
||||
SD = case StateData#state.active of
|
||||
false ->
|
||||
Input = StateData#state.input ++ if is_binary(Parsed) -> [Parsed]; true -> Parsed end,
|
||||
Input = StateData#state.input ++ Parsed,
|
||||
StateData#state{input = Input};
|
||||
true ->
|
||||
StateData#state.c2s_pid ! {tcp, StateData#state.socket, Parsed},
|
||||
@@ -313,53 +293,19 @@ get_human_html_xmlel() ->
|
||||
"client that supports it.">>}]}]}]}.
|
||||
|
||||
|
||||
parse(#state{rfc_compliant = C} = State, Data) ->
|
||||
case C of
|
||||
undefined ->
|
||||
P = fxml_stream:new(self()),
|
||||
P2 = fxml_stream:parse(P, Data),
|
||||
fxml_stream:close(P2),
|
||||
case parsed_items([]) of
|
||||
error ->
|
||||
{State#state{rfc_compliant = true}, <<"parse error">>};
|
||||
[] ->
|
||||
{State#state{rfc_compliant = true}, <<"parse error">>};
|
||||
[{xmlstreamstart, <<"open">>, _} | _] ->
|
||||
parse(State#state{rfc_compliant = true}, Data);
|
||||
_ ->
|
||||
parse(State#state{rfc_compliant = false}, Data)
|
||||
end;
|
||||
true ->
|
||||
El = fxml_stream:parse_element(Data),
|
||||
case El of
|
||||
#xmlel{name = <<"open">>, attrs = Attrs} ->
|
||||
Attrs2 = [{<<"xmlns:stream">>, ?NS_STREAM}, {<<"xmlns">>, <<"jabber:client">>} |
|
||||
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
|
||||
{State, [{xmlstreamstart, <<"stream:stream">>, Attrs2}]};
|
||||
#xmlel{name = <<"close">>} ->
|
||||
{State, [{xmlstreamend, <<"stream:stream">>}]};
|
||||
{error, _} ->
|
||||
{State, <<"parse error">>};
|
||||
_ ->
|
||||
{State, [El]}
|
||||
end;
|
||||
false ->
|
||||
{State, Data}
|
||||
end.
|
||||
|
||||
parsed_items(List) ->
|
||||
receive
|
||||
{'$gen_event', El}
|
||||
when element(1, El) == xmlel;
|
||||
element(1, El) == xmlstreamstart;
|
||||
element(1, El) == xmlstreamelement;
|
||||
element(1, El) == xmlstreamcdata;
|
||||
element(1, El) == xmlstreamend ->
|
||||
parsed_items([El | List]);
|
||||
{'$gen_event', {xmlstreamerror, _}} ->
|
||||
error
|
||||
after 0 ->
|
||||
lists:reverse(List)
|
||||
parse(State, Data) ->
|
||||
El = fxml_stream:parse_element(Data),
|
||||
case El of
|
||||
#xmlel{name = <<"open">>, attrs = Attrs} ->
|
||||
Attrs2 = [{<<"xmlns:stream">>, ?NS_STREAM}, {<<"xmlns">>, <<"jabber:client">>} |
|
||||
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
|
||||
{State, [{xmlstreamstart, <<"stream:stream">>, Attrs2}]};
|
||||
#xmlel{name = <<"close">>} ->
|
||||
{State, [{xmlstreamend, <<"stream:stream">>}]};
|
||||
{error, _} ->
|
||||
{State, [{xmlstreamerror, {4, <<"not well-formed">>}}]};
|
||||
_ ->
|
||||
{State, [El]}
|
||||
end.
|
||||
|
||||
-spec route_text(pid(), binary()) -> ok.
|
||||
@@ -369,3 +315,7 @@ route_text(Pid, Data) ->
|
||||
{text_reply, Pid} ->
|
||||
ok
|
||||
end.
|
||||
|
||||
-spec route_el(pid(), xmlel() | cdata()) -> ok.
|
||||
route_el(Pid, Data) ->
|
||||
route_text(Pid, fxml:element_to_binary(Data)).
|
||||
|
||||
@@ -60,8 +60,6 @@
|
||||
|
||||
-optional_callbacks([listen_opt_type/1, tcp_init/2, udp_init/2]).
|
||||
|
||||
-define(TCP_SEND_TIMEOUT, 15000).
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
|
||||
@@ -283,7 +283,7 @@ start(Level) ->
|
||||
burst_limit_window_time => LogBurstLimitWindowTime,
|
||||
burst_limit_max_count => LogBurstLimitCount},
|
||||
FmtConfig = #{legacy_header => false,
|
||||
time_designator => $ ,
|
||||
time_designator => $\s,
|
||||
max_size => 100*1024,
|
||||
single_line => false},
|
||||
FileFmtConfig = FmtConfig#{template => file_template()},
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-define(STORAGE_TYPES, [disc_copies, disc_only_copies, ram_copies]).
|
||||
-define(NEED_RESET, [local_content, type]).
|
||||
|
||||
-include("logger.hrl").
|
||||
|
||||
@@ -619,7 +619,7 @@ strings_to_binary(L) when is_list(L) ->
|
||||
end;
|
||||
strings_to_binary({A, B, C, D}) when
|
||||
is_integer(A), is_integer(B), is_integer(C), is_integer(D) ->
|
||||
{A, B, C ,D};
|
||||
{A, B, C, D};
|
||||
strings_to_binary(T) when is_tuple(T) ->
|
||||
list_to_tuple(strings_to_binary1(tuple_to_list(T)));
|
||||
strings_to_binary(X) ->
|
||||
|
||||
@@ -330,7 +330,7 @@ cache_size() ->
|
||||
cache_size(Host) ->
|
||||
ejabberd_config:get_option({cache_size, Host}).
|
||||
|
||||
-spec captcha_cmd() -> any().
|
||||
-spec captcha_cmd() -> 'undefined' | binary().
|
||||
captcha_cmd() ->
|
||||
ejabberd_config:get_option({captcha_cmd, global}).
|
||||
|
||||
|
||||
@@ -491,6 +491,7 @@ 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()} |
|
||||
|
||||
@@ -30,8 +30,9 @@ doc() ->
|
||||
[{hosts,
|
||||
#{value => ?T("[Domain1, Domain2, ...]"),
|
||||
desc =>
|
||||
?T("The option defines a list containing one or more "
|
||||
"domains that 'ejabberd' will serve. This is a "
|
||||
?T("List of one or more "
|
||||
"_`../configuration/basic.md#host-names|host names`_ "
|
||||
"(or domains) that 'ejabberd' will serve. This is a "
|
||||
"**mandatory** option.")}},
|
||||
{listen,
|
||||
#{value => "[Options, ...]",
|
||||
@@ -42,15 +43,15 @@ doc() ->
|
||||
{modules,
|
||||
#{value => "{Module: Options}",
|
||||
desc =>
|
||||
?T("The option for modules configuration. See "
|
||||
"_`modules.md|Modules`_ section "
|
||||
"for details.")}},
|
||||
?T("Set all the "
|
||||
"_`modules.md|modules`_ configuration options.")}},
|
||||
{loglevel,
|
||||
#{value =>
|
||||
"none | emergency | alert | critical | "
|
||||
"error | warning | notice | info | debug",
|
||||
desc =>
|
||||
?T("Verbosity of log files generated by ejabberd. "
|
||||
?T("Verbosity of ejabberd "
|
||||
"_`../configuration/basic.md#logging|logging`_. "
|
||||
"The default value is 'info'. "
|
||||
"NOTE: previous versions of ejabberd had log levels "
|
||||
"defined in numeric format ('0..5'). The numeric values "
|
||||
@@ -106,7 +107,8 @@ doc() ->
|
||||
{default_db,
|
||||
#{value => "mnesia | sql",
|
||||
desc =>
|
||||
?T("Default persistent storage for ejabberd. "
|
||||
?T("_`database.md#default-database|Default database`_ "
|
||||
"to store persistent data in ejabberd. "
|
||||
"Modules and other components (e.g. authentication) "
|
||||
"may have its own value. The default value is 'mnesia'.")}},
|
||||
{default_ram_db,
|
||||
@@ -135,7 +137,9 @@ doc() ->
|
||||
{acl,
|
||||
#{value => "{ACLName: {ACLType: ACLValue}}",
|
||||
desc =>
|
||||
?T("The option defines access control lists: named sets "
|
||||
?T("This option defines "
|
||||
"_`../configuration/basic.md#acl|access control lists`_: "
|
||||
"named sets "
|
||||
"of rules which are used to match against different targets "
|
||||
"(such as a JID or an IP address). Every set of rules "
|
||||
"has name 'ACLName': it can be any string except 'all' or 'none' "
|
||||
@@ -317,7 +321,9 @@ doc() ->
|
||||
{anonymous_protocol,
|
||||
#{value => "login_anon | sasl_anon | both",
|
||||
desc =>
|
||||
[?T("Define what anonymous protocol will be used: "), "",
|
||||
[?T("Define what "
|
||||
"_`authentication.md#anonymous-login-and-sasl-anonymous|anonymous`_ "
|
||||
"protocol will be used: "), "",
|
||||
?T("* 'login_anon' means that the anonymous login method will be used. "), "",
|
||||
?T("* 'sasl_anon' means that the SASL Anonymous method will be used. "), "",
|
||||
?T("* 'both' means that SASL Anonymous and login anonymous are both "
|
||||
@@ -332,10 +338,8 @@ doc() ->
|
||||
{append_host_config,
|
||||
#{value => "{Host: Options}",
|
||||
desc =>
|
||||
?T("To define specific ejabberd modules in a virtual host, "
|
||||
"you can define the global 'modules' option with the common modules, "
|
||||
"and later add specific modules to certain virtual hosts. "
|
||||
"To accomplish that, 'append_host_config' option can be used.")}},
|
||||
?T("Add a few specific options to a certain "
|
||||
"_`../configuration/basic.md#virtual-hosting|virtual host`_.")}},
|
||||
{auth_cache_life_time,
|
||||
#{value => "timeout()",
|
||||
desc =>
|
||||
@@ -354,7 +358,7 @@ doc() ->
|
||||
{auth_method,
|
||||
#{value => "[mnesia | sql | anonymous | external | jwt | ldap | pam, ...]",
|
||||
desc =>
|
||||
?T("A list of authentication methods to use. "
|
||||
?T("A list of _`authentication.md|authentication`_ methods to use. "
|
||||
"If several methods are defined, authentication is "
|
||||
"considered successful as long as authentication of "
|
||||
"at least one of the methods succeeds. "
|
||||
@@ -533,7 +537,9 @@ doc() ->
|
||||
{define_macro,
|
||||
#{value => "{MacroName: MacroValue}",
|
||||
desc =>
|
||||
?T("Defines a macro. The value can be any valid arbitrary "
|
||||
?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 "
|
||||
@@ -572,7 +578,9 @@ doc() ->
|
||||
{domain_balancing,
|
||||
#{value => "{Domain: Options}",
|
||||
desc =>
|
||||
?T("An algorithm to load balance the components that are plugged "
|
||||
?T("An algorithm to "
|
||||
"_`../guide/clustering.md#service-load-balancing|load-balance`_ "
|
||||
"the components that are plugged "
|
||||
"on an ejabberd cluster. It means that you can plug one or several "
|
||||
"instances of the same component on each ejabberd node and that "
|
||||
"the traffic will be automatically distributed. The algorithm "
|
||||
@@ -605,19 +613,23 @@ doc() ->
|
||||
{extauth_pool_name,
|
||||
#{value => ?T("Name"),
|
||||
desc =>
|
||||
?T("Define the pool name appendix, so the full pool name will be "
|
||||
?T("Define the pool name appendix in "
|
||||
"_`authentication.md#external-script|external auth`_, "
|
||||
"so the full pool name will be "
|
||||
"'extauth_pool_Name'. The default value is the hostname.")}},
|
||||
{extauth_pool_size,
|
||||
#{value => ?T("Size"),
|
||||
desc =>
|
||||
?T("The option defines the number of instances of the same "
|
||||
"external program to start for better load balancing. "
|
||||
"_`authentication.md#external-script|external auth`_ "
|
||||
"program to start for better load balancing. "
|
||||
"The default is the number of available CPU cores.")}},
|
||||
{extauth_program,
|
||||
#{value => ?T("Path"),
|
||||
desc =>
|
||||
?T("Indicate in this option the full path to the external "
|
||||
"authentication script. The script must be executable by ejabberd.")}},
|
||||
?T("Indicate in this option the full path to the "
|
||||
"_`authentication.md#external-script|external authentication script`_. "
|
||||
"The script must be executable by ejabberd.")}},
|
||||
{ext_api_headers,
|
||||
#{value => "Headers",
|
||||
desc =>
|
||||
@@ -655,8 +667,10 @@ doc() ->
|
||||
{host_config,
|
||||
#{value => "{Host: Options}",
|
||||
desc =>
|
||||
?T("The option is used to redefine 'Options' for virtual host "
|
||||
"'Host'. In the example below LDAP authentication method "
|
||||
?T("The option is used to redefine 'Options' for "
|
||||
"_`../configuration/basic.md#virtual-hosting|virtual host`_ "
|
||||
"'Host'. "
|
||||
"In the example below LDAP authentication method "
|
||||
"will be used on virtual host 'domain.tld' and SQL method "
|
||||
"will be used on virtual host 'example.org'."),
|
||||
example =>
|
||||
@@ -674,7 +688,9 @@ doc() ->
|
||||
{include_config_file,
|
||||
#{value => "[Filename, ...\\] | {Filename: Options}",
|
||||
desc =>
|
||||
?T("Read additional configuration from 'Filename'. If the "
|
||||
?T("Read and "
|
||||
"_`../configuration/file-format.md#include-additional-files|include additional file`_ "
|
||||
"from 'Filename'. If the "
|
||||
"value is provided in 'pass:[{Filename: Options}]' format, the "
|
||||
"'Options' must be one of the following:")},
|
||||
[{disallow,
|
||||
@@ -701,7 +717,8 @@ doc() ->
|
||||
{jwt_auth_only_rule,
|
||||
#{value => ?T("AccessName"),
|
||||
desc =>
|
||||
?T("This ACL rule defines accounts that can use only this auth "
|
||||
?T("This ACL rule defines accounts that can use only the "
|
||||
"_`authentication.md#jwt-authentication|JWT`_ auth "
|
||||
"method, even if others are also defined in the ejabberd "
|
||||
"configuration file. In other words: if there are several auth "
|
||||
"methods enabled for this host (JWT, SQL, ...), users that "
|
||||
@@ -711,36 +728,44 @@ doc() ->
|
||||
#{value => ?T("FieldName"),
|
||||
desc =>
|
||||
?T("By default, the JID is defined in the '\"jid\"' JWT field. "
|
||||
"In this option you can specify other JWT field name "
|
||||
"In this option you can specify other "
|
||||
"_`authentication.md#jwt-authentication|JWT`_ "
|
||||
"field name "
|
||||
"where the JID is defined.")}},
|
||||
{jwt_key,
|
||||
#{value => ?T("FilePath"),
|
||||
desc =>
|
||||
?T("Path to the file that contains the JWK Key. "
|
||||
?T("Path to the file that contains the "
|
||||
"_`authentication.md#jwt-authentication|JWT`_ key. "
|
||||
"The default value is 'undefined'.")}},
|
||||
{language,
|
||||
#{value => ?T("Language"),
|
||||
desc =>
|
||||
?T("The option defines the default language of server strings "
|
||||
?T("Define the "
|
||||
"_`../configuration/basic.md#default-language|default language`_ "
|
||||
"of server strings "
|
||||
"that can be seen by XMPP clients. If an XMPP client does not "
|
||||
"possess 'xml:lang' attribute, the specified language is used. "
|
||||
"The default value is '\"en\"'.")}},
|
||||
"The default value is '\"en\"'. ")}},
|
||||
{ldap_servers,
|
||||
#{value => "[Host, ...]",
|
||||
desc =>
|
||||
?T("A list of IP addresses or DNS names of your LDAP servers. "
|
||||
?T("A list of IP addresses or DNS names of your LDAP servers (see "
|
||||
"_`../configuration/ldap.md#ldap-connection|LDAP connection`_). "
|
||||
"ejabberd connects immediately to all of them, "
|
||||
"and reconnects infinitely if connection is lost. "
|
||||
"The default value is '[localhost]'.")}},
|
||||
{ldap_backups,
|
||||
#{value => "[Host, ...]",
|
||||
desc =>
|
||||
?T("A list of IP addresses or DNS names of LDAP backup servers. "
|
||||
?T("A list of IP addresses or DNS names of LDAP backup servers (see "
|
||||
"_`../configuration/ldap.md#ldap-connection|LDAP connection`_). "
|
||||
"When no servers listed in _`ldap_servers`_ option are reachable, "
|
||||
"ejabberd will try to connect to these backup servers. "
|
||||
"ejabberd connects to these backup servers. "
|
||||
"The default is an empty list, i.e. no backup servers specified. "
|
||||
"WARNING: ejabberd doesn't try to reconnect back to the main "
|
||||
"servers when they become operational again, so the only way "
|
||||
"to restore these connections is to restart ejabberd. This "
|
||||
"limitation might be fixed in future releases.")}},
|
||||
"Please notice that ejabberd only connects to the next server "
|
||||
"when the existing connection is lost; it doesn't detect when a "
|
||||
"previously-attempted server becomes available again.")}},
|
||||
{ldap_encrypt,
|
||||
#{value => "tls | none",
|
||||
desc =>
|
||||
@@ -909,7 +934,9 @@ doc() ->
|
||||
{new_sql_schema,
|
||||
#{value => "true | false",
|
||||
desc =>
|
||||
{?T("Whether to use 'new' SQL schema. All schemas are located "
|
||||
{?T("Whether to use the "
|
||||
"_`database.md#default-and-new-schemas|new SQL schema`_. "
|
||||
"All schemas are located "
|
||||
"at <https://github.com/processone/ejabberd/tree/~s/sql>. "
|
||||
"There are two schemas available. The default legacy schema "
|
||||
"stores one XMPP domain into one ejabberd database. "
|
||||
@@ -925,7 +952,8 @@ doc() ->
|
||||
#{value => "true | false",
|
||||
note => "updated in 24.06",
|
||||
desc =>
|
||||
?T("Allow ejabberd to update SQL schema. "
|
||||
?T("Allow ejabberd to update SQL schema in "
|
||||
"MySQL, PostgreSQL and SQLite databases. "
|
||||
"This option was added in ejabberd 23.10, "
|
||||
"and enabled by default since 24.06. "
|
||||
"The default value is 'true'.")}},
|
||||
@@ -1049,14 +1077,18 @@ doc() ->
|
||||
{pam_service,
|
||||
#{value => ?T("Name"),
|
||||
desc =>
|
||||
?T("This option defines the PAM service name. Refer to the PAM "
|
||||
?T("This option defines the "
|
||||
"_`authentication.md#pam-authentication|PAM`_ "
|
||||
"service name. Refer to the PAM "
|
||||
"documentation of your operation system for more information. "
|
||||
"The default value is 'ejabberd'.")}},
|
||||
{pam_userinfotype,
|
||||
#{value => "username | jid",
|
||||
desc =>
|
||||
?T("This option defines what type of information about the "
|
||||
"user ejabberd provides to the PAM service: only the username, "
|
||||
"user ejabberd provides to the "
|
||||
"_`authentication.md#pam-authentication|PAM`_ "
|
||||
"service: only the username, "
|
||||
"or the user's JID. Default is 'username'.")}},
|
||||
{pgsql_users_number_estimate,
|
||||
#{value => "true | false",
|
||||
@@ -1073,36 +1105,42 @@ doc() ->
|
||||
#{value => "timeout()",
|
||||
desc =>
|
||||
?T("A timeout to wait for the connection to be re-established "
|
||||
"to the Redis server. The default is '1 second'.")}},
|
||||
"to the _`database.md#redis|Redis`_ "
|
||||
"server. The default is '1 second'.")}},
|
||||
{redis_db,
|
||||
#{value => ?T("Number"),
|
||||
desc => ?T("Redis database number. The default is '0'.")}},
|
||||
desc => ?T("_`database.md#redis|Redis`_ "
|
||||
"database number. The default is '0'.")}},
|
||||
{redis_password,
|
||||
#{value => ?T("Password"),
|
||||
desc =>
|
||||
?T("The password to the Redis server. "
|
||||
?T("The password to the _`database.md#redis|Redis`_ server. "
|
||||
"The default is an empty string, i.e. no password.")}},
|
||||
{redis_pool_size,
|
||||
#{value => ?T("Number"),
|
||||
desc =>
|
||||
?T("The number of simultaneous connections to the Redis server. "
|
||||
?T("The number of simultaneous connections to the "
|
||||
"_`database.md#redis|Redis`_ server. "
|
||||
"The default value is '10'.")}},
|
||||
{redis_port,
|
||||
#{value => "1..65535",
|
||||
desc =>
|
||||
?T("The port where the Redis server is accepting connections. "
|
||||
?T("The port where the _`database.md#redis|Redis`_ "
|
||||
" server is accepting connections. "
|
||||
"The default is '6379'.")}},
|
||||
{redis_queue_type,
|
||||
#{value => "ram | file",
|
||||
desc =>
|
||||
?T("The type of request queue for the Redis server. "
|
||||
?T("The type of request queue for the "
|
||||
"_`database.md#redis|Redis`_ server. "
|
||||
"See description of _`queue_type`_ option for the explanation. "
|
||||
"The default value is the value defined in _`queue_type`_ "
|
||||
"or 'ram' if the latter is not set.")}},
|
||||
{redis_server,
|
||||
#{value => ?T("Hostname"),
|
||||
desc =>
|
||||
?T("A hostname or an IP address of the Redis server. "
|
||||
?T("A hostname or an IP address of the "
|
||||
"_`database.md#redis|Redis`_ server."
|
||||
"The default is 'localhost'.")}},
|
||||
{registration_timeout,
|
||||
#{value => "timeout()",
|
||||
@@ -1257,7 +1295,9 @@ doc() ->
|
||||
{shaper,
|
||||
#{value => "{ShaperName: Rate}",
|
||||
desc =>
|
||||
?T("The option defines a set of shapers. Every shaper is assigned "
|
||||
?T("The option defines a set of "
|
||||
"_`../configuration/basic.md#shapers|shapers`_. "
|
||||
"Every shaper is assigned "
|
||||
"a name 'ShaperName' that can be used in other parts of the "
|
||||
"configuration file, such as _`shaper_rules`_ option. The shaper "
|
||||
"itself is defined by its 'Rate', where 'Rate' stands for the "
|
||||
@@ -1274,7 +1314,9 @@ doc() ->
|
||||
{shaper_rules,
|
||||
#{value => "{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}",
|
||||
desc =>
|
||||
?T("An entry allowing to declaring shaper to use for matching user/hosts. "
|
||||
?T("This option defines "
|
||||
"_`../configuration/basic.md#shaper-rules|shaper rules`_ "
|
||||
"to use for matching user/hosts. "
|
||||
"Semantics is similar to _`access_rules`_ option, the only difference is "
|
||||
"that instead using 'allow' or 'deny', a name of a shaper (defined in "
|
||||
"_`shaper`_ option) or a positive number should be used."),
|
||||
|
||||
@@ -42,8 +42,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
-define(PROCNAME, 'ejabberd_redis_client').
|
||||
-define(TR_STACK, redis_transaction_stack).
|
||||
-define(DEFAULT_MAX_QUEUE, 10000).
|
||||
-define(MAX_RETRIES, 1).
|
||||
|
||||
+19
-2
@@ -380,8 +380,9 @@ code_change(_OldVsn, State, _Extra) ->
|
||||
%%% Internal functions
|
||||
%%--------------------------------------------------------------------
|
||||
-spec do_route(stanza()) -> ok.
|
||||
do_route(OrigPacket) ->
|
||||
?DEBUG("Route:~n~ts", [xmpp:pp(OrigPacket)]),
|
||||
do_route(OrigPacket1) ->
|
||||
?DEBUG("Route:~n~ts", [xmpp:pp(OrigPacket1)]),
|
||||
OrigPacket = process_privilege_iq(OrigPacket1),
|
||||
case ejabberd_hooks:run_fold(filter_packet, OrigPacket, []) of
|
||||
drop ->
|
||||
ok;
|
||||
@@ -405,6 +406,22 @@ do_route(OrigPacket) ->
|
||||
end
|
||||
end.
|
||||
|
||||
%% @format-begin
|
||||
process_privilege_iq(Packet) ->
|
||||
To = xmpp:get_to(Packet),
|
||||
case xmpp:get_meta(Packet, privilege_iq, none) of
|
||||
{OriginalId, OriginalHost, ReplacedJid} when ReplacedJid == To ->
|
||||
Privilege = #privilege{forwarded = #forwarded{sub_els = [Packet]}},
|
||||
#iq{type = xmpp:get_type(Packet),
|
||||
id = OriginalId,
|
||||
to = jid:make(OriginalHost),
|
||||
from = ReplacedJid,
|
||||
sub_els = [Privilege]};
|
||||
_ ->
|
||||
Packet
|
||||
end.
|
||||
%% @format-end
|
||||
|
||||
-spec do_route(stanza(), #route{}) -> any().
|
||||
do_route(Pkt, #route{local_hint = LocalHint,
|
||||
pid = Pid}) when is_pid(Pid) ->
|
||||
|
||||
+21
-1
@@ -43,7 +43,7 @@
|
||||
external_host_overloaded/1, is_temporarly_blocked/1,
|
||||
get_commands_spec/0, zlib_enabled/1, get_idle_timeout/1,
|
||||
tls_required/1, tls_enabled/1, tls_options/3,
|
||||
host_up/1, host_down/1, queue_type/1]).
|
||||
host_up/1, host_down/1, queue_type/1, register_connection/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
@@ -130,6 +130,10 @@ get_connections_pids(FromTo) ->
|
||||
[]
|
||||
end.
|
||||
|
||||
-spec register_connection(FromTo :: {binary(), binary()}) -> ok.
|
||||
register_connection(FromTo) ->
|
||||
gen_server:call(ejabberd_s2s, {register_connection, FromTo, self()}).
|
||||
|
||||
-spec dirty_get_connections() -> [{binary(), binary()}].
|
||||
dirty_get_connections() ->
|
||||
mnesia:dirty_all_keys(s2s).
|
||||
@@ -228,6 +232,8 @@ init([]) ->
|
||||
|
||||
handle_call({new_connection, Args}, _From, State) ->
|
||||
{reply, erlang:apply(fun new_connection_int/7, Args), State};
|
||||
handle_call({register_connection, FromTo, Pid}, _From, State) ->
|
||||
{reply, register_connection_int(FromTo, Pid), State};
|
||||
handle_call(Request, From, State) ->
|
||||
?WARNING_MSG("Unexpected call from ~p: ~p", [From, Request]),
|
||||
{noreply, State}.
|
||||
@@ -478,6 +484,20 @@ new_connection_int(MyServer, Server, From, FromTo,
|
||||
[]
|
||||
end.
|
||||
|
||||
-spec register_connection_int(FromTo :: {binary(), binary()}, Pid :: pid()) -> ok.
|
||||
register_connection_int(FromTo, Pid) ->
|
||||
F = fun() ->
|
||||
mnesia:write(#s2s{fromto = FromTo, pid = Pid})
|
||||
end,
|
||||
TRes = mnesia:transaction(F),
|
||||
case TRes of
|
||||
{atomic, _} ->
|
||||
erlang:monitor(process, Pid),
|
||||
ok;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
-spec max_s2s_connections_number({binary(), binary()}) -> pos_integer().
|
||||
max_s2s_connections_number({From, To}) ->
|
||||
case ejabberd_shaper:match(From, max_s2s_connections, jid:make(To)) of
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
terminate/2, code_change/3]).
|
||||
%% Hooks
|
||||
-export([process_auth_result/2, process_closed/2, handle_unexpected_info/2,
|
||||
handle_unexpected_cast/2, process_downgraded/2]).
|
||||
handle_unexpected_cast/2, process_downgraded/2, handle_unauthenticated_features/2]).
|
||||
%% API
|
||||
-export([start/3, start_link/3, connect/1, close/1, close/2, stop_async/1, send/2,
|
||||
route/2, establish/1, update_state/2, host_up/1, host_down/1]).
|
||||
@@ -216,6 +216,9 @@ dns_retries(#{server_host := ServerHost}) ->
|
||||
dns_timeout(#{server_host := ServerHost}) ->
|
||||
ejabberd_option:s2s_dns_timeout(ServerHost).
|
||||
|
||||
handle_unauthenticated_features(Features, #{server_host := ServerHost} = State) ->
|
||||
ejabberd_hooks:run_fold(s2s_out_unauthenticated_features, ServerHost, State, [Features]).
|
||||
|
||||
handle_auth_success(Mech, #{socket := Socket, ip := IP,
|
||||
remote_server := RServer,
|
||||
server_host := ServerHost,
|
||||
|
||||
@@ -206,6 +206,18 @@ bounce_offline_message(Acc) ->
|
||||
Acc.
|
||||
|
||||
-spec bounce_sm_packet({bounce | term(), stanza()}) -> any().
|
||||
bounce_sm_packet({bounce, #message{meta = #{ignore_sm_bounce := true}} = Packet} = Acc) ->
|
||||
?DEBUG("Dropping packet to unavailable resource:~n~ts",
|
||||
[xmpp:pp(Packet)]),
|
||||
Acc;
|
||||
bounce_sm_packet({bounce, #iq{meta = #{ignore_sm_bounce := true}} = Packet} = Acc) ->
|
||||
?DEBUG("Dropping packet to unavailable resource:~n~ts",
|
||||
[xmpp:pp(Packet)]),
|
||||
Acc;
|
||||
bounce_sm_packet({bounce, #presence{meta = #{ignore_sm_bounce := true}} = Packet} = Acc) ->
|
||||
?DEBUG("Dropping packet to unavailable resource:~n~ts",
|
||||
[xmpp:pp(Packet)]),
|
||||
Acc;
|
||||
bounce_sm_packet({bounce, Packet} = Acc) ->
|
||||
Lang = xmpp:get_lang(Packet),
|
||||
Txt = ?T("User session not found"),
|
||||
|
||||
@@ -183,8 +183,8 @@ keep_alive(Host, Proc) ->
|
||||
Timeout) of
|
||||
{selected,_,[[<<"1">>]]} ->
|
||||
ok;
|
||||
_Err ->
|
||||
?ERROR_MSG("Keep alive query failed, closing connection: ~p", [_Err]),
|
||||
Err ->
|
||||
?ERROR_MSG("Keep alive query failed, closing connection: ~p", [Err]),
|
||||
sync_send_event(Proc, force_timeout, Timeout)
|
||||
end.
|
||||
|
||||
|
||||
+3
-13
@@ -106,7 +106,6 @@ prepare_turn_opts(Opts) ->
|
||||
prepare_turn_opts(Opts, _UseTurn = false) ->
|
||||
set_certfile(Opts);
|
||||
prepare_turn_opts(Opts, _UseTurn = true) ->
|
||||
NumberOfMyHosts = length(ejabberd_option:hosts()),
|
||||
TurnIP = case proplists:get_value(turn_ipv4_address, Opts) of
|
||||
undefined ->
|
||||
MyIP = misc:get_my_ipv4_address(),
|
||||
@@ -129,18 +128,9 @@ prepare_turn_opts(Opts, _UseTurn = true) ->
|
||||
AuthType = proplists:get_value(auth_type, Opts, user),
|
||||
Realm = case proplists:get_value(auth_realm, Opts) of
|
||||
undefined when AuthType == user ->
|
||||
if NumberOfMyHosts > 1 ->
|
||||
?INFO_MSG("You have several virtual hosts "
|
||||
"configured, but option 'auth_realm' is "
|
||||
"undefined and 'auth_type' is set to "
|
||||
"'user', so the TURN relay might not be "
|
||||
"working properly. Using ~ts as a "
|
||||
"fallback",
|
||||
[ejabberd_config:get_myname()]);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
[{auth_realm, ejabberd_config:get_myname()}];
|
||||
MyName = ejabberd_config:get_myname(),
|
||||
?DEBUG("Using ~ts as TURN realm", [MyName]),
|
||||
[{auth_realm, MyName}];
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
|
||||
@@ -82,7 +82,9 @@ config_reloaded() ->
|
||||
%%%===================================================================
|
||||
%%% gen_event callbacks
|
||||
%%%===================================================================
|
||||
init([]) ->
|
||||
init({[], _}) -> % Called by gen_event:swap_handler
|
||||
{ok, #state{}};
|
||||
init([]) -> % Called by gen_event:add_handler
|
||||
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
|
||||
{ok, #state{}}.
|
||||
|
||||
|
||||
+21
-13
@@ -38,13 +38,17 @@
|
||||
%% Update all the modified modules
|
||||
update() ->
|
||||
case update_info() of
|
||||
{ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} ->
|
||||
Eval =
|
||||
eval_script(
|
||||
LowLevelScript, [],
|
||||
[{ejabberd, "", filename:join(Dir, "..")}]),
|
||||
?DEBUG("Eval: ~p~n", [Eval]),
|
||||
Eval;
|
||||
{ok, Dir, UpdatedBeams, _Script, LowLevelScript, _Check} ->
|
||||
case eval_script(
|
||||
LowLevelScript, [],
|
||||
[{ejabberd, "", filename:join(Dir, "..")}]) of
|
||||
{ok, _} ->
|
||||
?DEBUG("Updated: ~p~n", [UpdatedBeams]),
|
||||
{ok, UpdatedBeams};
|
||||
Eval ->
|
||||
?DEBUG("Eval: ~p~n", [Eval]),
|
||||
Eval
|
||||
end;
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
@@ -56,12 +60,16 @@ update(ModulesToUpdate) ->
|
||||
UpdatedBeamsNow =
|
||||
[A || A <- UpdatedBeamsAll, B <- ModulesToUpdate, A == B],
|
||||
{_, LowLevelScript, _} = build_script(Dir, UpdatedBeamsNow),
|
||||
Eval =
|
||||
eval_script(
|
||||
LowLevelScript, [],
|
||||
[{ejabberd, "", filename:join(Dir, "..")}]),
|
||||
?DEBUG("Eval: ~p~n", [Eval]),
|
||||
Eval;
|
||||
case eval_script(
|
||||
LowLevelScript, [],
|
||||
[{ejabberd, "", filename:join(Dir, "..")}]) of
|
||||
{ok, _} ->
|
||||
?DEBUG("Updated: ~p~n", [UpdatedBeamsNow]),
|
||||
{ok, UpdatedBeamsNow};
|
||||
Eval ->
|
||||
?DEBUG("Eval: ~p~n", [Eval]),
|
||||
Eval
|
||||
end;
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_web.erl
|
||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
||||
%%% Purpose :
|
||||
%%% Purpose :
|
||||
%%% Created : 28 Feb 2004 by Alexey Shchepin <alexey@process-one.net>
|
||||
%%%
|
||||
|
||||
+107
-46
@@ -747,46 +747,99 @@ list_users(Host, Level, PageSize, RPath, R, RegisterEl) ->
|
||||
end.
|
||||
|
||||
list_users(Host, Level, PageSize, RPath, R, Usernames, RegisterEl) ->
|
||||
IsOffline = gen_mod:is_loaded(Host, mod_offline),
|
||||
IsMam = gen_mod:is_loaded(Host, mod_mam),
|
||||
IsRoster = gen_mod:is_loaded(Host, mod_roster),
|
||||
IsLast = gen_mod:is_loaded(Host, mod_last),
|
||||
Columns =
|
||||
[<<"user">>,
|
||||
{<<"offline">>, right},
|
||||
{<<"roster">>, right},
|
||||
{<<"timestamp">>, left},
|
||||
{<<"status">>, left}],
|
||||
list_users_element(IsOffline, column, offline, {}),
|
||||
list_users_element(IsMam, column, mam, {}),
|
||||
list_users_element(IsRoster, column, roster, {}),
|
||||
list_users_element(IsLast, column, timestamp, {}),
|
||||
list_users_element(IsLast, column, status, {})],
|
||||
Rows =
|
||||
[{make_command(echo,
|
||||
R,
|
||||
[{<<"sentence">>,
|
||||
jid:encode(
|
||||
jid:make(Username, Host))}],
|
||||
[{only, raw_and_value}, {result_links, [{sentence, user, Level, <<"">>}]}]),
|
||||
make_command(get_offline_count,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}],
|
||||
[{only, raw_and_value},
|
||||
{result_links,
|
||||
[{value, arg_host, Level, <<"user/", Username/binary, "/queue/">>}]}]),
|
||||
make_command(get_roster_count,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}],
|
||||
[{only, raw_and_value},
|
||||
{result_links,
|
||||
[{value, arg_host, Level, <<"user/", Username/binary, "/roster/">>}]}]),
|
||||
?C(element(1,
|
||||
make_command_raw_value(get_last,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}]))),
|
||||
?C(element(2,
|
||||
make_command_raw_value(get_last,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}])))}
|
||||
[list_to_tuple(lists:flatten([make_command(echo,
|
||||
R,
|
||||
[{<<"sentence">>,
|
||||
jid:encode(
|
||||
jid:make(Username, Host))}],
|
||||
[{only, raw_and_value},
|
||||
{result_links,
|
||||
[{sentence, user, Level, <<"">>}]}]),
|
||||
list_users_element(IsOffline,
|
||||
row,
|
||||
offline,
|
||||
{R, Username, Host, Level}),
|
||||
list_users_element(IsMam,
|
||||
row,
|
||||
mam,
|
||||
{R, Username, Host, Level}),
|
||||
list_users_element(IsRoster,
|
||||
row,
|
||||
roster,
|
||||
{R, Username, Host, Level}),
|
||||
list_users_element(IsLast, row, last, {R, Username, Host})]))
|
||||
|| Username <- Usernames],
|
||||
[RegisterEl,
|
||||
make_command(registered_users, R, [], [{only, presentation}]),
|
||||
make_command(get_offline_count, R, [], [{only, presentation}]),
|
||||
make_command(get_roster_count, R, [], [{only, presentation}]),
|
||||
make_command(get_last, R, [], [{only, presentation}]),
|
||||
make_table(PageSize, RPath, Columns, Rows)].
|
||||
Table = make_table(PageSize, RPath, lists:flatten(Columns), Rows),
|
||||
Result =
|
||||
[RegisterEl,
|
||||
make_command(registered_users, R, [], [{only, presentation}]),
|
||||
list_users_element(IsOffline, presentation, offline, R),
|
||||
list_users_element(IsMam, presentation, mam, R),
|
||||
list_users_element(IsRoster, presentation, roster, R),
|
||||
list_users_element(IsLast, presentation, last, R),
|
||||
Table],
|
||||
lists:flatten(Result).
|
||||
|
||||
list_users_element(false, _, _, _) ->
|
||||
[];
|
||||
list_users_element(_, column, offline, _) ->
|
||||
{<<"offline">>, right};
|
||||
list_users_element(_, column, mam, _) ->
|
||||
{<<"mam">>, right};
|
||||
list_users_element(_, column, roster, _) ->
|
||||
{<<"roster">>, right};
|
||||
list_users_element(_, column, timestamp, _) ->
|
||||
{<<"timestamp">>, left};
|
||||
list_users_element(_, column, status, _) ->
|
||||
{<<"status">>, left};
|
||||
list_users_element(_, row, offline, {R, Username, Host, Level}) ->
|
||||
make_command(get_offline_count,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}],
|
||||
[{only, raw_and_value},
|
||||
{result_links,
|
||||
[{value, arg_host, Level, <<"user/", Username/binary, "/queue/">>}]}]);
|
||||
list_users_element(_, row, mam, {R, Username, Host, Level}) ->
|
||||
make_command(get_mam_count,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}],
|
||||
[{only, raw_and_value},
|
||||
{result_links,
|
||||
[{value, arg_host, Level, <<"user/", Username/binary, "/mam/">>}]}]);
|
||||
list_users_element(_, row, roster, {R, Username, Host, Level}) ->
|
||||
make_command(get_roster_count,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}],
|
||||
[{only, raw_and_value},
|
||||
{result_links,
|
||||
[{value, arg_host, Level, <<"user/", Username/binary, "/roster/">>}]}]);
|
||||
list_users_element(_, row, last, {R, Username, Host}) ->
|
||||
[?C(element(1,
|
||||
make_command_raw_value(get_last, R, [{<<"user">>, Username}, {<<"host">>, Host}]))),
|
||||
?C(element(2,
|
||||
make_command_raw_value(get_last,
|
||||
R,
|
||||
[{<<"user">>, Username}, {<<"host">>, Host}])))];
|
||||
list_users_element(_, presentation, offline, R) ->
|
||||
make_command(get_offline_count, R, [], [{only, presentation}]);
|
||||
list_users_element(_, presentation, mam, R) ->
|
||||
make_command(get_mam_count, R, [], [{only, presentation}]);
|
||||
list_users_element(_, presentation, roster, R) ->
|
||||
make_command(get_roster_count, R, [], [{only, presentation}]);
|
||||
list_users_element(_, presentation, last, R) ->
|
||||
make_command(get_last, R, [], [{only, presentation}]).
|
||||
|
||||
list_users_diapason(Host, R, Usernames, N, RegisterEl) ->
|
||||
URLFunc = fun url_func/1,
|
||||
@@ -952,6 +1005,17 @@ user_info(User, Server, #request{q = Query, lang = Lang} = R) ->
|
||||
Res = user_parse_query(User, Server, Query),
|
||||
UserItems = ejabberd_hooks:run_fold(webadmin_user,
|
||||
LServer, [], [User, Server, R]),
|
||||
Lasts = case gen_mod:is_loaded(Server, mod_last) of
|
||||
true ->
|
||||
[make_command(get_last, R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[]),
|
||||
make_command(set_last, R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[])];
|
||||
false ->
|
||||
[]
|
||||
end,
|
||||
[?XC(<<"h1">>, (str:translate_and_format(Lang, ?T("User ~ts"),
|
||||
[us_to_list(US)])))]
|
||||
++
|
||||
@@ -968,13 +1032,8 @@ user_info(User, Server, #request{q = Query, lang = Lang} = R) ->
|
||||
[{result_links, [{node, node, 4, <<>>}]}]),
|
||||
make_command(change_password, R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[{style, danger}]),
|
||||
make_command(get_last, R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[]),
|
||||
make_command(set_last, R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[])] ++
|
||||
[{style, danger}])] ++
|
||||
Lasts ++
|
||||
UserItems ++
|
||||
[?P,
|
||||
make_command(unregister, R,
|
||||
@@ -1180,7 +1239,7 @@ pretty_print_xml({xmlcdata, CData}, Prefix) ->
|
||||
($\n) -> true;
|
||||
($\t) -> true;
|
||||
($\v) -> true;
|
||||
($ ) -> true;
|
||||
($\s) -> true;
|
||||
(_) -> false
|
||||
end, binary_to_list(CData)),
|
||||
if IsBlankCData ->
|
||||
@@ -1667,7 +1726,7 @@ make_command_raw_value(Name, Request, BaseArguments) ->
|
||||
raw_value |
|
||||
raw_and_value} |
|
||||
{input_name_append, [binary()]} |
|
||||
{force_execution, boolean()} |
|
||||
{force_execution, boolean() | undefined} |
|
||||
{table_options, {PageSize :: integer(), RemainingPath :: [binary()]}} |
|
||||
{result_named, boolean()} |
|
||||
{result_links,
|
||||
@@ -1678,7 +1737,7 @@ make_command_raw_value(Name, Request, BaseArguments) ->
|
||||
{style, normal | danger}.
|
||||
make_command2(Name, Request, BaseArguments, Options) ->
|
||||
Only = proplists:get_value(only, Options, all),
|
||||
ForceExecution = proplists:get_value(force_execution, Options, false),
|
||||
ForceExecution = proplists:get_value(force_execution, Options, undefined),
|
||||
InputNameAppend = proplists:get_value(input_name_append, Options, []),
|
||||
Resultnamed = proplists:get_value(result_named, Options, false),
|
||||
ResultLinks = proplists:get_value(result_links, Options, []),
|
||||
@@ -1732,6 +1791,8 @@ make_command2(Name,
|
||||
case {ForceExecution, ResultFormatApi} of
|
||||
{true, _} ->
|
||||
auto;
|
||||
{false, _} ->
|
||||
manual;
|
||||
{_, {_, rescode}} ->
|
||||
manual;
|
||||
{_, {_, restuple}} ->
|
||||
|
||||
@@ -256,9 +256,9 @@ ws_loop(Codec, Socket, WsHandleLoopPid, SockMod, Shaper) ->
|
||||
"with pid ~p",
|
||||
[self()]),
|
||||
websocket_close(Codec, Socket, WsHandleLoopPid, SockMod, 1001); % going away
|
||||
_Ignored ->
|
||||
Ignored ->
|
||||
?WARNING_MSG("Received unexpected message, ignoring: ~p",
|
||||
[_Ignored]),
|
||||
[Ignored]),
|
||||
ws_loop(Codec, Socket, WsHandleLoopPid,
|
||||
SockMod, Shaper)
|
||||
end.
|
||||
|
||||
@@ -79,6 +79,11 @@ handle_cast(Msg, State) ->
|
||||
?WARNING_MSG("Unexpected cast: ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({'ETS-TRANSFER', Table, Process, Module}, State) ->
|
||||
?DEBUG("ejabberd now controls ETS table ~p from process ~p for module ~p",
|
||||
[Table, Process, Module]),
|
||||
{noreply, State};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
?WARNING_MSG("Unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
+5
-70
@@ -1425,8 +1425,10 @@ set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
|
||||
show = misc:binary_to_atom(Show),
|
||||
priority = Priority,
|
||||
sub_els = []},
|
||||
Ref = ejabberd_sm:get_session_pid(User, Host, Resource),
|
||||
ejabberd_c2s:set_presence(Ref, Pres).
|
||||
case ejabberd_sm:get_session_pid(User, Host, Resource) of
|
||||
none -> throw({error, "User session not found"});
|
||||
Ref -> ejabberd_c2s:set_presence(Ref, Pres)
|
||||
end.
|
||||
|
||||
user_sessions_info(User, Host) ->
|
||||
lists:filtermap(fun(Resource) ->
|
||||
@@ -2204,13 +2206,7 @@ web_page_host(Acc, _, _) ->
|
||||
%%% HostUser
|
||||
|
||||
web_menu_hostuser(Acc, _Host, _Username, _Lang) ->
|
||||
Acc
|
||||
++ [{<<"auth">>, <<"Authentication">>},
|
||||
{<<"mam">>, <<"MAM">>},
|
||||
{<<"privacy">>, <<"Privacy Lists">>},
|
||||
{<<"private">>, <<"Private XML Storage">>},
|
||||
{<<"session">>, <<"Sessions">>},
|
||||
{<<"vcard">>, <<"vCard">>}].
|
||||
Acc ++ [{<<"auth">>, <<"Authentication">>}, {<<"session">>, <<"Sessions">>}].
|
||||
|
||||
web_page_hostuser(_, Host, User, #request{path = [<<"auth">>]} = R) ->
|
||||
Ban = make_command(ban_account,
|
||||
@@ -2240,26 +2236,6 @@ web_page_hostuser(_, Host, User, #request{path = [<<"auth">>]} = R) ->
|
||||
[{<<"user">>, User}, {<<"host">>, Host}],
|
||||
[{style, danger}])],
|
||||
{stop, Res};
|
||||
web_page_hostuser(_, Host, User, #request{path = [<<"mam">>]} = R) ->
|
||||
Res = ?H1GL(<<"MAM">>, <<"modules/#mod_mam">>, <<"mod_mam">>)
|
||||
++ [make_command(remove_mam_for_user,
|
||||
R,
|
||||
[{<<"user">>, User}, {<<"host">>, Host}],
|
||||
[{style, danger}]),
|
||||
make_command(remove_mam_for_user_with_peer,
|
||||
R,
|
||||
[{<<"user">>, User}, {<<"host">>, Host}],
|
||||
[{style, danger}])],
|
||||
{stop, Res};
|
||||
web_page_hostuser(_, Host, User, #request{path = [<<"privacy">>]} = R) ->
|
||||
Res = ?H1GL(<<"Privacy Lists">>, <<"modules/#mod_privacy">>, <<"mod_privacy">>)
|
||||
++ [make_command(privacy_set, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Res};
|
||||
web_page_hostuser(_, Host, User, #request{path = [<<"private">>]} = R) ->
|
||||
Res = ?H1GL(<<"Private XML Storage">>, <<"modules/#mod_private">>, <<"mod_private">>)
|
||||
++ [make_command(private_set, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(private_get, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Res};
|
||||
web_page_hostuser(_, Host, User, #request{path = [<<"session">>]} = R) ->
|
||||
Head = [?XC(<<"h1">>, <<"Sessions">>), ?BR],
|
||||
Set = [make_command(resource_num, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
@@ -2278,47 +2254,6 @@ web_page_hostuser(_, Host, User, #request{path = [<<"session">>]} = R) ->
|
||||
make_command(get_presence, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(num_resources, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Head ++ Get ++ Set};
|
||||
web_page_hostuser(_, Host, User, #request{path = [<<"vcard">>]} = R) ->
|
||||
Head = ?H1GL(<<"vCard">>, <<"modules/#mod_vcard">>, <<"mod_vcard">>),
|
||||
Set = [make_command(set_nickname, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(set_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(set_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(set_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
timer:sleep(100), % setting vcard takes a while, let's delay the get commands
|
||||
FieldNames = [<<"VERSION">>, <<"FN">>, <<"NICKNAME">>, <<"BDAY">>],
|
||||
FieldNames2 =
|
||||
[{<<"N">>, <<"FAMILY">>},
|
||||
{<<"N">>, <<"GIVEN">>},
|
||||
{<<"N">>, <<"MIDDLE">>},
|
||||
{<<"ADR">>, <<"CTRY">>},
|
||||
{<<"ADR">>, <<"LOCALITY">>},
|
||||
{<<"EMAIL">>, <<"USERID">>}],
|
||||
Get = [make_command(get_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
?XE(<<"blockquote">>,
|
||||
[make_table([<<"name">>, <<"value">>],
|
||||
[{?C(FieldName),
|
||||
make_command(get_vcard,
|
||||
R,
|
||||
[{<<"user">>, User},
|
||||
{<<"host">>, Host},
|
||||
{<<"name">>, FieldName}],
|
||||
[{only, value}])}
|
||||
|| FieldName <- FieldNames])]),
|
||||
make_command(get_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
?XE(<<"blockquote">>,
|
||||
[make_table([<<"name">>, <<"subname">>, <<"value">>],
|
||||
[{?C(FieldName),
|
||||
?C(FieldSubName),
|
||||
make_command(get_vcard2,
|
||||
R,
|
||||
[{<<"user">>, User},
|
||||
{<<"host">>, Host},
|
||||
{<<"name">>, FieldName},
|
||||
{<<"subname">>, FieldSubName}],
|
||||
[{only, value}])}
|
||||
|| {FieldName, FieldSubName} <- FieldNames2])]),
|
||||
make_command(get_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Head ++ Get ++ Set};
|
||||
web_page_hostuser(Acc, _, _, _) ->
|
||||
Acc.
|
||||
|
||||
|
||||
@@ -494,9 +494,6 @@ announce_commands(From, To,
|
||||
{error, xmpp:err_bad_request(Txt, Lang)}
|
||||
end.
|
||||
|
||||
-define(TVFIELD(Type, Var, Val),
|
||||
#xdata_field{type = Type, var = Var, values = vvaluel(Val)}).
|
||||
|
||||
vvaluel(Val) ->
|
||||
case Val of
|
||||
<<>> -> [];
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
-export([start/2, stop/1, reload/3, mod_doc/0,
|
||||
depends/2, mod_opt_type/1, mod_options/1]).
|
||||
|
||||
-export([filter_packet/1, filter_offline_msg/1, filter_subscription/2]).
|
||||
-export([filter_packet/1, filter_offline_msg/1, filter_subscription/2,
|
||||
get_sm_features/5]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
@@ -40,13 +41,17 @@
|
||||
|
||||
-define(SETS, gb_sets).
|
||||
|
||||
-define(NS_BLOCK_STRANGERS, <<"urn:ejabberd:block-strangers">>).
|
||||
|
||||
-type c2s_state() :: ejabberd_c2s:state().
|
||||
|
||||
%%%===================================================================
|
||||
%%% Callbacks and hooks
|
||||
%%%===================================================================
|
||||
start(_Host, _Opts) ->
|
||||
{ok, [{hook, user_receive_packet, filter_packet, 25},
|
||||
{ok, [{hook, disco_local_features, get_sm_features, 50},
|
||||
{hook, disco_sm_features, get_sm_features, 50},
|
||||
{hook, user_receive_packet, filter_packet, 25},
|
||||
{hook, roster_in_subscription, filter_subscription, 25},
|
||||
{hook, offline_message_hook, filter_offline_msg, 25}]}.
|
||||
|
||||
@@ -56,6 +61,16 @@ stop(_Host) ->
|
||||
reload(_Host, _NewOpts, _OldOpts) ->
|
||||
ok.
|
||||
|
||||
get_sm_features(Acc, _From, _To, <<"">>, _Lang) ->
|
||||
Features = case Acc of
|
||||
{result, I} -> I;
|
||||
_ -> []
|
||||
end,
|
||||
{result, [?NS_BLOCK_STRANGERS | Features]};
|
||||
|
||||
get_sm_features(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
-spec filter_packet({stanza(), c2s_state()}) -> {stanza(), c2s_state()} |
|
||||
{stop, {drop, c2s_state()}}.
|
||||
filter_packet({#message{from = From} = Msg, State} = Acc) ->
|
||||
|
||||
+2
-2
@@ -74,8 +74,8 @@ process([], #request{method = 'GET', data = <<>>}) ->
|
||||
{200, ?HEADER(?CT_XML), get_human_html_xmlel()};
|
||||
process([], #request{method = 'OPTIONS', data = <<>>}) ->
|
||||
{200, ?OPTIONS_HEADER, []};
|
||||
process(_Path, _Request) ->
|
||||
?DEBUG("Bad Request: ~p", [_Request]),
|
||||
process(_Path, Request) ->
|
||||
?DEBUG("Bad Request: ~p", [Request]),
|
||||
{400, ?HEADER(?CT_XML),
|
||||
#xmlel{name = <<"h1">>, attrs = [],
|
||||
children = [{xmlcdata, <<"400 Bad Request">>}]}}.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_bosh_sql.erl
|
||||
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% Purpose :
|
||||
%%% Purpose :
|
||||
%%% Created : 28 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
|
||||
@@ -145,10 +145,10 @@ c2s_session_resumed(State) ->
|
||||
c2s_session_opened(State) ->
|
||||
maps:remove(carboncopy, State).
|
||||
|
||||
c2s_inline_features({Sasl, Bind} = Acc, Host) ->
|
||||
c2s_inline_features({Sasl, Bind, Extra} = Acc, Host) ->
|
||||
case gen_mod:is_loaded(Host, ?MODULE) of
|
||||
true ->
|
||||
{Sasl, [#bind2_feature{var = ?NS_CARBONS_2} | Bind]};
|
||||
{Sasl, [#bind2_feature{var = ?NS_CARBONS_2} | Bind], Extra};
|
||||
false ->
|
||||
Acc
|
||||
end.
|
||||
|
||||
@@ -139,8 +139,8 @@ handle_call(Request, From, State) ->
|
||||
?WARNING_MSG("Unexpected call from ~p: ~p", [From, Request]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_cast(_Msg, State) ->
|
||||
?WARNING_MSG("Unexpected cast = ~p", [_Msg]),
|
||||
handle_cast(Msg, State) ->
|
||||
?WARNING_MSG("Unexpected cast = ~p", [Msg]),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(clean, State) ->
|
||||
@@ -151,8 +151,8 @@ handle_info(clean, State) ->
|
||||
ets:fun2ms(fun({_, _, UnbanTS, _}) -> UnbanTS =< Now end)),
|
||||
erlang:send_after(?CLEAN_INTERVAL, self(), clean),
|
||||
{noreply, State};
|
||||
handle_info(_Info, State) ->
|
||||
?WARNING_MSG("Unexpected info = ~p", [_Info]),
|
||||
handle_info(Info, State) ->
|
||||
?WARNING_MSG("Unexpected info = ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{host = Host}) ->
|
||||
|
||||
@@ -542,7 +542,7 @@ log(Call, Args, IP) ->
|
||||
?INFO_MSG("API call ~ts ~p (~p)", [Call, hide_sensitive_args(Args), IP]).
|
||||
|
||||
hide_sensitive_args(Args=[_H|_T]) ->
|
||||
lists:map( fun({<<"password">>, Password}) -> {<<"password">>, ejabberd_config:may_hide_data(Password)};
|
||||
lists:map(fun({<<"password">>, Password}) -> {<<"password">>, ejabberd_config:may_hide_data(Password)};
|
||||
({<<"newpass">>,NewPassword}) -> {<<"newpass">>, ejabberd_config:may_hide_data(NewPassword)};
|
||||
(E) -> E end,
|
||||
Args);
|
||||
|
||||
+154
-4
@@ -38,6 +38,7 @@
|
||||
|
||||
-export([sm_receive_packet/1, user_receive_packet/1, user_send_packet/1,
|
||||
user_send_packet_strip_tag/1, process_iq_v0_2/1, process_iq_v0_3/1,
|
||||
disco_local_features/5,
|
||||
disco_sm_features/5, remove_user/2, remove_room/3, mod_opt_type/1,
|
||||
muc_process_iq/2, muc_filter_message/3, message_is_archived/3,
|
||||
delete_old_messages/2, get_commands_spec/0, msg_to_el/4,
|
||||
@@ -45,13 +46,21 @@
|
||||
mod_options/1, remove_mam_for_user_with_peer/3, remove_mam_for_user/2,
|
||||
is_empty_for_user/2, is_empty_for_room/3, check_create_room/4,
|
||||
process_iq/3, store_mam_message/7, make_id/0, wrap_as_mucsub/2, select/7,
|
||||
get_mam_count/2,
|
||||
webadmin_menu_hostuser/4,
|
||||
webadmin_page_hostuser/4,
|
||||
get_mam_messages/2, webadmin_user/4,
|
||||
delete_old_messages_batch/5, delete_old_messages_status/1, delete_old_messages_abort/1,
|
||||
remove_message_from_archive/3]).
|
||||
|
||||
-import(ejabberd_web_admin, [make_command/4, make_command/2]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("mod_muc_room.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
-include("ejabberd_web_admin.hrl").
|
||||
-include("mod_mam.hrl").
|
||||
-include("translate.hrl").
|
||||
|
||||
@@ -139,6 +148,8 @@ start(Host, Opts) ->
|
||||
muc_filter_message, 50),
|
||||
ejabberd_hooks:add(muc_process_iq, Host, ?MODULE,
|
||||
muc_process_iq, 50),
|
||||
ejabberd_hooks:add(disco_local_features, Host, ?MODULE,
|
||||
disco_local_features, 50),
|
||||
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE,
|
||||
disco_sm_features, 50),
|
||||
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
||||
@@ -149,6 +160,12 @@ start(Host, Opts) ->
|
||||
set_room_option, 50),
|
||||
ejabberd_hooks:add(store_mam_message, Host, ?MODULE,
|
||||
store_mam_message, 100),
|
||||
ejabberd_hooks:add(webadmin_menu_hostuser, Host, ?MODULE,
|
||||
webadmin_menu_hostuser, 50),
|
||||
ejabberd_hooks:add(webadmin_page_hostuser, Host, ?MODULE,
|
||||
webadmin_page_hostuser, 50),
|
||||
ejabberd_hooks:add(webadmin_user, Host, ?MODULE,
|
||||
webadmin_user, 50),
|
||||
case mod_mam_opt:assume_mam_usage(Opts) of
|
||||
true ->
|
||||
ejabberd_hooks:add(message_is_archived, Host, ?MODULE,
|
||||
@@ -212,6 +229,8 @@ stop(Host) ->
|
||||
muc_filter_message, 50),
|
||||
ejabberd_hooks:delete(muc_process_iq, Host, ?MODULE,
|
||||
muc_process_iq, 50),
|
||||
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE,
|
||||
disco_local_features, 50),
|
||||
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE,
|
||||
disco_sm_features, 50),
|
||||
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
||||
@@ -222,6 +241,12 @@ stop(Host) ->
|
||||
set_room_option, 50),
|
||||
ejabberd_hooks:delete(store_mam_message, Host, ?MODULE,
|
||||
store_mam_message, 100),
|
||||
ejabberd_hooks:delete(webadmin_menu_hostuser, Host, ?MODULE,
|
||||
webadmin_menu_hostuser, 50),
|
||||
ejabberd_hooks:delete(webadmin_page_hostuser, Host, ?MODULE,
|
||||
webadmin_page_hostuser, 50),
|
||||
ejabberd_hooks:delete(webadmin_user, Host, ?MODULE,
|
||||
webadmin_user, 50),
|
||||
case mod_mam_opt:assume_mam_usage(Host) of
|
||||
true ->
|
||||
ejabberd_hooks:delete(message_is_archived, Host, ?MODULE,
|
||||
@@ -592,6 +617,20 @@ parse_query(#mam_query{xdata = #xdata{}} = Query, Lang) ->
|
||||
parse_query(#mam_query{}, _Lang) ->
|
||||
{ok, []}.
|
||||
|
||||
disco_local_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc;
|
||||
disco_local_features(Acc, _From, _To, <<"">>, _Lang) ->
|
||||
Features = case Acc of
|
||||
{result, Fs} -> Fs;
|
||||
empty -> []
|
||||
end,
|
||||
{result, [?NS_MESSAGE_RETRACT | Features]};
|
||||
disco_local_features(empty, _From, _To, _Node, Lang) ->
|
||||
Txt = ?T("No features available"),
|
||||
{error, xmpp:err_item_not_found(Txt, Lang)};
|
||||
disco_local_features(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
disco_sm_features(empty, From, To, Node, Lang) ->
|
||||
disco_sm_features({result, []}, From, To, Node, Lang);
|
||||
disco_sm_features({result, OtherFeatures},
|
||||
@@ -614,6 +653,52 @@ message_is_archived(false, #{lserver := LServer}, Pkt) ->
|
||||
false
|
||||
end.
|
||||
|
||||
%%%
|
||||
%%% Commands
|
||||
%%%
|
||||
|
||||
%% @format-begin
|
||||
|
||||
get_mam_count(User, Host) ->
|
||||
Jid = jid:make(User, Host),
|
||||
{_, _, Count} = select(Host, Jid, Jid, [], #rsm_set{}, chat, only_count),
|
||||
Count.
|
||||
|
||||
get_mam_messages(User, Host) ->
|
||||
Jid = jid:make(User, Host),
|
||||
{Messages, _, _} = select(Host, Jid, Jid, [], #rsm_set{}, chat, only_messages),
|
||||
format_user_messages(Messages).
|
||||
|
||||
format_user_messages(Messages) ->
|
||||
lists:map(fun({_ID, _IDInt, Fwd}) ->
|
||||
El = hd(Fwd#forwarded.sub_els),
|
||||
FPacket =
|
||||
ejabberd_web_admin:pretty_print_xml(
|
||||
xmpp:encode(El)),
|
||||
SFrom = jid:encode(El#message.from),
|
||||
STo = jid:encode(El#message.to),
|
||||
Time = format_time(Fwd#forwarded.delay#delay.stamp),
|
||||
{Time, SFrom, STo, FPacket}
|
||||
end,
|
||||
Messages).
|
||||
|
||||
format_time(Now) ->
|
||||
{{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(Now),
|
||||
str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
|
||||
[Year, Month, Day, Hour, Minute, Second]).
|
||||
|
||||
webadmin_user(Acc, User, Server, R) ->
|
||||
Acc
|
||||
++ [make_command(get_mam_count,
|
||||
R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[{result_links, [{value, arg_host, 4, <<"user/", User/binary, "/mam/">>}]}])].
|
||||
%% @format-end
|
||||
|
||||
%%%
|
||||
%%% Commands: Purge
|
||||
%%%
|
||||
|
||||
delete_old_messages_batch(Server, Type, Days, BatchSize, Rate) when Type == <<"chat">>;
|
||||
Type == <<"groupchat">>;
|
||||
Type == <<"all">> ->
|
||||
@@ -1487,7 +1572,29 @@ get_jids(Js) ->
|
||||
[jid:tolower(jid:remove_resource(J)) || J <- Js].
|
||||
|
||||
get_commands_spec() ->
|
||||
[#ejabberd_commands{name = delete_old_mam_messages, tags = [purge],
|
||||
[
|
||||
#ejabberd_commands{name = get_mam_count, tags = [mam],
|
||||
desc = "Get number of MAM messages in a local user archive",
|
||||
module = ?MODULE, function = get_mam_count,
|
||||
note = "added in 24.10",
|
||||
policy = user,
|
||||
args = [],
|
||||
result_example = 5,
|
||||
result_desc = "Number",
|
||||
result = {value, integer}},
|
||||
#ejabberd_commands{name = get_mam_messages,
|
||||
tags = [internal, mam],
|
||||
desc = "Get the mam messages",
|
||||
policy = user,
|
||||
module = mod_mam, function = get_mam_messages,
|
||||
args = [],
|
||||
result = {archive, {list, {messages, {tuple, [{time, string},
|
||||
{from, string},
|
||||
{to, string},
|
||||
{packet, string}
|
||||
]}}}}},
|
||||
|
||||
#ejabberd_commands{name = delete_old_mam_messages, tags = [mam, purge],
|
||||
desc = "Delete MAM messages older than DAYS",
|
||||
longdesc = "Valid message TYPEs: "
|
||||
"`chat`, `groupchat`, `all`.",
|
||||
@@ -1497,7 +1604,7 @@ get_commands_spec() ->
|
||||
args_example = [<<"all">>, 31],
|
||||
args = [{type, binary}, {days, integer}],
|
||||
result = {res, rescode}},
|
||||
#ejabberd_commands{name = delete_old_mam_messages_batch, tags = [purge],
|
||||
#ejabberd_commands{name = delete_old_mam_messages_batch, tags = [mam, purge],
|
||||
desc = "Delete MAM messages older than DAYS",
|
||||
note = "added in 22.05",
|
||||
longdesc = "Valid message TYPEs: "
|
||||
@@ -1513,7 +1620,7 @@ get_commands_spec() ->
|
||||
result = {res, restuple},
|
||||
result_desc = "Result tuple",
|
||||
result_example = {ok, <<"Removal of 5000 messages in progress">>}},
|
||||
#ejabberd_commands{name = delete_old_mam_messages_status, tags = [purge],
|
||||
#ejabberd_commands{name = delete_old_mam_messages_status, tags = [mam, purge],
|
||||
desc = "Status of delete old MAM messages operation",
|
||||
note = "added in 22.05",
|
||||
module = ?MODULE, function = delete_old_messages_status,
|
||||
@@ -1523,7 +1630,7 @@ get_commands_spec() ->
|
||||
result = {status, string},
|
||||
result_desc = "Status test",
|
||||
result_example = "Operation in progress, delete 5000 messages"},
|
||||
#ejabberd_commands{name = abort_delete_old_mam_messages, tags = [purge],
|
||||
#ejabberd_commands{name = abort_delete_old_mam_messages, tags = [mam, purge],
|
||||
desc = "Abort currently running delete old MAM messages operation",
|
||||
note = "added in 22.05",
|
||||
module = ?MODULE, function = delete_old_messages_abort,
|
||||
@@ -1555,6 +1662,49 @@ get_commands_spec() ->
|
||||
result_example = {ok, <<"MAM archive removed">>}}
|
||||
].
|
||||
|
||||
|
||||
%%%
|
||||
%%% WebAdmin
|
||||
%%%
|
||||
|
||||
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
|
||||
Acc ++ [{<<"mam">>, <<"MAM">>},
|
||||
{<<"mam-archive">>, <<"MAM Archive">>}].
|
||||
|
||||
webadmin_page_hostuser(_, Host, U,
|
||||
#request{us = _US, path = [<<"mam">>]} = R) ->
|
||||
Res = ?H1GL(<<"MAM">>, <<"modules/#mod_mam">>, <<"mod_mam">>)
|
||||
++ [make_command(get_mam_count,
|
||||
R,
|
||||
[{<<"user">>, U}, {<<"host">>, Host}],
|
||||
[{result_links,
|
||||
[{value, arg_host, 5, <<"user/", U/binary, "/mam-archive/">>}]}]),
|
||||
make_command(remove_mam_for_user,
|
||||
R,
|
||||
[{<<"user">>, U}, {<<"host">>, Host}],
|
||||
[{style, danger}]),
|
||||
make_command(remove_mam_for_user_with_peer,
|
||||
R,
|
||||
[{<<"user">>, U}, {<<"host">>, Host}],
|
||||
[{style, danger}])],
|
||||
{stop, Res};
|
||||
webadmin_page_hostuser(_, Host, U,
|
||||
#request{us = _US, path = [<<"mam-archive">> | RPath],
|
||||
lang = Lang} = R) ->
|
||||
PageTitle =
|
||||
str:translate_and_format(Lang, ?T("~ts's MAM Archive"), [jid:encode({U, Host, <<"">>})]),
|
||||
Head = ?H1GL(PageTitle, <<"modules/#mod_mam">>, <<"mod_mam">>),
|
||||
Res = make_command(get_mam_messages, R, [{<<"user">>, U},
|
||||
{<<"host">>, Host}],
|
||||
[{table_options, {10, RPath}},
|
||||
{result_links, [{packet, paragraph, 1, <<"">>}]}]),
|
||||
{stop, Head ++ [Res]};
|
||||
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
|
||||
|
||||
%%%
|
||||
%%% Documentation
|
||||
%%%
|
||||
|
||||
mod_opt_type(compress_xml) ->
|
||||
econf:bool();
|
||||
mod_opt_type(assume_mam_usage) ->
|
||||
|
||||
@@ -386,8 +386,8 @@ process([<<"federation">>, <<"v2">>, <<"send_join">>, RoomID, EventID],
|
||||
{result, HTTPResult} ->
|
||||
HTTPResult
|
||||
end;
|
||||
process(_Path, _Request) ->
|
||||
?DEBUG("matrix 404: ~p~n~p~n", [_Path, _Request]),
|
||||
process(Path, Request) ->
|
||||
?DEBUG("matrix 404: ~p~n~p~n", [Path, Request]),
|
||||
ejabberd_web:error(not_found).
|
||||
|
||||
preprocess_federation_request(Request) ->
|
||||
@@ -869,17 +869,17 @@ mod_opt_type(key) ->
|
||||
crypto:generate_key(eddsa, ed25519, Key2)
|
||||
end;
|
||||
mod_opt_type(matrix_id_as_jid) ->
|
||||
econf:bool();
|
||||
mod_opt_type(persist) ->
|
||||
econf:bool().
|
||||
|
||||
-spec mod_options(binary()) -> [{key, {binary(), binary()}} |
|
||||
{atom(), any()}].
|
||||
|
||||
mod_options(Host) ->
|
||||
[{matrix_domain, Host},
|
||||
{host, <<"matrix.", Host/binary>>},
|
||||
{key_name, <<"">>},
|
||||
{key, {<<"">>, <<"">>}},
|
||||
{matrix_id_as_jid, false},
|
||||
{persist, false}].
|
||||
{matrix_id_as_jid, false}].
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
-export([key_name/1]).
|
||||
-export([matrix_domain/1]).
|
||||
-export([matrix_id_as_jid/1]).
|
||||
-export([persist/1]).
|
||||
|
||||
-spec host(gen_mod:opts() | global | binary()) -> binary().
|
||||
host(Opts) when is_map(Opts) ->
|
||||
@@ -16,7 +15,7 @@ host(Opts) when is_map(Opts) ->
|
||||
host(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_matrix_gw, host).
|
||||
|
||||
-spec key(gen_mod:opts() | global | binary()) -> any().
|
||||
-spec key(gen_mod:opts() | global | binary()) -> {binary(),binary()}.
|
||||
key(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(key, Opts);
|
||||
key(Host) ->
|
||||
@@ -40,9 +39,3 @@ matrix_id_as_jid(Opts) when is_map(Opts) ->
|
||||
matrix_id_as_jid(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_matrix_gw, matrix_id_as_jid).
|
||||
|
||||
-spec persist(gen_mod:opts() | global | binary()) -> boolean().
|
||||
persist(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(persist, Opts);
|
||||
persist(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_matrix_gw, persist).
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
-export([init/1, terminate/3, code_change/4, callback_mode/0]).
|
||||
-export([handle_event/4]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
@@ -35,8 +35,6 @@
|
||||
-export([init/1, terminate/3, code_change/4, callback_mode/0]).
|
||||
-export([handle_event/4]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
-include_lib("kernel/include/inet.hrl").
|
||||
|
||||
@@ -142,8 +142,8 @@ mod_opt_type(servers) ->
|
||||
econf:options(
|
||||
#{
|
||||
certfile => econf:pem()
|
||||
}, [{return, map}])
|
||||
)}, [{return, map}]),
|
||||
}, [{return, map}]))},
|
||||
[{return, map}]),
|
||||
[{return, map}]),
|
||||
fun(Servers) ->
|
||||
maps:fold(
|
||||
|
||||
@@ -620,9 +620,6 @@ web_menu_host(Acc, _Host, Lang) ->
|
||||
%%---------------
|
||||
%% Web Admin Page
|
||||
|
||||
-define(TDTD(L, N),
|
||||
?XE(<<"tr">>, [?XCT(<<"td">>, L), ?XC(<<"td">>, integer_to_binary(N))])).
|
||||
|
||||
web_page_main(_, #request{path = [<<"muc">>], lang = Lang} = R) ->
|
||||
PageTitle = translate:translate(Lang, ?T("Multi-User Chat")),
|
||||
Title = ?H1GL(PageTitle, <<"modules/#mod_muc">>, <<"mod_muc">>),
|
||||
@@ -1474,7 +1471,7 @@ get_room_occupants(Pid) ->
|
||||
|
||||
get_room_occupants_number(Room, Host) ->
|
||||
case get_room_pid_validate(Room, Host, <<"name">>, <<"service">>) of
|
||||
{Pid, _, _} when is_pid(Pid )->
|
||||
{Pid, _, _} when is_pid(Pid)->
|
||||
{ok, #{occupants_number := N}} = mod_muc_room:get_info(Pid),
|
||||
N;
|
||||
_ ->
|
||||
@@ -1504,8 +1501,10 @@ send_direct_invitation(RoomName, RoomService, Password, Reason, UsersStrings) ->
|
||||
get_users_to_invite(RoomJid, UsersStrings) ->
|
||||
OccupantsTuples = get_room_occupants(RoomJid#jid.luser,
|
||||
RoomJid#jid.lserver),
|
||||
OccupantsJids = [jid:decode(JidString)
|
||||
|| {JidString, _Nick, _} <- OccupantsTuples],
|
||||
OccupantsJids = try [jid:decode(JidString)
|
||||
|| {JidString, _Nick, _} <- OccupantsTuples]
|
||||
catch _:{bad_jid, _} -> throw({error, "Malformed JID of invited user"})
|
||||
end,
|
||||
lists:filtermap(
|
||||
fun(UserString) ->
|
||||
UserJid = jid:decode(UserString),
|
||||
|
||||
@@ -540,7 +540,7 @@ normal_state({route, <<"">>,
|
||||
case NewStateData of
|
||||
stop ->
|
||||
Conf = StateData#state.config,
|
||||
{stop, normal, StateData#state{config = Conf#config{persistent = false}}};
|
||||
{stop, normal, StateData#state{config = Conf#config{persistent = {destroying, Conf#config.persistent}}}};
|
||||
_ when NewStateData#state.just_created ->
|
||||
close_room_if_temporary_and_empty(NewStateData);
|
||||
_ ->
|
||||
@@ -736,7 +736,7 @@ handle_event({destroy, Reason}, _StateName,
|
||||
[jid:encode(StateData#state.jid), Reason]),
|
||||
add_to_log(room_existence, destroyed, StateData),
|
||||
Conf = StateData#state.config,
|
||||
{stop, shutdown, StateData#state{config = Conf#config{persistent = false}}};
|
||||
{stop, shutdown, StateData#state{config = Conf#config{persistent = {destroying, Conf#config.persistent}}}};
|
||||
handle_event(destroy, StateName, StateData) ->
|
||||
?INFO_MSG("Destroyed MUC room ~ts",
|
||||
[jid:encode(StateData#state.jid)]),
|
||||
@@ -856,7 +856,7 @@ handle_sync_event({muc_unsubscribe, From}, _From, StateName,
|
||||
from = From, sub_els = [#muc_unsubscribe{}]},
|
||||
case process_iq_mucsub(From, IQ, StateData) of
|
||||
{result, _, stop} ->
|
||||
{stop, normal, StateData#state{config = Conf#config{persistent = false}}};
|
||||
{stop, normal, StateData#state{config = Conf#config{persistent = {destroying, Conf#config.persistent}}}};
|
||||
{result, _, NewState} ->
|
||||
{reply, ok, StateName, NewState};
|
||||
{ignore, NewState} ->
|
||||
@@ -1015,8 +1015,10 @@ terminate(Reason, _StateName,
|
||||
_ ->
|
||||
add_to_log(room_existence, stopped, StateData),
|
||||
case (StateData#state.config)#config.persistent of
|
||||
false ->
|
||||
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host]);
|
||||
false ->
|
||||
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host, false]);
|
||||
{destroying, Persistent} ->
|
||||
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host, Persistent]);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
|
||||
@@ -46,7 +46,7 @@ start(Host, _Opts) ->
|
||||
gen_server:start({local, gen_mod:get_module_proc(Host, ?MODULE)}, ?MODULE, [Host], []).
|
||||
|
||||
stop(Host) ->
|
||||
gen_server:stop({local, gen_mod:get_module_proc(Host, ?MODULE)}).
|
||||
gen_server:stop(gen_mod:get_module_proc(Host, ?MODULE)).
|
||||
|
||||
init([Host]) ->
|
||||
ejabberd_mnesia:create(?MODULE, muc_rtbl,
|
||||
|
||||
+3
-1
@@ -1002,7 +1002,9 @@ get_queue_length(LUser, LServer) ->
|
||||
count_offline_messages(LUser, LServer).
|
||||
|
||||
webadmin_user(Acc, User, Server, R) ->
|
||||
Acc ++ [make_command(get_offline_count, R, [{<<"user">>, User}, {<<"host">>, Server}], [])].
|
||||
Acc ++ [make_command(get_offline_count, R, [{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[{result_links, [{value, arg_host, 4, <<"user/", User/binary, "/queue/">>}]}]
|
||||
)].
|
||||
|
||||
%%%
|
||||
%%%
|
||||
|
||||
@@ -217,7 +217,7 @@ need_transform(_) ->
|
||||
|
||||
transform({offline_msg, {U, S}, Timestamp, Expire, From, To, _, Packet}) ->
|
||||
#offline_msg{us = {U, S}, timestamp = Timestamp, expire = Expire,
|
||||
from = From ,to = To, packet = Packet};
|
||||
from = From, to = To, packet = Packet};
|
||||
transform(#offline_msg{us = {U, S}, from = From, to = To,
|
||||
packet = El} = R) ->
|
||||
R#offline_msg{us = {iolist_to_binary(U), iolist_to_binary(S)},
|
||||
|
||||
@@ -127,8 +127,8 @@ remove_old_messages(Days, LServer) ->
|
||||
of
|
||||
{updated, N} ->
|
||||
?INFO_MSG("~p message(s) deleted from offline spool", [N]);
|
||||
_Error ->
|
||||
?ERROR_MSG("Cannot delete message in offline spool: ~p", [_Error])
|
||||
Error ->
|
||||
?ERROR_MSG("Cannot delete message in offline spool: ~p", [Error])
|
||||
end,
|
||||
{atomic, ok}.
|
||||
|
||||
|
||||
@@ -40,8 +40,14 @@
|
||||
import_start/2, import_stop/2, import/5, import_info/0,
|
||||
mod_opt_type/1, mod_options/1, depends/2]).
|
||||
|
||||
-export([webadmin_menu_hostuser/4, webadmin_page_hostuser/4]).
|
||||
|
||||
-import(ejabberd_web_admin, [make_command/4, make_command/2]).
|
||||
|
||||
-include("logger.hrl").
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
-include("ejabberd_web_admin.hrl").
|
||||
-include("mod_privacy.hrl").
|
||||
-include("translate.hrl").
|
||||
|
||||
@@ -78,6 +84,8 @@ start(Host, Opts) ->
|
||||
{hook, user_send_packet, user_send_packet, 50},
|
||||
{hook, privacy_check_packet, check_packet, 50},
|
||||
{hook, remove_user, remove_user, 50},
|
||||
{hook, webadmin_menu_hostuser, webadmin_menu_hostuser, 50},
|
||||
{hook, webadmin_page_hostuser, webadmin_page_hostuser, 50},
|
||||
{iq_handler, ejabberd_sm, ?NS_PRIVACY, process_iq}]}.
|
||||
|
||||
stop(_Host) ->
|
||||
@@ -840,6 +848,24 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
%%%
|
||||
%%% WebAdmin
|
||||
%%%
|
||||
|
||||
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
|
||||
Acc ++ [{<<"privacy">>, <<"Privacy Lists">>}].
|
||||
|
||||
webadmin_page_hostuser(_, Host, User,
|
||||
#request{us = _US, path = [<<"privacy">>]} = R) ->
|
||||
Res = ?H1GL(<<"Privacy Lists">>, <<"modules/#mod_privacy">>, <<"mod_privacy">>)
|
||||
++ [make_command(privacy_set, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Res};
|
||||
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
|
||||
|
||||
%%%
|
||||
%%% Documentation
|
||||
%%%
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
|
||||
@@ -41,10 +41,16 @@
|
||||
|
||||
-export([get_commands_spec/0, bookmarks_to_pep/2]).
|
||||
|
||||
-export([webadmin_menu_hostuser/4, webadmin_page_hostuser/4]).
|
||||
|
||||
-import(ejabberd_web_admin, [make_command/4, make_command/2]).
|
||||
|
||||
-include("logger.hrl").
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("mod_private.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
-include("ejabberd_web_admin.hrl").
|
||||
-include("translate.hrl").
|
||||
-include("pubsub.hrl").
|
||||
|
||||
@@ -71,6 +77,8 @@ start(Host, Opts) ->
|
||||
{hook, pubsub_publish_item, pubsub_publish_item, 50},
|
||||
{hook, pubsub_delete_item, pubsub_delete_item, 50},
|
||||
{hook, pubsub_tree_call, pubsub_tree_call, 50},
|
||||
{hook, webadmin_menu_hostuser, webadmin_menu_hostuser, 50},
|
||||
{hook, webadmin_page_hostuser, webadmin_page_hostuser, 50},
|
||||
{iq_handler, ejabberd_sm, ?NS_PRIVATE, process_sm_iq}]}.
|
||||
|
||||
stop(Host) ->
|
||||
@@ -544,6 +552,21 @@ bookmarks_to_pep(User, Server) ->
|
||||
{error, <<"Cannot retrieve bookmarks from private XML storage">>}
|
||||
end.
|
||||
|
||||
%%%===================================================================
|
||||
%%% WebAdmin
|
||||
%%%===================================================================
|
||||
|
||||
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
|
||||
Acc ++ [{<<"private">>, <<"Private XML Storage">>}].
|
||||
|
||||
webadmin_page_hostuser(_, Host, User,
|
||||
#request{path = [<<"private">>]} = R) ->
|
||||
Res = ?H1GL(<<"Private XML Storage">>, <<"modules/#mod_private">>, <<"mod_private">>)
|
||||
++ [make_command(private_set, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(private_get, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Res};
|
||||
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Cache
|
||||
%%%===================================================================
|
||||
|
||||
+188
-9
@@ -25,7 +25,7 @@
|
||||
|
||||
-author('amuhar3@gmail.com').
|
||||
|
||||
-protocol({xep, 356, '0.2.1', '16.09', "", ""}).
|
||||
-protocol({xep, 356, '0.4.1', '24.10', "", ""}).
|
||||
|
||||
-behaviour(gen_server).
|
||||
-behaviour(gen_mod).
|
||||
@@ -37,6 +37,7 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
-export([component_connected/1, component_disconnected/2,
|
||||
component_send_packet/1,
|
||||
roster_access/2, process_message/1,
|
||||
process_presence_out/1, process_presence_in/1]).
|
||||
|
||||
@@ -45,14 +46,17 @@
|
||||
-include("translate.hrl").
|
||||
|
||||
-type roster_permission() :: both | get | set.
|
||||
-type iq_permission() :: both | get | set.
|
||||
-type presence_permission() :: managed_entity | roster.
|
||||
-type message_permission() :: outgoing.
|
||||
-type roster_permissions() :: [{roster_permission(), acl:acl()}].
|
||||
-type iq_permissions() :: [{iq_permission(), acl:acl()}].
|
||||
-type presence_permissions() :: [{presence_permission(), acl:acl()}].
|
||||
-type message_permissions() :: [{message_permission(), acl:acl()}].
|
||||
-type access() :: [{roster, roster_permissions()} |
|
||||
{presence, presence_permissions()} |
|
||||
{message, message_permissions()}].
|
||||
-type access() :: [{roster, roster_permission()} |
|
||||
{iq, [privilege_namespace()]} |
|
||||
{presence, presence_permission()} |
|
||||
{message, message_permission()}].
|
||||
-type permissions() :: #{binary() => access()}.
|
||||
-record(state, {server_host = <<"">> :: binary()}).
|
||||
|
||||
@@ -71,6 +75,10 @@ reload(_Host, _NewOpts, _OldOpts) ->
|
||||
mod_opt_type(roster) ->
|
||||
econf:options(
|
||||
#{both => econf:acl(), get => econf:acl(), set => econf:acl()});
|
||||
mod_opt_type(iq) ->
|
||||
econf:map(
|
||||
econf:binary(),
|
||||
econf:options(#{both => econf:acl(), get => econf:acl(), set => econf:acl()}));
|
||||
mod_opt_type(message) ->
|
||||
econf:options(
|
||||
#{outgoing => econf:acl()});
|
||||
@@ -80,6 +88,7 @@ mod_opt_type(presence) ->
|
||||
|
||||
mod_options(_) ->
|
||||
[{roster, [{both, none}, {get, none}, {set, none}]},
|
||||
{iq, []},
|
||||
{presence, [{managed_entity, none}, {roster, none}]},
|
||||
{message, [{outgoing,none}]}].
|
||||
|
||||
@@ -108,6 +117,7 @@ mod_doc() ->
|
||||
"carefully, only if you trust a component."), "",
|
||||
?T("NOTE: This module is complementary to _`mod_delegation`_, "
|
||||
"but can also be used separately.")],
|
||||
note => "improved in 24.10",
|
||||
opts =>
|
||||
[{roster,
|
||||
#{value => ?T("Options"),
|
||||
@@ -130,6 +140,27 @@ mod_doc() ->
|
||||
desc =>
|
||||
?T("Sets write access to a user's roster. "
|
||||
"The default value is 'none'.")}}]},
|
||||
{iq,
|
||||
#{value => "{Namespace: Options}",
|
||||
desc =>
|
||||
?T("This option defines namespaces and their IQ permissions. "
|
||||
"By default no permissions are given. "
|
||||
"The 'Options' are:")},
|
||||
[{both,
|
||||
#{value => ?T("AccessName"),
|
||||
desc =>
|
||||
?T("Allows sending IQ stanzas of type 'get' and 'set'. "
|
||||
"The default value is 'none'.")}},
|
||||
{get,
|
||||
#{value => ?T("AccessName"),
|
||||
desc =>
|
||||
?T("Allows sending IQ stanzas of type 'get'. "
|
||||
"The default value is 'none'.")}},
|
||||
{set,
|
||||
#{value => ?T("AccessName"),
|
||||
desc =>
|
||||
?T("Allows sending IQ stanzas of type 'set'. "
|
||||
"The default value is 'none'.")}}]},
|
||||
{message,
|
||||
#{value => ?T("Options"),
|
||||
desc =>
|
||||
@@ -164,6 +195,9 @@ mod_doc() ->
|
||||
example =>
|
||||
["modules:",
|
||||
" mod_privilege:",
|
||||
" iq:",
|
||||
" http://jabber.org/protocol/pubsub:",
|
||||
" get: all",
|
||||
" roster:",
|
||||
" get: all",
|
||||
" presence:",
|
||||
@@ -190,6 +224,10 @@ component_disconnected(Host, _Reason) ->
|
||||
gen_server:cast(Proc, {component_disconnected, Host})
|
||||
end, ejabberd_option:hosts()).
|
||||
|
||||
%%
|
||||
%% Message processing
|
||||
%%
|
||||
|
||||
-spec process_message(stanza()) -> stop | ok.
|
||||
process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From,
|
||||
to = #jid{lresource = <<"">>} = To,
|
||||
@@ -212,9 +250,73 @@ process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From,
|
||||
%% Component is disconnected
|
||||
ok
|
||||
end;
|
||||
|
||||
process_message(_Stanza) ->
|
||||
ok.
|
||||
|
||||
%%
|
||||
%% IQ processing
|
||||
%%
|
||||
|
||||
%% @format-begin
|
||||
|
||||
component_send_packet({#iq{from = From,
|
||||
to = #jid{lresource = <<"">>} = To,
|
||||
id = Id,
|
||||
type = Type} =
|
||||
IQ,
|
||||
State})
|
||||
when Type /= error ->
|
||||
Host = From#jid.lserver,
|
||||
ServerHost = To#jid.lserver,
|
||||
Permissions = get_permissions(ServerHost),
|
||||
Result =
|
||||
case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of
|
||||
{{ok, Access}, {ok, EncapType, EncapNs, EncapFrom, EncIq}}
|
||||
when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) ->
|
||||
NsPermissions = proplists:get_value(iq, Access, none),
|
||||
Permission =
|
||||
case lists:keyfind(EncapNs, 2, NsPermissions) of
|
||||
#privilege_namespace{type = AllowedType} ->
|
||||
AllowedType;
|
||||
_ ->
|
||||
none
|
||||
end,
|
||||
case Permission == both
|
||||
orelse Permission == get andalso Type == get
|
||||
orelse Permission == set andalso Type == set
|
||||
of
|
||||
true ->
|
||||
forward_iq(Host, To, Id, EncIq);
|
||||
false ->
|
||||
?INFO_MSG("IQ not forwarded: Permission not granted to ns=~s with type=~p",
|
||||
[EncapNs, Type]),
|
||||
drop
|
||||
end;
|
||||
{error, _} ->
|
||||
%% Component is disconnected
|
||||
?INFO_MSG("IQ not forwarded: Component seems disconnected", []),
|
||||
drop;
|
||||
{_, {ok, 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) ->
|
||||
?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
|
||||
end,
|
||||
{Result, State};
|
||||
component_send_packet(Acc) ->
|
||||
Acc.
|
||||
%% @format-end
|
||||
|
||||
%%
|
||||
%% Roster processing
|
||||
%%
|
||||
|
||||
-spec roster_access({true, iq()} | false, iq()) -> {true, iq()} | false.
|
||||
roster_access({true, _IQ} = Acc, _) ->
|
||||
Acc;
|
||||
@@ -309,6 +411,8 @@ init([Host|_]) ->
|
||||
process_presence_out, 50),
|
||||
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE,
|
||||
process_presence_in, 50),
|
||||
ejabberd_hooks:add(component_send_packet, ?MODULE,
|
||||
component_send_packet, 50),
|
||||
{ok, #state{server_host = Host}}.
|
||||
|
||||
handle_call(Request, From, State) ->
|
||||
@@ -320,22 +424,26 @@ handle_cast({component_connected, Host}, State) ->
|
||||
From = jid:make(ServerHost),
|
||||
To = jid:make(Host),
|
||||
RosterPerm = get_roster_permission(ServerHost, Host),
|
||||
IqNamespaces = get_iq_namespaces(ServerHost, Host),
|
||||
PresencePerm = get_presence_permission(ServerHost, Host),
|
||||
MessagePerm = get_message_permission(ServerHost, Host),
|
||||
if RosterPerm /= none; PresencePerm /= none; MessagePerm /= none ->
|
||||
if RosterPerm /= none; IqNamespaces /= []; PresencePerm /= none; MessagePerm /= none ->
|
||||
Priv = #privilege{perms = [#privilege_perm{access = message,
|
||||
type = MessagePerm},
|
||||
#privilege_perm{access = roster,
|
||||
type = RosterPerm},
|
||||
#privilege_perm{access = iq,
|
||||
namespaces = IqNamespaces},
|
||||
#privilege_perm{access = presence,
|
||||
type = PresencePerm}]},
|
||||
?INFO_MSG("Granting permissions to external "
|
||||
"component '~ts': roster = ~ts, presence = ~ts, "
|
||||
"message = ~ts",
|
||||
[Host, RosterPerm, PresencePerm, MessagePerm]),
|
||||
"message = ~ts,~n iq = ~p",
|
||||
[Host, RosterPerm, PresencePerm, MessagePerm, IqNamespaces]),
|
||||
Msg = #message{from = From, to = To, sub_els = [Priv]},
|
||||
ejabberd_router:route(Msg),
|
||||
Permissions = maps:put(Host, [{roster, RosterPerm},
|
||||
{iq, IqNamespaces},
|
||||
{presence, PresencePerm},
|
||||
{message, MessagePerm}],
|
||||
get_permissions(ServerHost)),
|
||||
@@ -366,6 +474,8 @@ terminate(_Reason, State) ->
|
||||
Host = State#state.server_host,
|
||||
case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of
|
||||
false ->
|
||||
ejabberd_hooks:delete(component_send_packet, ?MODULE,
|
||||
component_send_packet, 50),
|
||||
ejabberd_hooks:delete(component_connected, ?MODULE,
|
||||
component_connected, 50),
|
||||
ejabberd_hooks:delete(component_disconnected, ?MODULE,
|
||||
@@ -391,10 +501,15 @@ code_change(_OldVsn, State, _Extra) ->
|
||||
%%%===================================================================
|
||||
-spec get_permissions(binary()) -> permissions().
|
||||
get_permissions(ServerHost) ->
|
||||
try ets:lookup_element(?MODULE, ServerHost, 2)
|
||||
catch _:badarg -> #{}
|
||||
case ets:lookup(?MODULE, ServerHost) of
|
||||
[] -> #{};
|
||||
[{_, Permissions}] -> Permissions
|
||||
end.
|
||||
|
||||
%%
|
||||
%% Message
|
||||
%%
|
||||
|
||||
-spec forward_message(message()) -> ok.
|
||||
forward_message(#message{to = To} = Msg) ->
|
||||
ServerHost = To#jid.lserver,
|
||||
@@ -435,6 +550,45 @@ forward_message(#message{to = To} = Msg) ->
|
||||
ejabberd_router:route_error(Msg, Err)
|
||||
end.
|
||||
|
||||
%%
|
||||
%% IQ
|
||||
%%
|
||||
|
||||
%% @format-begin
|
||||
|
||||
-spec get_iq_encapsulated_details(iq()) ->
|
||||
{ok, set | get, binary(), jid(), iq()} |
|
||||
{error, Why :: atom(), any(), iq()}.
|
||||
get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) ->
|
||||
Lang = xmpp:get_lang(Msg),
|
||||
try xmpp:try_subtag(Msg, #privileged_iq{}) of
|
||||
#privileged_iq{iq = #iq{type = EncapsulatedType, from = From} = EncIq} ->
|
||||
[IqSubSub] = xmpp:get_els(IqSub),
|
||||
[Element] = xmpp:get_els(IqSubSub),
|
||||
Ns = xmpp:get_ns(Element),
|
||||
{ok, EncapsulatedType, Ns, From, EncIq};
|
||||
_ ->
|
||||
Txt = ?T("No <privileged_iq/> 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.
|
||||
|
||||
-spec forward_iq(binary(), jid(), binary(), iq()) -> iq().
|
||||
forward_iq(Host, ToplevelTo, Id, Iq) ->
|
||||
FromJID = ToplevelTo,
|
||||
NewIq0 = Iq#iq{from = FromJID},
|
||||
xmpp:put_meta(NewIq0, privilege_iq, {Id, Host, FromJID}).
|
||||
%% @format-end
|
||||
|
||||
%%
|
||||
%% Permissions
|
||||
%%
|
||||
|
||||
-spec get_roster_permission(binary(), binary()) -> roster_permission() | none.
|
||||
get_roster_permission(ServerHost, Host) ->
|
||||
Perms = mod_privilege_opt:roster(ServerHost),
|
||||
@@ -451,6 +605,26 @@ get_roster_permission(ServerHost, Host) ->
|
||||
end
|
||||
end.
|
||||
|
||||
-spec get_iq_namespaces(binary(), binary()) -> [privilege_namespace()].
|
||||
get_iq_namespaces(ServerHost, Host) ->
|
||||
NsPerms = mod_privilege_opt:iq(ServerHost),
|
||||
[#privilege_namespace{ns = Ns, type = get_iq_permission(ServerHost, Host, Perms)} || {Ns, Perms} <- NsPerms].
|
||||
|
||||
-spec get_iq_permission(binary(), binary(), [iq_permission()]) -> iq_permission() | none.
|
||||
get_iq_permission(ServerHost, Host, Perms) ->
|
||||
case match_rule(ServerHost, Host, Perms, both) of
|
||||
allow ->
|
||||
both;
|
||||
deny ->
|
||||
Get = match_rule(ServerHost, Host, Perms, get),
|
||||
Set = match_rule(ServerHost, Host, Perms, set),
|
||||
if Get == allow, Set == allow -> both;
|
||||
Get == allow -> get;
|
||||
Set == allow -> set;
|
||||
true -> none
|
||||
end
|
||||
end.
|
||||
|
||||
-spec get_message_permission(binary(), binary()) -> message_permission() | none.
|
||||
get_message_permission(ServerHost, Host) ->
|
||||
Perms = mod_privilege_opt:message(ServerHost),
|
||||
@@ -472,7 +646,12 @@ get_presence_permission(ServerHost, Host) ->
|
||||
end
|
||||
end.
|
||||
|
||||
-ifdef(OTP_BELOW_26).
|
||||
-dialyzer({no_contracts, match_rule/4}).
|
||||
-endif.
|
||||
|
||||
-spec match_rule(binary(), binary(), roster_permissions(), roster_permission()) -> allow | deny;
|
||||
(binary(), binary(), iq_permissions(), iq_permission()) -> allow | deny;
|
||||
(binary(), binary(), presence_permissions(), presence_permission()) -> allow | deny;
|
||||
(binary(), binary(), message_permissions(), message_permission()) -> allow | deny.
|
||||
match_rule(ServerHost, Host, Perms, Type) ->
|
||||
|
||||
@@ -3,10 +3,17 @@
|
||||
|
||||
-module(mod_privilege_opt).
|
||||
|
||||
-export([iq/1]).
|
||||
-export([message/1]).
|
||||
-export([presence/1]).
|
||||
-export([roster/1]).
|
||||
|
||||
-spec iq(gen_mod:opts() | global | binary()) -> [{binary(),[{'both',acl:acl()} | {'get',acl:acl()} | {'set',acl:acl()}]}].
|
||||
iq(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(iq, Opts);
|
||||
iq(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_privilege, iq).
|
||||
|
||||
-spec message(gen_mod:opts() | global | binary()) -> [{'outgoing','none' | acl:acl()}].
|
||||
message(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(message, Opts);
|
||||
|
||||
+13
-19
@@ -265,10 +265,7 @@ init([ServerHost|_]) ->
|
||||
ejabberd_router:register_route(
|
||||
Host, ServerHost, {apply, ?MODULE, route}),
|
||||
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
|
||||
DefaultModule = plugin(Host, hd(Plugins)),
|
||||
DefaultNodeCfg = merge_config(
|
||||
[mod_pubsub_opt:default_node_config(Opts),
|
||||
DefaultModule:options()]),
|
||||
DefaultNodeCfg = mod_pubsub_opt:default_node_config(Opts),
|
||||
lists:foreach(
|
||||
fun(H) ->
|
||||
T = gen_mod:get_module_proc(H, config),
|
||||
@@ -3029,7 +3026,8 @@ broadcast_stanza(Host, _Node, _Nidx, _Type, NodeOptions, SubsByDepth, NotifyType
|
||||
end,
|
||||
lists:foreach(fun(To) ->
|
||||
ejabberd_router:route(
|
||||
xmpp:set_to(StanzaToSend, jid:make(To)))
|
||||
xmpp:set_to(xmpp:put_meta(StanzaToSend, ignore_sm_bounce, true),
|
||||
jid:make(To)))
|
||||
end, LJIDs)
|
||||
end, SubIDsByJID).
|
||||
|
||||
@@ -3051,8 +3049,7 @@ broadcast_stanza({LUser, LServer, LResource}, Publisher, Node, Nidx, Type, NodeO
|
||||
extended_headers([Publisher])),
|
||||
Pred = fun(To) -> delivery_permitted(Owner, To, NodeOptions) end,
|
||||
ejabberd_sm:route(jid:make(LUser, LServer, SenderResource),
|
||||
{pep_message, <<((Node))/binary, "+notify">>, Stanza, Pred}),
|
||||
ejabberd_router:route(xmpp:set_to(Stanza, jid:make(LUser, LServer)));
|
||||
{pep_message, <<((Node))/binary, "+notify">>, Stanza, Pred});
|
||||
broadcast_stanza(Host, _Publisher, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) ->
|
||||
broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM).
|
||||
|
||||
@@ -3369,22 +3366,19 @@ get_option(Options, Var, Def) ->
|
||||
|
||||
-spec node_options(host(), binary()) -> [{atom(), any()}].
|
||||
node_options(Host, Type) ->
|
||||
DefaultOpts = node_plugin_options(Host, Type),
|
||||
case lists:member(Type, config(Host, plugins)) of
|
||||
true ->
|
||||
config(Host, default_node_config, DefaultOpts);
|
||||
false -> DefaultOpts
|
||||
end.
|
||||
ConfigOpts = config(Host, default_node_config),
|
||||
PluginOpts = node_plugin_options(Host, Type),
|
||||
merge_config([ConfigOpts, PluginOpts]).
|
||||
|
||||
-spec node_plugin_options(host(), binary()) -> [{atom(), any()}].
|
||||
node_plugin_options(Host, Type) ->
|
||||
Module = plugin(Host, Type),
|
||||
case catch Module:options() of
|
||||
{'EXIT', {undef, _}} ->
|
||||
case {lists:member(Type, config(Host, plugins)), catch Module:options()} of
|
||||
{true, Opts} when is_list(Opts) ->
|
||||
Opts;
|
||||
{_, _} ->
|
||||
DefaultModule = plugin(Host, ?STDNODE),
|
||||
DefaultModule:options();
|
||||
Result ->
|
||||
Result
|
||||
DefaultModule:options()
|
||||
end.
|
||||
|
||||
-spec node_owners_action(host(), binary(), nodeIdx(), [ljid()]) -> [ljid()].
|
||||
@@ -4200,7 +4194,7 @@ delete_old_items(N) ->
|
||||
fun(#pubsub_node{id = Nidx, type = Type}) ->
|
||||
case node_action(Host, Type,
|
||||
remove_extra_items,
|
||||
[Nidx , N]) of
|
||||
[Nidx, N]) of
|
||||
{result, _} ->
|
||||
ok;
|
||||
{error, _} ->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_push_sql.erl
|
||||
%%% Author : Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% Purpose :
|
||||
%%% Purpose :
|
||||
%%% Created : 26 Oct 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
|
||||
+10
-7
@@ -573,24 +573,24 @@ may_remove_resource(From) -> From.
|
||||
get_ip_access(Host) ->
|
||||
mod_register_opt:ip_access(Host).
|
||||
|
||||
check_ip_access({User, Server, Resource}, IPAccess) ->
|
||||
check_ip_access(Server, {User, Server, Resource}, IPAccess) ->
|
||||
case ejabberd_sm:get_user_ip(User, Server, Resource) of
|
||||
{IPAddress, _PortNumber} ->
|
||||
check_ip_access(IPAddress, IPAccess);
|
||||
check_ip_access(Server, IPAddress, IPAccess);
|
||||
_ ->
|
||||
deny
|
||||
end;
|
||||
check_ip_access(undefined, _IPAccess) ->
|
||||
check_ip_access(_Server, undefined, _IPAccess) ->
|
||||
deny;
|
||||
check_ip_access(IPAddress, IPAccess) ->
|
||||
acl:match_rule(global, IPAccess, IPAddress).
|
||||
check_ip_access(Server, IPAddress, IPAccess) ->
|
||||
acl:match_rule(Server, IPAccess, IPAddress).
|
||||
|
||||
check_access(User, Server, Source) ->
|
||||
JID = jid:make(User, Server),
|
||||
Access = mod_register_opt:access(Server),
|
||||
IPAccess = get_ip_access(Server),
|
||||
case acl:match_rule(Server, Access, JID) of
|
||||
allow -> check_ip_access(Source, IPAccess);
|
||||
allow -> check_ip_access(Server, Source, IPAccess);
|
||||
deny -> deny
|
||||
end.
|
||||
|
||||
@@ -654,7 +654,10 @@ mod_doc() ->
|
||||
?T("Specify rules to restrict what usernames can be registered. "
|
||||
"If a rule returns 'deny' on the requested username, "
|
||||
"registration of that user name is denied. There are no "
|
||||
"restrictions by default.")}},
|
||||
"restrictions by default. "
|
||||
"If 'AccessName' is 'none', then registering new accounts using "
|
||||
"In-Band Registration is disabled and the corresponding "
|
||||
"stream feature is not announced to clients.")}},
|
||||
{access_from,
|
||||
#{value => ?T("AccessName"),
|
||||
desc =>
|
||||
|
||||
+5
-1
@@ -1096,7 +1096,11 @@ make_webadmin_roster_table(Host, Username, R, RPath) ->
|
||||
|
||||
webadmin_user(Acc, User, Server, R) ->
|
||||
Acc
|
||||
++ [make_command(get_roster_count, R, [{<<"user">>, User}, {<<"host">>, Server}], [])].
|
||||
++ [make_command(get_roster_count,
|
||||
R,
|
||||
[{<<"user">>, User}, {<<"host">>, Server}],
|
||||
[{result_links,
|
||||
[{value, arg_host, 4, <<"user/", User/binary, "/roster/">>}]}])].
|
||||
%%% @format-end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
@@ -340,16 +340,16 @@ update_roster_sql({LUser, LServer, SJID, Name, SSubscription, SAsk, AskMessage},
|
||||
|
||||
raw_to_record(LServer,
|
||||
[User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
|
||||
_SServer, _SSubscribe, _SType]) ->
|
||||
SServer, SSubscribe, SType]) ->
|
||||
raw_to_record(LServer,
|
||||
{User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
|
||||
_SServer, _SSubscribe, _SType});
|
||||
SServer, SSubscribe, SType});
|
||||
raw_to_record(LServer,
|
||||
{User, SJID, Nick, SSubscription, SAsk, SAskMessage,
|
||||
_SServer, _SSubscribe, _SType}) ->
|
||||
SServer, SSubscribe, SType}) ->
|
||||
raw_to_record(LServer,
|
||||
{User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
|
||||
_SServer, _SSubscribe, _SType});
|
||||
SServer, SSubscribe, SType});
|
||||
raw_to_record(LServer,
|
||||
{User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
|
||||
_SServer, _SSubscribe, _SType}) ->
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% Created : 20 Oct 2024 by Pawel Chmielowski <pawel@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2024 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(mod_s2s_bidi).
|
||||
-behaviour(gen_mod).
|
||||
-protocol({xep, 288, '1.0.1', '24.10', "complete", ""}).
|
||||
|
||||
%% gen_mod API
|
||||
-export([start/2, stop/1, reload/3, depends/2, mod_options/1]).
|
||||
-export([mod_doc/0]).
|
||||
%% Hooks
|
||||
-export([s2s_in_packet/2, s2s_out_packet/2,
|
||||
s2s_in_features/2, s2s_in_auth_result/3, s2s_out_unauthenticated_features/2, s2s_in_handle_info/2]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("translate.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
start(_Host, _Opts) ->
|
||||
{ok, [{hook, s2s_in_pre_auth_features, s2s_in_features, 50},
|
||||
{hook, s2s_in_post_auth_features, s2s_in_features, 50},
|
||||
{hook, s2s_in_unauthenticated_packet, s2s_in_packet, 50},
|
||||
{hook, s2s_in_authenticated_packet, s2s_in_packet, 50},
|
||||
{hook, s2s_in_handle_info, s2s_in_handle_info, 50},
|
||||
{hook, s2s_in_auth_result, s2s_in_auth_result, 50},
|
||||
{hook, s2s_out_unauthenticated_features, s2s_out_unauthenticated_features, 50},
|
||||
{hook, s2s_out_packet, s2s_out_packet, 50}]}.
|
||||
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
reload(_Host, _NewOpts, _OldOpts) ->
|
||||
ok.
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
mod_options(_Host) ->
|
||||
[].
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
[?T("The module adds support for "
|
||||
"https://xmpp.org/extensions/xep-0288.html"
|
||||
"[XEP-0288: Bidirectional Server-to-Server Connections] that allows using "
|
||||
"single s2s connection to communicate in both directions.")],
|
||||
note => "added in 24.10",
|
||||
opts => [],
|
||||
example =>
|
||||
["modules:",
|
||||
" mod_s2s_bidi: {}"]}.
|
||||
|
||||
s2s_in_features(Acc, _) ->
|
||||
[#s2s_bidi{}|Acc].
|
||||
|
||||
s2s_in_packet(State, #s2s_bidi{}) ->
|
||||
{stop, State#{bidi_enabled => true}};
|
||||
s2s_in_packet(State, _) ->
|
||||
State.
|
||||
|
||||
s2s_out_unauthenticated_features(#{db_verify := _} = State, _) ->
|
||||
State;
|
||||
s2s_out_unauthenticated_features(State, #stream_features{} = Pkt) ->
|
||||
try xmpp:try_subtag(Pkt, #s2s_bidi{}) of
|
||||
#s2s_bidi{} ->
|
||||
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{})
|
||||
catch _:{xmpp_codec, _Why} ->
|
||||
State
|
||||
end.
|
||||
|
||||
s2s_out_packet(#{bidi_enabled := true, ip := {IP, _}} = State, Pkt0)
|
||||
when ?is_stanza(Pkt0) ->
|
||||
To = xmpp:get_to(Pkt0),
|
||||
case check_from_to(State, xmpp:get_from(Pkt0), To) of
|
||||
ok ->
|
||||
Pkt = xmpp:put_meta(Pkt0, ip, IP),
|
||||
LServer = ejabberd_router:host_of_route(To#jid.lserver),
|
||||
State1 = ejabberd_hooks:run_fold(s2s_in_authenticated_packet,
|
||||
LServer, State, [Pkt]),
|
||||
{Pkt1, State2} = ejabberd_hooks:run_fold(s2s_receive_packet, LServer,
|
||||
{Pkt, State1}, []),
|
||||
case Pkt1 of
|
||||
drop -> ok;
|
||||
_ -> ejabberd_router:route(Pkt1)
|
||||
end,
|
||||
{stop, State2};
|
||||
{error, Err} ->
|
||||
{stop, ejabberd_s2s_out:send(State, Err)}
|
||||
end;
|
||||
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{} ->
|
||||
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{})
|
||||
catch _:{xmpp_codec, _Why} ->
|
||||
State
|
||||
end;
|
||||
s2s_out_packet(State, _Pkt) ->
|
||||
State.
|
||||
|
||||
s2s_in_handle_info(State, {route, Pkt}) when ?is_stanza(Pkt) ->
|
||||
ejabberd_s2s_in:send(State, Pkt);
|
||||
s2s_in_handle_info(State, _Info) ->
|
||||
State.
|
||||
|
||||
check_from_to(#{remote_server := RServer}, #jid{lserver = FromServer},
|
||||
#jid{lserver = ToServer}) ->
|
||||
if
|
||||
RServer /= FromServer -> {error, xmpp:serr_invalid_from()};
|
||||
true ->
|
||||
case ejabberd_router:is_my_route(ToServer) of
|
||||
false -> {error, xmpp:serr_host_unknown()};
|
||||
_ -> ok
|
||||
end
|
||||
end.
|
||||
|
||||
s2s_in_auth_result(#{server := LServer, bidi_enabled := true} = State, true, RServer) ->
|
||||
ejabberd_s2s:register_connection({LServer, RServer}),
|
||||
State;
|
||||
s2s_in_auth_result(State, _, _) ->
|
||||
State.
|
||||
@@ -0,0 +1,121 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% Created : 20 Oct 2024 by Pawel Chmielowski <pawel@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2024 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(mod_scram_upgrade).
|
||||
-behaviour(gen_mod).
|
||||
-protocol({xep, 480, '0.1', '24.10', "complete", ""}).
|
||||
|
||||
%% gen_mod API
|
||||
-export([start/2, stop/1, reload/3, depends/2, mod_options/1, mod_opt_type/1]).
|
||||
-export([mod_doc/0]).
|
||||
%% Hooks
|
||||
-export([c2s_inline_features/2, c2s_handle_sasl2_inline/1,
|
||||
c2s_handle_sasl2_task_next/4, c2s_handle_sasl2_task_data/3]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include_lib("xmpp/include/scram.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("translate.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
start(_Host, _Opts) ->
|
||||
{ok, [{hook, c2s_inline_features, c2s_inline_features, 50},
|
||||
{hook, c2s_handle_sasl2_inline, c2s_handle_sasl2_inline, 10},
|
||||
{hook, c2s_handle_sasl2_task_next, c2s_handle_sasl2_task_next, 10},
|
||||
{hook, c2s_handle_sasl2_task_data, c2s_handle_sasl2_task_data, 10}]}.
|
||||
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
reload(_Host, _NewOpts, _OldOpts) ->
|
||||
ok.
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
mod_opt_type(offered_upgrades) ->
|
||||
econf:list(econf:enum([sha256, sha512])).
|
||||
|
||||
mod_options(_Host) ->
|
||||
[{offered_upgrades, [sha256, sha512]}].
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
[?T("The module adds support for "
|
||||
"https://xmpp.org/extensions/xep-0480.html"
|
||||
"[XEP-0480: SASL Upgrade Tasks] that allows users to upgrade "
|
||||
"passwords to more secure representation.")],
|
||||
note => "added in 24.10",
|
||||
opts => [{offered_upgrades,
|
||||
#{value => "list(sha256, sha512)",
|
||||
desc => ?T("List with upgrade types that should be offered")}}],
|
||||
example =>
|
||||
["modules:",
|
||||
" mod_scram_upgrade:",
|
||||
" offered_upgrades:",
|
||||
" - sha256",
|
||||
" - sha512"]}.
|
||||
|
||||
c2s_inline_features({Sasl, Bind, Extra}, Host) ->
|
||||
Methods = lists:map(
|
||||
fun(sha256) -> #sasl_upgrade{cdata = <<"UPGR-SCRAM-SHA-256">>};
|
||||
(sha512) -> #sasl_upgrade{cdata = <<"UPGR-SCRAM-SHA-512">>}
|
||||
end, mod_scram_upgrade_opt:offered_upgrades(Host)),
|
||||
{Sasl, Bind, Methods ++ Extra}.
|
||||
|
||||
c2s_handle_sasl2_inline({State, Els, _Results} = Acc) ->
|
||||
case lists:keyfind(sasl_upgrade, 1, Els) of
|
||||
false ->
|
||||
Acc;
|
||||
#sasl_upgrade{cdata = Type} ->
|
||||
{stop, {State, {continue, [Type]}, []}}
|
||||
end.
|
||||
|
||||
c2s_handle_sasl2_task_next({_, State}, Task, _Els, _InlineEls) ->
|
||||
Algo = case Task of
|
||||
<<"UPGR-SCRAM-SHA-256">> -> sha256;
|
||||
<<"UPGR-SCRAM-SHA-512">> -> sha512
|
||||
end,
|
||||
Salt = p1_rand:bytes(16),
|
||||
{task_data, [#scram_upgrade_salt{cdata = Salt, iterations = 4096}],
|
||||
State#{scram_upgrade => {Algo, Salt, 4096}}}.
|
||||
|
||||
c2s_handle_sasl2_task_data({_, #{user := User, server := Server,
|
||||
scram_upgrade := {Algo, Salt, Iter}} = State},
|
||||
Els, InlineEls) ->
|
||||
case xmpp:get_subtag(#sasl2_task_data{sub_els = Els}, #scram_upgrade_hash{}) of
|
||||
#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,
|
||||
#scram{hash = Algo, iterationcount = Iter, salt = Salt,
|
||||
serverkey = ServerKey, storedkey = StoredKey}),
|
||||
State2 = maps:remove(scram_upgrade, State),
|
||||
InlineEls = lists:keydelete(sasl_upgrade, 1, InlineEls),
|
||||
case ejabberd_c2s:handle_sasl2_inline(InlineEls, State2) of
|
||||
{State3, NewEls, Results} ->
|
||||
{success, NewEls, Results, State3}
|
||||
end;
|
||||
_ ->
|
||||
{abort, State}
|
||||
end.
|
||||
@@ -0,0 +1,13 @@
|
||||
%% Generated automatically
|
||||
%% DO NOT EDIT: run `make options` instead
|
||||
|
||||
-module(mod_scram_upgrade_opt).
|
||||
|
||||
-export([offered_upgrades/1]).
|
||||
|
||||
-spec offered_upgrades(gen_mod:opts() | global | binary()) -> ['sha256' | 'sha512'].
|
||||
offered_upgrades(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(offered_upgrades, Opts);
|
||||
offered_upgrades(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_scram_upgrade, offered_upgrades).
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
-define(GROUP_CACHE, shared_roster_ldap_group_cache).
|
||||
-define(DISPLAYED_CACHE, shared_roster_ldap_displayed_cache).
|
||||
-define(LDAP_SEARCH_TIMEOUT, 5). %% Timeout for LDAP search queries in seconds
|
||||
-define(INVALID_SETTING_MSG, "~ts is not properly set! ~ts will not function.").
|
||||
|
||||
-record(state,
|
||||
{host = <<"">> :: binary(),
|
||||
|
||||
@@ -122,11 +122,12 @@ c2s_stream_features(Acc, Host) ->
|
||||
Acc
|
||||
end.
|
||||
|
||||
c2s_inline_features({Sasl, Bind} = Acc, Host) ->
|
||||
c2s_inline_features({Sasl, Bind, Extra} = Acc, Host) ->
|
||||
case gen_mod:is_loaded(Host, ?MODULE) of
|
||||
true ->
|
||||
{[#feature_sm{xmlns = ?NS_STREAM_MGMT_3} | Sasl],
|
||||
[#bind2_feature{var = ?NS_STREAM_MGMT_3} | Bind]};
|
||||
[#bind2_feature{var = ?NS_STREAM_MGMT_3} | Bind],
|
||||
Extra};
|
||||
false ->
|
||||
Acc
|
||||
end.
|
||||
|
||||
+75
-1
@@ -43,12 +43,17 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
handle_info/2, terminate/2, code_change/3]).
|
||||
-export([route/1]).
|
||||
-export([webadmin_menu_hostuser/4, webadmin_page_hostuser/4]).
|
||||
|
||||
-import(ejabberd_web_admin, [make_command/4, make_command/2, make_table/2]).
|
||||
|
||||
-include("logger.hrl").
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("mod_vcard.hrl").
|
||||
-include("translate.hrl").
|
||||
-include("ejabberd_stacktrace.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
-include("ejabberd_web_admin.hrl").
|
||||
|
||||
-define(VCARD_CACHE, vcard_cache).
|
||||
|
||||
@@ -98,6 +103,8 @@ init([Host|_]) ->
|
||||
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE,
|
||||
get_sm_features, 50),
|
||||
ejabberd_hooks:add(vcard_iq_set, Host, ?MODULE, vcard_iq_set, 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),
|
||||
MyHosts = gen_mod:get_opt_hosts(Opts),
|
||||
Search = mod_vcard_opt:search(Opts),
|
||||
if Search ->
|
||||
@@ -161,6 +168,8 @@ terminate(_Reason, #state{hosts = MyHosts, server_host = Host}) ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
|
||||
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
||||
ejabberd_hooks:delete(vcard_iq_set, Host, ?MODULE, vcard_iq_set, 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),
|
||||
Mod = gen_mod:db_mod(Host, ?MODULE),
|
||||
Mod:stop(Host),
|
||||
lists:foreach(
|
||||
@@ -391,6 +400,12 @@ make_vcard_search(User, LUser, LServer, VCARD) ->
|
||||
lorgunit = LOrgUnit}.
|
||||
|
||||
-spec vcard_iq_set(iq()) -> iq() | {stop, stanza_error()}.
|
||||
vcard_iq_set(#iq{from = #jid{user = FromUser, lserver = FromLServer},
|
||||
to = #jid{user = ToUser, lserver = ToLServer},
|
||||
lang = Lang})
|
||||
when (FromUser /= ToUser) or (FromLServer /= ToLServer) ->
|
||||
Txt = ?T("User not allowed to perform an IQ set on another user's vCard."),
|
||||
{stop, xmpp:err_forbidden(Txt, Lang)};
|
||||
vcard_iq_set(#iq{from = From, lang = Lang, sub_els = [VCard]} = IQ) ->
|
||||
#jid{user = User, lserver = LServer} = From,
|
||||
case set_vcard(User, LServer, VCard) of
|
||||
@@ -398,13 +413,17 @@ vcard_iq_set(#iq{from = From, lang = Lang, sub_els = [VCard]} = IQ) ->
|
||||
%% Should not be here?
|
||||
Txt = ?T("Nodeprep has failed"),
|
||||
{stop, xmpp:err_internal_server_error(Txt, Lang)};
|
||||
{error, not_implemented} ->
|
||||
Txt = ?T("Updating the vCard is not supported by the vCard storage backend"),
|
||||
{stop, xmpp:err_feature_not_implemented(Txt, Lang)};
|
||||
ok ->
|
||||
IQ
|
||||
end;
|
||||
vcard_iq_set(Acc) ->
|
||||
Acc.
|
||||
|
||||
-spec set_vcard(binary(), binary(), xmlel() | vcard_temp()) -> {error, badarg|binary()} | ok.
|
||||
-spec set_vcard(binary(), binary(), xmlel() | vcard_temp()) ->
|
||||
{error, badarg | not_implemented | binary()} | ok.
|
||||
set_vcard(User, LServer, VCARD) ->
|
||||
case jid:nodeprep(User) of
|
||||
error ->
|
||||
@@ -550,6 +569,61 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
%%%
|
||||
%%% WebAdmin
|
||||
%%%
|
||||
|
||||
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
|
||||
Acc ++ [{<<"vcard">>, <<"vCard">>}].
|
||||
|
||||
webadmin_page_hostuser(_, Host, User,
|
||||
#request{path = [<<"vcard">>]} = R) ->
|
||||
Head = ?H1GL(<<"vCard">>, <<"modules/#mod_vcard">>, <<"mod_vcard">>),
|
||||
Set = [make_command(set_nickname, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(set_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(set_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
make_command(set_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
timer:sleep(100), % setting vcard takes a while, let's delay the get commands
|
||||
FieldNames = [<<"VERSION">>, <<"FN">>, <<"NICKNAME">>, <<"BDAY">>],
|
||||
FieldNames2 =
|
||||
[{<<"N">>, <<"FAMILY">>},
|
||||
{<<"N">>, <<"GIVEN">>},
|
||||
{<<"N">>, <<"MIDDLE">>},
|
||||
{<<"ADR">>, <<"CTRY">>},
|
||||
{<<"ADR">>, <<"LOCALITY">>},
|
||||
{<<"EMAIL">>, <<"USERID">>}],
|
||||
Get = [make_command(get_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
?XE(<<"blockquote">>,
|
||||
[make_table([<<"name">>, <<"value">>],
|
||||
[{?C(FieldName),
|
||||
make_command(get_vcard,
|
||||
R,
|
||||
[{<<"user">>, User},
|
||||
{<<"host">>, Host},
|
||||
{<<"name">>, FieldName}],
|
||||
[{only, value}])}
|
||||
|| FieldName <- FieldNames])]),
|
||||
make_command(get_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
|
||||
?XE(<<"blockquote">>,
|
||||
[make_table([<<"name">>, <<"subname">>, <<"value">>],
|
||||
[{?C(FieldName),
|
||||
?C(FieldSubName),
|
||||
make_command(get_vcard2,
|
||||
R,
|
||||
[{<<"user">>, User},
|
||||
{<<"host">>, Host},
|
||||
{<<"name">>, FieldName},
|
||||
{<<"subname">>, FieldSubName}],
|
||||
[{only, value}])}
|
||||
|| {FieldName, FieldSubName} <- FieldNames2])]),
|
||||
make_command(get_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
|
||||
{stop, Head ++ Get ++ Set};
|
||||
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
|
||||
|
||||
%%%
|
||||
%%% Documentation
|
||||
%%%
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ remove_user(LUser, LServer) ->
|
||||
" where lusername=%(LUser)s and %(LServer)H"))
|
||||
end).
|
||||
|
||||
export(_Server) ->
|
||||
export(_Server) ->
|
||||
[{vcard,
|
||||
fun(Host, #vcard{us = {LUser, LServer}, vcard = VCARD})
|
||||
when LServer == Host ->
|
||||
|
||||
+2
-3
@@ -39,9 +39,8 @@ get_nameservers() ->
|
||||
is_good_ns(Addr) ->
|
||||
element(1,
|
||||
inet_res:nnslookup("a.root-servers.net", in, a, [{Addr,53}],
|
||||
timer:seconds(5)
|
||||
)
|
||||
) =:= ok.
|
||||
timer:seconds(5)))
|
||||
=:= ok.
|
||||
|
||||
reg() ->
|
||||
{ok, R} = win32reg:open([read]),
|
||||
|
||||
@@ -18,7 +18,7 @@ GO
|
||||
USE ejabberd_test;
|
||||
GO
|
||||
|
||||
CREATE LOGIN ejabberd_test WITH PASSWORD = 'ejabberd_Test1';
|
||||
CREATE LOGIN ejabberd_test WITH PASSWORD = 'ejabberd_Test1', CHECK_POLICY = OFF;
|
||||
GO
|
||||
|
||||
CREATE USER ejabberd_test FOR LOGIN ejabberd_test;
|
||||
|
||||
@@ -305,6 +305,8 @@ warn_type({var, _, 'Type'}, #state{module = mod_delegation}, "not an atom") ->
|
||||
ok;
|
||||
warn_type({var, _, 'NS'}, #state{module = mod_delegation}, "not a binary") ->
|
||||
ok;
|
||||
warn_type({var, _, _}, #state{module = gen_mod}, _) ->
|
||||
ok;
|
||||
warn_type(Form, State, Warning) ->
|
||||
log("~s:~p: Warning: " ++ Warning ++ ": ~s~n",
|
||||
[State#state.file,
|
||||
|
||||
+9
-9
@@ -67,19 +67,19 @@ 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'
|
||||
termcap_vsn='1.3.1'
|
||||
expat_vsn='2.6.2'
|
||||
expat_vsn='2.6.3'
|
||||
zlib_vsn='1.3.1'
|
||||
yaml_vsn='0.2.5'
|
||||
ssl_vsn='3.3.1'
|
||||
otp_vsn='26.2.5'
|
||||
elixir_vsn='1.16.3'
|
||||
ssl_vsn='3.3.2'
|
||||
otp_vsn='26.2.5.4'
|
||||
elixir_vsn='1.17.2'
|
||||
pam_vsn='1.6.1'
|
||||
png_vsn='1.6.42'
|
||||
png_vsn='1.6.43'
|
||||
jpeg_vsn='9f'
|
||||
webp_vsn='1.3.2'
|
||||
webp_vsn='1.4.0'
|
||||
gd_vsn='2.3.3'
|
||||
odbc_vsn='2.3.12'
|
||||
sqlite_vsn='3450100'
|
||||
sqlite_vsn='3460100'
|
||||
root_dir="${BUILD_DIR:-$HOME/build}"
|
||||
bootstrap_dir="$root_dir/bootstrap"
|
||||
ct_prefix_dir="$root_dir/x-tools"
|
||||
@@ -179,7 +179,7 @@ check_vsn()
|
||||
check_configured_dep_vsns()
|
||||
{
|
||||
check_vsn 'OpenSSL' "$ssl_vsn" \
|
||||
'https://www.openssl.org/source/' \
|
||||
'https://openssl-library.org/source/' \
|
||||
'openssl-\(3\.[1-9]\.[0-9.]*\)\.tar\.gz'
|
||||
check_vsn 'LibYAML' "$yaml_vsn" \
|
||||
'https://pyyaml.org/wiki/LibYAML' \
|
||||
@@ -878,7 +878,7 @@ else
|
||||
curl -fsSLO "https://github.com/libexpat/libexpat/releases/download/R_$(printf '%s' "$expat_vsn" | sed 's/\./_/g')/$expat_tar"
|
||||
curl -fsSLO "https://zlib.net/fossils/$zlib_tar"
|
||||
curl -fsSLO "https://pyyaml.org/download/libyaml/$yaml_tar"
|
||||
curl -fsSLO "https://www.openssl.org/source/$ssl_tar"
|
||||
curl -fsSLO "https://github.com/openssl/openssl/releases/download/openssl-$ssl_vsn/$ssl_tar"
|
||||
curl -fsSLO "https://github.com/erlang/otp/releases/download/OTP-$otp_vsn/$otp_tar"
|
||||
curl -fsSLO "https://github.com/elixir-lang/elixir/archive/v$elixir_vsn.tar.gz"
|
||||
curl -fsSLO "https://github.com/linux-pam/linux-pam/releases/download/v$pam_vsn/$pam_tar"
|
||||
|
||||
Reference in New Issue
Block a user