Compare commits
194 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7511307868 | |||
| 1cadc6b1dc | |||
| 405437b086 | |||
| 51f4382b9f | |||
| e967a409d3 | |||
| eaebfc795e | |||
| 3bc66a7054 | |||
| 8cfcc69100 | |||
| ce3bc85d32 | |||
| 1fe9e3aa67 | |||
| d93a8e341f | |||
| 1107cefdb6 | |||
| 92b2bb7532 | |||
| 9a2a9187cd | |||
| 50b57ada7c | |||
| a8649767f2 | |||
| 2eb605873c | |||
| 26e8679359 | |||
| 2aa673e780 | |||
| 06303ae7ab | |||
| 2b3d588f10 | |||
| 3dd7febb98 | |||
| beb5bfea36 | |||
| 628f286eb6 | |||
| 9e14c7a803 | |||
| 863f2e019c | |||
| 4334ce9c29 | |||
| 7008e49675 | |||
| b84596be57 | |||
| 4fd26306fe | |||
| 8e9ea2d98c | |||
| 1024cbe5b3 | |||
| a16ef68a49 | |||
| 7726904f79 | |||
| 1481734f47 | |||
| 01955b867d | |||
| 549a2b0790 | |||
| 2caaa09c99 | |||
| da06a50072 | |||
| 2b02af13ba | |||
| ae238bc984 | |||
| 3d2036db61 | |||
| b8360cae08 | |||
| 790cb104cd | |||
| f3c935d2e1 | |||
| e589265921 | |||
| eb6f242d99 | |||
| ce6d5aa6a0 | |||
| f269d5b613 | |||
| a84c492130 | |||
| 3ae636b454 | |||
| 06e3f9f0a4 | |||
| 1669303a40 | |||
| 39e37b6175 | |||
| c72ba1f188 | |||
| 4d625e5574 | |||
| 803f95050f | |||
| c021cf34be | |||
| 7fce7d1049 | |||
| bd36895afe | |||
| b90c48f837 | |||
| 344775aa8e | |||
| 7d0c20e133 | |||
| ab5a2e8d10 | |||
| e34c1ebcba | |||
| 73dbc01c2e | |||
| f0773c4ab8 | |||
| cc5c9f6008 | |||
| da9c591eed | |||
| 6790ab01e8 | |||
| f9cecca362 | |||
| f4009939a6 | |||
| 17b5b34e3c | |||
| c291c20a3b | |||
| 22e7ce37d4 | |||
| 2137602a6a | |||
| c7b29b5a9a | |||
| 715b5b64c6 | |||
| c20ed8c7b3 | |||
| d3baacd78e | |||
| 07e20784cb | |||
| 9eb8bb6c40 | |||
| e10c0f3120 | |||
| 6f7efebb56 | |||
| a657778065 | |||
| 3650d94bb5 | |||
| 6a428f3d02 | |||
| abe1d96c58 | |||
| 29a59cfe48 | |||
| 18c54f4e9e | |||
| c7d967a2b5 | |||
| b50ea7ef1f | |||
| 4843cd432f | |||
| d56eae809d | |||
| af97211ecc | |||
| 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 |
+31
-32
@@ -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,21 +100,16 @@ 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: |
|
||||
~/.cache/rebar3/
|
||||
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
|
||||
|
||||
- name: Download test logs
|
||||
if: matrix.otp == '26' && github.repository == 'processone/ejabberd'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
mkdir -p _build/test
|
||||
curl -sSL https://github.com/processone/ecil/tarball/gh-pages |
|
||||
tar -C _build/test --strip-components=1 --wildcards -xzf -
|
||||
rm -rf _build/test/logs/last/
|
||||
- name: Get compatible Rebar binaries
|
||||
if: matrix.otp < 21
|
||||
run: ./rebar3 unlock eredis
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
@@ -133,6 +128,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 +142,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
|
||||
@@ -200,22 +215,6 @@ jobs:
|
||||
"payload":{"build_num":$GITHUB_RUN_ID,
|
||||
"status":"done"}}'
|
||||
|
||||
- name: Upload test logs
|
||||
if: always() && steps.ct.outcome == 'failure' && github.repository == 'processone/ejabberd'
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
publish_dir: _build/test
|
||||
exclude_assets: '.github,lib,plugins'
|
||||
external_repository: processone/ecil
|
||||
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
|
||||
keep_files: true
|
||||
|
||||
- name: View ECIL address
|
||||
if: always() && steps.ct.outcome == 'failure' && github.repository == 'processone/ejabberd'
|
||||
run: |
|
||||
CTRUN=`ls -la _build/test/logs/last | sed 's|.*-> ||'`
|
||||
echo "::notice::View CT results: https://processone.github.io/ecil/logs/$CTRUN/"
|
||||
|
||||
- name: Check for changes to trigger schema upgrade test
|
||||
uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
@@ -256,12 +255,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';"
|
||||
|
||||
@@ -19,7 +19,7 @@ env:
|
||||
jobs:
|
||||
container:
|
||||
name: Container
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
|
||||
@@ -21,7 +21,7 @@ on:
|
||||
jobs:
|
||||
binaries:
|
||||
name: Binaries
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Cache build directory
|
||||
uses: actions/cache@v4
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
release:
|
||||
name: Release
|
||||
needs: [binaries]
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.ref_type == 'tag'
|
||||
steps:
|
||||
- name: Download packages
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
exclude:
|
||||
- otp: '27'
|
||||
rebar: 'rebar'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
container:
|
||||
image: erlang:${{ matrix.otp }}
|
||||
|
||||
@@ -61,6 +61,17 @@ 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: Get compatible Rebar binaries
|
||||
if: matrix.rebar == 'rebar3' && matrix.otp < 21
|
||||
run: rebar3 unlock eredis
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -74,6 +85,8 @@ jobs:
|
||||
|
||||
- run: make xref
|
||||
|
||||
- run: make dialyzer
|
||||
|
||||
- name: Prepare rel (rebar2)
|
||||
if: matrix.rebar == 'rebar'
|
||||
run: |
|
||||
@@ -151,59 +164,42 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
otp: ['23.0', '25', '26', '27']
|
||||
elixir: ['1.13', '1.15', '1.16', '1.17']
|
||||
exclude:
|
||||
- otp: '23.0'
|
||||
elixir: '1.15'
|
||||
- otp: '23.0'
|
||||
elixir: '1.16'
|
||||
- otp: '23.0'
|
||||
elixir: '1.17'
|
||||
- otp: '26'
|
||||
elixir: '1.13'
|
||||
- otp: '27'
|
||||
elixir: '1.13'
|
||||
- otp: '27'
|
||||
elixir: '1.15'
|
||||
- otp: '27'
|
||||
elixir: '1.16'
|
||||
runs-on: ubuntu-20.04
|
||||
elixir: ['1.13', '1.14', '1.15', '1.16', '1.17']
|
||||
runs-on: ubuntu-24.04
|
||||
container:
|
||||
image: elixir:${{ matrix.elixir }}
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get specific Erlang/OTP
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: ${{matrix.otp}}
|
||||
elixir-version: ${{matrix.elixir}}
|
||||
|
||||
- name: Get compatible Rebar binaries
|
||||
if: matrix.otp < 24
|
||||
run: |
|
||||
rm rebar
|
||||
rm rebar3
|
||||
wget https://github.com/processone/ejabberd/raw/21.12/rebar
|
||||
wget https://github.com/processone/ejabberd/raw/21.12/rebar3
|
||||
chmod +x rebar
|
||||
chmod +x rebar3
|
||||
|
||||
- name: Prepare libraries
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -y purge libgd3 nginx
|
||||
sudo apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
|
||||
libsqlite3-dev libwebp-dev libyaml-dev
|
||||
apt-get -qq update
|
||||
apt-get -y purge libgd3 nginx
|
||||
apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
|
||||
libsqlite3-dev libwebp-dev libyaml-dev
|
||||
|
||||
- name: Enable ModPresenceDemo and an Elixir dependency
|
||||
- name: Enable Module.Example and an Elixir dependency
|
||||
run: |
|
||||
sed -i "s|^modules:|modules:\n 'ModPresenceDemo': {}|g" ejabberd.yml.example
|
||||
sed -i "s|^modules:|modules:\n 'Ejabberd.Module.Example': {}|g" ejabberd.yml.example
|
||||
cat ejabberd.yml.example
|
||||
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.elixir}}-${{hashFiles('rebar.config')}}
|
||||
|
||||
- name: Install Hex and Rebar3 manually on older Elixir
|
||||
if: matrix.elixir <= '1.14'
|
||||
run: |
|
||||
mix local.hex --force
|
||||
mix local.rebar --force
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -265,15 +261,15 @@ jobs:
|
||||
grep -q '^user3$' registered.log
|
||||
grep -q 'is started' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'is stopped' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'module Presence Demo' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'Stopping Ejabberd.Module.Example' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
test $(find _build/prod/ -empty -name error.log)
|
||||
grep -q 'is started' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'is stopped' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'module Presence Demo' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'Stopping Ejabberd.Module.Example' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
test $(find _build/dev/ -empty -name error.log)
|
||||
grep -q 'is started' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
grep -q 'is stopped' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
grep -q 'module Presence Demo' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
grep -q 'Stopping Ejabberd.Module.Example' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
test $(find /tmp/ejabberd/var/log/ejabberd/ -empty -name error.log)
|
||||
|
||||
- name: View logs failures
|
||||
@@ -291,41 +287,21 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
otp: ['23.0', '25', '26', '27']
|
||||
elixir: ['1.13', '1.15', '1.16', '1.17']
|
||||
exclude:
|
||||
- otp: '23.0'
|
||||
elixir: '1.15'
|
||||
- otp: '23.0'
|
||||
elixir: '1.16'
|
||||
- otp: '23.0'
|
||||
elixir: '1.17'
|
||||
- otp: '26'
|
||||
elixir: '1.13'
|
||||
- otp: '27'
|
||||
elixir: '1.13'
|
||||
- otp: '27'
|
||||
elixir: '1.15'
|
||||
- otp: '27'
|
||||
elixir: '1.16'
|
||||
runs-on: ubuntu-20.04
|
||||
elixir: ['1.13', '1.14', '1.15', '1.16', '1.17']
|
||||
runs-on: ubuntu-24.04
|
||||
container:
|
||||
image: elixir:${{ matrix.elixir }}
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get specific Erlang/OTP
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
otp-version: ${{matrix.otp}}
|
||||
elixir-version: ${{matrix.elixir}}
|
||||
|
||||
- name: Prepare libraries
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -y purge libgd3 nginx
|
||||
sudo apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
|
||||
libsqlite3-dev libwebp-dev libyaml-dev
|
||||
apt-get -qq update
|
||||
apt-get -y purge libgd3 nginx
|
||||
apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
|
||||
libsqlite3-dev libwebp-dev libyaml-dev
|
||||
|
||||
- name: Remove Elixir Matchers
|
||||
run: |
|
||||
@@ -335,17 +311,25 @@ jobs:
|
||||
echo "::remove-matcher owner=elixir-mixTestFailure::"
|
||||
echo "::remove-matcher owner=elixir-dialyzerOutputDefault::"
|
||||
|
||||
- name: Enable ModPresenceDemo and an Elixir dependency
|
||||
- name: Enable Module.Example and an Elixir dependency
|
||||
run: |
|
||||
sed -i "s|^modules:|modules:\n 'ModPresenceDemo': {}|g" ejabberd.yml.example
|
||||
sed -i "s|^modules:|modules:\n 'Ejabberd.Module.Example': {}|g" ejabberd.yml.example
|
||||
cat ejabberd.yml.example
|
||||
sed -i 's|^{deps, \(.*\)|{deps, \1\n {decimal, ".*", {git, "https://github.com/ericmj/decimal", {branch, "main"}}}, |g' rebar.config
|
||||
cat rebar.config
|
||||
|
||||
- name: Unlock Jose dependency on older Erlang
|
||||
if: matrix.otp < 24
|
||||
- name: Cache Hex.pm
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.hex/
|
||||
key: ${{matrix.elixir}}-${{hashFiles('mix.exs')}}
|
||||
|
||||
- name: Install Hex and Rebar3 manually on older Elixir
|
||||
if: matrix.elixir <= '1.14'
|
||||
run: |
|
||||
mix deps.unlock jose
|
||||
mix local.hex --force
|
||||
mix local.rebar --force
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
@@ -360,6 +344,7 @@ jobs:
|
||||
- run: make dialyzer
|
||||
|
||||
- run: make edoc
|
||||
if: matrix.elixir >= '1.14'
|
||||
|
||||
- name: Run rel
|
||||
run: |
|
||||
@@ -411,15 +396,15 @@ jobs:
|
||||
grep -q '^user3$' registered.log
|
||||
grep -q 'is started' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'is stopped' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'module Presence Demo' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'Stopping Ejabberd.Module.Example' _build/prod/rel/ejabberd/logs/ejabberd.log
|
||||
test $(find _build/prod/ -empty -name error.log)
|
||||
grep -q 'is started' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'is stopped' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'module Presence Demo' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
grep -q 'Stopping Ejabberd.Module.Example' _build/dev/rel/ejabberd/logs/ejabberd.log
|
||||
test $(find _build/dev/ -empty -name error.log)
|
||||
grep -q 'is started' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
grep -q 'is stopped' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
grep -q 'module Presence Demo' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
grep -q 'Stopping Ejabberd.Module.Example' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
|
||||
test $(find /tmp/ejabberd/var/log/ejabberd/ -empty -name error.log)
|
||||
|
||||
- name: View logs failures
|
||||
|
||||
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
|
||||
|
||||
+134
@@ -1,3 +1,137 @@
|
||||
## Version 24.12
|
||||
|
||||
#### Miscelanea
|
||||
|
||||
- Elixir: support loading Elixir modules for auth ([#4315](https://github.com/processone/ejabberd/issues/4315))
|
||||
- Environment variables `EJABBERD_MACRO` to define macros
|
||||
- Fix problem starting ejabberd when first host uses SQL, other one mnesia
|
||||
- HTTP Websocket: Enable `allow_unencrypted_sasl2` on websockets ([#4323](https://github.com/processone/ejabberd/issues/4323))
|
||||
- Relax checks for channels bindings for connections using external encryption
|
||||
- Redis: Add support for unix domain socket ([#4318](https://github.com/processone/ejabberd/issues/4318))
|
||||
- Redis: Use eredis 1.7.1 from Nordix when using mix/rebar3 and Erlang 21+
|
||||
- `mod_auth_fast`: New module with support XEP-0484: Fast Authentication Streamlining Tokens
|
||||
- `mod_http_api`: Fix crash when module not enabled (for example, in CT tests)
|
||||
- `mod_http_api`: New option `default_version`
|
||||
- `mod_muc`: Make rsm handling in disco items, correctly count skipped rooms
|
||||
- `mod_offline`: Only delete offline msgs when user has MAM enabled ([#4287](https://github.com/processone/ejabberd/issues/4287))
|
||||
- `mod_priviled`: Handle properly roster iq
|
||||
- `mod_pubsub`: Send notifications on PEP item retract
|
||||
- `mod_s2s_bidi`: Catch extra case in check for s2s bidi element
|
||||
- `mod_scram_upgrade`: Don't abort the upgrade
|
||||
- `mod_shared_roster`: The name of a new group is lowercased
|
||||
- `mod_shared_roster`: Get back support for `groupid@vhost` in `displayed`
|
||||
- `mod_stun_disco`: Fix syntax of credentials response
|
||||
|
||||
#### Commands API
|
||||
|
||||
- Change arguments and result to consistent names (API v3)
|
||||
- `create_rooms_file`: Improve to support vhosts with different config
|
||||
- `evacuate_kindly`: New command to kick users and prevent login ([#4309](https://github.com/processone/ejabberd/issues/4309))
|
||||
- `join_cluster`: Explain that this returns immediately (since 5a34020, 24.06)
|
||||
- `mod_muc_admin`: Rename argument `name` to `room` for consistency
|
||||
|
||||
#### Documentation
|
||||
|
||||
- Fix some documentation syntax, add links to toplevel, modules and API
|
||||
- `CONTAINER.md`: Add kubernetes yaml examples to use with podman
|
||||
- `SECURITY.md`: Add security policy and reporting guidelines
|
||||
- `ejabberd.service`: Disable the systemd watchdog by default
|
||||
- `ejabberd.yml.example`: Use non-standard STUN port
|
||||
|
||||
#### WebAdmin
|
||||
|
||||
- Shared group names are case sensitive, use original case instead of lowercase
|
||||
- Use lowercase username and server authentication credentials
|
||||
- Fix calculation of node's uptime days
|
||||
- Fix link to displayed group when it is from another vhost
|
||||
|
||||
## 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
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ There are several ways to obtain the ejabberd source code:
|
||||
- Source code package from [ejabberd GitHub Releases][ghr]
|
||||
- Latest development code from [ejabberd Git repository][gitrepo]
|
||||
|
||||
[p1dl]: https://www.process-one.net/en/ejabberd/downloads/
|
||||
[p1dl]: https://www.process-one.net/download/ejabberd/
|
||||
[ghr]: https://github.com/processone/ejabberd/releases
|
||||
[gitrepo]: https://github.com/processone/ejabberd
|
||||
|
||||
|
||||
+312
-24
@@ -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
|
||||
==========================
|
||||
@@ -44,7 +44,7 @@ docker run --name ejabberd -d -p 5222:5222 ghcr.io/processone/ejabberd
|
||||
```
|
||||
|
||||
That runs the container as a daemon,
|
||||
using ejabberd default configuration file and XMPP domain "localhost".
|
||||
using ejabberd default configuration file and XMPP domain `localhost`.
|
||||
|
||||
Stop the running container:
|
||||
|
||||
@@ -67,7 +67,7 @@ Start ejabberd with an Erlang console attached using the `live` command:
|
||||
docker run --name ejabberd -it -p 5222:5222 ghcr.io/processone/ejabberd live
|
||||
```
|
||||
|
||||
That uses the default configuration file and XMPP domain "localhost".
|
||||
That uses the default configuration file and XMPP domain `localhost`.
|
||||
|
||||
|
||||
### Start with your configuration and database
|
||||
@@ -234,6 +234,31 @@ Example usage (or check the [full example](#customized-example)):
|
||||
```
|
||||
|
||||
|
||||
### Macros in environment
|
||||
|
||||
ejabberd reads `EJABBERD_MACRO_*` environment variables
|
||||
and uses them to define the `*`
|
||||
[macros](https://docs.ejabberd.im/admin/configuration/file-format/#macros-in-configuration-file),
|
||||
overwriting the corresponding macro definition if it was set in the configuration file.
|
||||
This is supported since ejabberd 24.12.
|
||||
|
||||
For example, if you configure this in `ejabberd.yml`:
|
||||
|
||||
```yaml
|
||||
acl:
|
||||
admin:
|
||||
user: ADMINJID
|
||||
```
|
||||
|
||||
now you can define the admin account JID using an environment variable:
|
||||
```yaml
|
||||
environment:
|
||||
- EJABBERD_MACRO_ADMINJID=admin@localhost
|
||||
```
|
||||
|
||||
Check the [full example](#customized-example) for other example.
|
||||
|
||||
|
||||
### Clustering
|
||||
|
||||
When setting several containers to form a
|
||||
@@ -244,17 +269,19 @@ and the same
|
||||
[Erlang Cookie](https://docs.ejabberd.im/admin/guide/security/#erlang-cookie).
|
||||
|
||||
For this you can either:
|
||||
|
||||
- edit `conf/ejabberdctl.cfg` and set variables `ERLANG_NODE` and `ERLANG_COOKIE`
|
||||
- set the environment variables `ERLANG_NODE_ARG` and `ERLANG_COOKIE`
|
||||
|
||||
Example to connect a local `ejabberdctl` to a containerized ejabberd:
|
||||
|
||||
1. When creating the container, export port 5210, and set `ERLANG_COOKIE`:
|
||||
```sh
|
||||
docker run --name ejabberd -it \
|
||||
-e ERLANG_COOKIE=`cat $HOME/.erlang.cookie` \
|
||||
-p 5210:5210 -p 5222:5222 \
|
||||
ghcr.io/processone/ejabberd
|
||||
```
|
||||
```sh
|
||||
docker run --name ejabberd -it \
|
||||
-e ERLANG_COOKIE=`cat $HOME/.erlang.cookie` \
|
||||
-p 5210:5210 -p 5222:5222 \
|
||||
ghcr.io/processone/ejabberd
|
||||
```
|
||||
2. Set `ERL_DIST_PORT=5210` in ejabberdctl.cfg of container and local ejabberd
|
||||
3. Restart the container
|
||||
4. Now use `ejabberdctl` in your local ejabberd deployment
|
||||
@@ -296,10 +323,12 @@ docker buildx build \
|
||||
|
||||
### Podman build
|
||||
|
||||
It's also possible to use podman instead of docker, just notice:
|
||||
To build the image using Podman, please notice:
|
||||
|
||||
- `EXPOSE 4369-4399` port range is not supported, remove that in Dockerfile
|
||||
- It mentions that `healthcheck` is not supported by the Open Container Initiative image format
|
||||
- to start with command `live`, you may want to add environment variable `EJABBERD_BYPASS_WARNINGS=true`
|
||||
|
||||
```bash
|
||||
podman build \
|
||||
-t ejabberd \
|
||||
@@ -348,7 +377,9 @@ Composer Examples
|
||||
### Minimal Example
|
||||
|
||||
This is the barely minimal file to get a usable ejabberd.
|
||||
Store it as `docker-compose.yml`:
|
||||
|
||||
If using Docker, write this `docker-compose.yml` file
|
||||
and start it with `docker-compose up`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -362,15 +393,39 @@ services:
|
||||
- "5443:5443"
|
||||
```
|
||||
|
||||
Create and start the container with the command:
|
||||
```bash
|
||||
docker-compose up
|
||||
If using Podman, write this `minimal.yml` file
|
||||
and start it with `podman kube play minimal.yml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
|
||||
kind: Pod
|
||||
|
||||
metadata:
|
||||
name: ejabberd
|
||||
|
||||
spec:
|
||||
containers:
|
||||
|
||||
- name: ejabberd
|
||||
image: ghcr.io/processone/ejabberd
|
||||
ports:
|
||||
- containerPort: 5222
|
||||
hostPort: 5222
|
||||
- containerPort: 5269
|
||||
hostPort: 5269
|
||||
- containerPort: 5280
|
||||
hostPort: 5280
|
||||
- containerPort: 5443
|
||||
hostPort: 5443
|
||||
```
|
||||
|
||||
|
||||
### Customized Example
|
||||
|
||||
This example shows the usage of several customizations:
|
||||
it uses a local configuration file,
|
||||
defines a configuration macro using an environment variable,
|
||||
stores the mnesia database in a local path,
|
||||
registers an account when it's created,
|
||||
and checks the number of registered accounts every time it's started.
|
||||
@@ -381,13 +436,24 @@ wget https://raw.githubusercontent.com/processone/ejabberd/master/ejabberd.yml.e
|
||||
mv ejabberd.yml.example ejabberd.yml
|
||||
```
|
||||
|
||||
Use a macro in `ejabberd.yml` to set the served vhost, with `localhost` as default value:
|
||||
```yaml
|
||||
define_macro:
|
||||
XMPPHOST: localhost
|
||||
|
||||
hosts:
|
||||
- XMPPHOST
|
||||
```
|
||||
|
||||
Create the database directory and allow the container access to it:
|
||||
```bash
|
||||
mkdir database
|
||||
sudo chown 9000:9000 database
|
||||
```
|
||||
|
||||
Now write this `docker-compose.yml` file:
|
||||
If using Docker, write this `docker-compose.yml` file
|
||||
and start it with `docker-compose up`:
|
||||
|
||||
```yaml
|
||||
version: '3.7'
|
||||
|
||||
@@ -397,8 +463,9 @@ services:
|
||||
image: ghcr.io/processone/ejabberd
|
||||
container_name: ejabberd
|
||||
environment:
|
||||
- CTL_ON_CREATE=register admin localhost asd
|
||||
- CTL_ON_START=registered_users localhost ;
|
||||
- EJABBERD_MACRO_XMPPHOST=example.com
|
||||
- CTL_ON_CREATE=register admin example.com asd
|
||||
- CTL_ON_START=registered_users example.com ;
|
||||
status
|
||||
ports:
|
||||
- "5222:5222"
|
||||
@@ -410,6 +477,56 @@ services:
|
||||
- ./database:/opt/ejabberd/database
|
||||
```
|
||||
|
||||
If using Podman, write this `custom.yml` file
|
||||
and start it with `podman kube play custom.yml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
|
||||
kind: Pod
|
||||
|
||||
metadata:
|
||||
name: ejabberd
|
||||
|
||||
spec:
|
||||
containers:
|
||||
|
||||
- name: ejabberd
|
||||
image: ghcr.io/processone/ejabberd
|
||||
env:
|
||||
- name: CTL_ON_CREATE
|
||||
value: register admin example.com asd
|
||||
- name: CTL_ON_START
|
||||
value: registered_users example.com ;
|
||||
status
|
||||
ports:
|
||||
- containerPort: 5222
|
||||
hostPort: 5222
|
||||
- containerPort: 5269
|
||||
hostPort: 5269
|
||||
- containerPort: 5280
|
||||
hostPort: 5280
|
||||
- containerPort: 5443
|
||||
hostPort: 5443
|
||||
volumeMounts:
|
||||
- mountPath: /opt/ejabberd/conf/ejabberd.yml
|
||||
name: config
|
||||
readOnly: true
|
||||
- mountPath: /opt/ejabberd/database
|
||||
name: db
|
||||
|
||||
volumes:
|
||||
- name: config
|
||||
hostPath:
|
||||
path: ./ejabberd.yml
|
||||
type: File
|
||||
- name: db
|
||||
hostPath:
|
||||
path: ./database
|
||||
type: DirectoryOrCreate
|
||||
```
|
||||
|
||||
|
||||
### Clustering Example
|
||||
|
||||
In this example, the main container is created first.
|
||||
@@ -418,12 +535,15 @@ and once ejabberd is started in it, it joins the first one.
|
||||
|
||||
An account is registered in the first node when created (and
|
||||
we ignore errors that can happen when doing that - for example
|
||||
whenn account already exists),
|
||||
when account already exists),
|
||||
and it should exist in the second node after join.
|
||||
|
||||
Notice that in this example the main container does not have access
|
||||
to the exterior; the replica exports the ports and can be accessed.
|
||||
|
||||
If using Docker, write this `docker-compose.yml` file
|
||||
and start it with `docker-compose up`:
|
||||
|
||||
```yaml
|
||||
version: '3.7'
|
||||
|
||||
@@ -443,15 +563,183 @@ services:
|
||||
depends_on:
|
||||
main:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "5222:5222"
|
||||
- "5269:5269"
|
||||
- "5280:5280"
|
||||
- "5443:5443"
|
||||
environment:
|
||||
- ERLANG_NODE_ARG=ejabberd@replica
|
||||
- ERLANG_COOKIE=dummycookie123
|
||||
- CTL_ON_CREATE=join_cluster ejabberd@main
|
||||
- CTL_ON_START=registered_users localhost ;
|
||||
status
|
||||
ports:
|
||||
- "5222:5222"
|
||||
- "5269:5269"
|
||||
- "5280:5280"
|
||||
- "5443:5443"
|
||||
```
|
||||
|
||||
If using Podman, write this `cluster.yml` file
|
||||
and start it with `podman kube play cluster.yml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
|
||||
kind: Pod
|
||||
|
||||
metadata:
|
||||
name: cluster
|
||||
|
||||
spec:
|
||||
containers:
|
||||
|
||||
- name: first
|
||||
image: ghcr.io/processone/ejabberd
|
||||
env:
|
||||
- name: ERLANG_NODE_ARG
|
||||
value: main@cluster
|
||||
- name: ERLANG_COOKIE
|
||||
value: dummycookie123
|
||||
- name: CTL_ON_CREATE
|
||||
value: register admin localhost asd
|
||||
- name: CTL_ON_START
|
||||
value: stats registeredusers ;
|
||||
status
|
||||
- name: EJABBERD_MACRO_PORT_C2S
|
||||
value: 6222
|
||||
- name: EJABBERD_MACRO_PORT_C2S_TLS
|
||||
value: 6223
|
||||
- name: EJABBERD_MACRO_PORT_S2S
|
||||
value: 6269
|
||||
- name: EJABBERD_MACRO_PORT_HTTP_TLS
|
||||
value: 6443
|
||||
- name: EJABBERD_MACRO_PORT_HTTP
|
||||
value: 6280
|
||||
- name: EJABBERD_MACRO_PORT_MQTT
|
||||
value: 6883
|
||||
- name: EJABBERD_MACRO_PORT_PROXY65
|
||||
value: 6777
|
||||
volumeMounts:
|
||||
- mountPath: /opt/ejabberd/conf/ejabberd.yml
|
||||
name: config
|
||||
readOnly: true
|
||||
|
||||
- name: second
|
||||
image: ghcr.io/processone/ejabberd
|
||||
env:
|
||||
- name: ERLANG_NODE_ARG
|
||||
value: replica@cluster
|
||||
- name: ERLANG_COOKIE
|
||||
value: dummycookie123
|
||||
- name: CTL_ON_CREATE
|
||||
value: join_cluster main@cluster ;
|
||||
started ;
|
||||
list_cluster
|
||||
- name: CTL_ON_START
|
||||
value: stats registeredusers ;
|
||||
check_password admin localhost asd ;
|
||||
status
|
||||
ports:
|
||||
- containerPort: 5222
|
||||
hostPort: 5222
|
||||
- containerPort: 5280
|
||||
hostPort: 5280
|
||||
volumeMounts:
|
||||
- mountPath: /opt/ejabberd/conf/ejabberd.yml
|
||||
name: config
|
||||
readOnly: true
|
||||
|
||||
volumes:
|
||||
- name: config
|
||||
hostPath:
|
||||
path: ./conf/ejabberd.yml
|
||||
type: File
|
||||
|
||||
```
|
||||
|
||||
Your configuration file should use those macros to allow each ejabberd node
|
||||
use different listening port numbers:
|
||||
|
||||
```diff
|
||||
diff --git a/ejabberd.yml.example b/ejabberd.yml.example
|
||||
index 39e423a64..6e875b48f 100644
|
||||
--- a/ejabberd.yml.example
|
||||
+++ b/ejabberd.yml.example
|
||||
@@ -24,9 +24,19 @@ loglevel: info
|
||||
# - /etc/letsencrypt/live/domain.tld/fullchain.pem
|
||||
# - /etc/letsencrypt/live/domain.tld/privkey.pem
|
||||
|
||||
+define_macro:
|
||||
+ PORT_C2S: 5222
|
||||
+ PORT_C2S_TLS: 5223
|
||||
+ PORT_S2S: 5269
|
||||
+ PORT_HTTP_TLS: 5443
|
||||
+ PORT_HTTP: 5280
|
||||
+ PORT_STUN: 5478
|
||||
+ PORT_MQTT: 1883
|
||||
+ PORT_PROXY65: 7777
|
||||
+
|
||||
listen:
|
||||
-
|
||||
- port: 5222
|
||||
+ port: PORT_C2S
|
||||
ip: "::"
|
||||
module: ejabberd_c2s
|
||||
max_stanza_size: 262144
|
||||
@@ -34,7 +44,7 @@ listen:
|
||||
access: c2s
|
||||
starttls_required: true
|
||||
-
|
||||
- port: 5223
|
||||
+ port: PORT_C2S_TLS
|
||||
ip: "::"
|
||||
module: ejabberd_c2s
|
||||
max_stanza_size: 262144
|
||||
@@ -42,13 +52,13 @@ listen:
|
||||
access: c2s
|
||||
tls: true
|
||||
-
|
||||
- port: 5269
|
||||
+ port: PORT_S2S
|
||||
ip: "::"
|
||||
module: ejabberd_s2s_in
|
||||
max_stanza_size: 524288
|
||||
shaper: s2s_shaper
|
||||
-
|
||||
- port: 5443
|
||||
+ port: PORT_HTTP_TLS
|
||||
ip: "::"
|
||||
module: ejabberd_http
|
||||
tls: true
|
||||
@@ -60,14 +70,14 @@ listen:
|
||||
/upload: mod_http_upload
|
||||
/ws: ejabberd_http_ws
|
||||
-
|
||||
- port: 5280
|
||||
+ port: PORT_HTTP
|
||||
ip: "::"
|
||||
module: ejabberd_http
|
||||
request_handlers:
|
||||
/admin: ejabberd_web_admin
|
||||
/.well-known/acme-challenge: ejabberd_acme
|
||||
-
|
||||
- port: 5478
|
||||
+ port: PORT_STUN
|
||||
ip: "::"
|
||||
transport: udp
|
||||
module: ejabberd_stun
|
||||
@@ -77,7 +87,7 @@ listen:
|
||||
## The server's public IPv6 address:
|
||||
# turn_ipv6_address: "2001:db8::3"
|
||||
-
|
||||
- port: 1883
|
||||
+ port: PORT_MQTT
|
||||
ip: "::"
|
||||
module: mod_mqtt
|
||||
backlog: 1000
|
||||
@@ -207,6 +217,7 @@ modules:
|
||||
mod_proxy65:
|
||||
access: local
|
||||
max_connections: 5
|
||||
+ port: PORT_PROXY65
|
||||
mod_pubsub:
|
||||
access_createnode: pubsub_createnode
|
||||
plugins:
|
||||
```
|
||||
|
||||
+10
-10
@@ -25,18 +25,18 @@ support platforms, the best being [Stack Overflow][stackoverflow].
|
||||
|
||||
Stack Overflow is a much better place to ask questions since:
|
||||
|
||||
- there are thousands of people willing to help on Stack Overflow
|
||||
- questions and answers stay available for public viewing so your question / answer might help
|
||||
* there are thousands of people willing to help on Stack Overflow
|
||||
* questions and answers stay available for public viewing so your question / answer might help
|
||||
someone else
|
||||
- Stack Overflow's voting system assures that the best answers are prominently visible.
|
||||
* Stack Overflow's voting system assures that the best answers are prominently visible.
|
||||
|
||||
To save your and our time, we will systematically close all issues that are requests for general
|
||||
support and redirect people to the section you are reading right now.
|
||||
|
||||
Other channels for support are:
|
||||
- ejabberd XMPP room: [ejabberd@conference.process-one.net][muc]
|
||||
- [ejabberd XMPP room logs][logs]
|
||||
- [ejabberd Mailing List][list]
|
||||
|
||||
* ejabberd XMPP room: [ejabberd@conference.process-one.net][muc]
|
||||
* [ejabberd Mailing List][list]
|
||||
|
||||
### Found an Issue or Bug?
|
||||
|
||||
@@ -80,6 +80,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
* Test your changes and, if relevant, expand the automated test suite.
|
||||
* Create your patch commit, including appropriate test cases.
|
||||
* If the changes affect public APIs, change or add relevant [documentation][doc-repo].
|
||||
@@ -88,6 +89,7 @@ Before you submit your pull request consider the following guidelines:
|
||||
```shell
|
||||
git commit -a
|
||||
```
|
||||
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
* Push your branch to GitHub:
|
||||
@@ -128,22 +130,20 @@ That's it! Thank you for your contribution!
|
||||
Upon submitting a Pull Request, we will ask you to sign our CLA if you haven't done
|
||||
so before. It's a quick process, we promise, and you will be able to do it all online
|
||||
|
||||
You can read [ProcessOne Contribution License Agreement][cla] in PDF.
|
||||
Here's a link to the [ProcessOne Contribution License Agreement][cla].
|
||||
|
||||
This is part of the legal framework of the open-source ecosystem that adds some red tape,
|
||||
but protects both the contributor and the company / foundation behind the project. It also
|
||||
gives us the option to relicense the code with a more permissive license in the future.
|
||||
|
||||
|
||||
[coc]: https://github.com/processone/ejabberd/blob/master/CODE_OF_CONDUCT.md
|
||||
[stackoverflow]: https://stackoverflow.com/questions/tagged/ejabberd?sort=newest
|
||||
[list]: https://lists.jabber.ru/mailman/listinfo/ejabberd
|
||||
[muc]: xmpp:ejabberd@conference.process-one.net
|
||||
[logs]: https://process-one.net/logs/ejabberd@conference.process-one.net/
|
||||
[github]: https://github.com/processone/ejabberd
|
||||
[github-issues]: https://github.com/processone/ejabberd/issues
|
||||
[github-new-issue]: https://github.com/processone/ejabberd/issues/new
|
||||
[github-pr]: https://github.com/processone/ejabberd/pulls
|
||||
[doc-repo]: https://github.com/processone/docs.ejabberd.im
|
||||
[developer-setup]: https://docs.ejabberd.im/developer/
|
||||
[cla]: https://www.process-one.net/resources/ejabberd-cla.pdf
|
||||
[cla]: https://cla.process-one.net/
|
||||
|
||||
+12
-3
@@ -3,7 +3,8 @@
|
||||
#
|
||||
|
||||
ESCRIPT = @ESCRIPT@
|
||||
REBAR = @rebar@
|
||||
REBAR = @rebar@ # rebar|rebar3|mix binary (or path to binary)
|
||||
REBAR3 = @REBAR3@ # path to rebar3 binary
|
||||
MIX = @rebar@
|
||||
AWK = @AWK@
|
||||
INSTALL = @INSTALL@
|
||||
@@ -266,7 +267,7 @@ _build/edoc/logo.png: edoc_compile
|
||||
#
|
||||
|
||||
format:
|
||||
tools/rebar3-format.sh $(REBAR)
|
||||
tools/rebar3-format.sh $(REBAR3)
|
||||
|
||||
indent:
|
||||
tools/emacs-indent.sh
|
||||
@@ -642,6 +643,13 @@ dialyzer: erlang_plt deps_plt ejabberd_plt
|
||||
endif
|
||||
endif
|
||||
|
||||
#.
|
||||
#' elvis
|
||||
#
|
||||
|
||||
elvis:
|
||||
$(REBAR) lint
|
||||
|
||||
#.
|
||||
#' test
|
||||
#
|
||||
@@ -695,10 +703,11 @@ help:
|
||||
@echo " translations Extract translation files"
|
||||
@echo " TAGS Generate tags file for text editors"
|
||||
@echo ""
|
||||
@echo " format Format source code using rebar3_format [rebar3]"
|
||||
@echo " format Format source code using rebar3_format"
|
||||
@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]"
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
<img src="https://img.shields.io/github/v/tag/processone/docs.ejabberd.im?sort=semver&logo=&label=docs&logoWidth=0" /></a>
|
||||
</p>
|
||||
|
||||
|
||||
[ejabberd][im] is an open-source,
|
||||
robust, scalable and extensible realtime platform built using [Erlang/OTP][erlang],
|
||||
that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service.
|
||||
@@ -39,12 +38,16 @@ Installation
|
||||
There are several ways to install ejabberd:
|
||||
|
||||
- Source code: compile yourself, see [COMPILE](COMPILE.md)
|
||||
- Installers: [ProcessOne Download][p1download] and [GitHub Releases][releases] for releases, [GitHub Actions](https://github.com/processone/ejabberd/actions/workflows/installers.yml) for master branch (run/deb/rpm for x64 and arm64)
|
||||
- `ecs` container image: [Docker Hub][hubecs] and [Github Packages][packagesecs], see [ecs README][docker-ecs-readme] (for x64)
|
||||
- `ejabberd` container image: [Github Packages][packages] for releases and master branch, see [CONTAINER](CONTAINER.md) (for x64 and arm64)
|
||||
- Installers:
|
||||
- [ProcessOne Download Page][p1download] or [GitHub Releases][releases] for releases.
|
||||
- [GitHub Actions](https://github.com/processone/ejabberd/actions/workflows/installers.yml) for master branch (`run`/`deb`/`rpm` for `x64` and `arm64`)
|
||||
- Docker Containers:
|
||||
- `ecs` container image: [Docker Hub][hubecs] and [Github Packages][packagesecs], see [ecs README][docker-ecs-readme] (for `x64`)
|
||||
- `ejabberd` container image: [Github Packages][packages] for releases and master branch, see [CONTAINER](CONTAINER.md) (for `x64` and `arm64`)
|
||||
- Using your [Operating System package][osp]
|
||||
- Using the [Homebrew][homebrew] package manager
|
||||
|
||||
More info can be found in the `Installation` part of [ejabberd Docs](https://docs.ejabberd.im/admin/install/).
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
@@ -61,7 +64,6 @@ Once ejabberd is installed, try:
|
||||
ejabberdctl help
|
||||
man ejabberd.yml
|
||||
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
@@ -74,6 +76,7 @@ or in your local machine as explained in [Localization][localization].
|
||||
Documentation for developers is available in [ejabberd docs: Developers][docs-dev].
|
||||
|
||||
There are nightly builds of ejabberd, both for `master` branch and for Pull Requests:
|
||||
|
||||
- Installers: go to [GitHub Actions: Installers](https://github.com/processone/ejabberd/actions/workflows/installers.yml), open the most recent commit, on the bottom of that commit page, download the `ejabberd-packages.zip` artifact.
|
||||
- `ejabberd` container image: go to [ejabberd Github Packages][packages]
|
||||
|
||||
@@ -84,6 +87,10 @@ or some other method from [ProcessOne Contact][p1contact].
|
||||
For commercial offering and support, including [ejabberd Business Edition][p1home]
|
||||
and [Fluux (ejabberd in the Cloud)][fluux], please check [ProcessOne ejabberd page][p1home].
|
||||
|
||||
Security
|
||||
--------
|
||||
|
||||
For information on how to report security vulnerabilities, please refer to the [SECURITY.md](SECURITY.md) file. It contains guidelines on how to report vulnerabilities privately and securely, ensuring that any issues are addressed in a timely and confidential manner.
|
||||
|
||||
Community
|
||||
---------
|
||||
@@ -94,13 +101,11 @@ There are several places to get in touch with other ejabberd developers and admi
|
||||
- [GitHub Discussions][discussions]
|
||||
- [Stack Overflow][stackoverflow]
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
ejabberd is released under the GNU General Public License v2 (see [COPYING](COPYING)),
|
||||
and [ejabberd translations](https://github.com/processone/ejabberd-po/) under MIT License.
|
||||
|
||||
- `ejabberd` is released under the __GNU General Public License v2__ (see [COPYING](COPYING))
|
||||
- [ejabberd translations](https://github.com/processone/ejabberd-po/) under __MIT License__.
|
||||
|
||||
[discussions]: https://github.com/processone/ejabberd/discussions
|
||||
[docker-ecs-readme]: https://github.com/processone/docker-ejabberd/tree/master/ecs#readme
|
||||
@@ -117,16 +122,15 @@ and [ejabberd translations](https://github.com/processone/ejabberd-po/) under MI
|
||||
[mqtt]: https://mqtt.org/
|
||||
[muc]: xmpp:ejabberd@conference.process-one.net
|
||||
[osp]: https://docs.ejabberd.im/admin/install/os-package/
|
||||
[p1contact]: https://www.process-one.net/en/company/contact/
|
||||
[p1download]: https://www.process-one.net/en/ejabberd/downloads/
|
||||
[p1home]: https://www.process-one.net/en/ejabberd/
|
||||
[p1contact]: https://www.process-one.net/contact/
|
||||
[p1download]: https://www.process-one.net/download/ejabberd/
|
||||
[p1home]: https://www.process-one.net/ejabberd/
|
||||
[packages]: https://github.com/processone/ejabberd/pkgs/container/ejabberd
|
||||
[packagesecs]: https://github.com/processone/docker-ejabberd/pkgs/container/ecs
|
||||
[releases]: https://github.com/processone/ejabberd/releases
|
||||
[sip]: https://en.wikipedia.org/wiki/Session_Initiation_Protocol
|
||||
[stackoverflow]: https://stackoverflow.com/questions/tagged/ejabberd?sort=newest
|
||||
[weblate]: https://hosted.weblate.org/projects/ejabberd/ejabberd-po/
|
||||
[xeps]: https://www.process-one.net/en/ejabberd/protocols/
|
||||
[xeps]: https://www.process-one.net/ejabberd-features/
|
||||
[xmpp]: https://xmpp.org/
|
||||
[xmppej]: https://xmpp.org/software/servers/ejabberd/
|
||||
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We recommend that all users always use the latest version of ejabberd.
|
||||
|
||||
To ensure the best experience and security, upgrade to the latest version available on [this repo](https://github.com/processone/ejabberd).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
### Private Reporting
|
||||
|
||||
**Preferred Method**: Use GitHub's private vulnerability reporting system by clicking the "Report a Vulnerability" button in the [Security tab of this repository](https://github.com/processone/ejabberd/security). This ensures your report is securely transmitted and tracked.
|
||||
|
||||
**Alternative**: If you cannot use the GitHub system, send an email to **`contact@process-one.net`** with the following details:
|
||||
|
||||
- A clear description of the vulnerability.
|
||||
- Steps to reproduce the issue.
|
||||
- Any potential impact or exploitation scenarios.
|
||||
|
||||
### Response Time
|
||||
|
||||
We aim to acknowledge receipt of your report within 72 hours. You can expect regular updates on the status of your report.
|
||||
|
||||
### Resolution
|
||||
|
||||
If the vulnerability is confirmed, we will work on a patch or mitigation strategy.
|
||||
We will notify you once the issue is resolved and coordinate a public disclosure if needed.
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
We value and appreciate the contributions of security researchers and community members.
|
||||
If you wish, we are happy to acknowledge your efforts publicly by listing your name (or alias) below in this document.
|
||||
Please let us know if you would like to be recognized when reporting the vulnerability.
|
||||
|
||||
## Public Discussion
|
||||
|
||||
For general inquiries or discussions about the project’s security, feel free to chat with us here:
|
||||
|
||||
- XMPP room: `ejabberd@conference.process-one.net`
|
||||
- [GitHub Discussions](https://github.com/processone/ejabberd/discussions)
|
||||
|
||||
However, please note that if the issue is **critical** or potentially exploitable, **do not share it publicly**. Instead, we strongly recommend you contact the maintainers directly via the private reporting methods outlined above to ensure a secure and timely response.
|
||||
|
||||
Thank you for helping us improve the security of ejabberd!
|
||||
+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.12` | 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)"
|
||||
|
||||
|
||||
+185
-185
@@ -19,7 +19,7 @@
|
||||
<category rdf:resource="https://linkmauve.fr/ns/xmpp-doap#category-xmpp"/>
|
||||
|
||||
<homepage rdf:resource="https://www.ejabberd.im"/>
|
||||
<download-page rdf:resource="https://www.process-one.net/en/ejabberd/downloads/"/>
|
||||
<download-page rdf:resource="https://www.process-one.net/download/ejabberd/"/>
|
||||
<download-mirror rdf:resource="https://github.com/processone/ejabberd/tags"/>
|
||||
<license rdf:resource="https://raw.githubusercontent.com/processone/ejabberd/master/COPYING"/>
|
||||
<schema:logo rdf:resource="https://docs.ejabberd.im/assets/img/footer_logo_e@2x.png"/>
|
||||
@@ -48,8 +48,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0004.html"/>
|
||||
<xmpp:version>2.9</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -57,8 +57,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0012.html"/>
|
||||
<xmpp:version>2.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_last</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -67,7 +67,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0013.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since>16.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_offline</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -75,8 +75,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0016.html"/>
|
||||
<xmpp:version>1.6</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_privacy</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -84,8 +84,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0022.html"/>
|
||||
<xmpp:version>1.4</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_offline</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -93,8 +93,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0023.html"/>
|
||||
<xmpp:version>1.3</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.7.5</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_offline</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -102,8 +102,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0030.html"/>
|
||||
<xmpp:version>2.4</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_disco</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -112,7 +112,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0033.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since>15.04</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_multicast</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -120,8 +120,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0039.html"/>
|
||||
<xmpp:version>0.6.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_stats</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -129,8 +129,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0045.html"/>
|
||||
<xmpp:version>1.25</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_muc</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -138,8 +138,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0049.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_private</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -147,8 +147,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0050.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>1.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_adhoc</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -156,8 +156,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0054.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_vcard</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -165,8 +165,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0055.html"/>
|
||||
<xmpp:version>1.3</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_vcard</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -174,8 +174,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0059.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -183,8 +183,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0060.html"/>
|
||||
<xmpp:version>1.14</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>partial</xmpp:status>
|
||||
<xmpp:note>mod_pubsub</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -192,8 +192,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0065.html"/>
|
||||
<xmpp:version>1.8</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.0.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_proxy65</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -201,8 +201,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0077.html"/>
|
||||
<xmpp:version>2.4</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_register</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -210,17 +210,26 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0078.html"/>
|
||||
<xmpp:version>2.5</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>17.03</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_legacy_auth</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0082.html"/>
|
||||
<xmpp:version>1.1.1</xmpp:version>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0085.html"/>
|
||||
<xmpp:version>2.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_client_state</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -228,8 +237,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0086.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -237,8 +246,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0092.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_version</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -246,8 +255,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0106.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.5.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -255,8 +264,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0114.html"/>
|
||||
<xmpp:version>1.6</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>0.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_service</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -264,8 +273,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0115.html"/>
|
||||
<xmpp:version>1.5</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.4</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_caps</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -273,8 +282,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0124.html"/>
|
||||
<xmpp:version>1.11</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>16.12</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_bosh</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -283,7 +292,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0133.html"/>
|
||||
<xmpp:version>1.3.0</xmpp:version>
|
||||
<xmpp:since>13.10</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:status>partial</xmpp:status>
|
||||
<xmpp:note>mod_configure</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -291,8 +300,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0138.html"/>
|
||||
<xmpp:version>2.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>1.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_c2s</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -300,8 +309,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0153.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>17.09</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_vcard</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -310,7 +319,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0156.html"/>
|
||||
<xmpp:version>1.4.0</xmpp:version>
|
||||
<xmpp:since>22.05</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_host_meta</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -318,8 +327,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0157.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_disco</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -327,8 +336,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0158.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_captcha</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -336,8 +345,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0160.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>16.01</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_offline</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -345,8 +354,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0163.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.0.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_pubsub</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -354,8 +363,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0170.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>17.12</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -363,26 +372,26 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0175.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>1.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_auth_anonymous</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0176.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note>ejabberd_stun</xmpp:note>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0178.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since>17.03</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0185.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>17.03</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_s2s_dialback</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -390,8 +399,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0191.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.7</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_blocking</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -400,7 +409,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0198.html"/>
|
||||
<xmpp:version>1.5.2</xmpp:version>
|
||||
<xmpp:since>14.05</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_stream_mgmt</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -408,8 +417,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0199.html"/>
|
||||
<xmpp:version>2.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_ping</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -417,8 +426,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0202.html"/>
|
||||
<xmpp:version>2.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_time</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -426,8 +435,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0203.html"/>
|
||||
<xmpp:version>2.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_offline</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -435,8 +444,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0205.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>1.1.2</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -444,53 +453,35 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0206.html"/>
|
||||
<xmpp:version>1.4</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>16.12</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_bosh</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0212.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0215.html"/>
|
||||
<xmpp:version>0.7</xmpp:version>
|
||||
<xmpp:since>20.04</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_stun_disco</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0216.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0220.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note>ejabberd_s2s, mod_s2s_dialback</xmpp:note>
|
||||
<xmpp:version>1.1.1</xmpp:version>
|
||||
<xmpp:since>17.03</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_s2s_dialback</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0227.html"/>
|
||||
<xmpp:version>1.1</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>partial</xmpp:status>
|
||||
<xmpp:note>ejabberd_piefxis</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -498,8 +489,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0231.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>ejabberd_captcha</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -507,53 +498,26 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0237.html"/>
|
||||
<xmpp:version>1.3</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_roster</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0243.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0248.html"/>
|
||||
<xmpp:version>0.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.0</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_pubsub</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0249.html"/>
|
||||
<xmpp:version>1.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note>mod_muc</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0270.html"/>
|
||||
<xmpp:version>1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0279.html"/>
|
||||
<xmpp:version>0.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>2.1.3</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_sic</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -561,17 +525,26 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0280.html"/>
|
||||
<xmpp:version>0.13.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>13.06</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<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"/>
|
||||
<xmpp:version>0.6.1</xmpp:version>
|
||||
<xmpp:since>15.06</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mam</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -580,7 +553,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0317.html"/>
|
||||
<xmpp:version>0.1</xmpp:version>
|
||||
<xmpp:since>21.12</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_muc_room, conversejs/prosody compatible</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -589,7 +562,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0328.html"/>
|
||||
<xmpp:version>0.1</xmpp:version>
|
||||
<xmpp:since>19.09</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_jidprep</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -597,8 +570,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0334.html"/>
|
||||
<xmpp:version>0.2</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>16.01</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mam, mod_muc_log, mod_offline</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -607,7 +580,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0352.html"/>
|
||||
<xmpp:version>0.1</xmpp:version>
|
||||
<xmpp:since>14.12</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_client_state</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -616,16 +589,16 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0355.html"/>
|
||||
<xmpp:version>0.4.1</xmpp:version>
|
||||
<xmpp:since>16.09</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_delegation</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<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:status></xmpp:status>
|
||||
<xmpp:version>0.4.1</xmpp:version>
|
||||
<xmpp:since>24.10</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_privilege</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -634,7 +607,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0357.html"/>
|
||||
<xmpp:version>0.2</xmpp:version>
|
||||
<xmpp:since>17.08</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_push</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -642,17 +615,17 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0359.html"/>
|
||||
<xmpp:version>0.5.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>15.09</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mam</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0363.html"/>
|
||||
<xmpp:version>0.2</xmpp:version>
|
||||
<xmpp:version>0.3.0</xmpp:version>
|
||||
<xmpp:since>15.10</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_http_upload</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -660,8 +633,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0368.html"/>
|
||||
<xmpp:version>1.1.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>17.09</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -670,16 +643,25 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0369.html"/>
|
||||
<xmpp:version>0.14.1</xmpp:version>
|
||||
<xmpp:since>16.03</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mix</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0384.html"/>
|
||||
<xmpp:version>0.8.3</xmpp:version>
|
||||
<xmpp:since>21.12</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>node_pep</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0386.html"/>
|
||||
<xmpp:version>0.3.0</xmpp:version>
|
||||
<xmpp:since>24.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -688,7 +670,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0388.html"/>
|
||||
<xmpp:version>0.4.0</xmpp:version>
|
||||
<xmpp:since>24.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -697,7 +679,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0398.html"/>
|
||||
<xmpp:version>0.2.0</xmpp:version>
|
||||
<xmpp:since>18.03</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_avatar</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -706,7 +688,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0402.html"/>
|
||||
<xmpp:version>1.1.3</xmpp:version>
|
||||
<xmpp:since>23.10</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_private</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -714,8 +696,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0405.html"/>
|
||||
<xmpp:version>0.3.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>19.02</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mix_pam</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -724,7 +706,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0410.html"/>
|
||||
<xmpp:version>1.1.0</xmpp:version>
|
||||
<xmpp:since>18.12</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_muc_room</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -733,7 +715,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0411.html"/>
|
||||
<xmpp:version>0.2.0</xmpp:version>
|
||||
<xmpp:since>18.12</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_private</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -742,7 +724,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0421.html"/>
|
||||
<xmpp:version>0.1.0</xmpp:version>
|
||||
<xmpp:since>23.10</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_muc_occupantid</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -751,7 +733,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0424.html"/>
|
||||
<xmpp:version>0.4.0</xmpp:version>
|
||||
<xmpp:since>24.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -760,7 +742,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0425.html"/>
|
||||
<xmpp:version>0.3.0</xmpp:version>
|
||||
<xmpp:since>24.06</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mam</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -769,7 +751,7 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0440.html"/>
|
||||
<xmpp:version>0.4.0</xmpp:version>
|
||||
<xmpp:since>24.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -777,8 +759,8 @@
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0441.html"/>
|
||||
<xmpp:version>0.2.0</xmpp:version>
|
||||
<xmpp:since></xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:since>15.06</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_mam</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
@@ -787,16 +769,34 @@
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0474.html"/>
|
||||
<xmpp:version>0.3.0</xmpp:version>
|
||||
<xmpp:since>24.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note></xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0480.html"/>
|
||||
<xmpp:version>0.2.0</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-0484.html"/>
|
||||
<xmpp:version>0.2.0</xmpp:version>
|
||||
<xmpp:since>24.12</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_auth_fast</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
<xmpp:SupportedXep>
|
||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0485.html"/>
|
||||
<xmpp:version>0.2.0</xmpp:version>
|
||||
<xmpp:since>24.02</xmpp:since>
|
||||
<xmpp:status></xmpp:status>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>, mod_pubsub_serverinfo in ejabberd-contrib.git</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
|
||||
@@ -9,7 +9,6 @@ Group=@installuser@
|
||||
LimitNOFILE=65536
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
WatchdogSec=30
|
||||
ExecStart=@ctlscriptpath@/ejabberdctl foreground
|
||||
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
|
||||
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
|
||||
|
||||
@@ -67,7 +67,7 @@ listen:
|
||||
/admin: ejabberd_web_admin
|
||||
/.well-known/acme-challenge: ejabberd_acme
|
||||
-
|
||||
port: 3478
|
||||
port: 5478
|
||||
ip: "::"
|
||||
transport: udp
|
||||
module: ejabberd_stun
|
||||
@@ -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(),
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
defmodule Ejabberd.Module do
|
||||
|
||||
defmacro __using__(opts) do
|
||||
logger_enabled = Keyword.get(opts, :logger, true)
|
||||
|
||||
quote do
|
||||
@behaviour :gen_mod
|
||||
import Ejabberd.Module
|
||||
|
||||
unquote(if logger_enabled do
|
||||
quote do: import Ejabberd.Logger
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
# gen_mod callbacks
|
||||
def depends(_host, _opts), do: []
|
||||
def mod_opt_type(_), do: []
|
||||
end
|
||||
@@ -0,0 +1,44 @@
|
||||
defmodule Ejabberd.Auth.Example do
|
||||
|
||||
@moduledoc """
|
||||
Example ejabberd auth method written in Elixir.
|
||||
|
||||
This is an example to demonstrate the usage of Elixir to
|
||||
create ejabberd auth methods.
|
||||
|
||||
Example configuration:
|
||||
auth_method: 'Ejabberd.Auth.Example'
|
||||
"""
|
||||
|
||||
@behaviour :ejabberd_auth
|
||||
import Ejabberd.Logger
|
||||
|
||||
@impl true
|
||||
def start(host) do
|
||||
info("Starting Ejabberd.Auth.Example to authenticate '#{host}' users")
|
||||
nil
|
||||
end
|
||||
|
||||
@impl true
|
||||
def stop(host) do
|
||||
info("Stopping Ejabberd.Auth.Example to authenticate '#{host}' users")
|
||||
nil
|
||||
end
|
||||
|
||||
@impl true
|
||||
def check_password("alice", _authz_id, _host, "secret"), do: {:nocache, true}
|
||||
def check_password(_username, _authz_id, _host, _secret), do: {:nocache, false}
|
||||
|
||||
@impl true
|
||||
def user_exists("alice", _host), do: {:nocache, true}
|
||||
def user_exists(_username, _host), do: {:nocache, false}
|
||||
|
||||
@impl true
|
||||
def plain_password_required(_binary), do: true
|
||||
|
||||
@impl true
|
||||
def store_type(_host), do: :external
|
||||
|
||||
@impl true
|
||||
def use_cache(_host), do: false
|
||||
end
|
||||
@@ -1,14 +1,27 @@
|
||||
defmodule ModPresenceDemo do
|
||||
use Ejabberd.Module
|
||||
defmodule Ejabberd.Module.Example do
|
||||
|
||||
@moduledoc """
|
||||
Example ejabberd module written in Elixir.
|
||||
|
||||
This is an example to demonstrate the usage of Elixir to
|
||||
create ejabberd modules.
|
||||
|
||||
Example configuration:
|
||||
modules:
|
||||
'Ejabberd.Module.Example': {}
|
||||
"""
|
||||
|
||||
@behaviour :gen_mod
|
||||
import Ejabberd.Logger
|
||||
|
||||
def start(host, _opts) do
|
||||
info("Starting ejabberd module Presence Demo")
|
||||
info("Starting Ejabberd.Module.Example for host '#{host}'")
|
||||
Ejabberd.Hooks.add(:set_presence_hook, host, __MODULE__, :on_presence, 50)
|
||||
:ok
|
||||
end
|
||||
|
||||
def stop(host) do
|
||||
info("Stopping ejabberd module Presence Demo")
|
||||
info("Stopping Ejabberd.Module.Example for host '#{host}'")
|
||||
Ejabberd.Hooks.delete(:set_presence_hook, host, __MODULE__, :on_presence, 50)
|
||||
:ok
|
||||
end
|
||||
+444
-192
File diff suppressed because it is too large
Load Diff
@@ -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", override: true},
|
||||
{:fast_yaml, "~> 1.0"},
|
||||
{:idna, "~> 6.0"},
|
||||
{:mqtree, "~> 1.0"},
|
||||
@@ -145,8 +144,8 @@ defmodule Ejabberd.MixProject do
|
||||
{:p1_utils, "~> 1.0"},
|
||||
{:pkix, "~> 1.0"},
|
||||
{:stringprep, ">= 1.0.26"},
|
||||
{:xmpp, ">= 1.8.3"},
|
||||
{:yconf, "~> 1.0"}]
|
||||
{:xmpp, "~> 1.9.1"},
|
||||
{:yconf, "~> 1.0.17"}]
|
||||
++ cond_deps()
|
||||
end
|
||||
|
||||
@@ -166,8 +165,8 @@ defmodule Ejabberd.MixProject do
|
||||
{Mix.env() == :translations,
|
||||
{:ejabberd_po, git: "https://github.com/processone/ejabberd-po.git"}},
|
||||
{Mix.env() == :dev,
|
||||
{:exsync, "~> 0.2"}},
|
||||
{config(:redis), {:eredis, "~> 1.2.0"}},
|
||||
{:exsync, "~> 0.2", optional: true, runtime: false}},
|
||||
{config(:redis), {:eredis, "~> 1.7.1"}},
|
||||
{config(:sip), {:esip, "~> 1.0"}},
|
||||
{config(:zlib), {:ezlib, "~> 1.0"}},
|
||||
{if_version_above(~c"23", true), {:jose, "~> 1.11.10"}},
|
||||
@@ -184,9 +183,10 @@ 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:
|
||||
{config(:tools), :debugger},
|
||||
{config(:tools), :observer},
|
||||
{config(:tools), :wx}], do:
|
||||
app
|
||||
end
|
||||
|
||||
@@ -214,9 +214,9 @@ defmodule Ejabberd.MixProject do
|
||||
maintainers: ["ProcessOne"],
|
||||
licenses: ["GPL-2.0-or-later"],
|
||||
links: %{"ejabberd.im" => "https://www.ejabberd.im",
|
||||
"ejabberd Docs" => "http://docs.ejabberd.im",
|
||||
"ejabberd Docs" => "https://docs.ejabberd.im",
|
||||
"GitHub" => "https://github.com/processone/ejabberd",
|
||||
"ProcessOne" => "http://www.process-one.net/"}]
|
||||
"ProcessOne" => "https://www.process-one.net/"}]
|
||||
end
|
||||
|
||||
defp vars do
|
||||
|
||||
@@ -1,40 +1,39 @@
|
||||
%{
|
||||
"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.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
|
||||
"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"},
|
||||
"eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"},
|
||||
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
|
||||
"esip": {:hex, :esip, "1.0.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"},
|
||||
"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"},
|
||||
"esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"},
|
||||
"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.55", "ace020f2521f2a484ac8467d2822af85534a346e2aae03ffcbc34f29318befaf", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "83f3e23a780ed5f567cdec73953f06c95b838d709dbfa86b59a98a8d23c99f85"},
|
||||
"fast_yaml": {:hex, :fast_yaml, "1.0.37", "f71d472fbf787ccd161b914d1eb486116a0f4f2e835337a378fbd31b59d2e74b", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8de868721bf7e2172414f7d3148ede0f3c922b496455cd625dd5c4429515a769"},
|
||||
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
|
||||
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
|
||||
"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"},
|
||||
"luerl": {:hex, :luerl, "1.2.3", "df25f41944e57a7c4d9ef09d238bc3e850276c46039cfc12b8bb42eccf36fcb1", [:rebar3], [], "hexpm", "1b4b9d0ca5d7d280d1d2787a6a5ee9f5a212641b62bff91556baa53805df3aed"},
|
||||
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
|
||||
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
|
||||
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
|
||||
"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.25", "db91f0d6c193cd1d5c0b0fa3939a898dbf56a6075db4347cde26e802715de50c", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.17", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "a7b55b47495ddb4f98a15e65451ec3ad43f4637b955c74cd695d98e6a645d08c"},
|
||||
"p1_mysql": {:hex, :p1_mysql, "1.0.25", "875d4cbdc7c9990270df3292cce2514e4c18a9fdfd19bef258cb4d0c45b4f243", [:rebar3], [], "hexpm", "e6187ffae95b726098e88f3ee6f2344ac259ce2c26e0ee403b05feef341ae434"},
|
||||
"p1_oauth2": {:hex, :p1_oauth2, "0.6.14", "1c5f82535574de87e2059695ac4b91f8f9aebacbc1c80287dae6f02552d47aea", [:rebar3], [], "hexpm", "1fd3ac474e43722d9d5a87c6df8d36f698ed87af7bb81cbbb66361451d99ae8f"},
|
||||
"p1_pgsql": {:hex, :p1_pgsql, "1.1.27", "883e335d82ac062de0bde7981f8250a2e632258bb7a47df839a4cbdcb3e971e6", [:rebar3], [{:xmpp, "~> 1.8.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "8e4d1a7602cb68780e55d89dc5a9b2e1aaca3f4f1ee3d1a25f2f8c3d2364ffb9"},
|
||||
"p1_pgsql": {:hex, :p1_pgsql, "1.1.29", "fae0c90cbc5931865958150f1b667fb0d20b063f6a46a17770a4e5232ded632c", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "a6ff58e8b174993f3895da3ea6211a9f9d0c54d1a6e28bb321da3b3cd68b38c1"},
|
||||
"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"},
|
||||
"yconf": {:hex, :yconf, "1.0.16", "d59521d66ff89f219411b6e9277cd6feec7cc6fce11554e67de02a8d0a470479", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "e947813273f38711c7b2e5a8e4acc9a51c7bbe854f744a345f60300b38586c89"},
|
||||
"xmpp": {:hex, :xmpp, "1.9.1", "a1642d93cdbdf947f32344b0e05fcc8efcfb9f11c32832acc9bd826b52adbe48", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "d2b1431af6e4c1a4c8bf90caf0cc11cdeb047b8323b87e9d7e4826d4913275dc"},
|
||||
"yconf": {:hex, :yconf, "1.0.17", "dcf242e27f3fc5d0743d6b8175dd39bc14a1f4ed7e6ea986366a44a6ff3b2a3a", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "dd2892923241449a46cc8457b9ec0fb14030700735a5885955677c735c341a25"},
|
||||
}
|
||||
|
||||
+29
-2
@@ -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"}.
|
||||
@@ -156,8 +161,14 @@
|
||||
{"Get Pending","Виж чакащи"}.
|
||||
{"Get User Last Login Time","Покажи времето, когато потребителят е влязъл за последно"}.
|
||||
{"Get User Statistics","Покажи статистика за потребителя"}.
|
||||
{"Given Name","Име"}.
|
||||
{"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"}.
|
||||
@@ -280,6 +295,7 @@
|
||||
{"No pending subscriptions found","Не са намерени чакащи абонаменти"}.
|
||||
{"No privacy list with this name found","Не е намерен списък за поверителност с това име"}.
|
||||
{"No private data found in this query","Няма открити лични данни в тази заявка"}.
|
||||
{"No <privileged_iq/> element found","Елементът <privileged_iq/> не е намерен"}.
|
||||
{"No running node found","Не е намерен работещ нод"}.
|
||||
{"No services available","Няма налични услуги"}.
|
||||
{"No statistics found for this item","Не е налична статистика за този елемент"}.
|
||||
@@ -360,6 +376,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 +440,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 +500,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","Паролите са различни"}.
|
||||
@@ -494,7 +513,7 @@
|
||||
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","Строфата ТРЯБВА да съдържа само един <active/> елемент, един <default/> елемент или един <list/> елемент"}.
|
||||
{"The subscription identifier associated with the subscription request","Идентификаторът на абонамента, свързан със заявката за абонамент"}.
|
||||
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","URL адрес на XSL трансформацията, която може да се приложи към прикачените данни, за да се генерира подходящ елемент от тялото на съобщението."}.
|
||||
{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","URL адрес на XSL трансформацията, която може да се приложи към формата на прикачените данни, за да се генерира валиден резултат от Data Forms, който клиентът може да покаже с помощта на общ механизъм за визуализация на Data Forms."}.
|
||||
{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","URL адрес на XSL трансформацията, която може да се приложи към формата на прикачените данни, за да се генерира валиден резултат от Data Forms, който клиентът може да покаже с помощта на общ механизъм за визуализация на Data Forms"}.
|
||||
{"There was an error changing the password: ","Възникна грешка при промяна на паролата: "}.
|
||||
{"There was an error creating the account: ","Възникна грешка при създаването на профила: "}.
|
||||
{"There was an error deleting the account: ","Възникна грешка при изтриването на профила: "}.
|
||||
@@ -519,6 +538,7 @@
|
||||
{"Too many unacked stanzas","Твърде много непотвърдени строфи"}.
|
||||
{"Too many users in this conference","Твърде много потребители в тази конференция"}.
|
||||
{"Traffic rate limit is exceeded","Лимитът за трафик е надвишен"}.
|
||||
{"~ts's MAM Archive","~ts's MAM архив"}.
|
||||
{"~ts's Offline Messages Queue","Офлайн съобщения на ~ts"}.
|
||||
{"Tuesday","Вторник"}.
|
||||
{"Unable to generate a CAPTCHA","Не може да се генерира CAPTCHA"}.
|
||||
@@ -535,12 +555,14 @@
|
||||
{"Update message of the day on all hosts (don't send)","Актуализирай съобщението на деня на всички хостове (не изпращай)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","Актуализирайте спецификациите, за да получите източник на модули, след което инсталирайте желаните."}.
|
||||
{"Update Specs","Актуализирай спецификациите"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","Актуализирането на vCard не се поддържа от настройката за съхранение на vCard"}.
|
||||
{"Upgrade","Обнови"}.
|
||||
{"URL for Archived Discussion Logs","URL адрес за дневници на архивирани дискусии"}.
|
||||
{"User already exists","Потребителят вече съществува"}.
|
||||
{"User (jid)","Потребител (jid)"}.
|
||||
{"User JID","Потребител JID"}.
|
||||
{"User Management","Управление на потребители"}.
|
||||
{"User not allowed to perform an IQ set on another user's vCard.","Потребителят не може да извършва IQ настрийка на vCard на друг потребител."}.
|
||||
{"User removed","Потребителят е премахнат"}.
|
||||
{"User session not found","Потребителската сесия не е намерена"}.
|
||||
{"User session terminated","Потребителската сесия е прекратена"}.
|
||||
@@ -555,6 +577,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 +607,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 +618,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"}.
|
||||
@@ -294,6 +295,7 @@
|
||||
{"No pending subscriptions found","No s'han trobat subscripcions pendents"}.
|
||||
{"No privacy list with this name found","No s'ha trobat cap llista de privacitat amb aquest nom"}.
|
||||
{"No private data found in this query","No s'ha trobat dades privades en esta petició"}.
|
||||
{"No <privileged_iq/> element found","No s'ha trobat cap element <privileged_iq/>"}.
|
||||
{"No running node found","No s'ha trobat node en marxa"}.
|
||||
{"No services available","No n'hi ha serveis disponibles"}.
|
||||
{"No statistics found for this item","No n'hi ha estadístiques disponibles per a aquest element"}.
|
||||
@@ -536,6 +538,7 @@
|
||||
{"Too many unacked stanzas","Massa missatges sense haver reconegut la seva recepció"}.
|
||||
{"Too many users in this conference","N'hi ha massa usuaris en esta sala de conferència"}.
|
||||
{"Traffic rate limit is exceeded","El límit de tràfic ha sigut sobrepassat"}.
|
||||
{"~ts's MAM Archive","Arxiu MAM de ~ts"}.
|
||||
{"~ts's Offline Messages Queue","~ts's cua de missatges offline"}.
|
||||
{"Tuesday","Dimarts"}.
|
||||
{"Unable to generate a CAPTCHA","No s'ha pogut generar un CAPTCHA"}.
|
||||
@@ -552,12 +555,14 @@
|
||||
{"Update message of the day on all hosts (don't send)","Actualitza el missatge del dia en tots els hosts (no enviar)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","Actualitza les especificacions per obtindre el codi font dels mòduls, després instal·la els que vulgues."}.
|
||||
{"Update Specs","Actualitzar Especificacions"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","El sistema d'almacenament de vCard no te capacitat per a actualitzar la vCard"}.
|
||||
{"Upgrade","Actualitza"}.
|
||||
{"URL for Archived Discussion Logs","URL dels Arxius de Discussions"}.
|
||||
{"User already exists","El usuari ja existeix"}.
|
||||
{"User JID","JID del usuari"}.
|
||||
{"User (jid)","Usuari (jid)"}.
|
||||
{"User Management","Gestió d'Usuaris"}.
|
||||
{"User not allowed to perform an IQ set on another user's vCard.","L'usuari no te permis per a modificar la vCard d'altre usuari."}.
|
||||
{"User removed","Usuari borrat"}.
|
||||
{"User session not found","Sessió d'usuari no trobada"}.
|
||||
{"User session terminated","Sessió d'usuari terminada"}.
|
||||
|
||||
@@ -223,6 +223,7 @@
|
||||
{"leaves the room","verlässt den Raum"}.
|
||||
{"List of users with hats","Liste der Benutzer mit Funktionen"}.
|
||||
{"List users with hats","Benutzer mit Funktionen auflisten"}.
|
||||
{"Logged Out","Abgemeldet"}.
|
||||
{"Logging","Protokollierung"}.
|
||||
{"Make participants list public","Teilnehmerliste öffentlich machen"}.
|
||||
{"Make room CAPTCHA protected","Raum mittels CAPTCHA schützen"}.
|
||||
@@ -293,6 +294,7 @@
|
||||
{"No pending subscriptions found","Keine ausstehenden Abonnements gefunden"}.
|
||||
{"No privacy list with this name found","Keine Privacy-Liste mit diesem Namen gefunden"}.
|
||||
{"No private data found in this query","Keine privaten Daten in dieser Anfrage gefunden"}.
|
||||
{"No <privileged_iq/> element found","Kein <privileged_iq/>-Element gefunden"}.
|
||||
{"No running node found","Kein laufender Knoten gefunden"}.
|
||||
{"No services available","Keine Dienste verfügbar"}.
|
||||
{"No statistics found for this item","Keine Statistiken für dieses Item gefunden"}.
|
||||
@@ -532,6 +534,7 @@
|
||||
{"Too many unacked stanzas","Zu viele unbestätigte Stanzas"}.
|
||||
{"Too many users in this conference","Zu viele Benutzer in dieser Konferenz"}.
|
||||
{"Traffic rate limit is exceeded","Datenratenlimit wurde überschritten"}.
|
||||
{"~ts's MAM Archive","~ts's MAM Archiv"}.
|
||||
{"~ts's Offline Messages Queue","Offline-Nachrichten-Warteschlange von ~ts"}.
|
||||
{"Tuesday","Dienstag"}.
|
||||
{"Unable to generate a CAPTCHA","Konnte kein CAPTCHA erstellen"}.
|
||||
@@ -588,6 +591,7 @@
|
||||
{"Whether to allow subscriptions","Ob Abonnements erlaubt sind"}.
|
||||
{"Whether to make all subscriptions temporary, based on subscriber presence","Ob alle Abonnements temporär gemacht werden sollen, basierend auf der Abonnentenpräsenz"}.
|
||||
{"Whether to notify owners about new subscribers and unsubscribes","Ob Besitzer über neue Abonnenten und Abbestellungen benachrichtigt werden sollen"}.
|
||||
{"Who can send private messages","Wer kann private Nachrichten senden"}.
|
||||
{"Who may associate leaf nodes with a collection","Wer Blattknoten mit einer Sammlung verknüpfen darf"}.
|
||||
{"Wrong parameters in the web formulary","Falsche Parameter im Webformular"}.
|
||||
{"Wrong xmlns","Falscher xmlns"}.
|
||||
|
||||
@@ -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"}.
|
||||
@@ -294,6 +295,7 @@
|
||||
{"No pending subscriptions found","No se han encontrado suscripciones pendientes"}.
|
||||
{"No privacy list with this name found","No se ha encontrado una lista de privacidad con este nombre"}.
|
||||
{"No private data found in this query","No se ha encontrado ningún elemento de dato privado en esta petición"}.
|
||||
{"No <privileged_iq/> element found","No se encontró ningún elemento <privileged_iq/>"}.
|
||||
{"No running node found","No se ha encontrado ningún nodo activo"}.
|
||||
{"No services available","No hay servicios disponibles"}.
|
||||
{"No statistics found for this item","No se han encontrado estadísticas para este elemento"}.
|
||||
@@ -536,6 +538,7 @@
|
||||
{"Too many unacked stanzas","Demasiados mensajes sin haber reconocido recibirlos"}.
|
||||
{"Too many users in this conference","Demasiados usuarios en esta sala"}.
|
||||
{"Traffic rate limit is exceeded","Se ha excedido el límite de tráfico"}.
|
||||
{"~ts's MAM Archive","Archivo MAM de ~ts"}.
|
||||
{"~ts's Offline Messages Queue","Cola de mensajes diferidos de ~ts"}.
|
||||
{"Tuesday","Martes"}.
|
||||
{"Unable to generate a CAPTCHA","No se pudo generar un CAPTCHA"}.
|
||||
@@ -552,12 +555,14 @@
|
||||
{"Update message of the day on all hosts (don't send)","Actualizar el mensaje del día en todos los dominos (pero no enviarlo)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","Actualizar Especificaciones para conseguir el código fuente de los módulos, luego instala los que quieras."}.
|
||||
{"Update Specs","Actualizar Especificaciones"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","La actualización de la vCard no es compatible con el vCard almacenamiento backend"}.
|
||||
{"Upgrade","Actualizar"}.
|
||||
{"URL for Archived Discussion Logs","URL del registro de discusiones archivadas"}.
|
||||
{"User already exists","El usuario ya existe"}.
|
||||
{"User JID","Jabber ID del usuario"}.
|
||||
{"User (jid)","Usuario (jid)"}.
|
||||
{"User Management","Administración de usuarios"}.
|
||||
{"User not allowed to perform an IQ set on another user's vCard.","No se permite al usuario realizar un IQ establecido en la vCard de otro usuario."}.
|
||||
{"User removed","Usuario eliminado"}.
|
||||
{"User session not found","Sesión de usuario no encontrada"}.
|
||||
{"User session terminated","Sesión de usuario terminada"}.
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
{"Incorrect value of 'action' attribute","Valeur de l'attribut 'action' incorrecte"}.
|
||||
{"Incorrect value of 'action' in data form","Valeur de l'attribut 'action' incorrecte dans le formulaire"}.
|
||||
{"Incorrect value of 'path' in data form","Valeur de l'attribut 'path' incorrecte dans le formulaire"}.
|
||||
{"Install","Installer"}.
|
||||
{"Insufficient privilege","Droits insuffisants"}.
|
||||
{"Internal server error","Erreur interne du serveur"}.
|
||||
{"Invalid 'from' attribute in forwarded message","L'attribut 'from' du message transféré est incorrect"}.
|
||||
@@ -480,12 +481,14 @@
|
||||
{"Unauthorized","Non autorisé"}.
|
||||
{"Unexpected action","Action inattendu"}.
|
||||
{"Unexpected error condition: ~p","Condition d’erreur inattendue : ~p"}.
|
||||
{"Uninstall","Désinstaller"}.
|
||||
{"Unregister an XMPP account","Annuler l’enregistrement d’un compte XMPP"}.
|
||||
{"Unregister","Désinscrire"}.
|
||||
{"Unsupported <index/> element","Elément <index/> non supporté"}.
|
||||
{"Unsupported version","Version non prise en charge"}.
|
||||
{"Update message of the day (don't send)","Mise à jour du message du jour (pas d'envoi)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Mettre à jour le message du jour sur tous les domaines (ne pas envoyer)"}.
|
||||
{"Upgrade","Mise à niveau"}.
|
||||
{"URL for Archived Discussion Logs","URL des journaux de discussion archivés"}.
|
||||
{"User already exists","L'utilisateur existe déjà"}.
|
||||
{"User JID","JID de l'utilisateur"}.
|
||||
|
||||
+9
-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","è stato espulso a causa di un cambiamento di appartenenza"}.
|
||||
{"has been kicked because the room has been changed to members-only","è stato espulso per la limitazione della stanza ai soli membri"}.
|
||||
{"has been kicked","è stata/o espulsa/o"}.
|
||||
{"Hash of the vCard-temp avatar of this room","Hash dell'avatar vCard-temp di questa stanza"}.
|
||||
{"Hat title","Titolo del Cappello"}.
|
||||
{"Hat URI","URI Cappello"}.
|
||||
{"Hats limit exceeded","Limite di cappelli superato"}.
|
||||
@@ -294,6 +295,7 @@
|
||||
{"No pending subscriptions found","Nessuna sottoscrizione in attesa trovata"}.
|
||||
{"No privacy list with this name found","Nessun elenco di privacy con questo nome trovato"}.
|
||||
{"No private data found in this query","Non sono stati trovati dati privati in questa query"}.
|
||||
{"No <privileged_iq/> element found","Nessun elemento <privileged_iq/> trovato"}.
|
||||
{"No running node found","Nessun nodo in esecuzione trovato"}.
|
||||
{"No services available","Nessun servizio disponibile"}.
|
||||
{"No statistics found for this item","Nessuna statistica trovata per questa voce"}.
|
||||
@@ -536,6 +538,7 @@
|
||||
{"Too many unacked stanzas","Troppe stanze non riconosciute"}.
|
||||
{"Too many users in this conference","Troppi utenti in questa conferenza"}.
|
||||
{"Traffic rate limit is exceeded","Limite di traffico superato"}.
|
||||
{"~ts's MAM Archive","Archivio MAM di ~ts"}.
|
||||
{"~ts's Offline Messages Queue","La Coda dei Messaggi Offline di ~ts"}.
|
||||
{"Tuesday","Martedì"}.
|
||||
{"Unable to generate a CAPTCHA","Impossibile generare un CAPTCHA"}.
|
||||
@@ -552,12 +555,14 @@
|
||||
{"Update message of the day on all hosts (don't send)","Aggiornare il messaggio del giorno (MOTD) su tutti gli host (non inviarlo)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","Aggiorna le specifiche per ottenere il sorgente dei moduli, quindi installa quelli desiderati."}.
|
||||
{"Update Specs","Aggiorna Specifiche"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","L'aggiornamento della vCard non è supportato dal backend di archiviazione vCard"}.
|
||||
{"Upgrade","Aggiornamento"}.
|
||||
{"URL for Archived Discussion Logs","URL per i Registri delle Discussioni Archiviati"}.
|
||||
{"User already exists","L'utente esiste già"}.
|
||||
{"User JID","JID utente"}.
|
||||
{"User (jid)","Utente (jid)"}.
|
||||
{"User Management","Gestione degli utenti"}.
|
||||
{"User not allowed to perform an IQ set on another user's vCard.","L'utente non è autorizzato a eseguire un set IQ sulla vCard di un altro utente."}.
|
||||
{"User removed","Utente rimosso"}.
|
||||
{"User session not found","Sessione utente non trovata"}.
|
||||
{"User session terminated","Sessione utente terminata"}.
|
||||
|
||||
@@ -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"}.
|
||||
@@ -294,6 +295,7 @@
|
||||
{"No pending subscriptions found","Não foram encontradas subscrições"}.
|
||||
{"No privacy list with this name found","Nenhuma lista de privacidade encontrada com este nome"}.
|
||||
{"No private data found in this query","Nenhum dado privado encontrado nesta consulta"}.
|
||||
{"No <privileged_iq/> element found","Nenhum elemento <privileged_iq/> foi encontrado"}.
|
||||
{"No running node found","Nenhum nó em execução foi encontrado"}.
|
||||
{"No services available","Não há serviços disponíveis"}.
|
||||
{"No statistics found for this item","Não foram encontradas estatísticas para este item"}.
|
||||
@@ -536,6 +538,7 @@
|
||||
{"Too many unacked stanzas","Número excessivo de instâncias sem confirmação"}.
|
||||
{"Too many users in this conference","Há uma quantidade excessiva de usuários nesta conferência"}.
|
||||
{"Traffic rate limit is exceeded","Limite de banda excedido"}.
|
||||
{"~ts's MAM Archive","Arquivo ~ts's MAM"}.
|
||||
{"~ts's Offline Messages Queue","~s's Fila de Mensagens Offline"}.
|
||||
{"Tuesday","Terça"}.
|
||||
{"Unable to generate a CAPTCHA","Impossível gerar um CAPTCHA"}.
|
||||
@@ -552,12 +555,14 @@
|
||||
{"Update message of the day on all hosts (don't send)","Atualizar a mensagem do dia em todos os host (não enviar)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","Atualize as especificações para obter a fonte dos módulos e instale os que desejar."}.
|
||||
{"Update Specs","Atualizar as especificações"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","A atualização do vCard não é compatível com o back-end de armazenamento do vCard"}.
|
||||
{"Upgrade","Atualização"}.
|
||||
{"URL for Archived Discussion Logs","A URL para o arquivamento dos registros da discussão"}.
|
||||
{"User already exists","Usuário já existe"}.
|
||||
{"User (jid)","Usuário (jid)"}.
|
||||
{"User JID","Usuário JID"}.
|
||||
{"User Management","Gerenciamento de Usuários"}.
|
||||
{"User not allowed to perform an IQ set on another user's vCard.","O usuário não tem permissão para executar um conjunto de QI no vCard de outro usuário."}.
|
||||
{"User removed","O usuário foi removido"}.
|
||||
{"User session not found","A sessão do usuário não foi encontrada"}.
|
||||
{"User session terminated","Sessão de usuário terminada"}.
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
{"Changing role/affiliation is not allowed","Nuk lejohet ndryshim roli/përkatësie"}.
|
||||
{"Channel already exists","Kanali ekziston tashmë"}.
|
||||
{"Channel does not exist","Kanali s’ekziston"}.
|
||||
{"Channel JID","JID Kanali"}.
|
||||
{"Channels","Kanale"}.
|
||||
{"Characters not allowed:","Shenja të palejuara:"}.
|
||||
{"Chatroom configuration modified","Ndryshoi formësimi i dhomës së fjalosjeve"}.
|
||||
@@ -99,6 +100,8 @@
|
||||
{"Full List of Room Admins","Listë e Plotë Përgjegjësish Dhome"}.
|
||||
{"Full List of Room Owners","Listë e Plotë të Zotësh Dhome"}.
|
||||
{"Full Name","Emër i Plotë"}.
|
||||
{"Get List of Online Users","Merr Listë Përdoruesish Në Linjë"}.
|
||||
{"Get List of Registered Users","Merr Listë Përdoruesish të Regjistruar"}.
|
||||
{"Get Number of Online Users","Merr Numër Përdoruesish Në Linjë"}.
|
||||
{"Get Number of Registered Users","Merr Numër Përdoruesish të Regjistruar"}.
|
||||
{"Get User Statistics","Merr Statistika Përdoruesi"}.
|
||||
@@ -106,6 +109,7 @@
|
||||
{"Grant voice to this person?","T’i akordohet zë këtij personi?"}.
|
||||
{"has been banned","është dëbuar"}.
|
||||
{"has been kicked","është përzënë"}.
|
||||
{"Hat title","Titull kapeleje"}.
|
||||
{"Host unknown","Strehë e panjohur"}.
|
||||
{"HTTP File Upload","Ngarkim Kartelash HTTP"}.
|
||||
{"Idle connection","Lidhje e plogësht"}.
|
||||
@@ -182,6 +186,7 @@
|
||||
{"No node specified","S’u përcaktua nyjë"}.
|
||||
{"No pending subscriptions found","S’u gjetën pajtime pezull"}.
|
||||
{"No privacy list with this name found","S’u gjet listë privatësie me atë emër"}.
|
||||
{"No <privileged_iq/> element found","S’u gjetën elementë <privileged_iq/>"}.
|
||||
{"No running node found","S’u gjet nyjë në funksionim"}.
|
||||
{"No services available","S’ka shërbime të gatshme"}.
|
||||
{"No statistics found for this item","S’u gjetën statistika për këtë objekt"}.
|
||||
@@ -191,6 +196,7 @@
|
||||
{"Node index not found","S’u gjet tregues nyje"}.
|
||||
{"Node not found","S’u gjet nyjë"}.
|
||||
{"Node ~p","Nyjë ~p"}.
|
||||
{"Node","Nyjë"}.
|
||||
{"Nodes","Nyja"}.
|
||||
{"None","Asnjë"}.
|
||||
{"Not allowed","E palejuar"}.
|
||||
@@ -203,6 +209,7 @@
|
||||
{"Number of online users","Numër përdoruesish në linjë"}.
|
||||
{"Number of registered users","Numër përdoruesish të regjistruar"}.
|
||||
{"Occupants are allowed to invite others","Të pranishmëve u është lejuar të ftojnë të tjerë"}.
|
||||
{"Occupants are allowed to query others","Të pranishmëve u është lejuar t’u bëjnë kërkim të tjerëve"}.
|
||||
{"Occupants May Change the Subject","Të pranishmit Mund të Ndryshojnë Subjektin"}.
|
||||
{"October","Tetor"}.
|
||||
{"OK","OK"}.
|
||||
@@ -210,12 +217,14 @@
|
||||
{"Online Users","Përdorues Në Linjë"}.
|
||||
{"Online","Në linjë"}.
|
||||
{"Only deliver notifications to available users","Dorëzo njoftime vetëm te përdoruesit e pranishëm"}.
|
||||
{"Only moderators are allowed to retract messages","Vetëm të moderatorëve u lejohet të tërheqin mbrapsht mesazhe"}.
|
||||
{"Only occupants are allowed to send messages to the conference","Vetëm të pranishmëve u lejohet të dërgojnë mesazhe te konferenca"}.
|
||||
{"Only publishers may publish","Vetëm botuesit mund të botojnë"}.
|
||||
{"Organization Name","Emër Enti"}.
|
||||
{"Organization Unit","Njësi Organizative"}.
|
||||
{"Outgoing s2s Connections","Lidhje s2s Ikëse"}.
|
||||
{"Owner privileges required","Lypset privilegje të zoti"}.
|
||||
{"Participant ID","ID Pjesëmarrësi"}.
|
||||
{"Participant","Pjesëmarrës"}.
|
||||
{"Password Verification","Verifikim Fjalëkalimi"}.
|
||||
{"Password Verification:","Verifikim Fjalëkalimi:"}.
|
||||
@@ -266,6 +275,7 @@
|
||||
{"Specify the access model","Specifikoni model hyrjeje"}.
|
||||
{"Specify the event message type","Përcaktoni llojin e mesazhit për aktin"}.
|
||||
{"Specify the publisher model","Përcaktoni model botuesi"}.
|
||||
{"Stanza id is not valid","ID Stanza s’është i vlefshëm"}.
|
||||
{"Stopped Nodes","Nyja të Ndalura"}.
|
||||
{"Subject","Subjekti"}.
|
||||
{"Submitted","Parashtruar"}.
|
||||
@@ -277,6 +287,7 @@
|
||||
{"The default language of the node","Gjuha parazgjedhje e nyjës"}.
|
||||
{"The feature requested is not supported by the conference","Veçoria e kërkuar nuk mbulohen nga konferenca"}.
|
||||
{"The JID of the node creator","JID i krijjuesit të nyjës"}.
|
||||
{"The list of all online users","Lista e krejt përdoruesve në linjë"}.
|
||||
{"The name of the node","Emri i nyjës"}.
|
||||
{"The number of subscribers to the node","Numri i pajtimtarëve te nyja"}.
|
||||
{"The number of unread or undelivered messages","Numri i mesazheve të palexuar ose të padorëzuar"}.
|
||||
@@ -303,6 +314,7 @@
|
||||
{"Unregister an XMPP account","Çregjistroni një llogari XMPP"}.
|
||||
{"Unregister","Çregjistrohuni"}.
|
||||
{"Unsupported version","Version i pambuluar"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","Përditësimi i vCard-it nuk mbulohet nga mekanizmi i depozitimit të vCard-ve"}.
|
||||
{"User already exists","Ka tashmë një përdorues të tillë"}.
|
||||
{"User JID","JID përdoruesi"}.
|
||||
{"User (jid)","Përdorues (jid)"}.
|
||||
@@ -319,9 +331,11 @@
|
||||
{"Wednesday","E mërkurë"}.
|
||||
{"When a new subscription is processed","Kur përpunohet një pajtim i ri"}.
|
||||
{"Whether to allow subscriptions","Nëse duhen lejuar apo jo pajtime"}.
|
||||
{"Who can send private messages","Cilët mund të dërgojnë mesazhe private"}.
|
||||
{"Wrong parameters in the web formulary","Parametër i gabuar në formular web"}.
|
||||
{"XMPP Account Registration","Regjistrim Llogarish XMPP"}.
|
||||
{"XMPP Domains","Përkatësi XMPP"}.
|
||||
{"You are not allowed to send private messages","S’keni leje të dërgoni mesazhe private"}.
|
||||
{"You are not joined to the channel","S’keni hyrë te kanali"}.
|
||||
{"You have been banned from this room","Jeni dëbuar prej kësaj dhome"}.
|
||||
{"You have joined too many conferences","Keni hyrë në shumë konferenca"}.
|
||||
|
||||
+11
-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","三月"}.
|
||||
@@ -294,6 +295,7 @@
|
||||
{"No pending subscriptions found","未找到待处理的订阅"}.
|
||||
{"No privacy list with this name found","未找到具有此名称的隐私列表"}.
|
||||
{"No private data found in this query","在此查询中找不到专用数据"}.
|
||||
{"No <privileged_iq/> element found","未找到 <privileged_iq/> 元素"}.
|
||||
{"No running node found","找不到正在运行的节点"}.
|
||||
{"No services available","无可用服务"}.
|
||||
{"No statistics found for this item","未找到此项目的统计数据"}.
|
||||
@@ -536,6 +538,7 @@
|
||||
{"Too many unacked stanzas","太多未确认的节"}.
|
||||
{"Too many users in this conference","此群聊中的用户太多"}.
|
||||
{"Traffic rate limit is exceeded","超过流量速率限制"}.
|
||||
{"~ts's MAM Archive","~ts 的 MAM 存档"}.
|
||||
{"~ts's Offline Messages Queue","~ts 的离线消息队列"}.
|
||||
{"Tuesday","周二"}.
|
||||
{"Unable to generate a CAPTCHA","无法生成验证码"}.
|
||||
@@ -552,12 +555,14 @@
|
||||
{"Update message of the day on all hosts (don't send)","更新所有主机上的每日消息(不发送)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","更新规格以获取模块源,然后安装所需的模块。"}.
|
||||
{"Update Specs","更新规格"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","vCard 存储后端不支持更新 vCard"}.
|
||||
{"Upgrade","升级"}.
|
||||
{"URL for Archived Discussion Logs","存档讨论日志的 URL"}.
|
||||
{"User already exists","用户已存在"}.
|
||||
{"User (jid)","用户 (jid)"}.
|
||||
{"User JID","用户 JID"}.
|
||||
{"User Management","用户管理"}.
|
||||
{"User not allowed to perform an IQ set on another user's vCard.","不允许用户在其他用户的 vCard 上执行 IQ 设置。"}.
|
||||
{"User removed","用户已移除"}.
|
||||
{"User session not found","用户会话未找到"}.
|
||||
{"User session terminated","用户会话已终止"}.
|
||||
@@ -607,7 +612,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 和验证码的客户端来注册"}.
|
||||
|
||||
+20
-11
@@ -31,13 +31,21 @@
|
||||
{if_var_true, pam,
|
||||
{epam, "~> 1.0.14", {git, "https://github.com/processone/epam", {tag, "1.0.14"}}}},
|
||||
{if_var_true, redis,
|
||||
{eredis, "~> 1.2.0", {git, "https://github.com/wooga/eredis", {tag, "v1.2.0"}}}},
|
||||
{if_not_rebar3,
|
||||
{eredis, "~> 1.2.0", {git, "https://github.com/wooga/eredis/", {tag, "v1.2.0"}}}
|
||||
}},
|
||||
{if_var_true, redis,
|
||||
{if_rebar3,
|
||||
{if_version_below, "21",
|
||||
{eredis, "1.2.0", {git, "https://github.com/wooga/eredis/", {tag, "v1.2.0"}}},
|
||||
{eredis, "~> 1.7.1", {git, "https://github.com/Nordix/eredis/", {tag, "v1.7.1"}}}
|
||||
}}},
|
||||
{if_var_true, sip,
|
||||
{esip, "~> 1.0.52", {git, "https://github.com/processone/esip", {tag, "1.0.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.55"}}},
|
||||
{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,21 +64,21 @@
|
||||
{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.25"}}},
|
||||
{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.29"}}}},
|
||||
{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"}}},
|
||||
{yconf, "~> 1.0.15", {git, "https://github.com/processone/yconf", {tag, "1.0.16"}}}
|
||||
{stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}},
|
||||
{xmpp, "~> 1.9.1", {git, "https://github.com/processone/xmpp", {tag, "1.9.1"}}},
|
||||
{yconf, "~> 1.0.17", {git, "https://github.com/processone/yconf", {tag, "1.0.17"}}}
|
||||
]}.
|
||||
|
||||
{gitonly_deps, [ejabberd_po]}.
|
||||
@@ -156,7 +164,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
|
||||
|
||||
+33
-33
@@ -3,84 +3,84 @@
|
||||
{<<"cache_tab">>,{pkg,<<"cache_tab">>,<<"1.0.31">>},0},
|
||||
{<<"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},
|
||||
{<<"eredis">>,{pkg,<<"eredis">>,<<"1.7.1">>},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.55">>},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},
|
||||
{<<"luerl">>,{pkg,<<"luerl">>,<<"1.2.3">>},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.25">>},0},
|
||||
{<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.25">>},0},
|
||||
{<<"p1_oauth2">>,{pkg,<<"p1_oauth2">>,<<"0.6.14">>},0},
|
||||
{<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.27">>},0},
|
||||
{<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.29">>},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},
|
||||
{<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.16">>},0}]}.
|
||||
{<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.1">>},0},
|
||||
{<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.17">>},0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"base64url">>, <<"F8C7F2DA04CA9A5D0F5F50258F055E1D699F0E8BF4CFDB30B750865368403CF6">>},
|
||||
{<<"cache_tab">>, <<"E4097B50A6F373AB1E0A5F01BAB0BEF6626771A4CD6C93404ED6D54810E11FBC">>},
|
||||
{<<"eimp">>, <<"AAF32EFAB061143403DADBAA63E699EF8E81702FBFA96FD436D5E9BE4D6A8D3A">>},
|
||||
{<<"epam">>, <<"AA0B85D27F4EF3A756AE995179DF952A0721237E83C6B79D644347B75016681A">>},
|
||||
{<<"eredis">>, <<"0B8E9CFC2C00FA1374CD107EA63B49BE08D933DF2CF175E6A89B73DD9C380DE4">>},
|
||||
{<<"esip">>, <<"DAE8FB8278FD3B2C0D38C2E832C4B8D26700EB239B9A42C8EA574FEE76F5E76A">>},
|
||||
{<<"eredis">>, <<"39E31AA02ADCD651C657F39AAFD4D31A9B2F63C6C700DC9CECE98D4BC3C897AB">>},
|
||||
{<<"esip">>, <<"63C0FDC667BE751714E1E5C14621A9334F21B60AC1BB68BE889454CA9CA021B7">>},
|
||||
{<<"ezlib">>, <<"3C7F62862850A241159C10B218ECF580BCE54D0890601B65144DACC2633BE2B0">>},
|
||||
{<<"fast_tls">>, <<"65D7D547A09EEFB37A1C0D04D8601FAC4F3E6E2C1EDE859A7787081670F9648D">>},
|
||||
{<<"fast_xml">>, <<"0289DAAFBF1190B0E53B444D4885CCCF41E4B05768D4B3ACC76DD8D143668E10">>},
|
||||
{<<"fast_tls">>, <<"44356B256AFAD4399C2FC5059A3066669DAFD8BD4E4E796C9C1CF8910DDD265E">>},
|
||||
{<<"fast_xml">>, <<"ACE020F2521F2A484AC8467D2822AF85534A346E2AAE03FFCBC34F29318BEFAF">>},
|
||||
{<<"fast_yaml">>, <<"F71D472FBF787CCD161B914D1EB486116A0F4F2E835337A378FBD31B59D2E74B">>},
|
||||
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
|
||||
{<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>},
|
||||
{<<"jose">>, <<"A903F5227417BD2A08C8A00A0CBCC458118BE84480955E8D251297A425723F83">>},
|
||||
{<<"luerl">>, <<"60F05F4240F0E7C148DDB79B67B8FF972734AAD237AA74C83D0748B8214C8EF0">>},
|
||||
{<<"luerl">>, <<"DF25F41944E57A7C4D9EF09D238BC3E850276C46039CFC12B8BB42ECCF36FCB1">>},
|
||||
{<<"mqtree">>, <<"82F54B8F2D22B4445DB1D6CCCB7FE9EAD049D61410C29E32475F3CEB3EE62A89">>},
|
||||
{<<"p1_acme">>, <<"791AEF0F79DC7F768B228808250C349FA9CE585CD8779DA50CA93106EB3394D0">>},
|
||||
{<<"p1_mysql">>, <<"0ED1E098C5A4525032448C65A2715F30980AAE725615A4D255FD25F26BB22507">>},
|
||||
{<<"p1_acme">>, <<"DB91F0D6C193CD1D5C0B0FA3939A898DBF56A6075DB4347CDE26E802715DE50C">>},
|
||||
{<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>},
|
||||
{<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>},
|
||||
{<<"p1_pgsql">>, <<"883E335D82AC062DE0BDE7981F8250A2E632258BB7A47DF839A4CBDCB3E971E6">>},
|
||||
{<<"p1_pgsql">>, <<"FAE0C90CBC5931865958150F1B667FB0D20B063F6A46A17770A4E5232DED632C">>},
|
||||
{<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>},
|
||||
{<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>},
|
||||
{<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>},
|
||||
{<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>},
|
||||
{<<"stun">>, <<"6F538AC80C842131DBD149055570D116BFABC9B5EBFF4BD6AF2E7888958C660C">>},
|
||||
{<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>},
|
||||
{<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>},
|
||||
{<<"xmpp">>, <<"ACF39A8B70B066BB8F10B0862E031E8ABCF92FE89D1C41D06C1E39AE5CAF89C4">>},
|
||||
{<<"yconf">>, <<"D59521D66FF89F219411B6E9277CD6FEEC7CC6FCE11554E67DE02A8D0A470479">>}]},
|
||||
{<<"xmpp">>, <<"A1642D93CDBDF947F32344B0E05FCC8EFCFB9F11C32832ACC9BD826B52ADBE48">>},
|
||||
{<<"yconf">>, <<"DCF242E27F3FC5D0743D6B8175DD39BC14A1F4ED7E6EA986366A44A6FF3B2A3A">>}]},
|
||||
{pkg_hash_ext,[
|
||||
{<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>},
|
||||
{<<"cache_tab">>, <<"8582B60A4A09B247EF86355BA9E07FCE9E11EDC0345A775C9171F971C72B6351">>},
|
||||
{<<"eimp">>, <<"907C780023CB2893E4FC4BDBE6A4F02C355913862AC67F0ECC26605E816B628A">>},
|
||||
{<<"epam">>, <<"2F3449E72885A72A6C2A843F561ADD0FC2F70D7A21F61456930A547473D4D989">>},
|
||||
{<<"eredis">>, <<"D9B5ABEF2C2C8ABA8F32AA018203E0B3DC8B1157773B254AB1D4C2002317F1E1">>},
|
||||
{<<"esip">>, <<"8187AF819D7259CDADDAF69726C239EF604C9B0B0298A5F2D3E687BF5E2237EE">>},
|
||||
{<<"eredis">>, <<"7C2B54C566FED55FEEF3341CA79B0100A6348FD3F162184B7ED5118D258C3CC1">>},
|
||||
{<<"esip">>, <<"9EF3660CEF93B623F7368DCD5C79F4E704358631909E6DD464E335378815DA1F">>},
|
||||
{<<"ezlib">>, <<"9EE62AB3F8ED55A0FD11A9569FCB8E458683F95575417272192B069F092ABFBB">>},
|
||||
{<<"fast_tls">>, <<"131542913937025E48CD80AA81F00359686D5501B75621E72026A87B5229505B">>},
|
||||
{<<"fast_xml">>, <<"795192390E06D2B65016A6990BBFA5727F4A26D2914808B1C3C9A32EEDCD1BFD">>},
|
||||
{<<"fast_tls">>, <<"E65779AEFB7AB15C4755230FEF8077E687D20CC5A3984A5974F9F657E8E2485B">>},
|
||||
{<<"fast_xml">>, <<"83F3E23A780ED5F567CDEC73953F06C95B838D709DBFA86B59A98A8D23C99F85">>},
|
||||
{<<"fast_yaml">>, <<"8DE868721BF7E2172414F7D3148EDE0F3C922B496455CD625DD5C4429515A769">>},
|
||||
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
|
||||
{<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>},
|
||||
{<<"jose">>, <<"0D6CD36FF8BA174DB29148FC112B5842186B68A90CE9FC2B3EC3AFE76593E614">>},
|
||||
{<<"luerl">>, <<"9CAFD4F6094FF0F5A9D278FD81D60D3E026C820BDFB6CACD4B1BD909F21B525D">>},
|
||||
{<<"luerl">>, <<"1B4B9D0CA5D7D280D1D2787A6A5EE9F5A212641B62BFF91556BAA53805DF3AED">>},
|
||||
{<<"mqtree">>, <<"5FE8B7CF8FBC4783D0FCEB94654AC2BBF3242A58CD0397D249DED8AE021BE2A3">>},
|
||||
{<<"p1_acme">>, <<"8CE196F26E3D22EA10B7809122950465878C127F80767E325207AED7E8D0DD59">>},
|
||||
{<<"p1_mysql">>, <<"F058865F64257F507A2C6A5AFF369B1375DBCB30B3D4258DAD4F1B3EAFFB655F">>},
|
||||
{<<"p1_acme">>, <<"A7B55B47495DDB4F98A15E65451EC3AD43F4637B955C74CD695D98E6A645D08C">>},
|
||||
{<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>},
|
||||
{<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>},
|
||||
{<<"p1_pgsql">>, <<"8E4D1A7602CB68780E55D89DC5A9B2E1AACA3F4F1EE3D1A25F2F8C3D2364FFB9">>},
|
||||
{<<"p1_pgsql">>, <<"A6FF58E8B174993F3895DA3EA6211A9F9D0C54D1A6E28BB321DA3B3CD68B38C1">>},
|
||||
{<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>},
|
||||
{<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>},
|
||||
{<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>},
|
||||
{<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>},
|
||||
{<<"stun">>, <<"E134807B1B7A8DFFD94E64EEFEE00E65C7B4042F3D14E16F8F43566D20371583">>},
|
||||
{<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>},
|
||||
{<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>},
|
||||
{<<"xmpp">>, <<"ED70065F9A89A818DCFF43B74C080C9E7F4F1414E1051BEDDB7280DB809AF711">>},
|
||||
{<<"yconf">>, <<"E947813273F38711C7B2E5A8E4ACC9A51C7BBE854F744A345F60300B38586C89">>}]}
|
||||
{<<"xmpp">>, <<"D2B1431AF6E4C1A4C8BF90CAF0CC11CDEB047B8323B87E9D7E4826D4913275DC">>},
|
||||
{<<"yconf">>, <<"DD2892923241449A46CC8457B9EC0FB14030700735A5885955677C735C341A25">>}]}
|
||||
].
|
||||
|
||||
+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));
|
||||
|
||||
|
||||
+9
-4
@@ -505,10 +505,15 @@ db_type(M) ->
|
||||
and_then(
|
||||
atom(),
|
||||
fun(T) ->
|
||||
case code:ensure_loaded(db_module(M, T)) of
|
||||
{module, _} -> T;
|
||||
{error, _} -> fail({bad_db_type, M, T})
|
||||
end
|
||||
case code:ensure_loaded(db_module(M, T)) of
|
||||
{module, _} -> T;
|
||||
{error, _} ->
|
||||
ElixirModule = "Elixir." ++ atom_to_list(T),
|
||||
case code:ensure_loaded(list_to_atom(ElixirModule)) of
|
||||
{module, _} -> list_to_atom(ElixirModule);
|
||||
{error, _} -> fail({bad_db_type, M, T})
|
||||
end
|
||||
end
|
||||
end).
|
||||
|
||||
-spec queue_type() -> yconf:validator(ram | file).
|
||||
|
||||
+24
-17
@@ -29,23 +29,21 @@
|
||||
|
||||
-protocol({rfc, 6122}).
|
||||
-protocol({rfc, 7590}).
|
||||
-protocol({xep, 4, '2.9'}).
|
||||
-protocol({xep, 59, '1.0'}).
|
||||
-protocol({xep, 86, '1.0'}).
|
||||
-protocol({xep, 106, '1.1'}).
|
||||
-protocol({xep, 170, '1.0'}).
|
||||
-protocol({xep, 205, '1.0'}).
|
||||
-protocol({xep, 212, '1.0'}).
|
||||
-protocol({xep, 216, '1.0'}).
|
||||
-protocol({xep, 243, '1.0'}).
|
||||
-protocol({xep, 270, '1.0'}).
|
||||
-protocol({xep, 368, '1.1.0'}).
|
||||
-protocol({xep, 386, '0.3.0', '24.02', "", ""}).
|
||||
-protocol({xep, 388, '0.4.0', '24.02', "", ""}).
|
||||
-protocol({xep, 424, '0.4.0', '24.02', "", ""}).
|
||||
-protocol({xep, 440, '0.4.0', '24.02', "", ""}).
|
||||
-protocol({xep, 474, '0.3.0', '24.02', "", ""}).
|
||||
-protocol({xep, 485, '0.2.0', '24.02', "", "mod_pubsub_serverinfo in ejabberd-contrib.git"}).
|
||||
-protocol({xep, 4, '2.9', '0.5.0', "complete", ""}).
|
||||
-protocol({xep, 59, '1.0', '2.1.0', "complete", ""}).
|
||||
-protocol({xep, 82, '1.1.1', '2.1.0', "complete", ""}).
|
||||
-protocol({xep, 86, '1.0', '0.5.0', "complete", ""}).
|
||||
-protocol({xep, 106, '1.1', '0.5.0', "complete", ""}).
|
||||
-protocol({xep, 170, '1.0', '17.12', "complete", ""}).
|
||||
-protocol({xep, 178, '1.1', '17.03', "complete", ""}).
|
||||
-protocol({xep, 205, '1.0', '1.1.2', "complete", ""}).
|
||||
-protocol({xep, 368, '1.1.0', '17.09', "complete", ""}).
|
||||
-protocol({xep, 386, '0.3.0', '24.02', "complete", ""}).
|
||||
-protocol({xep, 388, '0.4.0', '24.02', "complete", ""}).
|
||||
-protocol({xep, 424, '0.4.0', '24.02', "complete", ""}).
|
||||
-protocol({xep, 440, '0.4.0', '24.02', "complete", ""}).
|
||||
-protocol({xep, 474, '0.3.0', '24.02', "complete", ""}).
|
||||
-protocol({xep, 485, '0.2.0', '24.02', "complete", "mod_pubsub_serverinfo in ejabberd-contrib.git"}).
|
||||
|
||||
-export([start/0, stop/0, halt/0, start_app/1, start_app/2,
|
||||
get_pid_file/0, check_apps/0, module_name/1, is_loaded/0]).
|
||||
@@ -179,6 +177,15 @@ module_name([Dir, _, <<H,_/binary>> | _] = Mod) when H >= 65, H =< 90 ->
|
||||
Lib -> <<"Elixir.Ejabberd.", Lib/binary, ".">>
|
||||
end,
|
||||
misc:binary_to_atom(<<Prefix/binary, Module/binary>>);
|
||||
|
||||
module_name([<<"auth">> | T] = Mod) ->
|
||||
case hd(T) of
|
||||
%% T already starts with "Elixir" if an Elixir module is
|
||||
%% loaded with that name, as per `econf:db_type/1`
|
||||
<<"Elixir", _/binary>> -> misc:binary_to_atom(hd(T));
|
||||
_ -> module_name([<<"ejabberd">>] ++ Mod)
|
||||
end;
|
||||
|
||||
module_name([<<"ejabberd">> | _] = Mod) ->
|
||||
Module = str:join([erlang_name(M) || M<-Mod], $_),
|
||||
misc:binary_to_atom(Module);
|
||||
|
||||
+76
-39
@@ -33,6 +33,7 @@
|
||||
status/0, stop/0, restart/0,
|
||||
reopen_log/0, rotate_log/0,
|
||||
set_loglevel/1,
|
||||
evacuate_kindly/2,
|
||||
stop_kindly/2, send_service_message_all_mucs/2,
|
||||
registered_vhosts/0,
|
||||
reload_config/0,
|
||||
@@ -166,9 +167,24 @@ get_commands_spec() ->
|
||||
"only on log files generated by some modules.",
|
||||
module = ?MODULE, function = rotate_log,
|
||||
args = [], result = {res, rescode}},
|
||||
#ejabberd_commands{name = evacuate_kindly, tags = [server],
|
||||
desc = "Evacuate kindly all users (kick and prevent login)",
|
||||
longdesc = "Inform users and rooms, don't allow login, wait, "
|
||||
"restart the server, and don't allow new logins.\n"
|
||||
"Provide the delay in seconds, and the "
|
||||
"announcement quoted, for example: \n"
|
||||
"`ejabberdctl evacuate_kindly 60 "
|
||||
"\\\"The server will stop in one minute.\\\"`",
|
||||
note = "added in 24.12",
|
||||
module = ?MODULE, function = evacuate_kindly,
|
||||
args_desc = ["Seconds to wait", "Announcement to send, with quotes"],
|
||||
args_example = [60, <<"Server will stop now.">>],
|
||||
args = [{delay, integer}, {announcement, string}],
|
||||
result = {res, rescode}},
|
||||
#ejabberd_commands{name = stop_kindly, tags = [server],
|
||||
desc = "Inform users and rooms, wait, and stop the server",
|
||||
longdesc = "Provide the delay in seconds, and the "
|
||||
desc = "Stop kindly the server (informing users)",
|
||||
longdesc = "Inform users and rooms, wait, and stop the server.\n"
|
||||
"Provide the delay in seconds, and the "
|
||||
"announcement quoted, for example: \n"
|
||||
"`ejabberdctl stop_kindly 60 "
|
||||
"\\\"The server will stop in one minute.\\\"`",
|
||||
@@ -203,6 +219,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}],
|
||||
@@ -251,6 +268,16 @@ get_commands_spec() ->
|
||||
|
||||
#ejabberd_commands{name = join_cluster, tags = [cluster],
|
||||
desc = "Join our local node into the cluster handled by Node",
|
||||
longdesc = "This command returns immediately,
|
||||
even before the joining process has
|
||||
completed. Consequently, if you are using
|
||||
`ejabberdctl` (or some `CTL_ON_` container
|
||||
environment variables) to run more commands
|
||||
afterwards, you may want to precede them with
|
||||
the _`started`_ command to ensure the
|
||||
clustering process has completed before
|
||||
proceeding. For example: `join_cluster
|
||||
ejabberd@main` > `started` > `list_cluster`.",
|
||||
note = "improved in 24.06",
|
||||
module = ?MODULE, function = join_cluster,
|
||||
args_desc = ["Nodename of the node to join"],
|
||||
@@ -270,7 +297,7 @@ get_commands_spec() ->
|
||||
longdesc = "This command can be run from any running "
|
||||
"node of the cluster, even the node to be removed. "
|
||||
"In the removed node, this command works only when "
|
||||
"using ejabberdctl, not mod_http_api or other code that "
|
||||
"using ejabberdctl, not _`mod_http_api`_ or other code that "
|
||||
"runs inside the same ejabberd node that will leave.",
|
||||
module = ?MODULE, function = leave_cluster,
|
||||
args_desc = ["Nodename of the node to kick from the cluster"],
|
||||
@@ -370,17 +397,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 +420,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 +430,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 +555,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}],
|
||||
@@ -671,39 +698,49 @@ set_loglevel(LogLevel) ->
|
||||
%%% Stop Kindly
|
||||
%%%
|
||||
|
||||
evacuate_kindly(DelaySeconds, AnnouncementTextString) ->
|
||||
perform_kindly(DelaySeconds, AnnouncementTextString, evacuate).
|
||||
|
||||
stop_kindly(DelaySeconds, AnnouncementTextString) ->
|
||||
Subject = (str:format("Server stop in ~p seconds!", [DelaySeconds])),
|
||||
WaitingDesc = (str:format("Waiting ~p seconds", [DelaySeconds])),
|
||||
perform_kindly(DelaySeconds, AnnouncementTextString, stop).
|
||||
|
||||
perform_kindly(DelaySeconds, AnnouncementTextString, Action) ->
|
||||
Subject = str:format("Server stop in ~p seconds!", [DelaySeconds]),
|
||||
WaitingDesc = str:format("Waiting ~p seconds", [DelaySeconds]),
|
||||
AnnouncementText = list_to_binary(AnnouncementTextString),
|
||||
Steps = [
|
||||
{"Stopping ejabberd port listeners",
|
||||
ejabberd_listener, stop_listeners, []},
|
||||
{"Sending announcement to connected users",
|
||||
mod_announce, send_announcement_to_all,
|
||||
[ejabberd_config:get_myname(), Subject, AnnouncementText]},
|
||||
{"Sending service message to MUC rooms",
|
||||
ejabberd_admin, send_service_message_all_mucs,
|
||||
[Subject, AnnouncementText]},
|
||||
{WaitingDesc, timer, sleep, [DelaySeconds * 1000]},
|
||||
{"Stopping ejabberd", application, stop, [ejabberd]},
|
||||
{"Stopping Mnesia", mnesia, stop, []},
|
||||
{"Stopping Erlang node", init, stop, []}
|
||||
],
|
||||
PreSteps =
|
||||
[{"Stopping ejabberd port listeners", ejabberd_listener, stop_listeners, []},
|
||||
{"Sending announcement to connected users",
|
||||
mod_announce,
|
||||
send_announcement_to_all,
|
||||
[ejabberd_config:get_myname(), Subject, AnnouncementText]},
|
||||
{"Sending service message to MUC rooms",
|
||||
ejabberd_admin,
|
||||
send_service_message_all_mucs,
|
||||
[Subject, AnnouncementText]},
|
||||
{WaitingDesc, timer, sleep, [DelaySeconds * 1000]},
|
||||
{"Stopping ejabberd", application, stop, [ejabberd]}],
|
||||
SpecificSteps =
|
||||
case Action of
|
||||
evacuate ->
|
||||
[{"Starting ejabberd", application, start, [ejabberd]},
|
||||
{"Stopping ejabberd port listeners", ejabberd_listener, stop_listeners, []}];
|
||||
stop ->
|
||||
[{"Stopping Mnesia", mnesia, stop, []}, {"Stopping Erlang node", init, stop, []}]
|
||||
end,
|
||||
Steps = PreSteps ++ SpecificSteps,
|
||||
NumberLast = length(Steps),
|
||||
TimestampStart = calendar:datetime_to_gregorian_seconds({date(), time()}),
|
||||
lists:foldl(
|
||||
fun({Desc, Mod, Func, Args}, NumberThis) ->
|
||||
SecondsDiff =
|
||||
calendar:datetime_to_gregorian_seconds({date(), time()})
|
||||
- TimestampStart,
|
||||
io:format("[~p/~p ~ps] ~ts... ",
|
||||
[NumberThis, NumberLast, SecondsDiff, Desc]),
|
||||
Result = (catch apply(Mod, Func, Args)),
|
||||
io:format("~p~n", [Result]),
|
||||
NumberThis+1
|
||||
end,
|
||||
1,
|
||||
Steps),
|
||||
lists:foldl(fun({Desc, Mod, Func, Args}, NumberThis) ->
|
||||
SecondsDiff =
|
||||
calendar:datetime_to_gregorian_seconds({date(), time()}) - TimestampStart,
|
||||
io:format("[~p/~p ~ps] ~ts... ", [NumberThis, NumberLast, SecondsDiff, Desc]),
|
||||
Result = (catch apply(Mod, Func, Args)),
|
||||
io:format("~p~n", [Result]),
|
||||
NumberThis + 1
|
||||
end,
|
||||
1,
|
||||
Steps),
|
||||
ok.
|
||||
|
||||
send_service_message_all_mucs(Subject, AnnouncementText) ->
|
||||
@@ -746,7 +783,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
|
||||
@@ -888,7 +893,7 @@ auth_modules() ->
|
||||
auth_modules(Server) ->
|
||||
LServer = jid:nameprep(Server),
|
||||
Methods = ejabberd_option:auth_method(LServer),
|
||||
[ejabberd:module_name([<<"ejabberd">>, <<"auth">>,
|
||||
[ejabberd:module_name([<<"auth">>,
|
||||
misc:atom_to_binary(M)])
|
||||
|| M <- Methods].
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
-behaviour(ejabberd_auth).
|
||||
-author('mickael.remond@process-one.net').
|
||||
|
||||
-protocol({xep, 175, '1.2'}).
|
||||
-protocol({xep, 175, '1.2', '1.1.0', "complete", ""}).
|
||||
|
||||
-export([start/1,
|
||||
stop/1,
|
||||
|
||||
@@ -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;
|
||||
|
||||
+16
-16
@@ -25,8 +25,8 @@
|
||||
-module(ejabberd_bosh).
|
||||
-behaviour(xmpp_socket).
|
||||
-behaviour(p1_fsm).
|
||||
-protocol({xep, 124, '1.11'}).
|
||||
-protocol({xep, 206, '1.4'}).
|
||||
-protocol({xep, 124, '1.11', '16.12', "complete", ""}).
|
||||
-protocol({xep, 206, '1.4', '16.12', "complete", ""}).
|
||||
|
||||
%% API
|
||||
-export([start/2, start/3, start_link/3]).
|
||||
@@ -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) ->
|
||||
|
||||
+45
-13
@@ -27,7 +27,7 @@
|
||||
-protocol({rfc, 3921}).
|
||||
-protocol({rfc, 6120}).
|
||||
-protocol({rfc, 6121}).
|
||||
-protocol({xep, 138, '2.1'}).
|
||||
-protocol({xep, 138, '2.1', '1.1.0', "complete", ""}).
|
||||
|
||||
%% ejabberd_listener callbacks
|
||||
-export([start/3, start_link/3, accept/1, listen_opt_type/1, listen_options/0]).
|
||||
@@ -35,16 +35,18 @@
|
||||
-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,
|
||||
get_fast_tokens_fun/2, fast_mechanisms/1]).
|
||||
%% Hooks
|
||||
-export([handle_unexpected_cast/2, handle_unexpected_call/3,
|
||||
process_auth_result/3, reject_unauthenticated_packet/2,
|
||||
@@ -392,6 +394,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 +409,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),
|
||||
@@ -461,6 +466,20 @@ check_password_digest_fun(_Mech, #{lserver := LServer}) ->
|
||||
ejabberd_auth:check_password_with_authmodule(U, AuthzId, LServer, P, D, DG)
|
||||
end.
|
||||
|
||||
get_fast_tokens_fun(_Mech, #{lserver := LServer}) ->
|
||||
fun(User, UA) ->
|
||||
case gen_mod:is_loaded(LServer, mod_auth_fast) of
|
||||
false -> false;
|
||||
_ -> mod_auth_fast:get_tokens(LServer, User, UA)
|
||||
end
|
||||
end.
|
||||
|
||||
fast_mechanisms(#{lserver := LServer}) ->
|
||||
case gen_mod:is_loaded(LServer, mod_auth_fast) of
|
||||
false -> [];
|
||||
_ -> mod_auth_fast:get_mechanisms(LServer)
|
||||
end.
|
||||
|
||||
bind(<<"">>, State) ->
|
||||
bind(new_uniq_id(), State);
|
||||
bind(R, #{user := U, server := S, access := Access, lang := Lang,
|
||||
@@ -580,6 +599,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 +631,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 +1031,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 +1076,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 +1100,7 @@ listen_options() ->
|
||||
{tls_compression, false},
|
||||
{starttls, false},
|
||||
{starttls_required, false},
|
||||
{allow_unencrypted_sasl2, false},
|
||||
{tls_verify, false},
|
||||
{zlib, false},
|
||||
{max_stanza_size, infinity},
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
-module(ejabberd_captcha).
|
||||
|
||||
-protocol({xep, 158, '1.0'}).
|
||||
-protocol({xep, 231, '1.0'}).
|
||||
-protocol({xep, 158, '1.0', '2.1.0', "complete", ""}).
|
||||
-protocol({xep, 231, '1.0', '2.1.0', "complete", ""}).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
@@ -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, {}).
|
||||
|
||||
+17
-2
@@ -206,7 +206,7 @@ get_lang(Host) ->
|
||||
|
||||
-spec get_uri() -> binary().
|
||||
get_uri() ->
|
||||
<<"http://www.process-one.net/en/ejabberd/">>.
|
||||
<<"https://www.process-one.net/ejabberd/">>.
|
||||
|
||||
-spec get_copyright() -> binary().
|
||||
get_copyright() ->
|
||||
@@ -516,8 +516,23 @@ read_file(File, Opts) ->
|
||||
Err
|
||||
end.
|
||||
|
||||
get_additional_macros() ->
|
||||
MacroStrings = lists:foldl(fun([$E, $J, $A, $B, $B, $E, $R, $D, $_, $M, $A, $C, $R, $O, $_ | MacroString], Acc) ->
|
||||
[parse_macro_string(MacroString) | Acc];
|
||||
(_, Acc) ->
|
||||
Acc
|
||||
end,
|
||||
[],
|
||||
os:getenv()),
|
||||
{additional_macros, MacroStrings}.
|
||||
|
||||
parse_macro_string(MacroString) ->
|
||||
[NameString, ValueString] = string:split(MacroString, "="),
|
||||
{ok, [ValueDecoded]} = fast_yaml:decode(ValueString, [plain_as_atom]),
|
||||
{list_to_atom(NameString), ValueDecoded}.
|
||||
|
||||
read_yaml_files(Files, Opts) ->
|
||||
ParseOpts = [plain_as_atom | lists:flatten(Opts)],
|
||||
ParseOpts = [plain_as_atom, get_additional_macros() | lists:flatten(Opts)],
|
||||
lists:foldl(
|
||||
fun(File, {ok, Y1}) ->
|
||||
case econf:parse(File, #{'_' => econf:any()}, ParseOpts) of
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
default_host,
|
||||
custom_headers,
|
||||
trail = <<>>,
|
||||
allow_unencrypted_sasl2,
|
||||
addr_re,
|
||||
sock_peer_name = none
|
||||
}).
|
||||
@@ -133,10 +134,12 @@ init(SockMod, Socket, Opts) ->
|
||||
|
||||
CustomHeaders = proplists:get_value(custom_headers, Opts, []),
|
||||
|
||||
AllowUnencryptedSasl2 = proplists:get_bool(allow_unencrypted_sasl2, Opts),
|
||||
State = #state{sockmod = SockMod1,
|
||||
socket = Socket1,
|
||||
custom_headers = CustomHeaders,
|
||||
options = Opts,
|
||||
allow_unencrypted_sasl2 = AllowUnencryptedSasl2,
|
||||
request_handlers = RequestHandlers,
|
||||
sock_peer_name = SockPeer,
|
||||
addr_re = RE},
|
||||
@@ -916,6 +919,8 @@ normalize_path([Part | Path], Norm) ->
|
||||
|
||||
listen_opt_type(tag) ->
|
||||
econf:binary();
|
||||
listen_opt_type(allow_unencrypted_sasl2) ->
|
||||
econf:bool();
|
||||
listen_opt_type(request_handlers) ->
|
||||
econf:map(
|
||||
econf:and_then(
|
||||
@@ -941,6 +946,7 @@ listen_options() ->
|
||||
{protocol_options, undefined},
|
||||
{tls, false},
|
||||
{tls_compression, false},
|
||||
{allow_unencrypted_sasl2, false},
|
||||
{request_handlers, []},
|
||||
{tag, <<>>},
|
||||
{default_host, undefined},
|
||||
|
||||
+51
-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).
|
||||
|
||||
@@ -123,6 +122,7 @@ init([{#ws{ip = IP, http_opts = HOpts}, _} = WS]) ->
|
||||
({max_ack_queue, _}) -> true;
|
||||
({ack_timeout, _}) -> true;
|
||||
({resume_timeout, _}) -> true;
|
||||
({allow_unencrypted_sasl2, _}) -> true;
|
||||
({max_resume_timeout, _}) -> true;
|
||||
({resend_on_timeout, _}) -> true;
|
||||
({access, _}) -> true;
|
||||
@@ -166,57 +166,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 +211,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 +294,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 +316,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()} |
|
||||
|
||||
+128
-76
@@ -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. "
|
||||
@@ -399,7 +403,7 @@ doc() ->
|
||||
#{value => "true | false",
|
||||
note => "added in 23.10",
|
||||
desc =>
|
||||
?T("Supplement check for user existence based on 'mod_last' data, for authentication "
|
||||
?T("Supplement check for user existence based on _`mod_last`_ data, for authentication "
|
||||
"methods that don't have a way to reliably tell if a user exists (like is the case for "
|
||||
"'jwt' and certificate based authentication). This helps with processing offline message "
|
||||
"for those users. The default value is 'true'.")}},
|
||||
@@ -436,8 +440,8 @@ doc() ->
|
||||
desc =>
|
||||
?T("Full path to a file containing custom DH parameters "
|
||||
"to use for c2s connections. "
|
||||
"Such a file could be created with the command \"openssl "
|
||||
"dhparam -out dh.pem 2048\". If this option is not specified, "
|
||||
"Such a file could be created with the command '\"openssl "
|
||||
"dhparam -out dh.pem 2048\"'. If this option is not specified, "
|
||||
"2048-bit MODP Group with 256-bit Prime Order Subgroup will be "
|
||||
"used as defined in RFC5114 Section 2.3.")}},
|
||||
{c2s_protocol_options,
|
||||
@@ -496,7 +500,7 @@ doc() ->
|
||||
"If set to 'auto', it builds the URL using a 'request_handler' "
|
||||
"already enabled, with encryption if available. "
|
||||
"If set to 'undefined', it builds the URL using "
|
||||
"the deprecated _`captcha_host`_ + /captcha. "
|
||||
"the deprecated _`captcha_host`_ '+ /captcha'. "
|
||||
"The default value is 'auto'.")}},
|
||||
{certfiles,
|
||||
#{value => "[Path, ...]",
|
||||
@@ -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 "
|
||||
@@ -587,17 +595,25 @@ doc() ->
|
||||
" transport.example.org:",
|
||||
" type: bare_source"]},
|
||||
[{type,
|
||||
#{value => "random | source | destination | bare_source | bare_destination",
|
||||
#{value => ?T("Value"),
|
||||
desc =>
|
||||
?T("How to deliver stanzas to connected components: "
|
||||
"'random' - an instance is chosen at random; "
|
||||
"'destination' - an instance is chosen by the full JID of "
|
||||
"the packet's 'to' attribute; "
|
||||
"'source' - by the full JID of the packet's 'from' attribute; "
|
||||
"'bare_destination' - by the bare JID (without resource) "
|
||||
"of the packet's 'to' attribute; "
|
||||
"'bare_source' - by the bare JID (without resource) of the "
|
||||
"packet's 'from' attribute is used. The default value is 'random'.")}},
|
||||
?T("How to deliver stanzas to connected components. "
|
||||
"The default value is 'random'. Possible values: ")},
|
||||
[{'- random',
|
||||
#{desc =>
|
||||
?T("an instance is chosen at random")}},
|
||||
{'- source',
|
||||
#{desc =>
|
||||
?T("by the full JID of the packet's 'from' attribute")}},
|
||||
{'- bare_destination',
|
||||
#{desc =>
|
||||
?T("by the bare JID (without resource) of the packet's 'to' attribute")}},
|
||||
{'- bare_source',
|
||||
#{desc =>
|
||||
?T("by the bare JID (without resource) of the packet's 'from' attribute is used")}},
|
||||
{'- destination',
|
||||
#{desc =>
|
||||
?T("an instance is chosen by the full JID of the packet's 'to' attribute")}}]},
|
||||
{component_number,
|
||||
#{value => "2..1000",
|
||||
desc =>
|
||||
@@ -605,19 +621,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 +675,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 +696,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 +725,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 +736,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 =>
|
||||
@@ -856,20 +889,20 @@ doc() ->
|
||||
desc =>
|
||||
?T("The size (in bytes) of a log file to trigger rotation. "
|
||||
"If set to 'infinity', log rotation is disabled. "
|
||||
"The default value is '10485760' (that is, 10 Mb).")}},
|
||||
"The default value is 10 Mb expressed in bytes: '10485760'.")}},
|
||||
{log_burst_limit_count,
|
||||
#{value => ?T("Number"),
|
||||
note => "added in 22.10",
|
||||
desc =>
|
||||
?T("The number of messages to accept in "
|
||||
"`log_burst_limit_window_time` period before starting to "
|
||||
"drop them. Default 500")}},
|
||||
"drop them. Default `500`")}},
|
||||
{log_burst_limit_window_time,
|
||||
#{value => ?T("Number"),
|
||||
note => "added in 22.10",
|
||||
desc =>
|
||||
?T("The time period to rate-limit log messages "
|
||||
"by. Defaults to 1 second.")}},
|
||||
"by. Defaults to `1` second.")}},
|
||||
{log_modules_fully,
|
||||
#{value => "[Module, ...]",
|
||||
note => "added in 23.01",
|
||||
@@ -909,7 +942,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 +960,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'.")}},
|
||||
@@ -1004,7 +1040,7 @@ doc() ->
|
||||
?T("Trigger OOM killer when some of the running Erlang processes "
|
||||
"have messages queue above this 'Size'. Note that "
|
||||
"such processes won't be killed if _`oom_killer`_ option is set "
|
||||
"to 'false' or if 'oom_watermark' is not reached yet.")}},
|
||||
"to 'false' or if _`oom_watermark`_ is not reached yet.")}},
|
||||
{oom_watermark,
|
||||
#{value => ?T("Percent"),
|
||||
desc =>
|
||||
@@ -1027,7 +1063,7 @@ doc() ->
|
||||
note => "added in 20.12",
|
||||
desc =>
|
||||
?T("Specify the IPv4 address that will be used when establishing "
|
||||
"an outgoing S2S IPv4 connection, for example \"127.0.0.1\". "
|
||||
"an outgoing S2S IPv4 connection, for example '\"127.0.0.1\"'. "
|
||||
"The default value is 'undefined'.")}},
|
||||
{outgoing_s2s_ipv6_address,
|
||||
#{value => "Address",
|
||||
@@ -1035,7 +1071,7 @@ doc() ->
|
||||
desc =>
|
||||
?T("Specify the IPv6 address that will be used when establishing "
|
||||
"an outgoing S2S IPv6 connection, for example "
|
||||
"\"::FFFF:127.0.0.1\". The default value is 'undefined'.")}},
|
||||
"'\"::FFFF:127.0.0.1\"'. The default value is 'undefined'.")}},
|
||||
{outgoing_s2s_port,
|
||||
#{value => "1..65535",
|
||||
desc =>
|
||||
@@ -1049,14 +1085,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,37 +1113,45 @@ 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"),
|
||||
#{value => "Host | IP Address | Unix Socket Path",
|
||||
note => "improved in 24.12",
|
||||
desc =>
|
||||
?T("A hostname or an IP address of the Redis server. "
|
||||
"The default is 'localhost'.")}},
|
||||
?T("A hostname, IP address or unix domain socket file of the "
|
||||
"_`database.md#redis|Redis`_ server. "
|
||||
"Setup the path to unix domain socket like: '\"unix:/path/to/socket\"'. "
|
||||
"The default value is 'localhost'.")}},
|
||||
{registration_timeout,
|
||||
#{value => "timeout()",
|
||||
desc =>
|
||||
@@ -1192,8 +1240,8 @@ doc() ->
|
||||
desc =>
|
||||
?T("Full path to a file containing custom DH parameters "
|
||||
"to use for s2s connections. "
|
||||
"Such a file could be created with the command \"openssl "
|
||||
"dhparam -out dh.pem 2048\". If this option is not specified, "
|
||||
"Such a file could be created with the command '\"openssl "
|
||||
"dhparam -out dh.pem 2048\"'. If this option is not specified, "
|
||||
"2048-bit MODP Group with 256-bit Prime Order Subgroup will be "
|
||||
"used as defined in RFC5114 Section 2.3.")}},
|
||||
{s2s_protocol_options,
|
||||
@@ -1257,7 +1305,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 +1324,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."),
|
||||
@@ -1352,7 +1404,7 @@ doc() ->
|
||||
#{value => ?T("Size"),
|
||||
desc =>
|
||||
?T("Number of connections to the SQL server that ejabberd will "
|
||||
"open for each virtual host. The default value is 10. WARNING: "
|
||||
"open for each virtual host. The default value is '10'. WARNING: "
|
||||
"for SQLite this value is '1' by default and it's not recommended "
|
||||
"to change it due to potential race conditions.")}},
|
||||
{sql_port,
|
||||
@@ -1392,7 +1444,7 @@ doc() ->
|
||||
?T("The hostname or IP address of the SQL server. For _`sql_type`_ "
|
||||
"'mssql' or 'odbc' this can also be an ODBC connection string. "
|
||||
"When _`sql_type`_ is 'mysql' or 'pgsql', this can be the path to "
|
||||
"a unix domain socket expressed like: \"unix:/path/to/socket\"."
|
||||
"a unix domain socket expressed like: '\"unix:/path/to/socket\"'."
|
||||
"The default value is 'localhost'.")}},
|
||||
{sql_ssl,
|
||||
#{value => "true | false",
|
||||
@@ -1446,7 +1498,7 @@ doc() ->
|
||||
"possibly with masks. The default value is an empty list. "
|
||||
"Using this option you can know the real IP "
|
||||
"of the request, for admin purpose, or security configuration "
|
||||
"(for example using 'mod_fail2ban'). IMPORTANT: The proxy MUST "
|
||||
"(for example using _`mod_fail2ban`_). IMPORTANT: The proxy MUST "
|
||||
"be configured to set the 'X-Forwarded-For' header if you "
|
||||
"enable this option as, otherwise, the client can set it "
|
||||
"itself and as a result the IP value cannot be trusted for "
|
||||
@@ -1469,7 +1521,7 @@ doc() ->
|
||||
"balancer can be chosen for a specific ejabberd implementation "
|
||||
"while still providing a secure WebSocket connection. "
|
||||
"The default value is 'ignore'. An example value of the 'URL' is "
|
||||
"\"https://test.example.org:8081\".")}},
|
||||
"'\"https://test.example.org:8081\"'.")}},
|
||||
{websocket_ping_interval,
|
||||
#{value => "timeout()",
|
||||
desc =>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
-module(ejabberd_piefxis).
|
||||
|
||||
-protocol({xep, 227, '1.1'}).
|
||||
-protocol({xep, 227, '1.1', '2.1.0', "partial", ""}).
|
||||
|
||||
-export([import_file/1, export_server/1, export_host/2]).
|
||||
|
||||
|
||||
+29
-5
@@ -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).
|
||||
@@ -71,6 +69,14 @@
|
||||
|
||||
-export_type([error_reason/0]).
|
||||
|
||||
-ifdef(USE_OLD_HTTP_URI). % Erlang/OTP lower than 21
|
||||
-dialyzer([{no_return, do_connect/6},
|
||||
{no_unused, flush_queue/1},
|
||||
{no_match, flush_queue/1},
|
||||
{no_unused, re_subscribe/2},
|
||||
{no_match, handle_info/2}]).
|
||||
-endif.
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
@@ -459,11 +465,12 @@ code_change(_OldVsn, State, _Extra) ->
|
||||
%%%===================================================================
|
||||
-spec connect(state()) -> {ok, pid()} | {error, any()}.
|
||||
connect(#state{num = Num}) ->
|
||||
Server = ejabberd_option:redis_server(),
|
||||
Server1 = ejabberd_option:redis_server(),
|
||||
Port = ejabberd_option:redis_port(),
|
||||
DB = ejabberd_option:redis_db(),
|
||||
Pass = ejabberd_option:redis_password(),
|
||||
ConnTimeout = ejabberd_option:redis_connect_timeout(),
|
||||
Server = parse_server(Server1),
|
||||
try case do_connect(Num, Server, Port, Pass, DB, ConnTimeout) of
|
||||
{ok, Client} ->
|
||||
?DEBUG("Connection #~p established to Redis at ~ts:~p",
|
||||
@@ -483,16 +490,33 @@ connect(#state{num = Num}) ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
parse_server([$u,$n,$i,$x,$: | Path]) ->
|
||||
{local, Path};
|
||||
parse_server(Server) ->
|
||||
Server.
|
||||
|
||||
do_connect(1, Server, Port, Pass, _DB, _ConnTimeout) ->
|
||||
%% First connection in the pool is always a subscriber
|
||||
Res = eredis_sub:start_link(Server, Port, Pass, no_reconnect, infinity, drop),
|
||||
Options = [{host, Server},
|
||||
{port, Port},
|
||||
{password, Pass},
|
||||
{reconnect_sleep, no_reconnect},
|
||||
{max_queue_size, infinity},
|
||||
{queue_behaviour, drop}],
|
||||
Res = eredis_sub:start_link(Options),
|
||||
case Res of
|
||||
{ok, Pid} -> eredis_sub:controlling_process(Pid);
|
||||
_ -> ok
|
||||
end,
|
||||
Res;
|
||||
do_connect(_, Server, Port, Pass, DB, ConnTimeout) ->
|
||||
eredis:start_link(Server, Port, DB, Pass, no_reconnect, ConnTimeout).
|
||||
Options = [{host, Server},
|
||||
{port, Port},
|
||||
{database, DB},
|
||||
{password, Pass},
|
||||
{reconnect_sleep, no_reconnect},
|
||||
{connect_timeout, ConnTimeout}],
|
||||
eredis:start_link(Options).
|
||||
|
||||
-spec call(pos_integer(), {q, redis_command()}, integer()) ->
|
||||
{ok, redis_reply()} | redis_error();
|
||||
|
||||
+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
-3
@@ -25,8 +25,6 @@
|
||||
|
||||
-module(ejabberd_s2s).
|
||||
|
||||
-protocol({xep, 220, '1.1'}).
|
||||
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-behaviour(gen_server).
|
||||
@@ -43,7 +41,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 +128,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 +230,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 +482,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,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
-behaviour(xmpp_stream_in).
|
||||
-behaviour(ejabberd_listener).
|
||||
|
||||
-protocol({xep, 114, '1.6'}).
|
||||
-protocol({xep, 114, '1.6', '0.1.0', "complete", ""}).
|
||||
|
||||
%% ejabberd_listener callbacks
|
||||
-export([start/3, start_link/3, stop/0, accept/1]).
|
||||
|
||||
+14
-2
@@ -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"),
|
||||
@@ -1022,8 +1034,8 @@ get_commands_spec() ->
|
||||
desc = "List all established sessions",
|
||||
policy = admin,
|
||||
module = ?MODULE, function = connected_users, args = [],
|
||||
result_desc = "List of users sessions",
|
||||
result_example = [<<"user1@example.com">>, <<"user2@example.com">>],
|
||||
result_desc = "List of users sessions full JID",
|
||||
result_example = [<<"user1@example.com/Home">>, <<"user2@example.com/54134">>],
|
||||
result = {connected_users, {list, {sessions, string}}}},
|
||||
#ejabberd_commands{name = connected_users_number, tags = [session, statistics],
|
||||
desc = "Get the number of established sessions",
|
||||
|
||||
@@ -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
-14
@@ -26,7 +26,6 @@
|
||||
-module(ejabberd_stun).
|
||||
-behaviour(ejabberd_listener).
|
||||
-protocol({rfc, 5766}).
|
||||
-protocol({xep, 176, '1.0'}).
|
||||
|
||||
-ifndef(STUN).
|
||||
-include("logger.hrl").
|
||||
@@ -106,7 +105,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 +127,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>
|
||||
%%%
|
||||
|
||||
+113
-52
@@ -238,7 +238,7 @@ get_auth_admin(Auth, HostHTTP, RPath, Method) ->
|
||||
{SJID, Pass} ->
|
||||
{HostOfRule, AccessRule} = get_acl_rule(RPath, Method),
|
||||
try jid:decode(SJID) of
|
||||
#jid{user = <<"">>, server = User} ->
|
||||
#jid{luser = <<"">>, lserver = User} ->
|
||||
case ejabberd_router:is_my_host(HostHTTP) of
|
||||
true ->
|
||||
get_auth_account(HostOfRule, AccessRule, User, HostHTTP,
|
||||
@@ -246,7 +246,7 @@ get_auth_admin(Auth, HostHTTP, RPath, Method) ->
|
||||
_ ->
|
||||
{unauthorized, <<"missing-server">>}
|
||||
end;
|
||||
#jid{user = User, server = Server} ->
|
||||
#jid{luser = User, lserver = Server} ->
|
||||
get_auth_account(HostOfRule, AccessRule, User, Server,
|
||||
Pass)
|
||||
catch _:{bad_jid, _} ->
|
||||
@@ -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}} ->
|
||||
@@ -2224,13 +2285,13 @@ make_result(Binary,
|
||||
First = proplists:get_value(first, ArgumentsUsed),
|
||||
Second = proplists:get_value(second, ArgumentsUsed),
|
||||
FirstUrlencoded =
|
||||
hd(string:replace(
|
||||
misc:url_encode(First), "%40", "@")),
|
||||
list_to_binary(string:replace(
|
||||
misc:url_encode(First), "%40", "@")),
|
||||
{GroupId, Host} =
|
||||
case jid:decode(FirstUrlencoded) of
|
||||
#jid{luser = <<"">>, lserver = G} ->
|
||||
#jid{luser = <<"">>, server = G} ->
|
||||
{G, Second};
|
||||
#jid{luser = G, lserver = H} ->
|
||||
#jid{user = G, lserver = H} ->
|
||||
{G, H}
|
||||
end,
|
||||
UrlBinary =
|
||||
|
||||
@@ -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}.
|
||||
|
||||
+3
-3
@@ -56,15 +56,15 @@
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include_lib("kernel/include/file.hrl").
|
||||
|
||||
-ifdef(OTP_BELOW_27).
|
||||
%% Copied from erlang/otp/lib/stdlib/src/re.erl
|
||||
-type re_mp() :: {re_pattern, _, _, _, _}.
|
||||
-export_type([re_mp/0]).
|
||||
|
||||
-ifdef(OTP_BELOW_27).
|
||||
-type json_value() :: jiffy:json_value().
|
||||
-else.
|
||||
-type re_mp() :: re:mp().
|
||||
-type json_value() :: json:encode_value().
|
||||
-endif.
|
||||
-export_type([re_mp/0]).
|
||||
-export_type([json_value/0]).
|
||||
|
||||
-type distance_cache() :: #{{string(), string()} => non_neg_integer()}.
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
|
||||
-author('henoch@dtek.chalmers.se').
|
||||
|
||||
-protocol({xep, 50, '1.2'}).
|
||||
-protocol({xep, 50, '1.2', '1.1.0', "complete", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
|
||||
+63
-84
@@ -43,7 +43,8 @@
|
||||
% Sessions
|
||||
num_resources/2, resource_num/3,
|
||||
kick_session/4, status_num/2, status_num/1,
|
||||
status_list/2, status_list/1, connected_users_info/0,
|
||||
status_list/2, status_list_v3/2,
|
||||
status_list/1, status_list_v3/1, connected_users_info/0,
|
||||
connected_users_vhost/1, set_presence/7,
|
||||
get_presence/2, user_sessions_info/2, get_last/2, set_last/4,
|
||||
|
||||
@@ -274,9 +275,9 @@ get_commands_spec() ->
|
||||
longdesc = "This command kicks the account sessions, "
|
||||
"sets a random password, and stores ban details in the "
|
||||
"account private storage. "
|
||||
"This command requires mod_private to be enabled. "
|
||||
"This command requires _`mod_private`_ to be enabled. "
|
||||
"Check also _`get_ban_details`_ API "
|
||||
"and `_unban_account`_ API.",
|
||||
"and _`unban_account`_ API.",
|
||||
module = ?MODULE, function = ban_account_v2,
|
||||
version = 2,
|
||||
note = "improved in 24.06",
|
||||
@@ -380,6 +381,21 @@ get_commands_spec() ->
|
||||
{status, string}
|
||||
]}}
|
||||
}}},
|
||||
#ejabberd_commands{name = status_list_host, tags = [session],
|
||||
desc = "List of users logged in host with their statuses",
|
||||
module = ?MODULE, function = status_list_v3,
|
||||
version = 3,
|
||||
note = "updated in 24.12",
|
||||
args = [{host, binary}, {status, binary}],
|
||||
args_example = [<<"myserver.com">>, <<"dnd">>],
|
||||
args_desc = ["Server name", "Status type to check"],
|
||||
result_example = [{<<"peter@myserver.com/tka">>,6,<<"Busy">>}],
|
||||
result = {users, {list,
|
||||
{userstatus, {tuple, [{jid, string},
|
||||
{priority, integer},
|
||||
{status, string}
|
||||
]}}
|
||||
}}},
|
||||
#ejabberd_commands{name = status_list, tags = [session],
|
||||
desc = "List of logged users with this status",
|
||||
module = ?MODULE, function = status_list,
|
||||
@@ -396,6 +412,21 @@ get_commands_spec() ->
|
||||
{status, string}
|
||||
]}}
|
||||
}}},
|
||||
#ejabberd_commands{name = status_list, tags = [session],
|
||||
desc = "List of logged users with this status",
|
||||
module = ?MODULE, function = status_list_v3,
|
||||
version = 3,
|
||||
note = "updated in 24.12",
|
||||
args = [{status, binary}],
|
||||
args_example = [<<"dnd">>],
|
||||
args_desc = ["Status type to check"],
|
||||
result_example = [{<<"peter@myserver.com/tka">>,6,<<"Busy">>}],
|
||||
result = {users, {list,
|
||||
{userstatus, {tuple, [{jid, string},
|
||||
{priority, integer},
|
||||
{status, string}
|
||||
]}}
|
||||
}}},
|
||||
#ejabberd_commands{name = connected_users_info,
|
||||
tags = [session],
|
||||
desc = "List all established sessions and their information",
|
||||
@@ -426,8 +457,9 @@ get_commands_spec() ->
|
||||
module = ?MODULE, function = connected_users_vhost,
|
||||
args_example = [<<"myexample.com">>],
|
||||
args_desc = ["Server name"],
|
||||
result_example = [<<"user1@myserver.com/tka">>, <<"user2@localhost/tka">>],
|
||||
args = [{host, binary}],
|
||||
result_example = [<<"user1@myserver.com/tka">>, <<"user2@localhost/tka">>],
|
||||
result_desc = "List of sessions full JIDs",
|
||||
result = {connected_users_vhost, {list, {sessions, string}}}},
|
||||
#ejabberd_commands{name = user_sessions_info,
|
||||
tags = [session],
|
||||
@@ -683,6 +715,7 @@ get_commands_spec() ->
|
||||
module = ?MODULE, function = get_roster,
|
||||
args = [],
|
||||
args_rename = [{server, host}],
|
||||
result_example = [{<<"user2@localhost">>, <<"User 2">>, <<"none">>, <<"subscribe">>, [<<"Group1">>]}],
|
||||
result = {contacts, {list, {contact, {tuple, [
|
||||
{jid, string},
|
||||
{nick, string},
|
||||
@@ -696,6 +729,7 @@ get_commands_spec() ->
|
||||
policy = user,
|
||||
module = ?MODULE, function = get_roster_count,
|
||||
args = [],
|
||||
args_example = [<<"sun">>, <<"localhost">>],
|
||||
args_rename = [{server, host}],
|
||||
result_example = 5,
|
||||
result_desc = "Number",
|
||||
@@ -1333,6 +1367,14 @@ status_list(Host, Status) ->
|
||||
status_list(Status) ->
|
||||
status_list(<<"all">>, Status).
|
||||
|
||||
status_list_v3(ArgHost, Status) ->
|
||||
List = status_list(ArgHost, Status),
|
||||
[{jid:encode(jid:make(User, Host, Resource)), Priority, StatusText}
|
||||
|| {User, Host, Resource, Priority, StatusText} <- List].
|
||||
|
||||
status_list_v3(Status) ->
|
||||
status_list_v3(<<"all">>, Status).
|
||||
|
||||
|
||||
get_status_list(Host, Status_required) ->
|
||||
%% Get list of all logged users
|
||||
@@ -1425,8 +1467,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 +2248,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 +2278,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 +2296,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.
|
||||
|
||||
@@ -2348,7 +2325,9 @@ web_page_node(_, Node, #request{path = [<<"stats">>]} = R) ->
|
||||
ejabberd_web_admin,
|
||||
make_command,
|
||||
[stats, R, [{<<"name">>, <<"uptimeseconds">>}], [{only, value}]]),
|
||||
UpDaysBin = integer_to_binary(binary_to_integer(fxml:get_tag_cdata(UpSecs)) div 24000),
|
||||
UpDaysBin =
|
||||
integer_to_binary(binary_to_integer(fxml:get_tag_cdata(UpSecs))
|
||||
div 86400), % 24*60*60
|
||||
UpDays =
|
||||
#xmlel{name = <<"code">>,
|
||||
attrs = [],
|
||||
@@ -2389,22 +2368,22 @@ mod_doc() ->
|
||||
#{desc =>
|
||||
[?T("This module provides additional administrative commands."), "",
|
||||
?T("Details for some commands:"), "",
|
||||
?T("- 'ban_account':"),
|
||||
?T("_`ban_account`_ API:"),
|
||||
?T("This command kicks all the connected sessions of the account "
|
||||
"from the server. It also changes their password to a randomly "
|
||||
"generated one, so they can't login anymore unless a server "
|
||||
"administrator changes their password again. It is possible to "
|
||||
"define the reason of the ban. The new password also includes "
|
||||
"the reason and the date and time of the ban. See an example below."),
|
||||
?T("- 'pushroster': (and 'pushroster-all')"),
|
||||
"the reason and the date and time of the ban. See an example below."), "",
|
||||
?T("_`push_roster`_ API (and _`push_roster_all`_ API):"),
|
||||
?T("The roster file must be placed, if using Windows, on the "
|
||||
"directory where you installed ejabberd: "
|
||||
"`C:/Program Files/ejabberd` or similar. If you use other "
|
||||
"Operating System, place the file on the same directory where "
|
||||
"the .beam files are installed. See below an example roster file."),
|
||||
?T("- 'srg_create':"),
|
||||
"the .beam files are installed. See below an example roster file."), "",
|
||||
?T("_`srg_create`_ API:"),
|
||||
?T("If you want to put a group Name with blank spaces, use the "
|
||||
"characters \"\' and \'\" to define when the Name starts and "
|
||||
"characters '\"\'' and '\'\"' to define when the Name starts and "
|
||||
"ends. See an example below.")],
|
||||
example =>
|
||||
[{?T("With this configuration, vCards can only be modified with "
|
||||
@@ -2419,14 +2398,14 @@ mod_doc() ->
|
||||
" mod_admin_extra: {}",
|
||||
" mod_vcard:",
|
||||
" access_set: vcard_set"]},
|
||||
{?T("Content of roster file for 'pushroster' command:"),
|
||||
{?T("Content of roster file for _`push_roster`_ API:"),
|
||||
["[{<<\"bob\">>, <<\"example.org\">>, <<\"workers\">>, <<\"Bob\">>},",
|
||||
"{<<\"mart\">>, <<\"example.org\">>, <<\"workers\">>, <<\"Mart\">>},",
|
||||
"{<<\"Rich\">>, <<\"example.org\">>, <<\"bosses\">>, <<\"Rich\">>}]."]},
|
||||
{?T("With this call, the sessions of the local account which JID is "
|
||||
"boby@example.org will be kicked, and its password will be set "
|
||||
"'boby@example.org' will be kicked, and its password will be set "
|
||||
"to something like "
|
||||
"'BANNED_ACCOUNT--20080425T21:45:07--2176635--Spammed_rooms'"),
|
||||
["ejabberdctl vhost example.org ban_account boby \"Spammed rooms\""]},
|
||||
{?T("Call to srg_create using double-quotes and single-quotes:"),
|
||||
{?T("Call to _`srg_create`_ API using double-quotes and single-quotes:"),
|
||||
["ejabberdctl srg_create g1 example.org \"\'Group number 1\'\" this_is_g1 g1"]}]}.
|
||||
|
||||
@@ -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
|
||||
<<>> -> [];
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% File : mod_auth_fast.erl
|
||||
%%% Author : Pawel Chmielowski <pawel@process-one.net>
|
||||
%%% Created : 1 Dec 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_auth_fast).
|
||||
-behaviour(gen_mod).
|
||||
-protocol({xep, 484, '0.2.0', '24.12', "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,
|
||||
get_tokens/3, get_mechanisms/1]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include_lib("xmpp/include/scram.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("translate.hrl").
|
||||
|
||||
-callback get_tokens(binary(), binary(), binary()) ->
|
||||
[{current | next, binary(), non_neg_integer()}].
|
||||
-callback rotate_token(binary(), binary(), binary()) ->
|
||||
ok | {error, atom()}.
|
||||
-callback del_token(binary(), binary(), binary(), current | next) ->
|
||||
ok | {error, atom()}.
|
||||
-callback set_token(binary(), binary(), binary(), current | next, binary(), non_neg_integer()) ->
|
||||
ok | {error, atom()}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
-spec start(binary(), gen_mod:opts()) -> {ok, [gen_mod:registration()]}.
|
||||
start(Host, Opts) ->
|
||||
Mod = gen_mod:db_mod(Opts, ?MODULE),
|
||||
Mod:init(Host, Opts),
|
||||
{ok, [{hook, c2s_inline_features, c2s_inline_features, 50},
|
||||
{hook, c2s_handle_sasl2_inline, c2s_handle_sasl2_inline, 10}]}.
|
||||
|
||||
-spec stop(binary()) -> ok.
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
-spec reload(binary(), gen_mod:opts(), gen_mod:opts()) -> ok.
|
||||
reload(Host, NewOpts, OldOpts) ->
|
||||
NewMod = gen_mod:db_mod(NewOpts, ?MODULE),
|
||||
OldMod = gen_mod:db_mod(OldOpts, ?MODULE),
|
||||
if NewMod /= OldMod ->
|
||||
NewMod:init(Host, NewOpts);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
ok.
|
||||
|
||||
-spec depends(binary(), gen_mod:opts()) -> [{module(), hard | soft}].
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
-spec mod_opt_type(atom()) -> econf:validator().
|
||||
mod_opt_type(db_type) ->
|
||||
econf:db_type(?MODULE);
|
||||
mod_opt_type(token_lifetime) ->
|
||||
econf:timeout(second);
|
||||
mod_opt_type(token_refresh_age) ->
|
||||
econf:timeout(second).
|
||||
|
||||
-spec mod_options(binary()) -> [{atom(), any()}].
|
||||
mod_options(Host) ->
|
||||
[{db_type, ejabberd_config:default_db(Host, ?MODULE)},
|
||||
{token_lifetime, 30*24*60*60},
|
||||
{token_refresh_age, 24*60*60}].
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
[?T("The module adds support for "
|
||||
"https://xmpp.org/extensions/xep-0484.html"
|
||||
"[XEP-0480: Fast Authentication Streamlining Tokens] that allows users to authenticate "
|
||||
"using self managed tokens.")],
|
||||
note => "added in 24.12",
|
||||
opts =>
|
||||
[{db_type,
|
||||
#{value => "mnesia | sql",
|
||||
desc =>
|
||||
?T("Same as top-level _`default_db`_ option, but applied to this module only.")}},
|
||||
{token_lifetime,
|
||||
#{value => "timeout()",
|
||||
desc => ?T("Time that tokens will be keept, measured from it's creation time. "
|
||||
"Default value set to 30 days")}},
|
||||
{token_refresh_age,
|
||||
#{value => "timeout()",
|
||||
desc => ?T("This time determines age of token, that qualifies for automatic refresh. "
|
||||
"Default value set to 1 day")}}],
|
||||
example =>
|
||||
["modules:",
|
||||
" mod_auth_fast:",
|
||||
" token_timeout: 14days"]}.
|
||||
|
||||
get_mechanisms(_LServer) ->
|
||||
[<<"HT-SHA-256-NONE">>, <<"HT-SHA-256-UNIQ">>, <<"HT-SHA-256-EXPR">>, <<"HT-SHA-256-ENDP">>].
|
||||
|
||||
ua_hash(UA) ->
|
||||
crypto:hash(sha256, UA).
|
||||
|
||||
get_tokens(LServer, LUser, UA) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
ToRefresh = erlang:system_time(second) - mod_auth_fast_opt:token_refresh_age(LServer),
|
||||
lists:map(
|
||||
fun({Type, Token, CreatedAt}) ->
|
||||
{{Type, CreatedAt < ToRefresh}, Token}
|
||||
end, Mod:get_tokens(LServer, LUser, ua_hash(UA))).
|
||||
|
||||
c2s_inline_features({Sasl, Bind, Extra}, Host) ->
|
||||
{Sasl ++ [#fast{mechs = get_mechanisms(Host)}], Bind, Extra}.
|
||||
|
||||
gen_token(#{sasl2_ua_id := UA, server := Server, user := User}) ->
|
||||
Mod = gen_mod:db_mod(Server, ?MODULE),
|
||||
Token = base64:encode(ua_hash(<<UA/binary, (p1_rand:get_string())/binary>>)),
|
||||
ExpiresAt = erlang:system_time(second) + mod_auth_fast_opt:token_lifetime(Server),
|
||||
Mod:set_token(Server, User, ua_hash(UA), next, Token, ExpiresAt),
|
||||
#fast_token{token = Token, expiry = misc:usec_to_now(ExpiresAt*1000000)}.
|
||||
|
||||
c2s_handle_sasl2_inline({#{server := Server, user := User, sasl2_ua_id := UA,
|
||||
sasl2_axtra_auth_info := Extra} = State, Els, Results} = Acc) ->
|
||||
Mod = gen_mod:db_mod(Server, ?MODULE),
|
||||
NeedRegen =
|
||||
case Extra of
|
||||
{token, {next, Rotate}} ->
|
||||
Mod:rotate_token(Server, User, ua_hash(UA)),
|
||||
Rotate;
|
||||
{token, {_, true}} ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end,
|
||||
case {lists:keyfind(fast_request_token, 1, Els), lists:keyfind(fast, 1, Els)} of
|
||||
{#fast_request_token{mech = _Mech}, #fast{invalidate = true}} ->
|
||||
Mod:del_token(Server, User, ua_hash(UA), current),
|
||||
{State, Els, [gen_token(State) | Results]};
|
||||
{_, #fast{invalidate = true}} ->
|
||||
Mod:del_token(Server, User, ua_hash(UA), current),
|
||||
Acc;
|
||||
{#fast_request_token{mech = _Mech}, _} ->
|
||||
{State, Els, [gen_token(State) | Results]};
|
||||
_ when NeedRegen ->
|
||||
{State, Els, [gen_token(State) | Results]};
|
||||
_ ->
|
||||
Acc
|
||||
end.
|
||||
@@ -0,0 +1,123 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% File : mod_auth_fast_mnesia.erl
|
||||
%%% Author : Pawel Chmielowski <pawel@process-one.net>
|
||||
%%% Created : 1 Dec 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_auth_fast_mnesia).
|
||||
|
||||
-behaviour(mod_auth_fast).
|
||||
|
||||
%% API
|
||||
-export([init/2]).
|
||||
-export([get_tokens/3, del_token/4, set_token/6, rotate_token/3]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-record(mod_auth_fast, {key = {<<"">>, <<"">>, <<"">>} :: {binary(), binary(), binary()} | '$1',
|
||||
token = <<>> :: binary() | '_',
|
||||
created_at = 0 :: non_neg_integer() | '_',
|
||||
expires_at = 0 :: non_neg_integer() | '_'}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
init(_Host, _Opts) ->
|
||||
ejabberd_mnesia:create(?MODULE, mod_auth_fast,
|
||||
[{disc_only_copies, [node()]},
|
||||
{attributes,
|
||||
record_info(fields, mod_auth_fast)}]).
|
||||
|
||||
-spec get_tokens(binary(), binary(), binary()) ->
|
||||
[{current | next, binary(), non_neg_integer()}].
|
||||
get_tokens(LServer, LUser, UA) ->
|
||||
Now = erlang:system_time(second),
|
||||
case mnesia:dirty_read(mod_auth_fast, {LServer, LUser, token_id(UA, next)}) of
|
||||
[#mod_auth_fast{token = Token, created_at = Created, expires_at = Expires}] when Expires > Now ->
|
||||
[{next, Token, Created}];
|
||||
[#mod_auth_fast{}] ->
|
||||
del_token(LServer, LUser, UA, next),
|
||||
[];
|
||||
_ ->
|
||||
[]
|
||||
end ++
|
||||
case mnesia:dirty_read(mod_auth_fast, {LServer, LUser, token_id(UA, current)}) of
|
||||
[#mod_auth_fast{token = Token, created_at = Created, expires_at = Expires}] when Expires > Now ->
|
||||
[{current, Token, Created}];
|
||||
[#mod_auth_fast{}] ->
|
||||
del_token(LServer, LUser, UA, current),
|
||||
[];
|
||||
_ ->
|
||||
[]
|
||||
end.
|
||||
|
||||
-spec rotate_token(binary(), binary(), binary()) ->
|
||||
ok | {error, atom()}.
|
||||
rotate_token(LServer, LUser, UA) ->
|
||||
F = fun() ->
|
||||
case mnesia:dirty_read(mod_auth_fast, {LServer, LUser, token_id(UA, next)}) of
|
||||
[#mod_auth_fast{token = Token, created_at = Created, expires_at = Expires}] ->
|
||||
mnesia:write(#mod_auth_fast{key = {LServer, LUser, token_id(UA, current)},
|
||||
token = Token, created_at = Created,
|
||||
expires_at = Expires}),
|
||||
mnesia:delete({mod_auth_fast, {LServer, LUser, token_id(UA, next)}});
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end,
|
||||
transaction(F).
|
||||
|
||||
-spec del_token(binary(), binary(), binary(), current | next) ->
|
||||
ok | {error, atom()}.
|
||||
del_token(LServer, LUser, UA, Type) ->
|
||||
F = fun() ->
|
||||
mnesia:delete({mod_auth_fast, {LServer, LUser, token_id(UA, Type)}})
|
||||
end,
|
||||
transaction(F).
|
||||
|
||||
-spec set_token(binary(), binary(), binary(), current | next, binary(), non_neg_integer()) ->
|
||||
ok | {error, atom()}.
|
||||
set_token(LServer, LUser, UA, Type, Token, Expires) ->
|
||||
F = fun() ->
|
||||
mnesia:write(#mod_auth_fast{key = {LServer, LUser, token_id(UA, Type)},
|
||||
token = Token, created_at = erlang:system_time(second),
|
||||
expires_at = Expires})
|
||||
end,
|
||||
transaction(F).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
||||
token_id(UA, current) ->
|
||||
<<"c:", UA/binary>>;
|
||||
token_id(UA, _) ->
|
||||
<<"n:", UA/binary>>.
|
||||
|
||||
transaction(F) ->
|
||||
case mnesia:transaction(F) of
|
||||
{atomic, Res} ->
|
||||
Res;
|
||||
{aborted, Reason} ->
|
||||
?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
|
||||
{error, db_failure}
|
||||
end.
|
||||
@@ -0,0 +1,27 @@
|
||||
%% Generated automatically
|
||||
%% DO NOT EDIT: run `make options` instead
|
||||
|
||||
-module(mod_auth_fast_opt).
|
||||
|
||||
-export([db_type/1]).
|
||||
-export([token_lifetime/1]).
|
||||
-export([token_refresh_age/1]).
|
||||
|
||||
-spec db_type(gen_mod:opts() | global | binary()) -> atom().
|
||||
db_type(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(db_type, Opts);
|
||||
db_type(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_auth_fast, db_type).
|
||||
|
||||
-spec token_lifetime(gen_mod:opts() | global | binary()) -> pos_integer().
|
||||
token_lifetime(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(token_lifetime, Opts);
|
||||
token_lifetime(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_auth_fast, token_lifetime).
|
||||
|
||||
-spec token_refresh_age(gen_mod:opts() | global | binary()) -> pos_integer().
|
||||
token_refresh_age(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(token_refresh_age, Opts);
|
||||
token_refresh_age(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_auth_fast, token_refresh_age).
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
-module(mod_avatar).
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-protocol({xep, 398, '0.2.0', '18.03', "", ""}).
|
||||
-protocol({xep, 398, '0.2.0', '18.03', "complete", ""}).
|
||||
|
||||
%% gen_mod API
|
||||
-export([start/2, stop/1, reload/3, depends/2, mod_opt_type/1, mod_options/1]).
|
||||
|
||||
@@ -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) ->
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-protocol({xep, 191, '1.2'}).
|
||||
-protocol({xep, 191, '1.2', '2.1.7', "complete", ""}).
|
||||
|
||||
-export([start/2, stop/1, reload/3, process_iq/1, depends/2,
|
||||
disco_features/5, mod_options/1, mod_doc/0]).
|
||||
@@ -269,5 +269,5 @@ mod_doc() ->
|
||||
[?T("The module implements "
|
||||
"https://xmpp.org/extensions/xep-0191.html"
|
||||
"[XEP-0191: Blocking Command]."), "",
|
||||
?T("This module depends on 'mod_privacy' where "
|
||||
?T("This module depends on _`mod_privacy`_ where "
|
||||
"all the configuration is performed.")]}.
|
||||
|
||||
+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>
|
||||
%%%
|
||||
%%%
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
-author('henoch@dtek.chalmers.se').
|
||||
|
||||
-protocol({xep, 115, '1.5'}).
|
||||
-protocol({xep, 115, '1.5', '2.1.4', "complete", ""}).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
-module (mod_carboncopy).
|
||||
|
||||
-author ('ecestari@process-one.net').
|
||||
-protocol({xep, 280, '0.13.2'}).
|
||||
-protocol({xep, 280, '0.13.2', '13.06', "complete", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
-module(mod_client_state).
|
||||
-author('holger@zedat.fu-berlin.de').
|
||||
-protocol({xep, 85, '2.1'}).
|
||||
-protocol({xep, 352, '0.1', '14.12', "", ""}).
|
||||
-protocol({xep, 85, '2.1', '2.1.0', "complete", ""}).
|
||||
-protocol({xep, 352, '0.1', '14.12', "complete", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-protocol({xep, 133, '1.3.0', '13.10', "complete", ""}).
|
||||
-protocol({xep, 133, '1.3.0', '13.10', "partial", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
|
||||
@@ -256,9 +256,8 @@ mod_doc() ->
|
||||
?T("To use this module, in addition to adding it to the 'modules' "
|
||||
"section, you must also enable it in 'listen' -> 'ejabberd_http' -> "
|
||||
"_`listen-options.md#request_handlers|request_handlers`_."), "",
|
||||
?T("Make sure either 'mod_bosh' or 'ejabberd_http_ws' "
|
||||
"_`listen-options.md#request_handlers|request_handlers`_ "
|
||||
"are enabled."), "",
|
||||
?T("Make sure either _`mod_bosh`_ or _`listen.md#ejabberd_http_ws|ejabberd_http_ws`_ "
|
||||
"are enabled in at least one 'request_handlers'."), "",
|
||||
?T("When 'conversejs_css' and 'conversejs_script' are 'auto', "
|
||||
"by default they point to the public Converse client.")
|
||||
],
|
||||
@@ -308,7 +307,7 @@ mod_doc() ->
|
||||
#{value => ?T("auto | WebSocketURL"),
|
||||
desc =>
|
||||
?T("A WebSocket URL to which Converse can connect to. "
|
||||
"The keyword '@HOST@' is replaced with the real virtual "
|
||||
"The '@HOST@' keyword is replaced with the real virtual "
|
||||
"host name. "
|
||||
"If set to 'auto', it will build the URL of the first "
|
||||
"configured WebSocket request handler. "
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
-author('amuhar3@gmail.com').
|
||||
|
||||
-protocol({xep, 355, '0.4.1', '16.09', "", ""}).
|
||||
-protocol({xep, 355, '0.4.1', '16.09', "complete", ""}).
|
||||
|
||||
-behaviour(gen_server).
|
||||
-behaviour(gen_mod).
|
||||
@@ -117,7 +117,7 @@ mod_doc() ->
|
||||
[{?T("Make sure you do not delegate the same namespace to several "
|
||||
"services at the same time. As in the example provided later, "
|
||||
"to have the 'sat-pubsub.example.org' component perform "
|
||||
"correctly disable the 'mod_pubsub' module."),
|
||||
"correctly disable the _`mod_pubsub`_ module."),
|
||||
["access_rules:",
|
||||
" external_pubsub:",
|
||||
" allow: external_component",
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@
|
||||
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-protocol({xep, 30, '2.4'}).
|
||||
-protocol({xep, 157, '1.0'}).
|
||||
-protocol({xep, 30, '2.4', '0.1.0', "complete", ""}).
|
||||
-protocol({xep, 157, '1.0', '2.1.0', "complete", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
|
||||
@@ -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}) ->
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
-author('badlop@process-one.net').
|
||||
|
||||
-protocol({xep, 156, '1.4.0', '22.05', "", ""}).
|
||||
-protocol({xep, 156, '1.4.0', '22.05', "complete", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
@@ -214,7 +214,8 @@ mod_doc() ->
|
||||
?T("To use this module, in addition to adding it to the 'modules' "
|
||||
"section, you must also enable it in 'listen' -> 'ejabberd_http' -> "
|
||||
"_`listen-options.md#request_handlers|request_handlers`_."), "",
|
||||
?T("Notice it only works if ejabberd_http has tls enabled.")],
|
||||
?T("Notice it only works if _`listen.md#ejabberd_http|ejabberd_http`_ "
|
||||
"has _`listen-options.md#tls|tls`_ enabled.")],
|
||||
note => "added in 22.05",
|
||||
example =>
|
||||
["listen:",
|
||||
|
||||
+48
-15
@@ -31,7 +31,7 @@
|
||||
|
||||
-export([start/2, stop/1, reload/3, process/2, depends/2,
|
||||
format_arg/2,
|
||||
mod_options/1, mod_doc/0]).
|
||||
mod_opt_type/1, mod_options/1, mod_doc/0]).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
@@ -201,19 +201,25 @@ extract_args(Data) ->
|
||||
maps:to_list(Maps).
|
||||
|
||||
% get API version N from last "vN" element in URL path
|
||||
get_api_version(#request{path = Path}) ->
|
||||
get_api_version(lists:reverse(Path));
|
||||
get_api_version([<<"v", String/binary>> | Tail]) ->
|
||||
get_api_version(#request{path = Path, host = Host}) ->
|
||||
get_api_version(lists:reverse(Path), Host).
|
||||
|
||||
get_api_version([<<"v", String/binary>> | Tail], Host) ->
|
||||
case catch binary_to_integer(String) of
|
||||
N when is_integer(N) ->
|
||||
N;
|
||||
_ ->
|
||||
get_api_version(Tail)
|
||||
get_api_version(Tail, Host)
|
||||
end;
|
||||
get_api_version([_Head | Tail]) ->
|
||||
get_api_version(Tail);
|
||||
get_api_version([]) ->
|
||||
?DEFAULT_API_VERSION.
|
||||
get_api_version([_Head | Tail], Host) ->
|
||||
get_api_version(Tail, Host);
|
||||
get_api_version([], Host) ->
|
||||
try mod_http_api_opt:default_version(Host)
|
||||
catch error:{module_not_loaded, ?MODULE, Host} ->
|
||||
?WARNING_MSG("Using module ~p for host ~s, but it isn't configured "
|
||||
"in the configuration file", [?MODULE, Host]),
|
||||
?DEFAULT_API_VERSION
|
||||
end.
|
||||
|
||||
%% ----------------
|
||||
%% command handlers
|
||||
@@ -542,15 +548,31 @@ 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);
|
||||
hide_sensitive_args(NonListArgs) ->
|
||||
NonListArgs.
|
||||
|
||||
mod_opt_type(default_version) ->
|
||||
econf:either(
|
||||
econf:int(0, 3),
|
||||
econf:and_then(
|
||||
econf:binary(),
|
||||
fun(Binary) ->
|
||||
case binary_to_list(Binary) of
|
||||
F when F >= "24.06" ->
|
||||
2;
|
||||
F when (F > "23.10") and (F < "24.06") ->
|
||||
1;
|
||||
F when F =< "23.10" ->
|
||||
0
|
||||
end
|
||||
end)).
|
||||
|
||||
mod_options(_) ->
|
||||
[].
|
||||
[{default_version, ?DEFAULT_API_VERSION}].
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
@@ -561,10 +583,20 @@ mod_doc() ->
|
||||
"section, you must also enable it in 'listen' -> 'ejabberd_http' -> "
|
||||
"_`listen-options.md#request_handlers|request_handlers`_."), "",
|
||||
?T("To use a specific API version N, when defining the URL path "
|
||||
"in the request_handlers, add a 'vN'. "
|
||||
"For example: '/api/v2: mod_http_api'"), "",
|
||||
"in the request_handlers, add a vN. "
|
||||
"For example: '/api/v2: mod_http_api'."), "",
|
||||
?T("To run a command, send a POST request to the corresponding "
|
||||
"URL: 'http://localhost:5280/api/<command_name>'")],
|
||||
"URL: 'http://localhost:5280/api/COMMAND-NAME'")],
|
||||
opts =>
|
||||
[{default_version,
|
||||
#{value => "integer() | string()",
|
||||
note => "added in 24.12",
|
||||
desc =>
|
||||
?T("What API version to use when none is specified in the URL path. "
|
||||
"If setting an ejabberd version, it will use the latest API "
|
||||
"version that was available in that ejabberd version. "
|
||||
"For example, setting '\"24.06\"' in this option implies '2'. "
|
||||
"The default value is the latest version.")}}],
|
||||
example =>
|
||||
["listen:",
|
||||
" -",
|
||||
@@ -574,4 +606,5 @@ mod_doc() ->
|
||||
" /api: mod_http_api",
|
||||
"",
|
||||
"modules:",
|
||||
" mod_http_api: {}"]}.
|
||||
" mod_http_api:",
|
||||
" default_version: 2"]}.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user