Compare commits

...

95 Commits

Author SHA1 Message Date
Badlop 7511307868 Set version to 24.12
Container / Container (push) Failing after 48s
Installers / Binaries (push) Failing after 53s
Runtime / Rebars (20, rebar) (push) Failing after 4s
Runtime / Rebars (20, rebar3) (push) Failing after 5s
Runtime / Rebars (25, rebar) (push) Failing after 4s
Runtime / Rebars (25, rebar3) (push) Failing after 4s
Runtime / Rebars (26, rebar) (push) Failing after 4s
Runtime / Rebars (26, rebar3) (push) Failing after 5s
Runtime / Rebars (27, rebar3) (push) Failing after 4s
Runtime / Rebar3+Elixir (1.13) (push) Failing after 1m21s
Runtime / Rebar3+Elixir (1.14) (push) Failing after 1m29s
Runtime / Rebar3+Elixir (1.15) (push) Failing after 9s
Runtime / Rebar3+Elixir (1.16) (push) Failing after 8s
Runtime / Rebar3+Elixir (1.17) (push) Failing after 9s
Runtime / Mix (1.13) (push) Failing after 5s
Runtime / Mix (1.14) (push) Failing after 5s
Runtime / Mix (1.15) (push) Failing after 5s
Runtime / Mix (1.16) (push) Failing after 5s
Runtime / Mix (1.17) (push) Failing after 5s
Installers / Release (push) Has been skipped
CI / Tests (20.0) (push) Has been cancelled
CI / Tests (25) (push) Has been cancelled
CI / Tests (26) (push) Has been cancelled
CI / Tests (27) (push) Has been cancelled
2024-12-19 11:50:21 +01:00
Badlop 1cadc6b1dc CI: Revert old feature that published failed CT logs to website
Nowadays the CT logs can be downloaded from each action run in:
  https://github.com/processone/ejabberd/actions/workflows/ci.yml

This partially reverts commit 8ccad7f
  Publish CT logs and Cover on failure to an external GH Pages repo
2024-12-19 11:21:25 +01:00
Badlop 405437b086 mix.lock, rebar.lock: Update to recent versions 2024-12-19 10:56:30 +01:00
Badlop 51f4382b9f CHANGELOG.md: Update 2024-12-19 10:45:19 +01:00
Holger Weiss e967a409d3 stundisco_tests: Fix TURNS credentials syntax 2024-12-18 22:24:53 +01:00
Holger Weiss eaebfc795e rebar.config: Depend on current xmpp version
We now hard-depend on xmpp 1.9.1.
2024-12-18 21:31:55 +01:00
Holger Weiss 3bc66a7054 stundisco_tests: Check correct credentials syntax 2024-12-18 21:17:07 +01:00
Holger Weiss 8cfcc69100 mod_stun_disco: Fix syntax of credentials response
As per XEP-0215 (#3.3), the response to a credentials request must use
the <credentials/> element rather than <services/>.

Thanks to Thilo Molitor for spotting the issue.
2024-12-18 20:43:03 +01:00
Badlop ce3bc85d32 CHANGELOG.md: Update to 24.12, fix some newlines 2024-12-18 19:23:47 +01:00
Badlop 1fe9e3aa67 CONTAINER.md: Fix some typos 2024-12-18 19:23:45 +01:00
Badlop d93a8e341f mod_http_api: Annotate that default_version was added in new release 2024-12-18 19:23:41 +01:00
Paweł Chmielowski 1107cefdb6 Use tagged deps 2024-12-18 17:29:37 +01:00
Jérôme Sautret 92b2bb7532 Merge branch 'master' of github.com:processone/ejabberd 2024-12-18 16:24:12 +01:00
Jérôme Sautret 9a2a9187cd Revert "Experimental support for joining Matrix rooms as MUC rooms"
This reverts commit eb6f242d99.
2024-12-18 16:23:29 +01:00
Jérôme Sautret 50b57ada7c Revert "Fix dialyzer errors"
This reverts commit e589265921.
2024-12-18 16:22:21 +01:00
Paweł Chmielowski a8649767f2 Pull updated xmpp 2024-12-18 16:03:13 +01:00
Metalhearf 2eb605873c Add security policy and reporting guidelines 2024-12-18 15:51:08 +01:00
Paweł Chmielowski 26e8679359 Make rsm handling in disco items mod_muc, correctly count skipped rooms 2024-12-18 15:07:13 +01:00
Paweł Chmielowski 2aa673e780 Update xmpp dep once more 2024-12-17 15:11:33 +01:00
Paweł Chmielowski 06303ae7ab Relax checks for channels bindings for connections using external encryption
This should fix issue #4322
2024-12-17 13:49:05 +01:00
Paweł Chmielowski 2b3d588f10 Typo 2024-12-17 13:30:04 +01:00
Paweł Chmielowski 3dd7febb98 Fix expiration date calculation in mod_auth_fast 2024-12-17 13:28:54 +01:00
Badlop beb5bfea36 Update man page to 24.12 2024-12-17 12:31:59 +01:00
Badlop 628f286eb6 Update Spanish and Catalan translations 2024-12-17 12:31:57 +01:00
Badlop 9e14c7a803 Update Chinese (Simplified) translation (thanks to Sketch6580) 2024-12-17 12:31:56 +01:00
Badlop 863f2e019c Update Albanian translation (thanks to Besnik Bleta) 2024-12-17 12:31:55 +01:00
Badlop 4334ce9c29 Update Portuguese (Brazil) translation (thanks to Wellington Uemura) 2024-12-17 12:31:54 +01:00
Badlop 7008e49675 Update Italian translation (thanks to Ermete Melchiorre) 2024-12-17 12:31:53 +01:00
Badlop b84596be57 Update French translation (thanks to ButterflyOfFire) 2024-12-17 12:31:52 +01:00
Badlop 4fd26306fe Update German translation (thanks to Nautilusx) 2024-12-17 12:31:51 +01:00
Badlop 8e9ea2d98c Update Bulgarian translation (thanks to MrEddX) 2024-12-17 12:31:49 +01:00
Badlop 1024cbe5b3 Result of running "make doap" 2024-12-17 12:31:48 +01:00
Badlop a16ef68a49 Result of running "make format" 2024-12-17 12:31:47 +01:00
Badlop 7726904f79 Fix comment about file names 2024-12-17 12:31:45 +01:00
Badlop 1481734f47 Update version number to 24.12 2024-12-17 12:31:42 +01:00
Paweł Chmielowski 01955b867d Fix dialyzer warning 2024-12-17 11:13:56 +01:00
Paweł Chmielowski 549a2b0790 Remove message left from debugging 2024-12-17 11:01:11 +01:00
Paweł Chmielowski 2caaa09c99 Add support for XEP-0484: Fast Authentication Streamlining Tokens 2024-12-17 10:56:11 +01:00
Badlop da06a50072 WebAdmin: Use lowercase username and server authentication credentials 2024-12-17 10:13:00 +01:00
Badlop 2b02af13ba CONTAINER.md: Add kubernetes yaml examples to use with podman 2024-12-17 10:12:57 +01:00
Badlop ae238bc984 mod_http_api: Fix crash when module not enabled (for example, in CT tests) 2024-12-17 10:12:55 +01:00
Badlop 3d2036db61 mod_http_api: New option default_version
The server administrator can define default API version
for a vhost using the new module option:

modules:
  mod_http_api:
    default_version: 1

The server administrator can define default API version
for a port using the path:

listen:
  -
    request_handlers:
      /api/v2: mod_http_api

The client can use a specific API version,
regardless of what the admin has set,
by appending it in the URL:

http://localhost:5280/api/v2/get_loglevel/v3
2024-12-17 10:12:53 +01:00
Badlop b8360cae08 Rename argument "name" to "room" for consistency
And thanks to args_rename, both argument names can be used,
either "name" or "room". So, this doesn't involve an API
version change.
2024-12-17 10:12:51 +01:00
Badlop 790cb104cd Change arguments and result to consistent names (API v3)
Commands accept as argument: user, host, room, service
and return as result JIDs

Commands that change in API v3:
get_room_affiliations
muc_register_nick
muc_unregister_nick
set_room_affiliation
status_list
status_list_host
subscribe_room
subscribe_room_many
unsubscribe_room
2024-12-17 10:12:48 +01:00
Badlop f3c935d2e1 Fix some documentation syntax, add links to toplevel, modules and API 2024-12-09 17:25:27 +01:00
Alexey Shchepin e589265921 Fix dialyzer errors 2024-12-06 21:56:02 +03:00
Alexey Shchepin eb6f242d99 Experimental support for joining Matrix rooms as MUC rooms 2024-12-06 20:20:12 +03:00
Badlop ce6d5aa6a0 Redis: Disable some dialyzer warnings when using old Erlang 20 2024-12-05 13:03:43 +01:00
Badlop f269d5b613 Redis: Add support for unix domain socket (#4318) 2024-12-05 13:01:40 +01:00
Badlop a84c492130 Redis: Use the recommended eredis:start_link/1 function 2024-12-05 13:01:38 +01:00
Badlop 3ae636b454 Redis: Use eredis 1.7.1 from Nordix when using mix/rebar3 and Erlang 21+ 2024-12-05 13:01:37 +01:00
Badlop 06e3f9f0a4 Runtime: Disable edoc when using old problematic Elixir versions 2024-12-05 13:01:35 +01:00
dependabot[bot] 1669303a40 Bump ex_doc from 0.34.2 to 0.35.1
Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.34.2 to 0.35.1.
- [Release notes](https://github.com/elixir-lang/ex_doc/releases)
- [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.34.2...v0.35.1)

---
updated-dependencies:
- dependency-name: ex_doc
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-05 13:01:33 +01:00
Badlop 39e37b6175 Add support to define macros as environment variables
Define and macro by setting as environment variable:
  EJABBERD_MACRO_ + macro name

For example, if you configure in ejabberd.yml:
  define_macro:
    LOGLEVEL: 4
  loglevel: LOGLEVEL

You can define (and overwrite) that macro definition when starting ejabberd:
  EJABBERD_MACRO_LOGLEVEL=5 make relive
2024-12-05 13:01:31 +01:00
Badlop c72ba1f188 mod_scram_upgrade: Update XEP-0480 supported version (processone/xmpp#80) 2024-12-05 13:01:30 +01:00
Badlop 4d625e5574 Erlang/OTP 27 finally exports re:mp/0 2024-12-05 13:01:28 +01:00
Badlop 803f95050f WebAdmin: Fix calculation of node's uptime days 2024-12-05 13:01:26 +01:00
Badlop c021cf34be Explain that join_cluster returns immediately (since 5a34020, 24.06) 2024-12-05 13:01:23 +01:00
Holger Weiss 7fce7d1049 Merge remote-tracking branch 'processone/pr/4323'
* processone/pr/4323:
  Enable allow_unencrypted_sasl2 on websockets
2024-12-03 18:58:25 +01:00
Mark Zealey bd36895afe Enable allow_unencrypted_sasl2 on websockets
https://github.com/processone/ejabberd/commit/47232838 added the
allow_unencrypted_sasl2 option, but this was not added to websockets.
2024-12-03 17:39:58 +00:00
Holger Weiss b90c48f837 mod_scram_upgrade: Don't abort the upgrade
Fix a matching mistake that made the SASL mechanism upgrade fail.
2024-12-01 20:23:52 +01:00
Holger Weiss 344775aa8e mod_pubsub: Send notifications on PEP item retract 2024-11-30 20:38:33 +01:00
Badlop 7d0c20e133 mod_shared_roster: The name of a new group is lowercased
Until now it was possible to create a shared roster group with name
"Group1", and it was a different group that "group1".

From now on, new group names will be stored lowercase,
just like the username in a Jabber ID.

This only affects commands srg_add and srg_create.
All the other commands are still case sensitive, to allow admins of
existing databases with case-sensitive groups manage them.
2024-11-27 16:20:53 +01:00
Badlop ab5a2e8d10 mod_shared_roster: Get back support for groupid@vhost in displayed
Feature first implemented by 262157c in ejabberd 2.1.10
Bug introduced with cache improvements by 5b0f0d8 in ejabberd 21.07
2024-11-27 13:54:02 +01:00
Badlop e34c1ebcba WebAdmin: Fix link to displayed group when it is from another vhost 2024-11-27 13:54:00 +01:00
Badlop 73dbc01c2e WebAdmin: Shared group names are case sensitive, use original case instead of lowercase 2024-11-27 13:53:58 +01:00
Badlop f0773c4ab8 mix:exs: When development tools is enabled, add debugger and wx 2024-11-25 17:23:32 +01:00
Badlop cc5c9f6008 Fix problems introduced in two recent commits 2024-11-25 17:23:28 +01:00
Badlop da9c591eed Improve create_rooms_file command to support vhosts with different config
Until now it created all the rooms in the storage of the first vhost
listed in the ejabberd configuration file. Similarly, it used only
the default room options defined for the first vhost.
2024-11-25 16:20:30 +01:00
Badlop 6790ab01e8 Improve example Elixir modules 2024-11-25 16:20:19 +01:00
Badlop f9cecca362 Rename mod_presence_demo.ex to mod_example.ex 2024-11-25 16:20:16 +01:00
badlop f4009939a6 Merge pull request #4315 from Quobis/support-loading-elixir-modules-for-auth
feat: support loading Elixir modules for auth
2024-11-25 16:08:54 +01:00
Marcos de Vera Piquero 17b5b34e3c feat: support loading Elixir modules for auth
Allow to specify an Elixir module name in `auth_method`.

If the referenced module, `M`,  cannot be loaded as `ejabberd_auth_M`,
try to load it as `Elixir.M`.
2024-11-25 15:31:27 +01:00
Badlop c291c20a3b Fix problem starting ejabberd when first host uses SQL, other one mnesia
The problem appeared when there are several vhosts,
the first vhost uses SQL for persistent data (and RAM for volatile),
and another vhost wants to use Mnesia

Example config to trigger the problem:

  hosts:
    - mysql.localhost
    - localhost
  host_config:
    mysql.localhost:
      default_db: sql

In that case, ejabberd crashed at start with an error like:
[critical] Internal error of module mod_muc has occurred during start:
...
** exception exit: {aborted,
                     {no_exists,
                         [muc_room,
                          [{{muc_room,{'_',<<"conference.localhost">>},'_'},
                            [],
                            ['$_']}]]}}
2024-11-22 19:25:52 +01:00
Badlop 22e7ce37d4 Fix typos in previous commit 2024-11-22 19:25:49 +01:00
Badlop 2137602a6a Makefile: Add support to run "make format" when compiling with mix 2024-11-22 10:53:43 +01:00
dependabot[bot] c7b29b5a9a Bump dialyxir from 1.4.4 to 1.4.5
Bumps [dialyxir](https://github.com/jeremyjh/dialyxir) from 1.4.4 to 1.4.5.
- [Release notes](https://github.com/jeremyjh/dialyxir/releases)
- [Changelog](https://github.com/jeremyjh/dialyxir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jeremyjh/dialyxir/compare/1.4.4...1.4.5)

---
updated-dependencies:
- dependency-name: dialyxir
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 10:53:04 +01:00
Badlop 715b5b64c6 Runtime: Test Dialyzer in Rebars jobs (#4281)
The CI workflow uses ubuntu-24.04 and setup-beam action,
so it can test only Erlang/OTP 24 and higher.

To ensure Dialyzer is also ran with older Erlang versions,
let's add Dialyzer testing to the Runtime workflow,
which uses the erlang container, and that allows
to run Erlang/OTP 20 in ubuntu-24.04.
2024-11-14 13:58:14 +01:00
Badlop c20ed8c7b3 Runtime: Try using elixir container for Rebar3+Elixir and Mix jobs (#4281) 2024-11-14 13:58:11 +01:00
Badlop d3baacd78e Workflows: Bump ubuntu from 22.04 to 24.04 when possible (#4281) 2024-11-14 13:58:07 +01:00
Badlop 07e20784cb New evacuate_kindly command: kick users and prevent login (#4309) 2024-11-14 13:57:47 +01:00
Badlop 9eb8bb6c40 mod_matrix_gw_s2s probably works correctly only in Erlang/OTP >= 25
In Erlang/OTP 25, the function inet_res:getbyname/3
returns {ok, Hostent} where the last tuple element of Hostent
may be h_addr_list = [inet:ip_address()]}
or H_addr_list :: [dns_data()]}

However, in Erlang/OTP 24.1 and older, that element was only of type
h_addr_list = [inet:ip_address()]}

https://erlang.org/documentation/doc-13.0-rc3/lib/kernel-8.4/doc/html/inet_res.html#getbyname-3
https://erlang.org/documentation/doc-12.1/lib/kernel-8.1/doc/html/inet_res.html#getbyname-3
2024-11-14 13:57:47 +01:00
Badlop e10c0f3120 Bump Expat to 2.6.4 2024-11-14 13:57:47 +01:00
Badlop 6f7efebb56 Only delete offline msgs when user has MAM enabled (#4287) 2024-11-14 13:57:43 +01:00
Badlop a657778065 Result of running "make doap" 2024-11-14 13:57:43 +01:00
Badlop 3650d94bb5 Remove XEPs that are only a client thing 2024-11-14 13:57:43 +01:00
Badlop 6a428f3d02 Add ejabberd version and implementation status for many XEPs 2024-11-14 13:57:43 +01:00
Badlop abe1d96c58 Announce support for XEP-0384 OMEMO Encryption (#4305)
The last required piece to support XEP-0384 was
supporting max_items=max, which was added for ejabberd 21.12 in commit
8f8de0403b
2024-11-14 13:57:39 +01:00
Badlop 29a59cfe48 Add "XMPP Date and Time Profiles" implemented by xmpp and used everywhere 2024-11-14 13:49:41 +01:00
Holger Weiss 18c54f4e9e ejabberd.yml.example: Use non-standard STUN port
STUN via UDP can easily be abused for reflection/amplification DDoS
attacks.  Suggest a non-standard port to make it harder for attackers to
discover the service.

Modern XMPP clients discover the port via XEP-0215, so there's no
advantage in sticking to the standard port.
2024-11-14 12:21:58 +01:00
Paweł Chmielowski c7d967a2b5 Fix dialyzer issue 2024-11-05 17:10:09 +01:00
Paweł Chmielowski b50ea7ef1f Make mod_privilge properly handle roster iq 2024-11-05 16:57:52 +01:00
Holger Weiss 4843cd432f Disable the systemd watchdog by default
Some users reported ejabberd being restarted by systemd due to missing
watchdog pings despite the actual service operating just fine.  So far,
we weren't able to track down the issue, so we'll no longer enable the
watchdog in our example service unit.

Closes #4054.
2024-11-05 15:37:21 +01:00
Paweł Chmielowski d56eae809d Catch extra case in check for s2s bidi element 2024-11-05 13:26:42 +01:00
Metalhearf af97211ecc Update URLs in docs/conf files for consistency. 2024-10-31 17:30:20 +01:00
116 changed files with 2262 additions and 955 deletions
+3 -24
View File
@@ -107,14 +107,9 @@ jobs:
~/.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: |
@@ -220,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
+1 -1
View File
@@ -19,7 +19,7 @@ env:
jobs:
container:
name: Container
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
permissions:
packages: write
steps:
+2 -2
View File
@@ -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
+48 -84
View File
@@ -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 }}
@@ -68,6 +68,10 @@ jobs:
~/.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
@@ -81,6 +85,8 @@ jobs:
- run: make xref
- run: make dialyzer
- name: Prepare rel (rebar2)
if: matrix.rebar == 'rebar'
run: |
@@ -158,55 +164,25 @@ 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
@@ -216,7 +192,13 @@ jobs:
with:
path: |
~/.cache/rebar3/
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
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: |
@@ -279,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
@@ -305,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: |
@@ -349,24 +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
run: |
mix deps.unlock jose
- name: Cache Hex.pm
uses: actions/cache@v4
with:
path: |
~/.hex/
key: ${{matrix.otp}}-${{hashFiles('mix.exs')}}
key: ${{matrix.elixir}}-${{hashFiles('mix.exs')}}
- 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: |
@@ -381,6 +344,7 @@ jobs:
- run: make dialyzer
- run: make edoc
if: matrix.elixir >= '1.14'
- name: Run rel
run: |
@@ -432,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
+54
View File
@@ -1,3 +1,50 @@
## 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
@@ -29,17 +76,20 @@
- `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
@@ -51,6 +101,7 @@
- `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`
@@ -61,18 +112,21 @@
- 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
+1 -1
View File
@@ -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
+310 -22
View File
@@ -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
View File
@@ -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/
+4 -3
View File
@@ -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
@@ -702,7 +703,7 @@ 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"
+18 -14
View File
@@ -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
View File
@@ -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 projects 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
View File
@@ -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.10` | 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)"
+166 -184
View File
@@ -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,8 +525,8 @@
<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>
@@ -580,7 +544,7 @@
<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>
@@ -589,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>
@@ -598,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>
@@ -606,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>
@@ -616,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>
@@ -625,7 +589,7 @@
<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>
@@ -634,7 +598,7 @@
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0356.html"/>
<xmpp:version>0.4.1</xmpp:version>
<xmpp:since>24.10</xmpp:since>
<xmpp:status></xmpp:status>
<xmpp:status>complete</xmpp:status>
<xmpp:note>mod_privilege</xmpp:note>
</xmpp:SupportedXep>
</implements>
@@ -643,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>
@@ -651,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>
@@ -669,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>
@@ -679,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>
@@ -697,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>
@@ -706,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>
@@ -715,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>
@@ -723,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>
@@ -733,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>
@@ -742,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>
@@ -751,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>
@@ -760,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>
@@ -769,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>
@@ -778,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>
@@ -786,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>
@@ -796,25 +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.1</xmpp:version>
<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>
-1
View File
@@ -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
+1 -1
View File
@@ -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
-19
View File
@@ -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
+44
View File
@@ -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
+249 -144
View File
@@ -2,12 +2,12 @@
.\" Title: ejabberd.yml
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\" Date: 10/28/2024
.\" Date: 12/17/2024
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "EJABBERD\&.YML" "5" "10/28/2024" "\ \&" "\ \&"
.TH "EJABBERD\&.YML" "5" "12/17/2024" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -82,12 +82,12 @@ All options can be changed in runtime by running \fIejabberdctl reload\-config\f
.sp
Some options can be specified for particular virtual host(s) only using \fIhost_config\fR or \fIappend_host_config\fR options\&. Such options are called \fIlocal\fR\&. Examples are \fImodules\fR, \fIauth_method\fR and \fIdefault_db\fR\&. The options that cannot be defined per virtual host are called \fIglobal\fR\&. Examples are \fIloglevel\fR, \fIcertfiles\fR and \fIlisten\fR\&. It is a configuration mistake to put \fIglobal\fR options under \fIhost_config\fR or \fIappend_host_config\fR section \- ejabberd will refuse to load such configuration\&.
.sp
It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/24\&.10/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/24\&.12/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
.sp
Note that this document is intended to provide comprehensive description of all configuration options that can be consulted to understand the meaning of a particular option, its format and possible values\&. It will be quite hard to understand how to configure ejabberd by reading this document only \- for this purpose the reader is recommended to read online Configuration Guide available at https://docs\&.ejabberd\&.im/admin/configuration\&.
.SH "TOP LEVEL OPTIONS"
.sp
This section describes top level options of ejabberd 24\&.10\&. The options that changed in this version are marked with 🟤\&.
This section describes top level options of ejabberd 24\&.12\&. The options that changed in this version are marked with 🟤\&.
.PP
\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLRules|ACLName}}\fR
.RS 4
@@ -512,7 +512,8 @@ c2s_ciphers:
.PP
\fBc2s_dhfile\fR: \fIPath\fR
.RS 4
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, 2048\-bit MODP Group with 256\-bit Prime Order Subgroup will be used as defined in RFC5114 Section 2\&.3\&.
Full path to a file containing custom DH parameters to use for c2s connections\&. Such a file could be created with the command
\fI"openssl dhparam \-out dh\&.pem 2048"\fR\&. 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\&.
.RE
.PP
\fBc2s_protocol_options\fR: \fI[Option, \&.\&.\&.]\fR
@@ -639,7 +640,7 @@ listener as well\&. If set to
already enabled, with encryption if available\&. If set to
\fIundefined\fR, it builds the URL using the deprecated
\fIcaptcha_host\fR
+ /captcha\&. The default value is
\fI+ /captcha\fR\&. The default value is
\fIauto\fR\&.
.RE
.PP
@@ -758,28 +759,43 @@ are:
The number of components to balance\&.
.RE
.PP
\fBtype\fR: \fIrandom | source | destination | bare_source | bare_destination\fR
\fBtype\fR: \fIValue\fR
.RS 4
How to deliver stanzas to connected components:
\fIrandom\fR
\- an instance is chosen at random;
\fIdestination\fR
\- an instance is chosen by the full JID of the packet\(cqs
How to deliver stanzas to connected components\&. The default value is
\fIrandom\fR\&. Possible values:
.RE
.PP
\fB\- bare_destination\fR
.RS 4
by the bare JID (without resource) of the packet\(cqs
\fIto\fR
attribute;
\fIsource\fR
\- by the full JID of the packet\(cqs
attribute
.RE
.PP
\fB\- bare_source\fR
.RS 4
by the bare JID (without resource) of the packet\(cqs
\fIfrom\fR
attribute;
\fIbare_destination\fR
\- by the bare JID (without resource) of the packet\(cqs
attribute is used
.RE
.PP
\fB\- destination\fR
.RS 4
an instance is chosen by the full JID of the packet\(cqs
\fIto\fR
attribute;
\fIbare_source\fR
\- by the bare JID (without resource) of the packet\(cqs
attribute
.RE
.PP
\fB\- random\fR
.RS 4
an instance is chosen at random
.RE
.PP
\fB\- source\fR
.RS 4
by the full JID of the packet\(cqs
\fIfrom\fR
attribute is used\&. The default value is
\fIrandom\fR\&.
attribute
.RE
.sp
\fBExample\fR:
@@ -1104,13 +1120,16 @@ section for details\&.
\fINote\fR
about this option: added in 22\&.10\&. The number of messages to accept in
log_burst_limit_window_time
period before starting to drop them\&. Default 500
period before starting to drop them\&. Default
500
.RE
.PP
\fBlog_burst_limit_window_time\fR: \fINumber\fR
.RS 4
\fINote\fR
about this option: added in 22\&.10\&. The time period to rate\-limit log messages by\&. Defaults to 1 second\&.
about this option: added in 22\&.10\&. The time period to rate\-limit log messages by\&. Defaults to
1
second\&.
.RE
.PP
\fBlog_modules_fully\fR: \fI[Module, \&.\&.\&.]\fR
@@ -1132,9 +1151,8 @@ crash\&.log\&.0\&.
\fBlog_rotate_size\fR: \fIpos_integer() | infinity\fR
.RS 4
The size (in bytes) of a log file to trigger rotation\&. If set to
\fIinfinity\fR, log rotation is disabled\&. The default value is
\fI10485760\fR
(that is, 10 Mb)\&.
\fIinfinity\fR, log rotation is disabled\&. The default value is 10 Mb expressed in bytes:
\fI10485760\fR\&.
.RE
.PP
\fBloglevel\fR: \fInone | emergency | alert | critical | error | warning | notice | info | debug\fR
@@ -1175,7 +1193,7 @@ This option can be used to tune tick time parameter of
.RS 4
Whether to use the
\fIdatabase\&.md#default\-and\-new\-schemas|new SQL schema\fR\&. All schemas are located at
https://github\&.com/processone/ejabberd/tree/24\&.10/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The
https://github\&.com/processone/ejabberd/tree/24\&.12/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The
\fInew\fR
schema can handle several XMPP domains in a single ejabberd database\&. Using this
\fInew\fR
@@ -1295,14 +1313,16 @@ which means it first tries connecting with IPv6, if that fails it tries using IP
\fBoutgoing_s2s_ipv4_address\fR: \fIAddress\fR
.RS 4
\fINote\fR
about this option: added in 20\&.12\&. Specify the IPv4 address that will be used when establishing an outgoing S2S IPv4 connection, for example "127\&.0\&.0\&.1"\&. The default value is
about this option: added in 20\&.12\&. Specify the IPv4 address that will be used when establishing an outgoing S2S IPv4 connection, for example
\fI"127\&.0\&.0\&.1"\fR\&. The default value is
\fIundefined\fR\&.
.RE
.PP
\fBoutgoing_s2s_ipv6_address\fR: \fIAddress\fR
.RS 4
\fINote\fR
about this option: added in 20\&.12\&. 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
about this option: added in 20\&.12\&. Specify the IPv6 address that will be used when establishing an outgoing S2S IPv6 connection, for example
\fI"::FFFF:127\&.0\&.0\&.1"\fR\&. The default value is
\fIundefined\fR\&.
.RE
.PP
@@ -1414,11 +1434,13 @@ or
if the latter is not set\&.
.RE
.PP
\fBredis_server\fR: \fIHostname\fR
\fBredis_server 🟤\fR: \fIHost | IP Address | Unix Socket Path\fR
.RS 4
A hostname or an IP address of the
\fINote\fR
about this option: improved in 24\&.12\&. A hostname, IP address or unix domain socket file of the
\fIdatabase\&.md#redis|Redis\fR
server\&.The default is
server\&. Setup the path to unix domain socket like:
\fI"unix:/path/to/socket"\fR\&. The default value is
\fIlocalhost\fR\&.
.RE
.PP
@@ -1527,7 +1549,8 @@ s2s_ciphers:
.PP
\fBs2s_dhfile\fR: \fIPath\fR
.RS 4
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, 2048\-bit MODP Group with 256\-bit Prime Order Subgroup will be used as defined in RFC5114 Section 2\&.3\&.
Full path to a file containing custom DH parameters to use for s2s connections\&. Such a file could be created with the command
\fI"openssl dhparam \-out dh\&.pem 2048"\fR\&. 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\&.
.RE
.PP
\fBs2s_dns_retries\fR: \fINumber\fR
@@ -1775,7 +1798,8 @@ The password for SQL authentication\&. The default is empty string\&.
.PP
\fBsql_pool_size\fR: \fISize\fR
.RS 4
Number of connections to the SQL server that ejabberd will open for each virtual host\&. The default value is 10\&. WARNING: for SQLite this value is
Number of connections to the SQL server that ejabberd will open for each virtual host\&. The default value is
\fI10\fR\&. WARNING: for SQLite this value is
\fI1\fR
by default and it\(cqs not recommended to change it due to potential race conditions\&.
.RE
@@ -1830,7 +1854,8 @@ this can also be an ODBC connection string\&. When
is
\fImysql\fR
or
\fIpgsql\fR, this can be the path to a unix domain socket expressed like: "unix:/path/to/socket"\&.The default value is
\fIpgsql\fR, this can be the path to a unix domain socket expressed like:
\fI"unix:/path/to/socket"\fR\&.The default value is
\fIlocalhost\fR\&.
.RE
.PP
@@ -1944,7 +1969,8 @@ This option enables validation for
header to protect against connections from other domains than given in the configuration file\&. In this way, the lower layer load balancer can be chosen for a specific ejabberd implementation while still providing a secure WebSocket connection\&. The default value is
\fIignore\fR\&. An example value of the
\fIURL\fR
is "https://test\&.example\&.org:8081"\&.
is
\fI"https://test\&.example\&.org:8081"\fR\&.
.RE
.PP
\fBwebsocket_ping_interval\fR: \fItimeout()\fR
@@ -1964,7 +1990,7 @@ seconds\&.
.RE
.SH "MODULES"
.sp
This section describes modules options of ejabberd 24\&.10\&. The modules that changed in this version are marked with 🟤\&.
This section describes modules options of ejabberd 24\&.12\&. The modules that changed in this version are marked with 🟤\&.
.SS "mod_adhoc"
.sp
This module implements XEP\-0050: Ad\-Hoc Commands\&. It\(cqs an auxiliary module and is only needed by some of the other modules\&.
@@ -1989,41 +2015,11 @@ This module provides additional administrative commands\&.
.sp
Details for some commands:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fIban_account\fR: 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\(cqt 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\&.
.RE
\fIban_account\fR API: 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\(cqt 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\&.
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fIpushroster\fR: (and
\fIpushroster\-all\fR) 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\&.
.RE
\fIpush_roster\fR API (and \fIpush_roster_all\fR API): 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\&.
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fIsrg_create\fR: If you want to put a group Name with blank spaces, use the characters "\*(Aq and \*(Aq" to define when the Name starts and ends\&. See an example below\&.
.RE
\fIsrg_create\fR API: If you want to put a group Name with blank spaces, use the characters \fI"\fR\*(Aq and \fI\*(Aq"\fR to define when the Name starts and ends\&. See an example below\&.
.sp
The module has no options\&.
.sp
@@ -2056,7 +2052,7 @@ modules:
.RE
.\}
.sp
Content of roster file for \fIpushroster\fR command:
Content of roster file for \fIpush_roster\fR API:
.sp
.if n \{\
.RS 4
@@ -2070,7 +2066,7 @@ Content of roster file for \fIpushroster\fR command:
.RE
.\}
.sp
With this call, the sessions of the local account which JID is boby@example\&.org will be kicked, and its password will be set to something like \fIBANNED_ACCOUNT\(em20080425T21:45:07\(em2176635\(emSpammed_rooms\fR
With this call, the sessions of the local account which JID is \fIboby@example\&.org\fR will be kicked, and its password will be set to something like \fIBANNED_ACCOUNT\(em20080425T21:45:07\(em2176635\(emSpammed_rooms\fR
.sp
.if n \{\
.RS 4
@@ -2082,7 +2078,7 @@ ejabberdctl vhost example\&.org ban_account boby "Spammed rooms"
.RE
.\}
.sp
Call to srg_create using double\-quotes and single\-quotes:
Call to \fIsrg_create\fR API using double\-quotes and single\-quotes:
.sp
.if n \{\
.RS 4
@@ -2215,6 +2211,58 @@ Same as top\-level
option, but applied to this module only\&.
.RE
.RE
.SS "mod_auth_fast 🟤"
.sp
\fINote\fR about this option: added in 24\&.12\&.
.sp
The module adds support for XEP\-0480: Fast Authentication Streamlining Tokens that allows users to authenticate using self managed tokens\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBAvailable options:\fR
.RS 4
.PP
\fBdb_type\fR: \fImnesia | sql\fR
.RS 4
Same as top\-level
\fIdefault_db\fR
option, but applied to this module only\&.
.RE
.PP
\fBtoken_lifetime\fR: \fItimeout()\fR
.RS 4
Time that tokens will be keept, measured from it\(cqs creation time\&. Default value set to 30 days
.RE
.PP
\fBtoken_refresh_age\fR: \fItimeout()\fR
.RS 4
This time determines age of token, that qualifies for automatic refresh\&. Default value set to 1 day
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBExample:\fR
.RS 4
.sp
.if n \{\
.RS 4
.\}
.nf
modules:
mod_auth_fast:
token_timeout: 14days
.fi
.if n \{\
.RE
.\}
.RE
.SS "mod_avatar"
.sp
The purpose of the module is to cope with legacy and modern XMPP clients posting avatars\&. The process is described in XEP\-0398: User Avatar to vCard\-Based Avatars Conversion\&.
@@ -2541,7 +2589,7 @@ This module serves a simple page for the Converse XMPP web browser client\&.
.sp
To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
Make sure either \fImod_bosh\fR or \fIejabberd_http_ws\fR \fIlisten\-options\&.md#request_handlers|request_handlers\fR are enabled\&.
Make sure either \fImod_bosh\fR or \fIlisten\&.md#ejabberd_http_ws|ejabberd_http_ws\fR are enabled in at least one \fIrequest_handlers\fR\&.
.sp
When \fIconversejs_css\fR and \fIconversejs_script\fR are \fIauto\fR, by default they point to the public Converse client\&.
.sp
@@ -2601,9 +2649,9 @@ is replaced with the hostname\&. The default value is
.PP
\fBwebsocket_url\fR: \fIauto | WebSocketURL\fR
.RS 4
A WebSocket URL to which Converse can connect to\&. The keyword
A WebSocket URL to which Converse can connect to\&. The
\fI@HOST@\fR
is replaced with the real virtual host name\&. If set to
keyword is replaced with the real virtual host name\&. If set to
\fIauto\fR, it will build the URL of the first configured WebSocket request handler\&. The default value is
\fIauto\fR\&.
.RE
@@ -2930,7 +2978,7 @@ This module serves small \fIhost\-meta\fR files as described in XEP\-0156: Disco
.sp
To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
Notice it only works if ejabberd_http has tls enabled\&.
Notice it only works if \fIlisten\&.md#ejabberd_http|ejabberd_http\fR has \fIlisten\-options\&.md#tls|tls\fR enabled\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -2998,11 +3046,26 @@ This module provides a ReST interface to call \fI\&.\&./\&.\&./developer/ejabber
.sp
To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
To use a specific API version N, when defining the URL path in the request_handlers, add a \fIvN\fR\&. For example: \fI/api/v2: mod_http_api\fR
To use a specific API version N, when defining the URL path in the request_handlers, add a vN\&. For example: \fI/api/v2: mod_http_api\fR\&.
.sp
To run a command, send a POST request to the corresponding URL: \fIhttp://localhost:5280/api/<command_name>\fR
To run a command, send a POST request to the corresponding URL: \fIhttp://localhost:5280/api/COMMAND\-NAME\fR
.sp
The module has no options\&.
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBAvailable options:\fR
.RS 4
.PP
\fBdefault_version\fR: \fIinteger() | string()\fR
.RS 4
What API version to use when none is specified in the URL path\&. If setting an ejabberd version, it will use the latest API version that was available in that ejabberd version\&. For example, setting
\fI"24\&.06"\fR
in this option implies
\fI2\fR\&. The default value is the latest version\&.
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -3024,7 +3087,8 @@ listen:
/api: mod_http_api
modules:
mod_http_api: {}
mod_http_api:
default_version: 2
.fi
.if n \{\
.RE
@@ -3176,26 +3240,34 @@ This option specifies additional header fields to be included in all HTTP respon
.RS 4
This option defines the permission bits of the
\fIdocroot\fR
directory and any directories created during file uploads\&. The bits are specified as an octal number (see the chmod(1) manual page) within double quotes\&. For example: "0755"\&. The default is undefined, which means no explicit permissions will be set\&.
directory and any directories created during file uploads\&. The bits are specified as an octal number (see the
\fIchmod(1)\fR
manual page) within double quotes\&. For example:
\fI"0755"\fR\&. The default is undefined, which means no explicit permissions will be set\&.
.RE
.PP
\fBdocroot\fR: \fIPath\fR
.RS 4
Uploaded files are stored below the directory specified (as an absolute path) with this option\&. The keyword @HOME@ is replaced with the home directory of the user running ejabberd, and the keyword @HOST@ with the virtual host name\&. The default value is "@HOME@/upload"\&.
Uploaded files are stored below the directory specified (as an absolute path) with this option\&. The keyword
\fI@HOME@\fR
is replaced with the home directory of the user running ejabberd, and the keyword
\fI@HOST@\fR
with the virtual host name\&. The default value is
\fI"@HOME@/upload"\fR\&.
.RE
.PP
\fBexternal_secret\fR: \fIText\fR
.RS 4
This option makes it possible to offload all HTTP Upload processing to a separate HTTP server\&. Both ejabberd and the HTTP server should share this secret and behave exactly as described at
Prosody\(cqs mod_http_upload_external
in the
\fIImplementation\fR
section\&. There is no default value\&.
Prosody\(cqs mod_http_upload_external: Implementation\&. There is no default value\&.
.RE
.PP
\fBfile_mode\fR: \fIPermission\fR
.RS 4
This option defines the permission bits of uploaded files\&. The bits are specified as an octal number (see the chmod(1) manual page) within double quotes\&. For example: "0644"\&. The default is undefined, which means no explicit permissions will be set\&.
This option defines the permission bits of uploaded files\&. The bits are specified as an octal number (see the
\fIchmod(1)\fR
manual page) within double quotes\&. For example:
\fI"0644"\fR\&. The default is undefined, which means no explicit permissions will be set\&.
.RE
.PP
\fBget_url\fR: \fIURL\fR
@@ -3203,8 +3275,9 @@ This option defines the permission bits of uploaded files\&. The bits are specif
This option specifies the initial part of the GET URLs used for downloading the files\&. The default value is
\fIundefined\fR\&. When this option is
\fIundefined\fR, this option is set to the same value as
\fIput_url\fR\&. The keyword @HOST@ is replaced with the virtual host name\&. NOTE: if GET requests are handled by
\fImod_http_upload\fR, the
\fIput_url\fR\&. The keyword
\fI@HOST@\fR
is replaced with the virtual host name\&. NOTE: if GET requests are handled by this module, the
\fIget_url\fR
must match the
\fIput_url\fR\&. Setting it to a different value only makes sense if an external web server or
@@ -3223,7 +3296,8 @@ instead\&.
.RS 4
This option defines the Jabber IDs of the service\&. If the
\fIhosts\fR
option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix "upload\&."\&. The keyword
option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix
\fI"upload\&."\fR\&. The keyword
\fI@HOST@\fR
is replaced with the real virtual host name\&.
.RE
@@ -3246,12 +3320,16 @@ must be specified\&. The default value is
.PP
\fBname\fR: \fIName\fR
.RS 4
A name of the service in the Service Discovery\&. This will only be displayed by special XMPP clients\&. The default value is "HTTP File Upload"\&.
A name of the service in the Service Discovery\&. The default value is
\fI"HTTP File Upload"\fR\&. Please note this will only be displayed by some XMPP clients\&.
.RE
.PP
\fBput_url\fR: \fIURL\fR
.RS 4
This option specifies the initial part of the PUT URLs used for file uploads\&. The keyword @HOST@ is replaced with the virtual host name\&. NOTE: different virtual hosts cannot use the same PUT URL\&. The default value is "https://@HOST@:5443/upload"\&.
This option specifies the initial part of the PUT URLs used for file uploads\&. The keyword
\fI@HOST@\fR
is replaced with the virtual host name\&. NOTE: different virtual hosts cannot use the same PUT URL\&. The default value is
\fI"https://@HOST@:5443/upload"\fR\&.
.RE
.PP
\fBrm_on_unregister\fR: \fItrue | false\fR
@@ -3263,7 +3341,9 @@ This option specifies whether files uploaded by a user should be removed when th
\fBsecret_length\fR: \fILength\fR
.RS 4
This option defines the length of the random string included in the GET and PUT URLs generated by
\fImod_http_upload\fR\&. The minimum length is 8 characters, but it is recommended to choose a larger value\&. The default value is
\fImod_http_upload\fR\&. The minimum length is
\fI8\fR
characters, but it is recommended to choose a larger value\&. The default value is
\fI40\fR\&.
.RE
.PP
@@ -3358,7 +3438,7 @@ This module depends on \fImod_http_upload\fR\&.
.PP
\fBaccess_hard_quota\fR: \fIAccessName\fR
.RS 4
This option defines which access rule is used to specify the "hard quota" for the matching JIDs\&. That rule must yield a positive number for any JID that is supposed to have a quota limit\&. This is the number of megabytes a corresponding user may upload\&. When this threshold is exceeded, ejabberd deletes the oldest files uploaded by that user until their disk usage equals or falls below the specified soft quota (see
This option defines which access rule is used to specify the "hard quota" for the matching JIDs\&. That rule must yield a positive number for any JID that is supposed to have a quota limit\&. This is the number of megabytes a corresponding user may upload\&. When this threshold is exceeded, ejabberd deletes the oldest files uploaded by that user until their disk usage equals or falls below the specified soft quota (see also option
\fIaccess_soft_quota\fR)\&. The default value is
\fIhard_upload_quota\fR\&.
.RE
@@ -3388,7 +3468,7 @@ directory, once per day\&. The default value is
\fBExamples:\fR
.RS 4
.sp
Please note that it\(cqs not necessary to specify the \fIaccess_hard_quota\fR and \fIaccess_soft_quota\fR options in order to use the quota feature\&. You can stick to the default names and just specify access rules such as those in this example:
Notice it\(cqs not necessary to specify the \fIaccess_hard_quota\fR and \fIaccess_soft_quota\fR options in order to use the quota feature\&. You can stick to the default names and just specify access rules such as those in this example:
.sp
.if n \{\
.RS 4
@@ -3600,7 +3680,7 @@ When this option is disabled, for each individual subscriber a separate mucsub m
.sp
\fINote\fR about this option: added in 24\&.02\&.
.sp
Matrix gateway\&.
Matrix gateway\&. Erlang/OTP 25 or higher is required to use this module\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -3853,7 +3933,8 @@ instead\&.
.RS 4
This option defines the Jabber IDs of the service\&. If the
\fIhosts\fR
option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix "mix\&."\&. The keyword
option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix
\fI"mix\&."\fR\&. The keyword
\fI@HOST@\fR
is replaced with the real virtual host name\&.
.RE
@@ -4048,15 +4129,40 @@ This module adds ability to synchronize local MQTT topics with data on remote se
Identifier of a user that will be assigned as owner of local changes\&.
.RE
.PP
\fBservers\fR: \fI{ServerUrl: {publish: [TopicPairs, subscribe: [TopicPairs], authentication: [AuthInfo]}}]\fR
\fBservers\fR: \fI{ServerUrl: {Key: Value}}\fR
.RS 4
Declaration of data to share, must contain
\fIpublish\fR
or
\fIsubscribe\fR
or both, and
\fIauthentication\fR
section with username/password field or certfile pointing to client certificate\&. Accepted urls can use schema mqtt, mqtts (mqtt with tls), mqtt5, mqtt5s (both to trigger v5 protocol), ws, wss, ws5, wss5\&. Certificate authentication can be only used with mqtts, mqtt5s, wss, wss5\&.
Declaration of data to share for each ServerUrl\&. Server URLs can use schemas:
\fImqtt\fR,
\fImqtts\fR
(mqtt with tls),
\fImqtt5\fR,
\fImqtt5s\fR
(both to trigger v5 protocol),
\fIws\fR,
\fIwss\fR,
\fIws5\fR,
\fIwss5\fR\&. Keys must be:
.PP
\fBauthentication\fR: \fI{AuthKey: AuthValue}\fR
.RS 4
List of authentication information, where AuthKey can be:
\fIusername\fR
and
\fIpassword\fR
fields, or
\fIcertfile\fR
pointing to client certificate\&. Certificate authentication can be used only with mqtts, mqtt5s, wss, wss5\&.
.RE
.PP
\fBpublish\fR: \fI{LocalTopic: RemoteTopic}\fR
.RS 4
Either publish or subscribe must be set, or both\&.
.RE
.PP
\fBsubscribe\fR: \fI{RemoteTopic: LocalTopic}\fR
.RS 4
Either publish or subscribe must be set, or both\&.
.RE
.RE
.RE
.sp
@@ -4074,16 +4180,16 @@ section with username/password field or certfile pointing to client certificate\
.nf
modules:
mod_mqtt_bridge:
replication_user: "mqtt@xmpp\&.server\&.com"
servers:
"mqtt://server\&.com":
authentication:
certfile: "/etc/ejabberd/mqtt_server\&.pem"
publish:
"localA": "remoteA" # local changes to \*(AqlocalA\*(Aq will be replicated on remote server as \*(AqremoteA\*(Aq
"topicB": "topicB"
subscribe:
"remoteB": "localB" # changes to \*(AqremoteB\*(Aq on remote server will be stored as \*(AqlocalB\*(Aq on local server
authentication:
certfile: "/etc/ejabberd/mqtt_server\&.pem"
replication_user: "mqtt@xmpp\&.server\&.com"
.fi
.if n \{\
.RE
@@ -4311,7 +4417,7 @@ The room persists even if the last participant leaves\&. The default value is
\fIfalse\fR\&.
.RE
.PP
\fBpresence_broadcast\fR: \fI[moderator | participant | visitor, \&.\&.\&.]\fR
\fBpresence_broadcast\fR: \fI[Role]\fR
.RS 4
List of roles for which presence is broadcasted\&. The list can contain one or several of:
\fImoderator\fR,
@@ -4376,7 +4482,10 @@ Timeout before hibernating the room process, expressed in seconds\&. The default
.PP
\fBhistory_size\fR: \fISize\fR
.RS 4
A small history of the current discussion is sent to users when they enter the room\&. With this option you can define the number of history messages to keep and send to users joining the room\&. The value is a non\-negative integer\&. Setting the value to 0 disables the history feature and, as a result, nothing is kept in memory\&. The default value is 20\&. This value affects all rooms on the service\&. NOTE: modern XMPP clients rely on Message Archives (XEP\-0313), so feel free to disable the history feature if you\(cqre only using modern clients and have
A small history of the current discussion is sent to users when they enter the room\&. With this option you can define the number of history messages to keep and send to users joining the room\&. The value is a non\-negative integer\&. Setting the value to
\fI0\fR
disables the history feature and, as a result, nothing is kept in memory\&. The default value is
\fI20\fR\&. This value affects all rooms on the service\&. NOTE: modern XMPP clients rely on Message Archives (XEP\-0313), so feel free to disable the history feature if you\(cqre only using modern clients and have
\fImod_mam\fR
module loaded\&.
.RE
@@ -4462,12 +4571,16 @@ This option defines after how many users in the room, it is considered overcrowd
.PP
\fBmin_message_interval\fR: \fINumber\fR
.RS 4
This option defines the minimum interval between two messages send by an occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, message rate is not limited\&. This feature can be used to protect a MUC service from occupant abuses and limit number of messages that will be broadcasted by the service\&. A good value for this minimum message interval is 0\&.4 second\&. If an occupant tries to send messages faster, an error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable\&.
This option defines the minimum interval between two messages send by an occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, message rate is not limited\&. This feature can be used to protect a MUC service from occupant abuses and limit number of messages that will be broadcasted by the service\&. A good value for this minimum message interval is
\fI0\&.4\fR
second\&. If an occupant tries to send messages faster, an error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable\&.
.RE
.PP
\fBmin_presence_interval\fR: \fINumber\fR
.RS 4
This option defines the minimum of time between presence changes coming from a given occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, no restriction is applied\&. This option can be used to protect a MUC service for occupants abuses\&. If an occupant tries to change its presence more often than the specified interval, the presence is cached by ejabberd and only the last presence is broadcasted to all occupants in the room after expiration of the interval delay\&. Intermediate presence packets are silently discarded\&. A good value for this option is 4 seconds\&.
This option defines the minimum of time between presence changes coming from a given occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, no restriction is applied\&. This option can be used to protect a MUC service for occupants abuses\&. If an occupant tries to change its presence more often than the specified interval, the presence is cached by ejabberd and only the last presence is broadcasted to all occupants in the room after expiration of the interval delay\&. Intermediate presence packets are silently discarded\&. A good value for this option is
\fI4\fR
seconds\&.
.RE
.PP
\fBname\fR: \fIstring()\fR
@@ -4573,7 +4686,7 @@ This module depends on \fImod_muc\fR\&.
\fINote\fR
about this option: added in 22\&.05\&. How many users can be subscribed to a room at once using the
\fIsubscribe_room_many\fR
command\&. The default value is
API\&. The default value is
\fI50\fR\&.
.RE
.RE
@@ -5031,22 +5144,8 @@ modules:
.SS "mod_offline"
.sp
This module implements XEP\-0160: Best Practices for Handling Offline Messages and XEP\-0013: Flexible Offline Message Retrieval\&. This means that all messages sent to an offline user will be stored on the server until that user comes online again\&. Thus it is very similar to how email works\&. A user is considered offline if no session presence priority > 0 are currently open\&.
.if n \{\
.sp
.\}
.RS 4
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBNote\fR
.ps -1
.br
.sp
\fIejabberdctl\fR has a command to delete expired messages (see chapter \fI\&.\&./guide/managing\&.md|Managing an ejabberd server\fR in online documentation\&.
.sp .5v
.RE
The \fIdelete_expired_messages\fR API allows to delete expired messages, and \fIdelete_old_messages\fR API deletes older ones\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -5058,7 +5157,9 @@ This module implements XEP\-0160: Best Practices for Handling Offline Messages a
.PP
\fBaccess_max_user_messages\fR: \fIAccessName\fR
.RS 4
This option defines which access rule will be enforced to limit the maximum number of offline messages that a user can have (quota)\&. When a user has too many offline messages, any new messages that they receive are discarded, and a <resource\-constraint/> error is returned to the sender\&. The default value is
This option defines which access rule will be enforced to limit the maximum number of offline messages that a user can have (quota)\&. When a user has too many offline messages, any new messages that they receive are discarded, and a
\fI<resource\-constraint/>\fR
error is returned to the sender\&. The default value is
\fImax_user_offline_messages\fR\&.
.RE
.PP
@@ -5092,8 +5193,12 @@ option, but applied to this module only\&.
.PP
\fBstore_empty_body\fR: \fItrue | false | unless_chat_state\fR
.RS 4
Whether or not to store messages that lack a <body/> element\&. The default value is
\fIunless_chat_state\fR, which tells ejabberd to store messages even if they lack the <body/> element, unless they only contain a chat state notification (as defined in
Whether or not to store messages that lack a
\fI<body/>\fR
element\&. The default value is
\fIunless_chat_state\fR, which tells ejabberd to store messages even if they lack the
\fI<body/>\fR
element, unless they only contain a chat state notification (as defined in
XEP\-0085: Chat State Notifications\&.
.RE
.PP
@@ -5112,11 +5217,11 @@ option, but applied to this module only\&.
.PP
\fBuse_mam_for_storage\fR: \fItrue | false\fR
.RS 4
This is an experimental option\&. Enabling this option,
\fImod_offline\fR
uses the
This is an experimental option\&. By enabling the option, this module uses the
\fIarchive\fR
table from
\fImod_mam\fR
archive table instead of its own spool table to retrieve the messages received when the user was offline\&. This allows client developers to slowly drop XEP\-0160 and rely on XEP\-0313 instead\&. It also further reduces the storage required when you enable MucSub\&. Enabling this option has a known drawback for the moment: most of flexible message retrieval queries don\(cqt work (those that allow retrieval/deletion of messages by id), but this specification is not widely used\&. The default value is
instead of its own spool table to retrieve the messages received when the user was offline\&. This allows client developers to slowly drop XEP\-0160 and rely on XEP\-0313 instead\&. It also further reduces the storage required when you enable MucSub\&. Enabling this option has a known drawback for the moment: most of flexible message retrieval queries don\(cqt work (those that allow retrieval/deletion of messages by id), but this specification is not widely used\&. The default value is
\fIfalse\fR
to keep former behaviour as default\&.
.RE
@@ -5307,7 +5412,7 @@ This module implements XEP\-0016: Privacy Lists\&.
.ps -1
.br
.sp
Nowadays modern XMPP clients rely on XEP\-0191: Blocking Command which is implemented by \fImod_blocking\fR module\&. However, you still need \fImod_privacy\fR loaded in order for \fImod_blocking\fR to work\&.
Nowadays modern XMPP clients rely on XEP\-0191: Blocking Command which is implemented by \fImod_blocking\fR\&. However, you still need \fImod_privacy\fR loaded in order for \fImod_blocking\fR to work\&.
.sp .5v
.RE
.sp
@@ -5360,7 +5465,7 @@ This module adds support for XEP\-0049: Private XML Storage\&.
.sp
Using this method, XMPP entities can store private data on the server, retrieve it whenever necessary and share it between multiple connected clients of the same user\&. The data stored might be anything, as long as it is a valid XML\&. One typical usage is storing a bookmark of all user\(cqs conferences (XEP\-0048: Bookmarks)\&.
.sp
It also implements the bookmark conversion described in XEP\-0402: PEP Native Bookmarks, see the command \fIbookmarks_to_pep\fR API\&.
It also implements the bookmark conversion described in XEP\-0402: PEP Native Bookmarks, see \fIbookmarks_to_pep\fR API\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -6628,7 +6733,7 @@ This module enables you to create shared roster groups: groups of accounts that
.sp
The big advantages of this feature are that end users do not need to manually add all users to their rosters, and that they cannot permanently delete users from the shared roster groups\&. A shared roster group can have members from any XMPP server, but the presence will only be available from and to members of the same virtual host where the group is created\&. It still allows the users to have / add their own contacts, as it does not replace the standard roster\&. Instead, the shared roster contacts are merged to the relevant users at retrieval time\&. The standard user rosters thus stay unmodified\&.
.sp
Shared roster groups can be edited via the Web Admin, and some API commands called \fIsrg_*\fR\&. Each group has a unique name and those parameters:
Shared roster groups can be edited via the Web Admin, and some API commands called \fIsrg_\fR, for example \fIsrg_add\fR API\&. Each group has a unique name and those parameters:
.sp
.RS 4
.ie n \{\
@@ -7980,7 +8085,7 @@ Should the operating system be revealed or not\&. The default value is
.RE
.SH "LISTENERS"
.sp
This section describes listeners options of ejabberd 24\&.10\&.
This section describes listeners options of ejabberd 24\&.12\&.
.sp
TODO
.SH "AUTHOR"
@@ -7988,13 +8093,13 @@ TODO
ProcessOne\&.
.SH "VERSION"
.sp
This document describes the configuration file of ejabberd 24\&.10\&. Configuration options of other ejabberd versions may differ significantly\&.
This document describes the configuration file of ejabberd 24\&.12\&. Configuration options of other ejabberd versions may differ significantly\&.
.SH "REPORTING BUGS"
.sp
Report bugs to https://github\&.com/processone/ejabberd/issues
.SH "SEE ALSO"
.sp
Default configuration file: https://github\&.com/processone/ejabberd/blob/24\&.10/ejabberd\&.yml\&.example
Default configuration file: https://github\&.com/processone/ejabberd/blob/24\&.12/ejabberd\&.yml\&.example
.sp
Main site: https://ejabberd\&.im
.sp
+9 -7
View File
@@ -135,7 +135,7 @@ defmodule Ejabberd.MixProject do
{:eimp, "~> 1.0"},
{:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false},
{:fast_tls, "~> 1.1.22"},
{:fast_xml, "~> 1.1.53"},
{:fast_xml, "~> 1.1.53", override: true},
{:fast_yaml, "~> 1.0"},
{:idna, "~> 6.0"},
{:mqtree, "~> 1.0"},
@@ -144,8 +144,8 @@ defmodule Ejabberd.MixProject do
{:p1_utils, "~> 1.0"},
{:pkix, "~> 1.0"},
{:stringprep, ">= 1.0.26"},
{:xmpp, "~> 1.9"},
{:yconf, "~> 1.0"}]
{:xmpp, "~> 1.9.1"},
{:yconf, "~> 1.0.17"}]
++ cond_deps()
end
@@ -166,7 +166,7 @@ defmodule Ejabberd.MixProject do
{:ejabberd_po, git: "https://github.com/processone/ejabberd-po.git"}},
{Mix.env() == :dev,
{:exsync, "~> 0.2", optional: true, runtime: false}},
{config(:redis), {:eredis, "~> 1.2.0"}},
{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,7 +184,9 @@ defmodule Ejabberd.MixProject do
defp cond_apps do
for {:true, app} <- [{config(:stun), :stun},
{if_version_below(~c"27", true), :jiffy},
{config(:tools), :observer}], do:
{config(:tools), :debugger},
{config(:tools), :observer},
{config(:tools), :wx}], do:
app
end
@@ -212,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
+13 -11
View File
@@ -1,37 +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.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"},
"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"},
"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.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"},
"ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
"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.22", "44356b256afad4399c2fc5059a3066669dafd8bd4e4e796c9c1cf8910ddd265e", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e65779aefb7ab15c4755230fef8077e687d20cc5a3984a5974f9f657e8e2485b"},
"fast_xml": {:hex, :fast_xml, "1.1.53", "1ef4f6e5995bcfa94800a46b460c3400c19c0a533948b12200a2e2fb1a2be427", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "5064336d6f363eee5097aa5dc5ced9b67f05152f2e6b8520fd50d268c2ab839c"},
"fast_xml": {:hex, :fast_xml, "1.1.55", "ace020f2521f2a484ac8467d2822af85534a346e2aae03ffcbc34f29318befaf", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "83f3e23a780ed5f567cdec73953f06c95b838d709dbfa86b59a98a8d23c99f85"},
"fast_yaml": {:hex, :fast_yaml, "1.0.37", "f71d472fbf787ccd161b914d1eb486116a0f4f2e835337a378fbd31b59d2e74b", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8de868721bf7e2172414f7d3148ede0f3c922b496455cd625dd5c4429515a769"},
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
"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"},
"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.24", "e19876618eb0be22815aca99640cb88cd5c86e4239b8e8dc15b4e5d7854ef7e2", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.15", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "f1451d706595ef997ab1ca17162ddac58f874ac97e315a5fadbe3cfa26148002"},
"p1_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.28", "08eca7d2afc81ba6d757b572f4a57ef3a2383b0c7b785fde38184bc368376d54", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "655bb75df036ace55ddce17ca741143c42e0667c6206ac27a4dcbc65f71ac9ef"},
"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.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"xmpp": {:hex, :xmpp, "1.9.0", "d92446bf51d36adda02db63b963fe6d4a1ede33e59b38a43d9b90afd20c25b74", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "c1b91be74a9a9503afa6766f756477516920ffbfeea0c260c2fa171355f53c27"},
"yconf": {:hex, :yconf, "1.0.16", "d59521d66ff89f219411b6e9277cd6feec7cc6fce11554e67de02a8d0a470479", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "e947813273f38711c7b2e5a8e4acc9a51c7bbe854f744a345f60300b38586c89"},
"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"},
}
+6 -2
View File
@@ -161,7 +161,7 @@
{"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","е отстранен поради изключване на системата"}.
@@ -295,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","Не е налична статистика за този елемент"}.
@@ -512,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: ","Възникна грешка при изтриването на профила: "}.
@@ -537,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"}.
@@ -553,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","Потребителската сесия е прекратена"}.
+4
View File
@@ -295,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"}.
@@ -537,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"}.
@@ -553,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"}.
+4
View File
@@ -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"}.
+4
View File
@@ -295,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"}.
@@ -537,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"}.
@@ -553,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"}.
+3
View File
@@ -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 derreur inattendue : ~p"}.
{"Uninstall","Désinstaller"}.
{"Unregister an XMPP account","Annuler lenregistrement dun 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"}.
+5
View File
@@ -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"}.
+4
View File
@@ -295,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"}.
@@ -537,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"}.
@@ -553,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"}.
+14
View File
@@ -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 sekziston"}.
{"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?","Ti 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","Su përcaktua nyjë"}.
{"No pending subscriptions found","Su gjetën pajtime pezull"}.
{"No privacy list with this name found","Su gjet listë privatësie me atë emër"}.
{"No <privileged_iq/> element found","Su gjetën elementë <privileged_iq/>"}.
{"No running node found","Su gjet nyjë në funksionim"}.
{"No services available","Ska shërbime të gatshme"}.
{"No statistics found for this item","Su gjetën statistika për këtë objekt"}.
@@ -191,6 +196,7 @@
{"Node index not found","Su gjet tregues nyje"}.
{"Node not found","Su 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 tu 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","Skeni leje të dërgoni mesazhe private"}.
{"You are not joined to the channel","Skeni 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"}.
+4
View File
@@ -295,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","未找到此项目的统计数据"}.
@@ -537,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","无法生成验证码"}.
@@ -553,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","用户会话已终止"}.
+14 -6
View File
@@ -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.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.22"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.53"}}},
{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,12 +64,12 @@
{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.24"}}},
{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.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.28"}}}},
{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,
@@ -69,8 +77,8 @@
{stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}},
{if_var_true, stun,
{stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}},
{xmpp, "~> 1.9.0", {git, "https://github.com/processone/xmpp", {tag, "1.9.0"}}},
{yconf, "~> 1.0.15", {git, "https://github.com/processone/yconf", {tag, "1.0.16"}}}
{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]}.
+21 -21
View File
@@ -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},
{<<"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.22">>},0},
{<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.53">>},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.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.28">>},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.15">>},0},
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1},
{<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.0">>},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">>},
{<<"eredis">>, <<"39E31AA02ADCD651C657F39AAFD4D31A9B2F63C6C700DC9CECE98D4BC3C897AB">>},
{<<"esip">>, <<"63C0FDC667BE751714E1E5C14621A9334F21B60AC1BB68BE889454CA9CA021B7">>},
{<<"ezlib">>, <<"3C7F62862850A241159C10B218ECF580BCE54D0890601B65144DACC2633BE2B0">>},
{<<"fast_tls">>, <<"44356B256AFAD4399C2FC5059A3066669DAFD8BD4E4E796C9C1CF8910DDD265E">>},
{<<"fast_xml">>, <<"1EF4F6E5995BCFA94800A46B460C3400C19C0A533948B12200A2E2FB1A2BE427">>},
{<<"fast_xml">>, <<"ACE020F2521F2A484AC8467D2822AF85534A346E2AAE03FFCBC34F29318BEFAF">>},
{<<"fast_yaml">>, <<"F71D472FBF787CCD161B914D1EB486116A0F4F2E835337A378FBD31B59D2E74B">>},
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
{<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>},
{<<"jose">>, <<"A903F5227417BD2A08C8A00A0CBCC458118BE84480955E8D251297A425723F83">>},
{<<"luerl">>, <<"60F05F4240F0E7C148DDB79B67B8FF972734AAD237AA74C83D0748B8214C8EF0">>},
{<<"luerl">>, <<"DF25F41944E57A7C4D9EF09D238BC3E850276C46039CFC12B8BB42ECCF36FCB1">>},
{<<"mqtree">>, <<"82F54B8F2D22B4445DB1D6CCCB7FE9EAD049D61410C29E32475F3CEB3EE62A89">>},
{<<"p1_acme">>, <<"E19876618EB0BE22815ACA99640CB88CD5C86E4239B8E8DC15B4E5D7854EF7E2">>},
{<<"p1_acme">>, <<"DB91F0D6C193CD1D5C0B0FA3939A898DBF56A6075DB4347CDE26E802715DE50C">>},
{<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>},
{<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>},
{<<"p1_pgsql">>, <<"08ECA7D2AFC81BA6D757B572F4A57EF3A2383B0C7B785FDE38184BC368376D54">>},
{<<"p1_pgsql">>, <<"FAE0C90CBC5931865958150F1B667FB0D20B063F6A46A17770A4E5232DED632C">>},
{<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>},
{<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>},
{<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>},
{<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>},
{<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>},
{<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>},
{<<"xmpp">>, <<"D92446BF51D36ADDA02DB63B963FE6D4A1EDE33E59B38A43D9B90AFD20C25B74">>},
{<<"yconf">>, <<"D59521D66FF89F219411B6E9277CD6FEEC7CC6FCE11554E67DE02A8D0A470479">>}]},
{<<"xmpp">>, <<"A1642D93CDBDF947F32344B0E05FCC8EFCFB9F11C32832ACC9BD826B52ADBE48">>},
{<<"yconf">>, <<"DCF242E27F3FC5D0743D6B8175DD39BC14A1F4ED7E6EA986366A44A6FF3B2A3A">>}]},
{pkg_hash_ext,[
{<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>},
{<<"cache_tab">>, <<"8582B60A4A09B247EF86355BA9E07FCE9E11EDC0345A775C9171F971C72B6351">>},
{<<"eimp">>, <<"907C780023CB2893E4FC4BDBE6A4F02C355913862AC67F0ECC26605E816B628A">>},
{<<"epam">>, <<"2F3449E72885A72A6C2A843F561ADD0FC2F70D7A21F61456930A547473D4D989">>},
{<<"eredis">>, <<"D9B5ABEF2C2C8ABA8F32AA018203E0B3DC8B1157773B254AB1D4C2002317F1E1">>},
{<<"eredis">>, <<"7C2B54C566FED55FEEF3341CA79B0100A6348FD3F162184B7ED5118D258C3CC1">>},
{<<"esip">>, <<"9EF3660CEF93B623F7368DCD5C79F4E704358631909E6DD464E335378815DA1F">>},
{<<"ezlib">>, <<"9EE62AB3F8ED55A0FD11A9569FCB8E458683F95575417272192B069F092ABFBB">>},
{<<"fast_tls">>, <<"E65779AEFB7AB15C4755230FEF8077E687D20CC5A3984A5974F9F657E8E2485B">>},
{<<"fast_xml">>, <<"5064336D6F363EEE5097AA5DC5CED9B67F05152F2E6B8520FD50D268C2AB839C">>},
{<<"fast_xml">>, <<"83F3E23A780ED5F567CDEC73953F06C95B838D709DBFA86B59A98A8D23C99F85">>},
{<<"fast_yaml">>, <<"8DE868721BF7E2172414F7D3148EDE0F3C922B496455CD625DD5C4429515A769">>},
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
{<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>},
{<<"jose">>, <<"0D6CD36FF8BA174DB29148FC112B5842186B68A90CE9FC2B3EC3AFE76593E614">>},
{<<"luerl">>, <<"9CAFD4F6094FF0F5A9D278FD81D60D3E026C820BDFB6CACD4B1BD909F21B525D">>},
{<<"luerl">>, <<"1B4B9D0CA5D7D280D1D2787A6A5EE9F5A212641B62BFF91556BAA53805DF3AED">>},
{<<"mqtree">>, <<"5FE8B7CF8FBC4783D0FCEB94654AC2BBF3242A58CD0397D249DED8AE021BE2A3">>},
{<<"p1_acme">>, <<"F1451D706595EF997AB1CA17162DDAC58F874AC97E315A5FADBE3CFA26148002">>},
{<<"p1_acme">>, <<"A7B55B47495DDB4F98A15E65451EC3AD43F4637B955C74CD695D98E6A645D08C">>},
{<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>},
{<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>},
{<<"p1_pgsql">>, <<"655BB75DF036ACE55DDCE17CA741143C42E0667C6206AC27A4DCBC65F71AC9EF">>},
{<<"p1_pgsql">>, <<"A6FF58E8B174993F3895DA3EA6211A9F9D0C54D1A6E28BB321DA3B3CD68B38C1">>},
{<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>},
{<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>},
{<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>},
{<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>},
{<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>},
{<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>},
{<<"xmpp">>, <<"C1B91BE74A9A9503AFA6766F756477516920FFBFEEA0C260C2FA171355F53C27">>},
{<<"yconf">>, <<"E947813273F38711C7B2E5A8E4ACC9A51C7BBE854F744A345F60300B38586C89">>}]}
{<<"xmpp">>, <<"D2B1431AF6E4C1A4C8BF90CAF0CC11CDEB047B8323B87E9D7E4826D4913275DC">>},
{<<"yconf">>, <<"DD2892923241449A46CC8457B9EC0FB14030700735A5885955677C735C341A25">>}]}
].
+9 -4
View File
@@ -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
View File
@@ -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);
+68 -32
View File
@@ -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.\\\"`",
@@ -252,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"],
@@ -271,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"],
@@ -672,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) ->
+1 -1
View File
@@ -893,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].
+1 -1
View File
@@ -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,
+2 -2
View File
@@ -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]).
+17 -2
View File
@@ -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]).
@@ -45,7 +45,8 @@
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]).
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,
@@ -465,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,
+2 -2
View File
@@ -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).
+17 -2
View File
@@ -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
+6
View File
@@ -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},
+1
View File
@@ -122,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;
+40 -30
View File
@@ -403,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'.")}},
@@ -440,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,
@@ -500,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, ...]",
@@ -595,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 =>
@@ -881,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",
@@ -1032,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 =>
@@ -1055,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",
@@ -1063,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 =>
@@ -1137,11 +1145,13 @@ doc() ->
"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 "
"_`database.md#redis|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 =>
@@ -1230,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,
@@ -1394,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,
@@ -1434,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",
@@ -1488,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 "
@@ -1511,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 =>
+1 -1
View File
@@ -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 -3
View File
@@ -69,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
%%%===================================================================
@@ -457,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",
@@ -481,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();
-2
View File
@@ -25,8 +25,6 @@
-module(ejabberd_s2s).
-protocol({xep, 220, '1.1'}).
-author('alexey@process-one.net').
-behaviour(gen_server).
+1 -1
View File
@@ -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]).
+2 -2
View File
@@ -1034,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",
-1
View File
@@ -26,7 +26,6 @@
-module(ejabberd_stun).
-behaviour(ejabberd_listener).
-protocol({rfc, 5766}).
-protocol({xep, 176, '1.0'}).
-ifndef(STUN).
-include("logger.hrl").
+6 -6
View File
@@ -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, _} ->
@@ -2285,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 =
+3 -3
View File
@@ -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
View File
@@ -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).
+58 -14
View File
@@ -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
@@ -2283,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 = [],
@@ -2324,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 "
@@ -2354,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"]}]}.
+167
View File
@@ -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.
+123
View File
@@ -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.
+27
View File
@@ -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
View File
@@ -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]).
+2 -2
View File
@@ -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.")]}.
+1 -1
View File
@@ -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).
+1 -1
View File
@@ -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).
+2 -2
View File
@@ -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).
+1 -1
View File
@@ -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).
+3 -4
View File
@@ -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. "
+2 -2
View File
@@ -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
View File
@@ -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).
+3 -2
View File
@@ -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:",
+47 -14
View File
@@ -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
@@ -549,8 +555,24 @@ hide_sensitive_args(Args=[_H|_T]) ->
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"]}.
+6 -6
View File
@@ -3,11 +3,11 @@
-module(mod_http_api_opt).
-export([admin_ip_access/1]).
-export([default_version/1]).
-spec admin_ip_access(gen_mod:opts() | global | binary()) -> 'none' | acl:acl().
admin_ip_access(Opts) when is_map(Opts) ->
gen_mod:get_opt(admin_ip_access, Opts);
admin_ip_access(Host) ->
gen_mod:get_module_opt(Host, mod_http_api, admin_ip_access).
-spec default_version(gen_mod:opts() | global | binary()) -> any().
default_version(Opts) when is_map(Opts) ->
gen_mod:get_opt(default_version, Opts);
default_version(Host) ->
gen_mod:get_module_opt(Host, mod_http_api, default_version).
+19 -19
View File
@@ -27,7 +27,7 @@
-author('holger@zedat.fu-berlin.de').
-behaviour(gen_server).
-behaviour(gen_mod).
-protocol({xep, 363, '0.2', '15.10', "", ""}).
-protocol({xep, 363, '0.3.0', '15.10', "complete", ""}).
-define(SERVICE_REQUEST_TIMEOUT, 5000). % 5 seconds.
-define(CALL_TIMEOUT, 60000). % 1 minute.
@@ -243,14 +243,14 @@ mod_doc() ->
desc =>
?T("This option defines the Jabber IDs of the service. "
"If the 'hosts' option is not specified, the only Jabber ID will "
"be the hostname of the virtual host with the prefix \"upload.\". "
"be the hostname of the virtual host with the prefix '\"upload.\"'. "
"The keyword '@HOST@' is replaced with the real virtual host name.")}},
{name,
#{value => ?T("Name"),
desc =>
?T("A name of the service in the Service Discovery. "
"This will only be displayed by special XMPP clients. "
"The default value is \"HTTP File Upload\".")}},
"The default value is '\"HTTP File Upload\"'. "
"Please note this will only be displayed by some XMPP clients.")}},
{access,
#{value => ?T("AccessName"),
desc =>
@@ -270,7 +270,7 @@ mod_doc() ->
desc =>
?T("This option defines the length of the random "
"string included in the GET and PUT URLs generated "
"by 'mod_http_upload'. The minimum length is 8 characters, "
"by 'mod_http_upload'. The minimum length is '8' characters, "
"but it is recommended to choose a larger value. "
"The default value is '40'.")}},
{jid_in_url,
@@ -293,8 +293,8 @@ mod_doc() ->
#{value => ?T("Permission"),
desc =>
?T("This option defines the permission bits of uploaded files. "
"The bits are specified as an octal number (see the chmod(1) "
"manual page) within double quotes. For example: \"0644\". "
"The bits are specified as an octal number (see the 'chmod(1)' "
"manual page) within double quotes. For example: '\"0644\"'. "
"The default is undefined, which means no explicit permissions "
"will be set.")}},
{dir_mode,
@@ -302,8 +302,8 @@ mod_doc() ->
desc =>
?T("This option defines the permission bits of the 'docroot' "
"directory and any directories created during file uploads. "
"The bits are specified as an octal number (see the chmod(1) "
"manual page) within double quotes. For example: \"0755\". "
"The bits are specified as an octal number (see the 'chmod(1)' "
"manual page) within double quotes. For example: '\"0755\"'. "
"The default is undefined, which means no explicit permissions "
"will be set.")}},
{docroot,
@@ -311,26 +311,26 @@ mod_doc() ->
desc =>
?T("Uploaded files are stored below the directory specified "
"(as an absolute path) with this option. The keyword "
"@HOME@ is replaced with the home directory of the user "
"running ejabberd, and the keyword @HOST@ with the virtual "
"host name. The default value is \"@HOME@/upload\".")}},
"'@HOME@' is replaced with the home directory of the user "
"running ejabberd, and the keyword '@HOST@' with the virtual "
"host name. The default value is '\"@HOME@/upload\"'.")}},
{put_url,
#{value => ?T("URL"),
desc =>
?T("This option specifies the initial part of the PUT URLs "
"used for file uploads. The keyword @HOST@ is replaced "
"used for file uploads. The keyword '@HOST@' is replaced "
"with the virtual host name. NOTE: different virtual "
"hosts cannot use the same PUT URL. "
"The default value is \"https://@HOST@:5443/upload\".")}},
"The default value is '\"https://@HOST@:5443/upload\"'.")}},
{get_url,
#{value => ?T("URL"),
desc =>
?T("This option specifies the initial part of the GET URLs "
"used for downloading the files. The default value is 'undefined'. "
"When this option is 'undefined', this option is set "
"to the same value as 'put_url'. The keyword @HOST@ is "
"to the same value as 'put_url'. The keyword '@HOST@' is "
"replaced with the virtual host name. NOTE: if GET requests "
"are handled by 'mod_http_upload', the 'get_url' must match the "
"are handled by this module, the 'get_url' must match the "
"'put_url'. Setting it to a different value only makes "
"sense if an external web server or _`mod_http_fileserver`_ "
"is used to serve the uploaded files.")}},
@@ -349,9 +349,9 @@ mod_doc() ->
"Upload processing to a separate HTTP server. "
"Both ejabberd and the HTTP server should share this "
"secret and behave exactly as described at "
"https://modules.prosody.im/mod_http_upload_external.html"
"[Prosody's mod_http_upload_external] in the "
"'Implementation' section. There is no default value.")}},
"https://modules.prosody.im/mod_http_upload_external.html#implementation"
"[Prosody's mod_http_upload_external: Implementation]. "
"There is no default value.")}},
{rm_on_unregister,
#{value => "true | false",
desc =>
+3 -3
View File
@@ -96,7 +96,7 @@ mod_options(_) ->
mod_doc() ->
#{desc =>
[?T("This module adds quota support for mod_http_upload."), "",
?T("This module depends on 'mod_http_upload'.")],
?T("This module depends on _`mod_http_upload`_.")],
opts =>
[{max_days,
#{value => ?T("Days"),
@@ -126,10 +126,10 @@ mod_doc() ->
"user may upload. When this threshold is exceeded, "
"ejabberd deletes the oldest files uploaded by that "
"user until their disk usage equals or falls below "
"the specified soft quota (see 'access_soft_quota'). "
"the specified soft quota (see also option 'access_soft_quota'). "
"The default value is 'hard_upload_quota'.")}}],
example =>
[{?T("Please note that it's not necessary to specify the "
[{?T("Notice it's not necessary to specify the "
"'access_hard_quota' and 'access_soft_quota' options in order "
"to use the quota feature. You can stick to the default names "
"and just specify access rules such as those in this example:"),
+1 -1
View File
@@ -25,7 +25,7 @@
-module(mod_jidprep).
-author('holger@zedat.fu-berlin.de').
-protocol({xep, 328, '0.1', '19.09', "", ""}).
-protocol({xep, 328, '0.1', '19.09', "complete", ""}).
-behaviour(gen_mod).
+1 -1
View File
@@ -27,7 +27,7 @@
-author('alexey@process-one.net').
-protocol({xep, 12, '2.0'}).
-protocol({xep, 12, '2.0', '0.5.0', "complete", ""}).
-behaviour(gen_mod).
+1 -1
View File
@@ -22,7 +22,7 @@
-module(mod_legacy_auth).
-behaviour(gen_mod).
-protocol({xep, 78, '2.5'}).
-protocol({xep, 78, '2.5', '17.03', "complete", ""}).
%% gen_mod API
-export([start/2, stop/1, reload/3, depends/2, mod_options/1, mod_doc/0]).
+19 -5
View File
@@ -25,11 +25,11 @@
-module(mod_mam).
-protocol({xep, 313, '0.6.1', '15.06', "", ""}).
-protocol({xep, 334, '0.2'}).
-protocol({xep, 359, '0.5.0'}).
-protocol({xep, 425, '0.3.0', '24.06', "", ""}).
-protocol({xep, 441, '0.2.0'}).
-protocol({xep, 313, '0.6.1', '15.06', "complete", ""}).
-protocol({xep, 334, '0.2', '16.01', "complete", ""}).
-protocol({xep, 359, '0.5.0', '15.09', "complete", ""}).
-protocol({xep, 425, '0.3.0', '24.06', "complete", ""}).
-protocol({xep, 441, '0.2.0', '15.06', "complete", ""}).
-behaviour(gen_mod).
@@ -46,6 +46,7 @@
mod_options/1, remove_mam_for_user_with_peer/3, remove_mam_for_user/2,
is_empty_for_user/2, is_empty_for_room/3, check_create_room/4,
process_iq/3, store_mam_message/7, make_id/0, wrap_as_mucsub/2, select/7,
is_archiving_enabled/2,
get_mam_count/2,
webadmin_menu_hostuser/4,
webadmin_page_hostuser/4,
@@ -1571,6 +1572,19 @@ get_jids(undefined) ->
get_jids(Js) ->
[jid:tolower(jid:remove_resource(J)) || J <- Js].
is_archiving_enabled(LUser, LServer) ->
case gen_mod:is_loaded(LServer, mod_mam) of
true ->
case get_prefs(LUser, LServer) of
{ok, #archive_prefs{default = Default}} when Default /= never ->
true;
_ ->
false
end;
false ->
false
end.
get_commands_spec() ->
[
#ejabberd_commands{name = get_mam_count, tags = [mam],
+3 -2
View File
@@ -24,7 +24,7 @@
%%%----------------------------------------------------------------------
-module(mod_matrix_gw).
-ifndef(OTP_BELOW_24).
-ifndef(OTP_BELOW_25).
-author('alexey@process-one.net').
@@ -883,7 +883,8 @@ mod_options(Host) ->
mod_doc() ->
#{desc =>
[?T("https://matrix.org/[Matrix] gateway.")],
[?T("https://matrix.org/[Matrix] gateway. "
"Erlang/OTP 25 or higher is required to use this module.")],
note => "added in 24.02",
example =>
["listen:",
+1 -1
View File
@@ -24,7 +24,7 @@
%%%-------------------------------------------------------------------
-module(mod_matrix_gw_room).
-ifndef(OTP_BELOW_24).
-ifndef(OTP_BELOW_25).
-behaviour(gen_statem).
%% API
+1 -1
View File
@@ -23,7 +23,7 @@
%%%
%%%-------------------------------------------------------------------
-module(mod_matrix_gw_s2s).
-ifndef(OTP_BELOW_24).
-ifndef(OTP_BELOW_25).
-behaviour(gen_statem).
%% API
+1 -1
View File
@@ -20,7 +20,7 @@
%%%
%%%----------------------------------------------------------------------
-module(mod_matrix_gw_sup).
-ifndef(OTP_BELOW_24).
-ifndef(OTP_BELOW_25).
-behaviour(supervisor).
%% API
+2 -2
View File
@@ -24,7 +24,7 @@
-module(mod_mix).
-behaviour(gen_mod).
-behaviour(gen_server).
-protocol({xep, 369, '0.14.1', '16.03', "", ""}).
-protocol({xep, 369, '0.14.1', '16.03', "complete", ""}).
%% API
-export([route/1]).
@@ -122,7 +122,7 @@ mod_doc() ->
desc =>
?T("This option defines the Jabber IDs of the service. "
"If the 'hosts' option is not specified, the only Jabber ID will "
"be the hostname of the virtual host with the prefix \"mix.\". "
"be the hostname of the virtual host with the prefix '\"mix.\"'. "
"The keyword '@HOST@' is replaced with the real virtual host name.")}},
{name,
#{value => ?T("Name"),
+2 -2
View File
@@ -22,7 +22,7 @@
%%%----------------------------------------------------------------------
-module(mod_mix_pam).
-behaviour(gen_mod).
-protocol({xep, 405, '0.3.0'}).
-protocol({xep, 405, '0.3.0', '19.02', "complete", ""}).
%% gen_mod callbacks
-export([start/2, stop/1, reload/3, depends/2, mod_opt_type/1, mod_options/1]).
@@ -128,7 +128,7 @@ mod_doc() ->
"The module is needed if MIX compatible clients "
"on your server are going to join MIX channels "
"(either on your server or on any remote servers)."), "",
?T("NOTE: 'mod_mix' is not required for this module "
?T("NOTE: _`mod_mix`_ is not required for this module "
"to work, however, without 'mod_mix_pam' the MIX "
"functionality of your local XMPP clients will be impaired.")],
opts =>
+20 -9
View File
@@ -179,24 +179,35 @@ mod_doc() ->
example =>
["modules:",
" mod_mqtt_bridge:",
" replication_user: \"mqtt@xmpp.server.com\"",
" servers:",
" \"mqtt://server.com\":",
" authentication:",
" certfile: \"/etc/ejabberd/mqtt_server.pem\"",
" publish:",
" \"localA\": \"remoteA\" # local changes to 'localA' will be replicated on remote server as 'remoteA'",
" \"topicB\": \"topicB\"",
" subscribe:",
" \"remoteB\": \"localB\" # changes to 'remoteB' on remote server will be stored as 'localB' on local server",
" authentication:",
" certfile: \"/etc/ejabberd/mqtt_server.pem\"",
" replication_user: \"mqtt@xmpp.server.com\""],
" \"remoteB\": \"localB\" # changes to 'remoteB' on remote server will be stored as 'localB' on local server"],
opts =>
[{servers,
#{value => "{ServerUrl: {publish: [TopicPairs], subscribe: [TopicPairs], authentication: [AuthInfo]}}",
#{value => "{ServerUrl: {Key: Value}}",
desc =>
?T("Declaration of data to share, must contain 'publish' or 'subscribe' or both, and 'authentication' "
"section with username/password field or certfile pointing to client certificate. "
"Accepted urls can use schema mqtt, mqtts (mqtt with tls), mqtt5, mqtt5s (both to trigger v5 protocol), "
"ws, wss, ws5, wss5. Certificate authentication can be only used with mqtts, mqtt5s, wss, wss5.")}},
?T("Declaration of data to share for each ServerUrl. "
"Server URLs can use schemas: 'mqtt', 'mqtts' (mqtt with tls), 'mqtt5', "
"'mqtt5s' (both to trigger v5 protocol), 'ws', 'wss', 'ws5', 'wss5'. "
"Keys must be:")},
[{authentication,
#{value => "{AuthKey: AuthValue}",
desc => ?T("List of authentication information, where AuthKey can be: "
"'username' and 'password' fields, or 'certfile' pointing to client certificate. "
"Certificate authentication can be used only with mqtts, mqtt5s, wss, wss5.")}},
{publish,
#{value => "{LocalTopic: RemoteTopic}",
desc => ?T("Either publish or subscribe must be set, or both.")}},
{subscribe,
#{value => "{RemoteTopic: LocalTopic}",
desc => ?T("Either publish or subscribe must be set, or both.")}}]},
{replication_user,
#{value => "JID",
desc =>
+38 -16
View File
@@ -24,8 +24,7 @@
%%%----------------------------------------------------------------------
-module(mod_muc).
-author('alexey@process-one.net').
-protocol({xep, 45, '1.25'}).
-protocol({xep, 249, '1.2'}).
-protocol({xep, 45, '1.25', '0.5.0', "complete", ""}).
-ifndef(GEN_SERVER).
-define(GEN_SERVER, gen_server).
-endif.
@@ -995,15 +994,38 @@ iq_disco_items(ServerHost, Host, From, Lang, MaxRoomsDiscoItems, Node, RSM)
#rsm_set{max = Max} ->
Max
end,
{Items, HitMax} = lists:foldr(
fun(_, {Acc, _}) when length(Acc) >= MaxItems ->
{Acc, true};
(R, {Acc, _}) ->
case get_room_disco_item(R, Query) of
{ok, Item} -> {[Item | Acc], false};
{error, _} -> {Acc, false}
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
RsmSupported = RMod:rsm_supported(),
GetRooms =
fun GetRooms(AccInit, Rooms) ->
{Items, HitMax, DidSkip, Last, First} = lists:foldr(
fun(_, {Acc, _, Skip, F, L}) when length(Acc) >= MaxItems ->
{Acc, true, Skip, F, L};
({RN, _, _} = R, {Acc, _, Skip, F, _}) ->
F2 = if F == undefined -> RN; true -> F end,
case get_room_disco_item(R, Query) of
{ok, Item} -> {[Item | Acc], false, Skip, F2, RN};
{error, _} -> {Acc, false, true, F2, RN}
end
end, AccInit, Rooms),
if RsmSupported andalso not HitMax andalso DidSkip ->
RSM2 = case RSM of
#rsm_set{'after' = undefined, before = undefined} ->
#rsm_set{max = MaxItems - length(Items), 'after' = Last};
#rsm_set{'after' = undefined} ->
#rsm_set{max = MaxItems - length(Items), 'before' = First};
_ ->
#rsm_set{max = MaxItems - length(Items), 'after' = Last}
end,
GetRooms({Items, false, false, undefined, undefined},
get_online_rooms(ServerHost, Host, RSM2));
true -> {Items, HitMax}
end
end, {[], false}, get_online_rooms(ServerHost, Host, RSM)),
end,
{Items, HitMax} =
GetRooms({[], false, false, undefined, undefined},
get_online_rooms(ServerHost, Host, RSM)),
ResRSM = case Items of
[_|_] when RSM /= undefined; HitMax ->
#disco_item{jid = #jid{luser = First}} = hd(Items),
@@ -1498,12 +1520,12 @@ mod_doc() ->
?T("A small history of the current discussion is sent to users "
"when they enter the room. With this option you can define the "
"number of history messages to keep and send to users joining the room. "
"The value is a non-negative integer. Setting the value to 0 disables "
"The value is a non-negative integer. Setting the value to '0' disables "
"the history feature and, as a result, nothing is kept in memory. "
"The default value is 20. This value affects all rooms on the service. "
"The default value is '20'. This value affects all rooms on the service. "
"NOTE: modern XMPP clients rely on Message Archives (XEP-0313), so feel "
"free to disable the history feature if you're only using modern clients "
"and have 'mod_mam' module loaded.")}},
"and have _`mod_mam`_ module loaded.")}},
{host, #{desc => ?T("Deprecated. Use 'hosts' instead.")}},
{hosts,
#{value => ?T("[Host, ...]"),
@@ -1594,7 +1616,7 @@ mod_doc() ->
"When this option is not defined, message rate is not limited. "
"This feature can be used to protect a MUC service from occupant "
"abuses and limit number of messages that will be broadcasted by "
"the service. A good value for this minimum message interval is 0.4 second. "
"the service. A good value for this minimum message interval is '0.4' second. "
"If an occupant tries to send messages faster, an error is send back "
"explaining that the message has been discarded and describing the "
"reason why the message is not acceptable.")}},
@@ -1611,7 +1633,7 @@ mod_doc() ->
"the presence is cached by ejabberd and only the last presence "
"is broadcasted to all occupants in the room after expiration "
"of the interval delay. Intermediate presence packets are "
"silently discarded. A good value for this option is 4 seconds.")}},
"silently discarded. A good value for this option is '4' seconds.")}},
{queue_type,
#{value => "ram | file",
desc =>
@@ -1844,7 +1866,7 @@ mod_doc() ->
?T("Maximum number of occupants in the room. "
"The default value is '200'.")}},
{presence_broadcast,
#{value => "[moderator | participant | visitor, ...]",
#{value => "[Role]",
desc =>
?T("List of roles for which presence is broadcasted. "
"The list can contain one or several of: 'moderator', "
+238 -54
View File
@@ -30,7 +30,8 @@
-export([start/2, stop/1, reload/3, depends/2, mod_doc/0,
muc_online_rooms/1, muc_online_rooms_by_regex/2,
muc_register_nick/3, muc_unregister_nick/2,
muc_register_nick/3, muc_register_nick/4,
muc_unregister_nick/2, muc_unregister_nick/3,
create_room_with_opts/4, create_room/3, destroy_room/2,
create_rooms_file/1, destroy_rooms_file/1,
rooms_unused_list/2, rooms_unused_destroy/2,
@@ -38,9 +39,11 @@
get_user_rooms/2, get_user_subscriptions/2, get_room_occupants/2,
get_room_occupants_number/2, send_direct_invitation/5,
change_room_option/4, get_room_options/2,
set_room_affiliation/4, get_room_affiliations/2, get_room_affiliation/3,
subscribe_room/4, subscribe_room_many/3,
unsubscribe_room/2, get_subscribers/2,
set_room_affiliation/4, set_room_affiliation/5, get_room_affiliations/2,
get_room_affiliations_v3/2, get_room_affiliation/3,
subscribe_room/4, subscribe_room/6,
subscribe_room_many/3, subscribe_room_many_v3/4,
unsubscribe_room/2, unsubscribe_room/4, get_subscribers/2,
get_room_serverhost/1,
web_menu_main/2, web_page_main/2,
web_menu_host/3, web_page_host/3,
@@ -102,7 +105,7 @@ get_commands_spec() ->
module = ?MODULE, function = muc_online_rooms,
args_desc = ["MUC service, or `global` for all"],
args_example = ["conference.example.com"],
result_desc = "List of rooms",
result_desc = "List of rooms JIDs",
result_example = ["room1@conference.example.com", "room2@conference.example.com"],
args = [{service, binary}],
args_rename = [{host, service}],
@@ -133,6 +136,16 @@ get_commands_spec() ->
args = [{nick, binary}, {jid, binary}, {service, binary}],
args_rename = [{host, service}],
result = {res, rescode}},
#ejabberd_commands{name = muc_register_nick, tags = [muc],
desc = "Register a nick to a User JID in a MUC service",
module = ?MODULE, function = muc_register_nick,
version = 3,
note = "updated in 24.12",
args_desc = ["nick", "user name", "user host", "MUC service"],
args_example = [<<"Tim">>, <<"tim">>, <<"example.org">>, <<"conference.example.org">>],
args = [{nick, binary}, {user, binary}, {host, binary}, {service, binary}],
args_rename = [{host, service}],
result = {res, rescode}},
#ejabberd_commands{name = muc_unregister_nick, tags = [muc],
desc = "Unregister the nick registered by that account in the MUC service",
module = ?MODULE, function = muc_unregister_nick,
@@ -141,25 +154,38 @@ get_commands_spec() ->
args = [{jid, binary}, {service, binary}],
args_rename = [{host, service}],
result = {res, rescode}},
#ejabberd_commands{name = muc_unregister_nick, tags = [muc],
desc = "Unregister the nick registered by that account in the MUC service",
module = ?MODULE, function = muc_unregister_nick,
version = 3,
note = "updated in 24.12",
args_desc = ["user name", "user host", "MUC service"],
args_example = [<<"tim">>, <<"example.org">>, <<"conference.example.org">>],
args = [{user, binary}, {host, binary}, {service, binary}],
args_rename = [{host, service}],
result = {res, rescode}},
#ejabberd_commands{name = create_room, tags = [muc_room],
desc = "Create a MUC room name@service in host",
module = ?MODULE, function = create_room,
args_desc = ["Room name", "MUC service", "Server host"],
args_example = ["room1", "conference.example.com", "example.com"],
args = [{name, binary}, {service, binary},
args = [{room, binary}, {service, binary},
{host, binary}],
args_rename = [{name, room}],
result = {res, rescode}},
#ejabberd_commands{name = destroy_room, tags = [muc_room],
desc = "Destroy a MUC room",
module = ?MODULE, function = destroy_room,
args_desc = ["Room name", "MUC service"],
args_example = ["room1", "conference.example.com"],
args = [{name, binary}, {service, binary}],
args = [{room, binary}, {service, binary}],
args_rename = [{name, room}],
result = {res, rescode}},
#ejabberd_commands{name = create_rooms_file, tags = [muc],
desc = "Create the rooms indicated in file",
longdesc = "Provide one room JID per line. Rooms will be created after restart.",
note = "improved in 24.12",
module = ?MODULE, function = create_rooms_file,
args_desc = ["Path to the text file with one room JID per line"],
args_example = ["/home/ejabberd/rooms.txt"],
@@ -176,7 +202,7 @@ get_commands_spec() ->
[{"members_only","true"},
{"affiliations", "owner:bob@example.com,member:peter@example.com"},
{"subscribers", "bob@example.com:Bob:messages:subject,anne@example.com:Anne:messages"}]],
args = [{name, binary}, {service, binary},
args = [{room, binary}, {service, binary},
{host, binary},
{options, {list,
{option, {tuple,
@@ -184,6 +210,7 @@ get_commands_spec() ->
{value, binary}
]}}
}}],
args_rename = [{name, room}],
result = {res, rescode}},
#ejabberd_commands{name = destroy_rooms_file, tags = [muc],
desc = "Destroy the rooms indicated in file",
@@ -289,7 +316,8 @@ get_commands_spec() ->
args_example = ["room1", "conference.example.com"],
result_desc = "The list of occupants with JID, nick and affiliation",
result_example = [{"user1@example.com/psi", "User 1", "owner"}],
args = [{name, binary}, {service, binary}],
args = [{room, binary}, {service, binary}],
args_rename = [{name, room}],
result = {occupants, {list,
{occupant, {tuple,
[{jid, string},
@@ -305,7 +333,8 @@ get_commands_spec() ->
args_example = ["room1", "conference.example.com"],
result_desc = "Number of room occupants",
result_example = 7,
args = [{name, binary}, {service, binary}],
args = [{room, binary}, {service, binary}],
args_rename = [{name, room}],
result = {occupants, integer}},
#ejabberd_commands{name = send_direct_invitation, tags = [muc_room],
@@ -321,8 +350,9 @@ get_commands_spec() ->
args_example = [<<"room1">>, <<"conference.example.com">>,
<<>>, <<"Check this out!">>,
"user2@localhost:user3@example.com"],
args = [{name, binary}, {service, binary}, {password, binary},
args = [{room, binary}, {service, binary}, {password, binary},
{reason, binary}, {users, binary}],
args_rename = [{name, room}],
result = {res, rescode}},
#ejabberd_commands{name = send_direct_invitation, tags = [muc_room],
desc = "Send a direct invitation to several destinations",
@@ -338,8 +368,9 @@ get_commands_spec() ->
args_example = [<<"room1">>, <<"conference.example.com">>,
<<>>, <<"Check this out!">>,
["user2@localhost", "user3@example.com"]],
args = [{name, binary}, {service, binary}, {password, binary},
args = [{room, binary}, {service, binary}, {password, binary},
{reason, binary}, {users, {list, {jid, binary}}}],
args_rename = [{name, room}],
result = {res, rescode}},
#ejabberd_commands{name = change_room_option, tags = [muc_room],
@@ -347,8 +378,9 @@ get_commands_spec() ->
module = ?MODULE, function = change_room_option,
args_desc = ["Room name", "MUC service", "Option name", "Value to assign"],
args_example = ["room1", "conference.example.com", "members_only", "true"],
args = [{name, binary}, {service, binary},
args = [{room, binary}, {service, binary},
{option, binary}, {value, binary}],
args_rename = [{name, room}],
result = {res, rescode}},
#ejabberd_commands{name = get_room_options, tags = [muc_room],
desc = "Get options from a MUC room",
@@ -357,7 +389,8 @@ get_commands_spec() ->
args_example = ["room1", "conference.example.com"],
result_desc = "List of room options tuples with name and value",
result_example = [{"members_only", "true"}],
args = [{name, binary}, {service, binary}],
args = [{room, binary}, {service, binary}],
args_rename = [{name, room}],
result = {options, {list,
{option, {tuple,
[{name, string},
@@ -392,6 +425,21 @@ get_commands_spec() ->
args = [{user, binary}, {nick, binary}, {room, binary},
{nodes, {list, {node, binary}}}],
result = {nodes, {list, {node, string}}}},
#ejabberd_commands{name = subscribe_room, tags = [muc_room, muc_sub],
desc = "Subscribe to a MUC conference",
module = ?MODULE, function = subscribe_room,
version = 3,
note = "updated in 24.12",
args_desc = ["user name", "user host", "user nick",
"room name", "MUC service", "list of nodes"],
args_example = ["tom", "localhost", "Tom", "room1", "conference.localhost",
["urn:xmpp:mucsub:nodes:messages", "urn:xmpp:mucsub:nodes:affiliations"]],
result_desc = "The list of nodes that has subscribed",
result_example = ["urn:xmpp:mucsub:nodes:messages",
"urn:xmpp:mucsub:nodes:affiliations"],
args = [{user, binary}, {host, binary}, {nick, binary}, {room, binary},
{service, binary}, {nodes, {list, {node, binary}}}],
result = {nodes, {list, {node, string}}}},
#ejabberd_commands{name = subscribe_room_many, tags = [muc_room, muc_sub],
desc = "Subscribe several users to a MUC conference",
note = "added in 22.05",
@@ -439,6 +487,32 @@ get_commands_spec() ->
{room, binary},
{nodes, {list, {node, binary}}}],
result = {res, rescode}},
#ejabberd_commands{name = subscribe_room_many, tags = [muc_room, muc_sub],
desc = "Subscribe several users to a MUC conference",
longdesc = "This command accepts up to 50 users at once "
"(this is configurable with the _`mod_muc_admin`_ option "
"`subscribe_room_many_max_users`)",
module = ?MODULE, function = subscribe_room_many_v3,
version = 3,
note = "updated in 24.12",
args_desc = ["List of tuples with users name, host and nick",
"room name",
"MUC service",
"nodes separated by commas: `,`"],
args_example = [[{"tom", "localhost", "Tom"},
{"jerry", "localhost", "Jerry"}],
"room1", "conference.localhost",
["urn:xmpp:mucsub:nodes:messages", "urn:xmpp:mucsub:nodes:affiliations"]],
args = [{users, {list,
{user, {tuple,
[{user, binary},
{host, binary},
{nick, binary}
]}}
}},
{room, binary}, {service, binary},
{nodes, {list, {node, binary}}}],
result = {res, rescode}},
#ejabberd_commands{name = unsubscribe_room, tags = [muc_room, muc_sub],
desc = "Unsubscribe from a MUC conference",
module = ?MODULE, function = unsubscribe_room,
@@ -446,6 +520,15 @@ get_commands_spec() ->
args_example = ["tom@localhost", "room1@conference.localhost"],
args = [{user, binary}, {room, binary}],
result = {res, rescode}},
#ejabberd_commands{name = unsubscribe_room, tags = [muc_room, muc_sub],
desc = "Unsubscribe from a MUC conference",
module = ?MODULE, function = unsubscribe_room,
version = 3,
note = "updated in 24.12",
args_desc = ["user name", "user host", "room name", "MUC service"],
args_example = ["tom", "localhost", "room1", "conference.localhost"],
args = [{user, binary}, {host, binary}, {room, binary}, {service, binary}],
result = {res, rescode}},
#ejabberd_commands{name = get_subscribers, tags = [muc_room, muc_sub],
desc = "List subscribers of a MUC conference",
module = ?MODULE, function = get_subscribers,
@@ -453,7 +536,8 @@ get_commands_spec() ->
args_example = ["room1", "conference.example.com"],
result_desc = "The list of users that are subscribed to that room",
result_example = ["user2@example.com", "user3@example.com"],
args = [{name, binary}, {service, binary}],
args = [{room, binary}, {service, binary}],
args_rename = [{name, room}],
result = {subscribers, {list, {jid, string}}}},
#ejabberd_commands{name = set_room_affiliation, tags = [muc_room],
desc = "Change an affiliation in a MUC room",
@@ -463,6 +547,19 @@ get_commands_spec() ->
args = [{name, binary}, {service, binary},
{jid, binary}, {affiliation, binary}],
result = {res, rescode}},
#ejabberd_commands{name = set_room_affiliation, tags = [muc_room],
desc = "Change an affiliation in a MUC room",
longdesc = "If affiliation is `none`, then the affiliation is removed.",
module = ?MODULE, function = set_room_affiliation,
version = 3,
note = "updated in 24.12",
args_desc = ["room name", "MUC service", "user name", "user host", "affiliation to set"],
args_example = ["room1", "conference.example.com", "sun", "localhost", "member"],
args = [{room, binary}, {service, binary},
{user, binary}, {host, binary}, {affiliation, binary}],
result = {res, rescode}},
#ejabberd_commands{name = get_room_affiliations, tags = [muc_room],
desc = "Get the list of affiliations of a MUC room",
module = ?MODULE, function = get_room_affiliations,
@@ -479,6 +576,25 @@ get_commands_spec() ->
{reason, string}
]}}
}}},
#ejabberd_commands{name = get_room_affiliations, tags = [muc_room],
desc = "Get the list of affiliations of a MUC room",
module = ?MODULE, function = get_room_affiliations_v3,
version = 3,
note = "updated in 24.12",
args_desc = ["Room name", "MUC service"],
args_example = ["room1", "conference.example.com"],
result_desc = "The list of affiliations with jid, affiliation and reason",
result_example = [{"user1@example.com", member, "member"}],
args = [{room, binary}, {service, binary}],
result = {affiliations, {list,
{affiliation, {tuple,
[{jid, string},
{affiliation, atom},
{reason, string}
]}}
}}},
#ejabberd_commands{name = get_room_affiliation, tags = [muc_room],
desc = "Get affiliation of a user in MUC room",
module = ?MODULE, function = get_room_affiliation,
@@ -486,7 +602,8 @@ get_commands_spec() ->
args_example = ["room1", "conference.example.com", "user1@example.com"],
result_desc = "Affiliation of the user",
result_example = member,
args = [{name, binary}, {service, binary}, {jid, binary}],
args = [{room, binary}, {service, binary}, {jid, binary}],
args_rename = [{name, room}],
result = {affiliation, atom}},
#ejabberd_commands{name = get_room_history, tags = [muc_room],
desc = "Get history of messages stored inside MUC room state",
@@ -494,7 +611,8 @@ get_commands_spec() ->
module = ?MODULE, function = get_room_history,
args_desc = ["Room name", "MUC service"],
args_example = ["room1", "conference.example.com"],
args = [{name, binary}, {service, binary}],
args = [{room, binary}, {service, binary}],
args_rename = [{name, room}],
result = {history, {list,
{entry, {tuple,
[{timestamp, string},
@@ -546,6 +664,9 @@ build_summary_room(Name, Host, Pid) ->
Participants
}.
muc_register_nick(Nick, User, Host, Service) ->
muc_register_nick(Nick, makeencode(User, Host), Service).
muc_register_nick(Nick, FromBinary, Service) ->
try {get_room_serverhost(Service), jid:decode(FromBinary)} of
{ServerHost, From} ->
@@ -568,6 +689,9 @@ muc_register_nick(Nick, FromBinary, Service) ->
throw({error, "Internal error"})
end.
muc_unregister_nick(User, Host, Service) ->
muc_unregister_nick(makeencode(User, Host), Service).
muc_unregister_nick(FromBinary, Service) ->
muc_register_nick(<<"">>, FromBinary, Service).
@@ -727,12 +851,13 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"Affiliations">>, Name, R, RPath}),
Set = [make_command(set_room_affiliation,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[])],
Get = [make_command(get_room_affiliations,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{table_options, {20, RPath}}])],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{table_options, {20, RPath}},
{result_links, [{jid, user, 3 + Level, <<"">>}]}])],
Title ++ Breadcrumb ++ Get ++ Set;
webadmin_muc_host(_Host,
Service,
@@ -746,7 +871,7 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"History">>, Name, R, RPath}),
Get = [make_command(get_room_history,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{table_options, {10, RPath}},
{result_links, [{message, paragraph, 1, <<"">>}]}])],
Title ++ Breadcrumb ++ Get;
@@ -762,7 +887,7 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"Invite">>, Name, R, RPath}),
Set = [make_command(send_direct_invitation,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[])],
Title ++ Breadcrumb ++ Set;
webadmin_muc_host(_Host,
@@ -777,7 +902,7 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"Occupants">>, Name, R, RPath}),
Get = [make_command(get_room_occupants,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{table_options, {20, RPath}},
{result_links, [{jid, user, 3 + Level, <<"">>}]}])],
Title ++ Breadcrumb ++ Get;
@@ -793,11 +918,11 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"Options">>, Name, R, RPath}),
Set = [make_command(change_room_option,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[])],
Get = [make_command(get_room_options,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[])],
Title ++ Breadcrumb ++ Get ++ Set;
webadmin_muc_host(_Host,
@@ -815,15 +940,15 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"Subscribers">>, Name, R, RPath}),
Set = [make_command(subscribe_room,
R,
[{<<"room">>, jid:encode({Name, Service, <<"">>})}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[]),
make_command(unsubscribe_room,
R,
[{<<"room">>, jid:encode({Name, Service, <<"">>})}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{style, danger}])],
Get = [make_command(get_subscribers,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{table_options, {20, RPath}},
{result_links, [{jid, user, 3 + Level, <<"">>}]}])],
Title ++ Breadcrumb ++ Get ++ Set;
@@ -839,7 +964,7 @@ webadmin_muc_host(_Host,
make_breadcrumb({room_section, Level, Service, <<"Destroy">>, Name, R, RPath}),
Set = [make_command(destroy_room,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{style, danger}])],
Title ++ Breadcrumb ++ Set;
webadmin_muc_host(_Host,
@@ -875,7 +1000,7 @@ webadmin_muc_host(_Host, Service, [<<"rooms">> | RPath], R, _Lang, Level, PageTi
{result_links, [{sentence, room, 3 + Level, <<"">>}]}]),
make_command(get_room_occupants_number,
R,
[{<<"name">>, Name}, {<<"service">>, Service}],
[{<<"room">>, Name}, {<<"service">>, Service}],
[{only, raw_and_value}])}
end,
make_command_raw_value(muc_online_rooms, R, [{<<"service">>, Service}])),
@@ -1148,7 +1273,7 @@ create_room(Name1, Host1, ServerHost) ->
create_room_with_opts(Name1, Host1, ServerHost1, CustomRoomOpts) ->
ServerHost = validate_host(ServerHost1, <<"serverhost">>),
case get_room_pid_validate(Name1, Host1, <<"name">>, <<"host">>) of
case get_room_pid_validate(Name1, Host1, <<"service">>) of
{room_not_found, Name, Host} ->
%% Get the default room options from the muc configuration
DefRoomOpts = mod_muc_opt:default_room_options(ServerHost),
@@ -1178,7 +1303,7 @@ muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) ->
%% If the room has participants, they are not notified that the room was destroyed;
%% they will notice when they try to chat and receive an error that the room doesn't exist.
destroy_room(Name1, Service1) ->
case get_room_pid_validate(Name1, Service1, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name1, Service1, <<"service">>) of
{room_not_found, _, _} ->
throw({error, "Room doesn't exists"});
{Pid, _, _} ->
@@ -1245,11 +1370,31 @@ create_rooms_file(Filename) ->
RJID = read_room(F),
Rooms = read_rooms(F, RJID, []),
file:close(F),
%% Read the default room options defined for the first virtual host
DefRoomOpts = mod_muc_opt:default_room_options(ejabberd_config:get_myname()),
[muc_create_room(ejabberd_config:get_myname(), A, DefRoomOpts) || A <- Rooms],
HostsDetails = get_hosts_details(Rooms),
[muc_create_room(HostsDetails, A) || A <- Rooms],
ok.
muc_create_room(HostsDetails, {_, Host, _} = RoomTuple) ->
{_Host, ServerHost, DefRoomOpts} = get_host_details(Host, HostsDetails),
muc_create_room(ServerHost, RoomTuple, DefRoomOpts).
get_hosts_details(Rooms) ->
Hosts = lists_uniq([Host || {_, Host, _} <- Rooms]),
lists:map(fun(H) ->
SH = get_room_serverhost(H),
{H, SH, mod_muc_opt:default_room_options(SH)}
end, Hosts).
-ifdef(OTP_BELOW_25).
lists_uniq(List) ->
lists:usort(List).
-else.
lists_uniq(List) ->
lists:uniq(List).
-endif.
get_host_details(Host, ServerHostsDetails) ->
lists:keyfind(Host, 1, ServerHostsDetails).
%%---------------------------------
%% List/Delete Unused/Empty Rooms
@@ -1454,7 +1599,7 @@ act_on_room(_Method, list, _) ->
%%----------------------------
get_room_occupants(Room, Host) ->
case get_room_pid_validate(Room, Host, <<"name">>, <<"service">>) of
case get_room_pid_validate(Room, Host, <<"service">>) of
{Pid, _, _} when is_pid(Pid) -> get_room_occupants(Pid);
_ -> throw({error, room_not_found})
end.
@@ -1470,7 +1615,7 @@ get_room_occupants(Pid) ->
maps:to_list(S#state.users)).
get_room_occupants_number(Room, Host) ->
case get_room_pid_validate(Room, Host, <<"name">>, <<"service">>) of
case get_room_pid_validate(Room, Host, <<"service">>) of
{Pid, _, _} when is_pid(Pid)->
{ok, #{occupants_number := N}} = mod_muc_room:get_info(Pid),
N;
@@ -1549,7 +1694,7 @@ send_direct_invitation(FromJid, UserJid, Msg) ->
%% For example:
%% `change_room_option(<<"testroom">>, <<"conference.localhost">>, <<"title">>, <<"Test Room">>)'
change_room_option(Name, Service, OptionString, ValueString) ->
case get_room_pid_validate(Name, Service, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Service, <<"service">>) of
{room_not_found, _, _} ->
throw({error, "Room not found"});
{Pid, _, _} ->
@@ -1646,10 +1791,10 @@ parse_nodes([<<"subscribers">> | Rest], Acc) ->
parse_nodes(_, _) ->
throw({error, "Invalid 'subscribers' - unknown node name used"}).
-spec get_room_pid_validate(binary(), binary(), binary(), binary()) ->
-spec get_room_pid_validate(binary(), binary(), binary()) ->
{pid() | room_not_found, binary(), binary()}.
get_room_pid_validate(Name, Service, NameArg, ServiceArg) ->
Name2 = validate_room(Name, NameArg),
get_room_pid_validate(Name, Service, ServiceArg) ->
Name2 = validate_room(Name),
{ServerHost, Service2} = validate_muc2(Service, ServiceArg),
case mod_muc:unhibernate_room(ServerHost, Service2, Name2) of
error ->
@@ -1740,7 +1885,7 @@ change_option(Option, Value, Config) ->
%%----------------------------
get_room_options(Name, Service) ->
case get_room_pid_validate(Name, Service, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Service, <<"service">>) of
{Pid, _, _} when is_pid(Pid) -> get_room_options(Pid);
_ -> []
end.
@@ -1763,10 +1908,10 @@ get_options(Config) ->
%%----------------------------
%% @spec(Name::binary(), Service::binary()) ->
%% [{JID::string(), Domain::string(), Role::string(), Reason::string()}]
%% [{Username::string(), Domain::string(), Role::string(), Reason::string()}]
%% @doc Get the affiliations of the room Name@Service.
get_room_affiliations(Name, Service) ->
case get_room_pid_validate(Name, Service, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Service, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
%% Get the PID of the online room, then request its state
{ok, StateData} = mod_muc_room:get_state(Pid),
@@ -1781,8 +1926,29 @@ get_room_affiliations(Name, Service) ->
throw({error, "The room does not exist."})
end.
%% @spec(Name::binary(), Service::binary()) ->
%% [{JID::string(), Role::string(), Reason::string()}]
%% @doc Get the affiliations of the room Name@Service.
get_room_affiliations_v3(Name, Service) ->
case get_room_pid_validate(Name, Service, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
%% Get the PID of the online room, then request its state
{ok, StateData} = mod_muc_room:get_state(Pid),
Affiliations = maps:to_list(StateData#state.affiliations),
lists:map(
fun({{Uname, Domain, _Res}, {Aff, Reason}}) when is_atom(Aff)->
Jid = makeencode(Uname, Domain),
{Jid, Aff, Reason};
({{Uname, Domain, _Res}, Aff}) when is_atom(Aff)->
Jid = makeencode(Uname, Domain),
{Jid, Aff, <<>>}
end, Affiliations);
_ ->
throw({error, "The room does not exist."})
end.
get_room_history(Name, Service) ->
case get_room_pid_validate(Name, Service, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Service, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
case mod_muc_room:get_state(Pid) of
{ok, StateData} ->
@@ -1808,7 +1974,7 @@ get_room_history(Name, Service) ->
%% @doc Get affiliation of a user in the room Name@Service.
get_room_affiliation(Name, Service, JID) ->
case get_room_pid_validate(Name, Service, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Service, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
%% Get the PID of the online room, then request its state
{ok, StateData} = mod_muc_room:get_state(Pid),
@@ -1822,6 +1988,9 @@ get_room_affiliation(Name, Service, JID) ->
%% Change Room Affiliation
%%----------------------------
set_room_affiliation(Name, Service, User, Host, AffiliationString) ->
set_room_affiliation(Name, Service, makeencode(User, Host), AffiliationString).
%% @spec(Name, Service, JID, AffiliationString) -> ok | {error, Error}
%% Name = binary()
%% Service = binary()
@@ -1840,7 +2009,7 @@ set_room_affiliation(Name, Service, JID, AffiliationString) ->
_ ->
throw({error, "Invalid affiliation"})
end,
case get_room_pid_validate(Name, Service, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Service, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
%% Get the PID for the online room so we can get the state of the room
case mod_muc_room:change_item(Pid, jid:decode(JID), affiliation, Affiliation, <<"">>) of
@@ -1859,6 +2028,10 @@ set_room_affiliation(Name, Service, JID, AffiliationString) ->
%%% MUC Subscription
%%%
subscribe_room(Username, Host, Nick, Name, Service, Nodes) ->
subscribe_room(makeencode(Username, Host), Nick,
makeencode(Name, Service), Nodes).
subscribe_room(_User, Nick, _Room, _Nodes) when Nick == <<"">> ->
throw({error, "Nickname must be set"});
subscribe_room(User, Nick, Room, Nodes) when is_binary(Nodes) ->
@@ -1870,7 +2043,7 @@ subscribe_room(User, Nick, Room, NodeList) ->
try jid:decode(User) of
UserJID1 ->
UserJID = jid:replace_resource(UserJID1, <<"modmucadmin">>),
case get_room_pid_validate(Name, Host, <<"name">>, <<"room">>) of
case get_room_pid_validate(Name, Host, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
case mod_muc_room:subscribe(
Pid, UserJID, Nick, NodeList) of
@@ -1891,6 +2064,10 @@ subscribe_room(User, Nick, Room, NodeList) ->
throw({error, "Malformed room JID"})
end.
subscribe_room_many_v3(List, Name, Service, Nodes) ->
List2 = [{makeencode(User, Host), Nick} || {User, Host, Nick} <- List],
subscribe_room_many(List2, makeencode(Name, Service), Nodes).
subscribe_room_many(Users, Room, Nodes) ->
MaxUsers = mod_muc_admin_opt:subscribe_room_many_max_users(global),
if
@@ -1903,12 +2080,16 @@ subscribe_room_many(Users, Room, Nodes) ->
end, Users)
end.
unsubscribe_room(User, Host, Name, Service) ->
unsubscribe_room(makeencode(User, Host),
makeencode(Name, Service)).
unsubscribe_room(User, Room) ->
try jid:decode(Room) of
#jid{luser = Name, lserver = Host} when Name /= <<"">> ->
try jid:decode(User) of
UserJID ->
case get_room_pid_validate(Name, Host, <<"name">>, <<"room">>) of
case get_room_pid_validate(Name, Host, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
case mod_muc_room:unsubscribe(Pid, UserJID) of
ok ->
@@ -1929,7 +2110,7 @@ unsubscribe_room(User, Room) ->
end.
get_subscribers(Name, Host) ->
case get_room_pid_validate(Name, Host, <<"name">>, <<"service">>) of
case get_room_pid_validate(Name, Host, <<"service">>) of
{Pid, _, _} when is_pid(Pid) ->
{ok, JIDList} = mod_muc_room:get_subscribers(Pid),
[jid:encode(jid:remove_resource(J)) || J <- JIDList];
@@ -1941,6 +2122,9 @@ get_subscribers(Name, Host) ->
%% Utils
%%----------------------------
makeencode(User, Host) ->
jid:encode(jid:make(User, Host)).
-spec validate_host(Name :: binary(), ArgName::binary()) -> binary().
validate_host(Name, ArgName) ->
case jid:nameprep(Name) of
@@ -1996,11 +2180,11 @@ validate_muc2(Name, ArgName) ->
end
end.
-spec validate_room(Name :: binary(), ArgName :: binary()) -> binary().
validate_room(Name, ArgName) ->
-spec validate_room(Name :: binary()) -> binary().
validate_room(Name) ->
case jid:nodeprep(Name) of
error ->
throw({error, <<"Invalid value of '",ArgName/binary,"'">>});
throw({error, <<"Invalid value of room name">>});
Name2 ->
Name2
end.
@@ -2075,5 +2259,5 @@ mod_doc() ->
note => "added in 22.05",
desc =>
?T("How many users can be subscribed to a room at once using "
"the 'subscribe_room_many' command. "
"the _`subscribe_room_many`_ API. "
"The default value is '50'.")}}]}.
+1 -1
View File
@@ -25,7 +25,7 @@
-module(mod_muc_log).
-protocol({xep, 334, '0.2'}).
-protocol({xep, 334, '0.2', '15.09', "complete", ""}).
-author('badlop@process-one.net').
+4
View File
@@ -57,6 +57,10 @@ init(Host, Opts) ->
transient, 5000, worker, [?MODULE]},
case supervisor:start_child(ejabberd_backend_sup, Spec) of
{ok, _Pid} -> ok;
%% Maybe started for a vhost which only wanted mnesia for ram
%% and this vhost wants mnesia for persitent storage too
{error, {already_started, _Pid}} ->
init([Host, Opts]);
Err -> Err
end.
+1 -1
View File
@@ -27,7 +27,7 @@
-author('badlop@process-one.net').
-protocol({xep, 421, '0.1.0', '23.10', "", ""}).
-protocol({xep, 421, '0.1.0', '23.10', "complete", ""}).
-behaviour(gen_mod).
+2 -2
View File
@@ -27,8 +27,8 @@
-author('alexey@process-one.net').
-protocol({xep, 317, '0.1', '21.12', "", "conversejs/prosody compatible"}).
-protocol({xep, 410, '1.1.0', '18.12', "", ""}).
-protocol({xep, 317, '0.1', '21.12', "complete", "conversejs/prosody compatible"}).
-protocol({xep, 410, '1.1.0', '18.12', "complete", ""}).
-behaviour(p1_fsm).
+1 -1
View File
@@ -27,7 +27,7 @@
-author('badlop@process-one.net').
-protocol({xep, 33, '1.1', '15.04', "", ""}).
-protocol({xep, 33, '1.1', '15.04', "complete", ""}).
-behaviour(gen_server).
+19 -16
View File
@@ -27,12 +27,12 @@
-author('alexey@process-one.net').
-protocol({xep, 13, '1.2', '16.02', "", ""}).
-protocol({xep, 22, '1.4'}).
-protocol({xep, 23, '1.3'}).
-protocol({xep, 160, '1.0'}).
-protocol({xep, 203, '2.0'}).
-protocol({xep, 334, '0.2'}).
-protocol({xep, 13, '1.2', '16.02', "complete", ""}).
-protocol({xep, 22, '1.4', '0.1.0', "complete", ""}).
-protocol({xep, 23, '1.3', '0.7.5', "complete", ""}).
-protocol({xep, 160, '1.0', '16.01', "complete", ""}).
-protocol({xep, 203, '2.0', '2.1.0', "complete", ""}).
-protocol({xep, 334, '0.2', '16.01', "complete", ""}).
-behaviour(gen_mod).
@@ -306,7 +306,12 @@ c2s_copy_session(State, _) ->
State.
c2s_handle_bind2_inline({#{jid := #jid{luser = LUser, lserver = LServer}} = State, Els, Results}) ->
delete_all_msgs(LUser, LServer),
case mod_mam:is_archiving_enabled(LUser, LServer) of
true ->
delete_all_msgs(LUser, LServer);
false ->
ok
end,
{State, Els, Results}.
-spec handle_offline_query(iq()) -> iq().
@@ -1179,10 +1184,8 @@ mod_doc() ->
"again. Thus it is very similar to how email works. A user "
"is considered offline if no session presence priority > 0 "
"are currently open."), "",
?T("NOTE: 'ejabberdctl' has a command to "
"delete expired messages (see chapter "
"_`../guide/managing.md|Managing an ejabberd server`_ "
"in online documentation.")],
?T("The _`delete_expired_messages`_ API allows to delete expired messages, "
"and _`delete_old_messages`_ API deletes older ones.")],
opts =>
[{access_max_user_messages,
#{value => ?T("AccessName"),
@@ -1191,16 +1194,16 @@ mod_doc() ->
"enforced to limit the maximum number of offline "
"messages that a user can have (quota). When a user "
"has too many offline messages, any new messages that "
"they receive are discarded, and a <resource-constraint/> "
"they receive are discarded, and a '<resource-constraint/>' "
"error is returned to the sender. The default value is "
"'max_user_offline_messages'.")}},
{store_empty_body,
#{value => "true | false | unless_chat_state",
desc =>
?T("Whether or not to store messages that lack a <body/> "
?T("Whether or not to store messages that lack a '<body/>' "
"element. The default value is 'unless_chat_state', "
"which tells ejabberd to store messages even if they "
"lack the <body/> element, unless they only contain a "
"lack the '<body/>' element, unless they only contain a "
"chat state notification (as defined in "
"https://xmpp.org/extensions/xep-0085.html"
"[XEP-0085: Chat State Notifications].")}},
@@ -1212,8 +1215,8 @@ mod_doc() ->
{use_mam_for_storage,
#{value => "true | false",
desc =>
?T("This is an experimental option. Enabling this option, "
"'mod_offline' uses the 'mod_mam' archive table instead "
?T("This is an experimental option. By enabling the option, "
"this module uses the 'archive' table from _`mod_mam`_ instead "
"of its own spool table to retrieve the messages received "
"when the user was offline. This allows client "
"developers to slowly drop XEP-0160 and rely on XEP-0313 "
+1 -1
View File
@@ -27,7 +27,7 @@
-author('bjc@kublai.com').
-protocol({xep, 199, '2.0'}).
-protocol({xep, 199, '2.0', '2.1.0', "complete", ""}).
-behaviour(gen_mod).
+3 -3
View File
@@ -27,7 +27,7 @@
-author('alexey@process-one.net').
-protocol({xep, 16, '1.6'}).
-protocol({xep, 16, '1.6', '0.5.0', "complete", ""}).
-behaviour(gen_mod).
@@ -895,8 +895,8 @@ mod_doc() ->
?T("NOTE: Nowadays modern XMPP clients rely on "
"https://xmpp.org/extensions/xep-0191.html"
"[XEP-0191: Blocking Command] which is implemented by "
"'mod_blocking' module. However, you still need "
"'mod_privacy' loaded in order for _`mod_blocking`_ to work.")],
"_`mod_blocking`_. However, you still need "
"'mod_privacy' loaded in order for 'mod_blocking' to work.")],
opts =>
[{db_type,
#{value => "mnesia | sql",
+4 -4
View File
@@ -27,9 +27,9 @@
-author('alexey@process-one.net').
-protocol({xep, 49, '1.2'}).
-protocol({xep, 411, '0.2.0', '18.12', "", ""}).
-protocol({xep, 402, '1.1.3', '23.10', "", ""}).
-protocol({xep, 49, '1.2', '0.1.0', "complete", ""}).
-protocol({xep, 411, '0.2.0', '18.12', "complete", ""}).
-protocol({xep, 402, '1.1.3', '23.10', "complete", ""}).
-behaviour(gen_mod).
@@ -135,7 +135,7 @@ mod_doc() ->
"[XEP-0048: Bookmarks])."), "",
?T("It also implements the bookmark conversion described in "
"https://xmpp.org/extensions/xep-0402.html[XEP-0402: PEP Native Bookmarks]"
", see the command _`bookmarks_to_pep`_ API.")],
", see _`bookmarks_to_pep`_ API.")],
opts =>
[{db_type,
#{value => "mnesia | sql",
+26 -7
View File
@@ -25,7 +25,7 @@
-author('amuhar3@gmail.com').
-protocol({xep, 356, '0.4.1', '24.10', "", ""}).
-protocol({xep, 356, '0.4.1', '24.10', "complete", ""}).
-behaviour(gen_server).
-behaviour(gen_mod).
@@ -274,7 +274,7 @@ component_send_packet({#iq{from = From,
case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of
{{ok, Access}, {ok, EncapType, EncapNs, EncapFrom, EncIq}}
when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) ->
NsPermissions = proplists:get_value(iq, Access, none),
NsPermissions = proplists:get_value(iq, Access, []),
Permission =
case lists:keyfind(EncapNs, 2, NsPermissions) of
#privilege_namespace{type = AllowedType} ->
@@ -306,6 +306,15 @@ component_send_packet({#iq{from = From,
?INFO_MSG("IQ not forwarded: The FROM attribute in the encapsulated "
"IQ stanza and the TO in top-level IQ stanza do not match",
[]),
drop;
{_, {error, no_privileged_iq, _Err}} ->
?INFO_MSG("IQ not forwarded: Component tried to send not wrapped IQ stanza.", []),
drop;
{_, {error, roster_query, _Err}} ->
IQ;
{_, {error, ErrType, _Err}} ->
?INFO_MSG("IQ not forwarded: Component tried to send not valid IQ stanza: ~p.",
[ErrType]),
drop
end,
{Result, State};
@@ -557,8 +566,8 @@ forward_message(#message{to = To} = Msg) ->
%% @format-begin
-spec get_iq_encapsulated_details(iq()) ->
{ok, set | get, binary(), jid(), iq()} |
{error, Why :: atom(), any(), iq()}.
{ok, iq_type(), binary(), jid(), iq()} |
{error, Why :: atom(), stanza_error()}.
get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) ->
Lang = xmpp:get_lang(Msg),
try xmpp:try_subtag(Msg, #privileged_iq{}) of
@@ -568,9 +577,19 @@ get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) ->
Ns = xmpp:get_ns(Element),
{ok, EncapsulatedType, Ns, From, EncIq};
_ ->
Txt = ?T("No <privileged_iq/> element found"),
Err = xmpp:err_bad_request(Txt, Lang),
{error, no_privileged_iq, Err}
try xmpp:try_subtag(Msg, #roster_query{}) of
#roster_query{} ->
{error, roster_query, xmpp:err_bad_request()};
_ ->
Txt = ?T("No <privileged_iq/> element found"),
Err = xmpp:err_bad_request(Txt, Lang),
{error, no_privileged_iq, Err}
catch
_:{xmpp_codec, Why} ->
Txt = xmpp:io_format_error(Why),
Err = xmpp:err_bad_request(Txt, Lang),
{error, codec_error, Err}
end
catch
_:{xmpp_codec, Why} ->
Txt = xmpp:io_format_error(Why),
+1 -1
View File
@@ -27,7 +27,7 @@
-author('xram@jabber.ru').
-protocol({xep, 65, '1.8'}).
-protocol({xep, 65, '1.8', '2.0.0', "complete", ""}).
-behaviour(gen_mod).
+21 -23
View File
@@ -35,9 +35,9 @@
-behaviour(gen_mod).
-behaviour(gen_server).
-author('christophe.romain@process-one.net').
-protocol({xep, 60, '1.14'}).
-protocol({xep, 163, '1.2'}).
-protocol({xep, 248, '0.2'}).
-protocol({xep, 60, '1.14', '0.5.0', "partial", ""}).
-protocol({xep, 163, '1.2', '2.0.0', "complete", ""}).
-protocol({xep, 248, '0.2', '2.1.0', "complete", ""}).
-include("logger.hrl").
-include_lib("xmpp/include/xmpp.hrl").
@@ -596,7 +596,7 @@ on_self_presence(Acc) ->
-spec on_user_offline(ejabberd_c2s:state(), atom()) -> ejabberd_c2s:state().
on_user_offline(#{jid := JID} = C2SState, _Reason) ->
purge_offline(jid:tolower(JID)),
purge_offline(JID),
C2SState;
on_user_offline(C2SState, _Reason) ->
C2SState.
@@ -1897,14 +1897,14 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, PubOpts, Access
Nidx = TNode#pubsub_node.id,
Type = TNode#pubsub_node.type,
Options = TNode#pubsub_node.options,
broadcast_retract_items(Host, Node, Nidx, Type, Options, Removed),
broadcast_retract_items(Host, Publisher, Node, Nidx, Type, Options, Removed),
set_cached_item(Host, Nidx, ItemId, Publisher, Payload),
{result, Reply};
{result, {TNode, {Result, Removed}}} ->
Nidx = TNode#pubsub_node.id,
Type = TNode#pubsub_node.type,
Options = TNode#pubsub_node.options,
broadcast_retract_items(Host, Node, Nidx, Type, Options, Removed),
broadcast_retract_items(Host, Publisher, Node, Nidx, Type, Options, Removed),
set_cached_item(Host, Nidx, ItemId, Publisher, Payload),
{result, Result};
{result, {_, default}} ->
@@ -1975,7 +1975,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
ServerHost = serverhost(Host),
ejabberd_hooks:run(pubsub_delete_item, ServerHost,
[ServerHost, Node, Publisher, service_jid(Host), ItemId]),
broadcast_retract_items(Host, Node, Nidx, Type, Options, [ItemId], ForceNotify),
broadcast_retract_items(Host, Publisher, Node, Nidx, Type, Options, [ItemId], ForceNotify),
case get_cached_item(Host, Nidx) of
#pubsub_item{itemid = {ItemId, Nidx}} -> unset_cached_item(Host, Nidx);
_ -> ok
@@ -2834,16 +2834,16 @@ broadcast_publish_item(Host, Node, Nidx, Type, NodeOptions, ItemId, From, Payloa
{result, false}
end.
-spec broadcast_retract_items(host(), binary(), nodeIdx(), binary(),
-spec broadcast_retract_items(host(), jid(), binary(), nodeIdx(), binary(),
nodeOptions(), [itemId()]) -> {result, boolean()}.
broadcast_retract_items(Host, Node, Nidx, Type, NodeOptions, ItemIds) ->
broadcast_retract_items(Host, Node, Nidx, Type, NodeOptions, ItemIds, false).
broadcast_retract_items(Host, Publisher, Node, Nidx, Type, NodeOptions, ItemIds) ->
broadcast_retract_items(Host, Publisher, Node, Nidx, Type, NodeOptions, ItemIds, false).
-spec broadcast_retract_items(host(), binary(), nodeIdx(), binary(),
-spec broadcast_retract_items(host(), jid(), binary(), nodeIdx(), binary(),
nodeOptions(), [itemId()], boolean()) -> {result, boolean()}.
broadcast_retract_items(_Host, _Node, _Nidx, _Type, _NodeOptions, [], _ForceNotify) ->
broadcast_retract_items(_Host, _Publisher, _Node, _Nidx, _Type, _NodeOptions, [], _ForceNotify) ->
{result, false};
broadcast_retract_items(Host, Node, Nidx, Type, NodeOptions, ItemIds, ForceNotify) ->
broadcast_retract_items(Host, Publisher, Node, Nidx, Type, NodeOptions, ItemIds, ForceNotify) ->
case (get_option(NodeOptions, notify_retract) or ForceNotify) of
true ->
case get_collection_subscriptions(Host, Node) of
@@ -2854,7 +2854,7 @@ broadcast_retract_items(Host, Node, Nidx, Type, NodeOptions, ItemIds, ForceNotif
items = #ps_items{
node = Node,
retract = ItemIds}}]},
broadcast_stanza(Host, Node, Nidx, Type,
broadcast_stanza(Host, Publisher, Node, Nidx, Type,
NodeOptions, SubsByDepth, items, Stanza, true),
{result, true};
_ ->
@@ -4100,9 +4100,8 @@ subid_shim(SubIds) ->
extended_headers(Jids) ->
[#address{type = replyto, jid = Jid} || Jid <- Jids].
-spec purge_offline(ljid()) -> ok.
purge_offline(LJID) ->
Host = host(element(2, LJID)),
-spec purge_offline(jid()) -> ok.
purge_offline(#jid{lserver = Host} = JID) ->
Plugins = plugins(Host),
Result = lists:foldl(
fun(Type, {Status, Acc}) ->
@@ -4117,7 +4116,7 @@ purge_offline(LJID) ->
andalso lists:member(<<"persistent-items">>, Features),
if Items ->
case node_action(Host, Type,
get_entity_affiliations, [Host, LJID]) of
get_entity_affiliations, [Host, JID]) of
{result, Affs} ->
{Status, [Affs | Acc]};
{error, _} = Err ->
@@ -4138,7 +4137,7 @@ purge_offline(LJID) ->
Purge = (get_option(Options, purge_offline)
andalso get_option(Options, persist_items)),
if (Publisher or Open) and Purge ->
purge_offline(Host, LJID, Node);
purge_offline(Host, JID, Node);
true ->
ok
end
@@ -4147,8 +4146,8 @@ purge_offline(LJID) ->
ok
end.
-spec purge_offline(host(), ljid(), #pubsub_node{}) -> ok | {error, stanza_error()}.
purge_offline(Host, LJID, Node) ->
-spec purge_offline(host(), jid(), #pubsub_node{}) -> ok | {error, stanza_error()}.
purge_offline(Host, #jid{luser = User, lserver = Server, lresource = Resource} = JID, Node) ->
Nidx = Node#pubsub_node.id,
Type = Node#pubsub_node.type,
Options = Node#pubsub_node.options,
@@ -4156,7 +4155,6 @@ purge_offline(Host, LJID, Node) ->
{result, {[], _}} ->
ok;
{result, {Items, _}} ->
{User, Server, Resource} = LJID,
PublishModel = get_option(Options, publish_model),
ForceNotify = get_option(Options, notify_retract),
{_, NodeId} = Node#pubsub_node.nodeid,
@@ -4165,7 +4163,7 @@ purge_offline(Host, LJID, Node) ->
when (U == User) and (S == Server) and (R == Resource) ->
case node_action(Host, Type, delete_item, [Nidx, {U, S, <<>>}, PublishModel, ItemId]) of
{result, {_, broadcast}} ->
broadcast_retract_items(Host, NodeId, Nidx, Type, Options, [ItemId], ForceNotify),
broadcast_retract_items(Host, JID, NodeId, Nidx, Type, Options, [ItemId], ForceNotify),
case get_cached_item(Host, Nidx) of
#pubsub_item{itemid = {ItemId, Nidx}} -> unset_cached_item(Host, Nidx);
_ -> ok
+1 -1
View File
@@ -25,7 +25,7 @@
-module(mod_push).
-author('holger@zedat.fu-berlin.de').
-protocol({xep, 357, '0.2', '17.08', "", ""}).
-protocol({xep, 357, '0.2', '17.08', "complete", ""}).
-behaviour(gen_mod).
+1 -1
View File
@@ -27,7 +27,7 @@
-author('alexey@process-one.net').
-protocol({xep, 77, '2.4'}).
-protocol({xep, 77, '2.4', '0.1.0', "complete", ""}).
-behaviour(gen_mod).
+1 -1
View File
@@ -34,7 +34,7 @@
-module(mod_roster).
-protocol({xep, 237, '1.3'}).
-protocol({xep, 237, '1.3', '2.1.0', "complete", ""}).
-author('alexey@process-one.net').
+6 -2
View File
@@ -84,10 +84,14 @@ s2s_out_unauthenticated_features(#{db_verify := _} = State, _) ->
s2s_out_unauthenticated_features(State, #stream_features{} = Pkt) ->
try xmpp:try_subtag(Pkt, #s2s_bidi{}) of
#s2s_bidi{} ->
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{})
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{});
_ ->
State
catch _:{xmpp_codec, _Why} ->
State
end.
end;
s2s_out_unauthenticated_features(State, _Pkt) ->
State.
s2s_out_packet(#{bidi_enabled := true, ip := {IP, _}} = State, Pkt0)
when ?is_stanza(Pkt0) ->

Some files were not shown because too many files have changed in this diff Show More