Compare commits

..

99 Commits

Author SHA1 Message Date
Badlop bb28265261 Set version to 23.04
Container / Container (push) Failing after 1m47s
Installers / Binaries (push) Failing after 56s
Runtime / Rebars (20.3, rebar) (push) Failing after 3s
Runtime / Rebars (20.3, rebar3) (push) Failing after 3s
Runtime / Rebars (25.3, rebar) (push) Failing after 3s
Runtime / Rebars (25.3, rebar3) (push) Failing after 2s
Runtime / Rebars (26, rebar3) (push) Failing after 1m24s
Installers / Release (push) Has been skipped
CI / Tests (20.0) (push) Has been cancelled
CI / Tests (25.3) (push) Has been cancelled
CI / Tests (26.0-rc3) (push) Has been cancelled
Runtime / Mix (1.10.3, 21.3) (push) Has been cancelled
Runtime / Mix (1.10.3, 22.0) (push) Has been cancelled
Runtime / Mix (1.11.4, 21.3) (push) Has been cancelled
Runtime / Mix (1.11.4, 22.0) (push) Has been cancelled
Runtime / Mix (1.12.3, 22.0) (push) Has been cancelled
Runtime / Mix (1.13.0, 22.0) (push) Has been cancelled
Runtime / Mix (1.13.0, 25.0) (push) Has been cancelled
Runtime / Mix (1.14.0, 25.0) (push) Has been cancelled
2023-04-18 11:39:33 +02:00
Paweł Chmielowski 46f33e5051 Update dependencies 2023-04-18 11:22:33 +02:00
Badlop 06669b12e8 Update changelog 2023-04-18 11:12:18 +02:00
Badlop 1ca126381b Update man 2023-04-18 10:37:22 +02:00
dependabot[bot] bf5de81b24 Bump ex_doc from 0.29.3 to 0.29.4
Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.29.3 to 0.29.4.
- [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.29.3...v0.29.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-18 10:37:16 +02:00
Badlop d717ffd1a0 Update version notes of options and commands 2023-04-18 10:37:14 +02:00
Badlop c271d73dbd CI: Update Erlang/OTP to 26.0-rc3 2023-04-18 10:37:11 +02:00
Badlop e1a8980d6c Container: no need to specify captcha_url, auto may be enough in most cases 2023-04-18 10:37:08 +02:00
Badlop ec7ff88dda Update Portuguese translation (thanks to Silvério Santos) 2023-04-18 10:37:06 +02:00
Badlop 5b695766ae Mention what ejabberd version first supports rtbl 2023-04-18 10:37:04 +02:00
Paweł Chmielowski f5b6909cca Unregister hooks on stop in mod_muc_rbtl 2023-04-17 18:03:21 +02:00
Paweł Chmielowski 98d348893b Make mod_muc_rtbl notify only local node rooms 2023-04-17 17:07:59 +02:00
Paweł Chmielowski c942c31e38 Add mod_muc_rtbl
This implements Real-time blocklists for XMPP (xmppbl.org).

Closes #4017
2023-04-17 16:59:42 +02:00
Paweł Chmielowski 70cbdd1117 Allow to update state from muc_process_iq hook 2023-04-17 16:57:54 +02:00
Paweł Chmielowski 1114a35e0a Recognize message retractions in mod_muc 2023-04-14 12:32:35 +02:00
Paweł Chmielowski d12e5a44b8 Add by attribute to generated muc moderation messages 2023-04-14 12:31:34 +02:00
Badlop 34420444db Container: Revert change in entrypoint that was added in d15cf994a 2023-04-11 15:29:28 +02:00
Badlop 38eb50bf5c Container: Reorganize how to build container image 2023-04-11 15:29:26 +02:00
Badlop 6705679cf3 Container: Update instructions to build image following d15cf994a (#3983) 2023-04-11 15:29:24 +02:00
Badlop 10635bccc9 Container: Reword sentences about docker.io and ghcr.io 2023-04-11 15:29:23 +02:00
Badlop dee0ec50b9 Remove ci-19.3, as Github Actions no longer supports ubuntu-18.04 2023-04-11 15:29:21 +02:00
sando38 401bdedae8 Dockerfile: Detect runtime dependencies automatically
Only libcap2 and tini can't be auto-detected. libcap2 has been renamed in Alpine version 3.17, hence the Dockerfile is not compatible with Alpine versions <3.17
2023-04-11 15:27:49 +02:00
Badlop 99e51a2123 Mention in mod_mam.erl its support for XEP-0425: Message Moderation
Then run "make doap" to regenerate ejabberd.doap
2023-03-30 17:02:54 +02:00
Badlop d43ce53f9a Update xmpp version in mix following commit 6da1bb5b2 2023-03-30 16:54:35 +02:00
Paweł Chmielowski f6385fae50 Fix dialyzer warning 2023-03-30 14:53:51 +02:00
Paweł Chmielowski 6da1bb5b22 Add support for "xep-0424 Message Moderation"
This fixes issue #3730
2023-03-30 14:38:08 +02:00
Badlop 64e1cfcbba Test only with oldest OTP supported, newest stable and bleeding edge 2023-03-28 11:41:57 +02:00
Badlop fbfcebf417 Container: Remove Elixir Matchers to prevent useless warnings in github actions page 2023-03-28 11:41:56 +02:00
Saarko d15cf994a2 Container: Add METHOD to build container using packages (#3983)
make-*: include musl build in make-binaries

Ctr actions: use github runners to provide bootstrap erlang

- adjust make-binaries script to use github runners' installed erlang
  for bootstrapping
- this reduces the need to build an unnecessary toolchain for glibc
  based binaries
2023-03-28 11:41:54 +02:00
Saarko c71887db43 Container: Add tini as runtime init 2023-03-28 11:41:52 +02:00
Badlop 7c634f3615 Container: No need of openssl package at runtime 2023-03-28 11:41:51 +02:00
Badlop 874b961680 Container: Remove unused Mix stuff: ejabberd script and static COOKIE
Instead of including this file in the container with static content:
  /opt/ejabberd-master/releases/COOKIE
the cookie file will be generated by erlang in
  /opt/ejabberd/.erlang.cookie
or by ejabberdctl if ERLANG_COOKIE environment variable was provided.
2023-03-28 11:41:49 +02:00
Badlop 2c1ee698cc Container: Copy captcha scripts to /opt/ejabberd-*/lib like the installers
Instead of a path like
  /opt/ejabberd-master/lib/ejabberd-23.1.0/priv/bin
they are now in
  /opt/ejabberd-master/lib
2023-03-28 11:41:47 +02:00
Badlop b0f0dd3227 Container: Expose only HOME volume, it contains all the required subdirs 2023-03-28 11:41:46 +02:00
Badlop de477f7b6c Container: Update Alpine to 3.17 to get Erlang/OTP 25 and Elixir 1.14 2023-03-28 11:41:44 +02:00
Saarko 440ede313b make-binaries: fix building with erlang/otp v25.x
Signed-off-by: sando38 <sandomir@tutanota.com>
2023-03-28 11:41:43 +02:00
Saarko 976c6c5e41 make-binaries: bump versions, e.g. erlang/otp to 25.3 2023-03-28 11:41:41 +02:00
Badlop 7e6d25314d make-packages: Fix for installers workflow, which didn't find lynx... 2023-03-28 11:41:39 +02:00
Badlop cc5c3f7b2c ejabberdctl: Don't use .../releases/COOKIE, it's no longer included
And slightly clean the .erlang.cookie line
This partially reverts 9c23a7dc3f
2023-03-28 11:41:33 +02:00
Badlop 1d62dc4621 Set roster name from XEP-0172, or the stored one (#1611) 2023-03-28 11:41:27 +02:00
Badlop e2496562f9 Preliminary support to store extra elements in subscription request (#840) 2023-03-28 11:41:24 +02:00
Badlop c4a2f8d64f captcha_url option now accepts 'auto' value, and it's the default 2023-03-22 16:23:41 +01:00
Badlop 6c620f6f43 Remove wrong get_room_history command fields specification 2023-03-22 16:23:37 +01:00
dependabot[bot] af29adb558 Bump ex_doc from 0.29.2 to 0.29.3
Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.29.2 to 0.29.3.
- [Release notes](https://github.com/elixir-lang/ex_doc/releases)
- [Changelog](https://github.com/elixir-lang/ex_doc/blob/v0.29.3/CHANGELOG.md)
- [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.29.2...v0.29.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-22 16:23:33 +01:00
Paweł Chmielowski 3c97775573 Pubsub xdata fields max_item/item_expira/children_max use 'max' not 'infinity'
Codec in xmpp crashes when we use infinity (see issue #4011), so lets
convert those values before passing them to xmpp:encode(0
2023-03-21 15:30:44 +01:00
Blake Miller f953dc3f5e Persist none role for outcasts
`none` roles *should* be persisted for banned users. I totally forgot about this, my bad. I'm shocked nobody else noticed it.
2023-03-20 17:07:10 +01:00
dependabot[bot] 04b431f191 Bump ex_doc from 0.29.1 to 0.29.2
Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.29.1 to 0.29.2.
- [Release notes](https://github.com/elixir-lang/ex_doc/releases)
- [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.29.1...v0.29.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-07 13:11:26 +01:00
Badlop 5cd6c524ea Allow XML to be visible in web browser in Common Test page 2023-03-07 13:11:24 +01:00
Badlop 37676757e3 CI: Add OTP 26.0-rc1 to the test matrix
But disable dialyzer in 26, as it complains verbosely without reason
2023-03-07 13:11:22 +01:00
Badlop 1c82daacb2 CI: Upload Common Test logs as artifact in case of failure 2023-03-07 13:11:21 +01:00
Badlop 9f0a5c5ef0 CI: Produce less verbose logs for tests
This gets a line first introduced in 5b5548b8c that was lost later
2023-03-07 13:11:19 +01:00
Badlop 9bb86132c6 CI: Use default verbosity to let log files contain XMPP stanzas
This partially reverts 2a7780507
2023-03-07 13:11:17 +01:00
Badlop 2137a4f663 Fix Shellcheck warnings in shell scripts 2023-02-21 18:17:26 +01:00
Badlop c9143dd3d8 Fix TSQLlint warnings in MSSQL test script 2023-02-21 18:17:25 +01:00
Badlop 66d58504d0 Fix TSQLlint warning about typo in mssql.new.sql 2023-02-21 18:16:59 +01:00
Badlop 0def333550 Fix Remark-lint warnings 2023-02-21 18:14:02 +01:00
Badlop dea452bdfd Fix Prospector and Pylint warnings in test extauth.py 2023-02-21 18:14:02 +01:00
dependabot[bot] d504ed8a9b Container: Bump docker/build-push-action from 3 to 4
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 18:13:15 +01:00
Paweł Chmielowski 9503beca6c Make mod_muc_room:set_opts process persistent flag first
As processing some other options depends on this setting flag in room
state.
2023-02-20 13:42:52 +01:00
Paweł Chmielowski dfe4884d16 Allow passing affiliations and subscribers to create_room_with_opts command 2023-02-20 13:03:46 +01:00
Paweł Chmielowski f10f6d176f Store state in db in mod_muc:create_room() 2023-02-20 12:56:41 +01:00
Paweł Chmielowski 4e7aa41e3f Make subscribers members by default 2023-02-20 12:55:31 +01:00
Paweł Chmielowski d91812730b Stop ejabberd_system_monitor before stopping node
Sometimes monitor module is performing checks when node is stopping and
this causes crash in monitoring process.
2023-02-08 19:53:19 +01:00
Paweł Chmielowski 54cf37e917 Invalidate vcard_xupdate cache on all nodes when vcard is updated 2023-02-08 19:06:44 +01:00
Paweł Chmielowski 3de803be2f Add get_room_history command in mod_muc_admin 2023-02-08 11:04:26 +01:00
Paweł Chmielowski 5ca59807d9 Fix problem with results of mam queries using rsm with max and before
Plus add test case for it.
2023-02-03 11:37:54 +01:00
Paweł Chmielowski 5c3b43cd63 Update spec 2023-02-01 17:32:22 +01:00
Paweł Chmielowski 1a6baf223c Re-allow anonymous connection for connection without client certificates
This fixes issue #3985. Initial issue was introduced in
5506b838c8 adding tls client cert
authentication.
2023-02-01 16:58:25 +01:00
Paweł Chmielowski 74c9aa8ac0 Merge pull request #3982 from nosnilmot/sql-update-tests
SQL schema migration fixes and testing
2023-02-01 12:03:48 +01:00
Badlop fb16727180 Ammend previous commit with another fix 2023-01-27 15:40:34 +01:00
Badlop 9842b035e3 Fix compilation problem with Erlang/OTP older than 21 introduced recently
Those macros were first introduced in c88a2d0
2023-01-27 15:29:41 +01:00
Alexey Shchepin f6b5a52104 Add s2s_out_bounce_packet hook 2023-01-27 03:54:31 +03:00
Alexey Shchepin f650b1e83c Log HTTP handler exceptions 2023-01-27 03:54:31 +03:00
Badlop 03cbc9b004 Revert previous commit, stick with Alpine 3.16 and Erlang/OTP 24 (#3983)
Alpine 3.17 includes Erlang/OTP 25, and it segfaults when
used in QEMU for arm64.

Revert "Update Alpine to 3.17 to get Elixir 1.14 required by recent libraries"
This reverts commit 43cae922f3.
2023-01-26 14:53:14 +01:00
Badlop 43cae922f3 Update Alpine to 3.17 to get Elixir 1.14 required by recent libraries 2023-01-25 17:58:27 +01:00
Badlop c5c7e7fc4d ext_mod: Improve support for loading *.so files from ext_mod dependencies
Copying files from deps/*/priv/*.so to the ejabberd priv/
is not possible when running ejabberd as OTP release or in a container.
Instead, let's copy the deps/*/priv/*.so maintaining the file structure,
and then using code:add_pathz for those dirs.

This partially reverts 5c1b72853f
2023-01-25 17:58:12 +01:00
Stu Tomlinson 0c1cf43519 Fix a long standing bug in new schema migration
... and make the test that uncovered it explicitly fail (there was already a
TODO) instead of passing but with errors logged
2023-01-21 15:42:43 +00:00
Stu Tomlinson cbbf85c555 Add support for running tests on MS SQL 2023-01-21 15:42:43 +00:00
Stu Tomlinson 56e974ab80 Add ability to run tests on upgraded DB
To test update_sql operation and functionality of resulting DB:

1. Load original schema to DB
2. Set {update_sql, true} in suite.erl
3. Run tests
2023-01-21 15:42:43 +00:00
Stu Tomlinson 9398052b65 New schema migration 'update_sql' improvements
- check that server_host column does not already exist before addding it
  and making other changes to table (update_sql becomes idempotent,
  yay!)
- check that indexes exist before dropping them (some are historical and
  are not created in more recent deployments), elminating spurious
  errors from logs
- update new_sql_schema config after migration, to allow near
  zero-downtime migrations (and help with automated testing)
2023-01-21 14:54:36 +00:00
Stu Tomlinson 6a8899677d Un-deprecate ejabberd_config:set_option/2
There does not appear to be an alternative way to set individual config
options, and this is already used by test/ejabberd_SUITE.erl
2023-01-21 14:54:36 +00:00
Paweł Chmielowski 3b34538038 Remove debug line from last commit 2023-01-20 17:12:50 +01:00
Paweł Chmielowski 6cf1e05993 Try to populate room history from mam when unhibernating 2023-01-20 16:27:08 +01:00
Paweł Chmielowski baf1336761 Merge pull request #3980 from nosnilmot/sql-maintenance
SQL related fixes and updates
2023-01-20 14:18:55 +01:00
Stu Tomlinson 4f0e426a12 Change PostgreSQL SERIAL to BIGSERIAL columns
This is consistent with other schemas, internally consistent with
foreign keys, and allows for > 2B records in these tables.
2023-01-19 23:36:42 +00:00
Stu Tomlinson d5bf051e79 Fix minor SQL schema inconsistencies 2023-01-19 23:36:42 +00:00
Stu Tomlinson c7c982b67b Add MS SQL support for new schema migration 2023-01-19 23:36:42 +00:00
Stu Tomlinson f7f0d3b1fb Enable MySQL support for new schema migration 2023-01-19 23:36:42 +00:00
Stu Tomlinson d4ab4d16e8 Use python3 to run extauth.py for tests 2023-01-19 23:36:42 +00:00
Stu Tomlinson aeed1679d8 Add 'new' schema for MS SQL 2023-01-19 23:36:42 +00:00
Stu Tomlinson 6fc67d83f4 Minor MS SQL improvements
Support 'sql_ssl' option for MS SQL - set Encryption=required and
Encrypt=yes in ODBC connection string to require SSL using default
FreeTDS driver and Microsoft ODBC Driver for SQL Server repectively.

Allow setting full ODBC connection string in 'sql_server' for MS SQL,
allowing custom connection configuration beyond what is possible with
just 'sql_odbc_driver' option.
2023-01-19 23:36:42 +00:00
Stu Tomlinson 06ffe995e1 Remove unnecessary indexes
For columns are already included in a compound index there is no
benefit to having a separate index with a subset of the same columns in
the same order, it just wastes space.
2023-01-19 23:36:42 +00:00
Stu Tomlinson 93bf4d5411 New SQL schema migrate fix
'server_host' column on 'route' table already exists in old schema and
does not need adding for new schema migration.
2023-01-19 23:36:42 +00:00
Stu Tomlinson 19f2f1fa86 Fix MS SQL error caused by ORDER BY in subquery
'The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP, OFFSET
or FOR XML is also specified.'

Omit the ORDER BY clause from subquery if the SELECT is not constrained
by TOP.
2023-01-19 23:36:42 +00:00
Stu Tomlinson 5e94fdcfd5 MS SQL schema fixes
* Add missing 'mix' tables and indexes

* Fix text vs varchar issues

Various tests triggered this error:
The data types text and varchar are incompatible in the equal to operator.

Caused by incompatible 'text' columns in muc_online_room,
muc_online_users, pubsub_node_option, and pubsub_node tables.

* Fix definition of mqtt_pub table

This table incorrectly included 'server_host' column in old schema, and
had other inconsistencies.
2023-01-19 23:35:05 +00:00
Stu Tomlinson ec6f5c17c8 Correct README for creating test docker MS SQL DB 2023-01-19 14:06:11 +00:00
Paweł Chmielowski 758c87f564 Revert notes placement when generating markdown api commands documentation 2023-01-19 13:24:51 +01:00
Paweł Chmielowski b6dde41000 Improve output in gen_html_doc_for_commands command 2023-01-19 11:45:33 +01:00
Stu Tomlinson 648c83ea03 Fix ejabberdctl output formatting (#3979)
ECMA-48 SGR sequence ESC [21m is actually 'set double underline' but was
incorrectly implemented as 'set normal intensity' in Linux prior to
4.17.

The correct sequence for 'set normal intensity' is ESC [22m, which fixes
output formatting of 'ejabberdctl' and 'ejabberdctl help' on macos.
2023-01-19 11:18:59 +01:00
83 changed files with 2771 additions and 1018 deletions
+1 -2
View File
@@ -6,8 +6,7 @@ assignees: ''
---
Before creating a ticket, please consider if this should fit the discussion forum better:
https://github.com/processone/ejabberd/discussions
Before creating a ticket, please consider if this should fit the [discussion forum](https://github.com/processone/ejabberd/discussions) better.
## Environment
+6 -3
View File
@@ -7,17 +7,20 @@ assignees: ''
---
Before creating a ticket, please consider if this should fit the discussion forum better:
https://github.com/processone/ejabberd/discussions
Before creating a ticket, please consider if this should fit the [discussion forum](https://github.com/processone/ejabberd/discussions) better.
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what the problem is. Ex. I'm always frustrated when...
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+138 -83
View File
@@ -1,55 +1,103 @@
FROM alpine:3.16 AS build
ARG VERSION=master
#' Define default build variables
ARG ALPINE_VSN='3.17'
ARG UID='9000'
ARG USER='ejabberd'
ARG HOME="opt/$USER"
ARG METHOD='direct'
ARG BUILD_DIR="/$USER"
ARG VERSION='master'
RUN apk upgrade --update musl \
&& apk add \
autoconf \
automake \
bash \
build-base \
curl \
elixir \
erlang-odbc \
erlang-reltool \
expat-dev \
file \
gd-dev \
git \
jpeg-dev \
libpng-dev \
libwebp-dev \
linux-pam-dev \
openssl \
openssl-dev \
sqlite-dev \
yaml-dev \
zlib-dev
################################################################################
#' METHOD='direct' - build and install ejabberd directly from source
FROM alpine:${ALPINE_VSN} AS direct
RUN apk -U add --no-cache \
autoconf \
automake \
bash \
build-base \
curl \
elixir \
erlang-odbc \
erlang-reltool \
expat-dev \
file \
gd-dev \
git \
jpeg-dev \
libpng-dev \
libwebp-dev \
linux-pam-dev \
openssl-dev \
sqlite-dev \
yaml-dev \
zlib-dev
RUN mix local.hex --force \
&& mix local.rebar --force
COPY . ./ejabberd
WORKDIR ejabberd
ARG BUILD_DIR
COPY / $BUILD_DIR/
WORKDIR $BUILD_DIR
RUN mv .github/container/ejabberdctl.template . \
&& ./autogen.sh \
&& ./configure --with-rebar=mix --enable-all \
&& make deps \
&& make rel
RUN cp -r _build/prod/rel/ejabberd/ /opt/ejabberd-$VERSION \
&& mkdir -p /opt/ejabberd \
&& mv /opt/ejabberd-$VERSION/conf /opt/ejabberd/conf
WORKDIR /rootfs
ARG VERSION
ARG HOME
RUN mkdir -p $HOME $HOME-$VERSION \
&& cp -r $BUILD_DIR/_build/prod/rel/ejabberd/* $HOME-$VERSION \
&& mv $HOME-$VERSION/conf $HOME/conf
RUN BINPATH=$(dirname $(find /opt -name msgs))/bin/ \
&& mkdir -p $BINPATH \
&& cp tools/captcha*.sh $BINPATH
RUN cp -p $BUILD_DIR/tools/captcha*.sh $HOME-$VERSION/lib
RUN [ ! -d .ejabberd-modules ] || cp -r .ejabberd-modules /opt/ejabberd/
RUN find "$HOME-$VERSION/bin" -name 'ejabberd' -delete \
&& find "$HOME-$VERSION/releases" -name 'COOKIE' -delete
RUN export PEM=/opt/ejabberd/conf/server.pem \
&& curl -o "/opt/ejabberd/conf/cacert.pem" 'https://curl.se/ca/cacert.pem' \
RUN wget -O "$HOME/conf/cacert.pem" 'https://curl.se/ca/cacert.pem' \
&& sed -i '/^loglevel:/a \ \
\nca_file: /opt/ejabberd/conf/cacert.pem \
\ncertfiles: \
\n - /opt/ejabberd/conf/server.pem' "$HOME/conf/ejabberd.yml"
################################################################################
#' METHOD='package' - install ejabberd from binary tarball package
FROM alpine:${ALPINE_VSN} AS package
COPY tarballs/ejabberd-*-linux-musl-*.tar.gz /tmp/
WORKDIR /rootfs
ARG HOME
RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \
&& mkdir -p $home_root_dir \
&& ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/') \
&& tar -xzf /tmp/ejabberd-*-linux-musl-$ARCH.tar.gz -C $home_root_dir
################################################################################
#' Prepare ejabberd for runtime
FROM ${METHOD} AS ejabberd
RUN apk -U add --no-cache \
git \
libcap-utils \
openssl
WORKDIR /rootfs
ARG HOME
RUN mkdir -p usr/local/bin $HOME/conf $HOME/database $HOME/logs $HOME/upload
ARG BUILD_DIR
RUN if [ ! -d $HOME/.ejabberd-modules ]; \
then \
if [ -d $BUILD_DIR/.ejabberd-modules ]; \
then cp -r $BUILD_DIR/.ejabberd-modules $HOME; \
else git clone https://github.com/processone/ejabberd-contrib --depth 1 \
$HOME/.ejabberd-modules/sources/ejabberd-contrib; \
fi \
fi
RUN export PEM=$HOME/conf/server.pem \
&& openssl req -x509 \
-batch \
-nodes \
@@ -57,63 +105,70 @@ RUN export PEM=/opt/ejabberd/conf/server.pem \
-keyout $PEM \
-out $PEM \
-days 3650 \
-subj "/CN=localhost" \
&& sed -i '/^loglevel:/a \ \
\nca_file: /opt/ejabberd/conf/cacert.pem \
\ncertfiles: \
\n - /opt/ejabberd/conf/server.pem' "/opt/ejabberd/conf/ejabberd.yml"
-subj "/CN=localhost"
FROM alpine:3.16
ENV HOME=/opt/ejabberd
ARG VERSION=master
RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \
&& setcap 'cap_net_bind_service=+ep' $(find $home_root_dir -name beam.smp) \
&& echo -e \
"#!/bin/sh \
\n[ -z \$ERLANG_NODE_ARG ] && export ERLANG_NODE_ARG=ejabberd@localhost \
\nexport CONFIG_DIR=/$HOME/conf \
\nexport LOGS_DIR=/$HOME/logs \
\nexport SPOOL_DIR=/$HOME/database \
\nexec /$(find $home_root_dir -name ejabberdctl) \"\$@\"" \
> usr/local/bin/ejabberdctl \
&& chmod +x usr/local/bin/* \
&& scanelf --needed --nobanner --format '%n#p' --recursive $home_root_dir \
| tr ',' '\n' | sort -u | awk 'system("[ -e $home_root_dir" $1 " ]") == 0 { next } \
{ print "so:" $1 }' > /tmp/runDeps
RUN apk upgrade --update musl \
&& apk add \
expat \
freetds \
gd \
jpeg \
libgd \
libpng \
libstdc++ \
libwebp \
linux-pam \
ncurses-libs \
openssl \
sqlite \
sqlite-libs \
unixodbc \
yaml \
zlib \
&& ln -fs /usr/lib/libtdsodbc.so.0 /usr/lib/libtdsodbc.so \
&& rm -rf /var/cache/apk/*
ARG UID
RUN chown -R $UID:$UID $HOME
COPY --from=build /opt /opt
RUN echo -e \
"#!/bin/sh \
\n[ -z \$ERLANG_NODE_ARG ] && export ERLANG_NODE_ARG=ejabberd@localhost \
\nexport CONFIG_DIR=/opt/ejabberd/conf \
\nexport LOGS_DIR=/opt/ejabberd/logs \
\nexport SPOOL_DIR=/opt/ejabberd/database \
\nexec /opt/ejabberd-$VERSION/bin/ejabberdctl \"\$@\"" > /usr/local/bin/ejabberdctl \
&& chmod +x /usr/local/bin/ejabberdctl
################################################################################
#' METHOD='package' - install runtime dependencies
FROM alpine:${ALPINE_VSN} AS runtime-package
RUN apk -U upgrade --available --no-cache \
&& apk add --no-cache \
libcap2 \
tini
RUN addgroup ejabberd -g 9000 \
&& adduser -s /bin/sh -D -G ejabberd ejabberd -u 9000 \
&& mkdir -p $HOME/conf $HOME/database $HOME/logs $HOME/upload \
&& chown -R ejabberd:ejabberd $HOME
################################################################################
#' METHOD='direct' - install runtime dependencies
FROM runtime-package AS runtime-direct
COPY --from=ejabberd /tmp/runDeps /tmp/runDeps
RUN apk add --no-cache \
$(cat /tmp/runDeps)
################################################################################
#' Finalize runtime environment
FROM runtime-${METHOD} AS runtime
ARG USER
ARG UID
ARG HOME
RUN addgroup $USER -g $UID \
&& adduser -s /sbin/nologin -D -u $UID -h /$HOME -G $USER $USER
################################################################################
#' Build together production image
FROM scratch AS prod
ARG USER
ARG HOME
COPY --from=runtime / /
COPY --from=ejabberd /rootfs /
HEALTHCHECK \
--interval=1m \
--timeout=5s \
--start-period=5s \
--retries=10 \
CMD /usr/local/bin/ejabberdctl status
CMD ejabberdctl status
WORKDIR $HOME
USER ejabberd
VOLUME ["$HOME/conf", "$HOME/database", "$HOME/logs", "$HOME/upload"]
WORKDIR /$HOME
USER $USER
VOLUME ["/$HOME"]
EXPOSE 1883 4369-4399 5210 5222 5269 5280 5443
ENTRYPOINT ["/usr/local/bin/ejabberdctl"]
ENTRYPOINT ["/sbin/tini","--","/usr/local/bin/ejabberdctl"]
CMD ["foreground"]
+2 -2
View File
@@ -17,8 +17,8 @@ ERTS_VSN="{{erts_vsn}}"
ERL="{{erl}}"
IEX="{{bindir}}/iex"
EPMD="{{epmd}}"
[ -z "$ERLANG_COOKIE" ] && ERL_OPTIONS="-setcookie $(cat "${SCRIPT_DIR%/*}/releases/COOKIE")"
[ -n "$ERLANG_COOKIE" ] && [ ! -f "$HOME"/.erlang.cookie ] && echo "$ERLANG_COOKIE" > "$HOME"/.erlang.cookie && chmod 400 "$HOME"/.erlang.cookie
COOKIE_FILE="$HOME"/.erlang.cookie
[ -n "$ERLANG_COOKIE" ] && [ ! -f "$COOKIE_FILE" ] && echo "$ERLANG_COOKIE" > "$COOKIE_FILE" && chmod 400 "$COOKIE_FILE"
# check the proper system user is used
case $(id -un) in
-229
View File
@@ -1,229 +0,0 @@
name: CI (19.3)
on:
push:
paths-ignore:
- '.devcontainer/**'
- 'examples/**'
- 'lib/**'
- 'man/**'
- 'priv/**'
- '**.md'
pull_request:
paths-ignore:
- '.devcontainer/**'
- 'examples/**'
- 'lib/**'
- 'man/**'
- 'priv/**'
- '**.md'
jobs:
tests:
name: Tests
strategy:
fail-fast: false
matrix:
otp: ['19.3']
runs-on: ubuntu-18.04
services:
redis:
image: redis
ports:
- 6379:6379
steps:
- uses: actions/checkout@v3
- name: Get specific Erlang/OTP
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
- name: Get a compatible Rebar3
run: |
rm rebar3
wget https://github.com/processone/ejabberd/raw/21.12/rebar3
chmod +x rebar3
- name: Prepare databases
run: |
sudo systemctl start mysql.service
sudo systemctl start postgresql.service
mysql -u root -proot -e "CREATE USER 'ejabberd_test'@'localhost'
IDENTIFIED BY 'ejabberd_test';"
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
mysql -u root -proot ejabberd_test < sql/mysql.sql
pg_isready
sudo -u postgres psql -c "CREATE USER ejabberd_test
WITH PASSWORD 'ejabberd_test';"
sudo -u postgres psql -c "CREATE DATABASE ejabberd_test;"
sudo -u postgres psql ejabberd_test -f sql/pg.sql
sudo -u postgres psql -c "GRANT ALL PRIVILEGES
ON DATABASE ejabberd_test TO ejabberd_test;"
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
TABLES IN SCHEMA public
TO ejabberd_test;"
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
SEQUENCES IN SCHEMA public
TO ejabberd_test;"
- 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
- name: Prepare rebar
run: |
echo '{xref_ignores, [{eldap_filter_yecc, return_error, 2}
]}.' >>rebar.config
echo '{xref_checks, [deprecated_function_calls, deprecated_functions,
locals_not_used, undefined_function_calls, undefined_functions]}.
% Disabled: exports_not_used,' >>rebar.config
echo '{dialyzer, [{get_warnings, true}, {plt_extra_apps, [cache_tab,
eimp, epam, esip, ezlib, fast_tls, fast_xml, fast_yaml,
mqtree, p1_acme, p1_mysql, p1_oauth2, p1_pgsql, p1_utils, pkix,
sqlite3, stringprep, stun, xmpp, yconf]} ]}.' >>rebar.config
echo '{ct_extra_params, "-verbosity 20"}.' >>rebar.config
echo "{ct_opts, [{verbosity, 20}, {keep_logs, 20}]}." >>rebar.config
- name: Remove syntax_tools from release
run: sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
- name: Cache rebar
uses: actions/cache@v3
with:
path: |
~/.cache/rebar3/
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
- name: Compile
run: |
./autogen.sh
./configure --with-rebar=./rebar3 \
--prefix=/tmp/ejabberd \
--enable-all \
--disable-elixir \
--disable-mssql \
--disable-odbc
make update
make
- run: make install -s
- run: make hooks
- run: make options
- run: make xref
- run: make dialyzer
- name: Check Production Release
run: |
make rel
RE=_build/prod/rel/ejabberd
$RE/bin/ejabberdctl start
$RE/bin/ejabberdctl started
$RE/bin/ejabberdctl stop
$RE/bin/ejabberdctl stopped
cat $RE/logs/ejabberd.log
grep -q "is stopped in" $RE/logs/ejabberd.log
- name: Check Development Release
run: |
make dev
RE=_build/dev/rel/ejabberd
$RE/bin/ejabberdctl start
$RE/bin/ejabberdctl started
$RE/bin/ejabberdctl stop
$RE/bin/ejabberdctl stopped
cat $RE/logs/ejabberd.log
grep -q "is stopped in" $RE/logs/ejabberd.log
- name: Run tests
id: ct
run: |
(cd priv && ln -sf ../sql)
COMMIT=`echo $GITHUB_SHA | cut -c 1-7`
DATE=`date +%s`
REF_NAME=`echo $GITHUB_REF_NAME | tr "/" "_"`
NODENAME=$DATE@$GITHUB_RUN_NUMBER-$GITHUB_ACTOR-$REF_NAME-$COMMIT
LABEL=`git show -s --format=%s | cut -c 1-30`
./rebar3 ct --name $NODENAME --label "$LABEL"
./rebar3 cover
- name: Check results
if: always() && (steps.ct.outcome != 'skipped' || steps.ct2.outcome != 'skipped')
id: ctresults
run: |
[[ -d _build ]] && ln -s _build/test/logs/last/ logs || true
ln `find logs/ -name suite.log` logs/suite.log
grep 'TEST COMPLETE' logs/suite.log
grep -q 'TEST COMPLETE,.* 0 failed' logs/suite.log
test $(find logs/ -empty -name error.log)
- name: View logs failures
if: failure() && steps.ctresults.outcome == 'failure'
run: |
cat logs/suite.log | awk \
'BEGIN{RS="\n=case";FS="\n"} /=result\s*failed/ {print "=case" $0}'
find logs/ -name error.log -exec cat '{}' ';'
find logs/ -name exunit.log -exec cat '{}' ';'
- name: Upload test logs
if: always() && steps.ct.outcome == 'failure' && github.repository == 'processone/ejabberd'
uses: peaceiris/actions-gh-pages@v3
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: Prepare new schema
run: |
[[ -d logs ]] && rm -rf logs
[[ -d _build/test/logs ]] && rm -rf _build/test/logs || true
mysql -u root -proot -e "DROP DATABASE ejabberd_test;"
sudo -u postgres psql -c "DROP DATABASE ejabberd_test;"
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
mysql -u root -proot ejabberd_test < sql/mysql.new.sql
sudo -u postgres psql -c "CREATE DATABASE ejabberd_test;"
sudo -u postgres psql ejabberd_test -f sql/pg.new.sql
sudo -u postgres psql -c "GRANT ALL PRIVILEGES
ON DATABASE ejabberd_test TO ejabberd_test;"
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
TABLES IN SCHEMA public
TO ejabberd_test;"
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
SEQUENCES IN SCHEMA public
TO ejabberd_test;"
sed -i 's|new_schema, false|new_schema, true|g' test/suite.erl
- run: CT_BACKENDS=mysql,pgsql make test
id: ctnewschema
- name: Check results
if: always() && steps.ctnewschema.outcome != 'skipped'
run: |
[[ -d _build ]] && ln -s _build/test/logs/last/ logs || true
ln `find logs/ -name suite.log` logs/suite.log
grep 'TEST COMPLETE' logs/suite.log
grep -q 'TEST COMPLETE,.* 0 failed' logs/suite.log
test $(find logs/ -empty -name error.log)
- name: View logs failures
if: failure() && steps.ctnewschema.outcome != 'skipped'
run: |
cat logs/suite.log | awk \
'BEGIN{RS="\n=case";FS="\n"} /=result\s*failed/ {print "=case" $0}'
find logs/ -name error.log -exec cat '{}' ';'
find logs/ -name exunit.log -exec cat '{}' ';'
+81 -14
View File
@@ -25,7 +25,7 @@ jobs:
strategy:
fail-fast: false
matrix:
otp: ['20.0', '21.3', '24.3', '25']
otp: ['20.0', '25.3', '26.0-rc3']
runs-on: ubuntu-20.04
services:
redis:
@@ -38,7 +38,7 @@ jobs:
- uses: actions/checkout@v3
- name: Test shell scripts
if: matrix.otp == 25
if: matrix.otp == '25.3'
run: |
shellcheck test/ejabberd_SUITE_data/gencerts.sh
shellcheck tools/captcha.sh
@@ -46,7 +46,7 @@ jobs:
shellcheck -x ejabberdctl.template
- name: Get specific Erlang/OTP
if: matrix.otp != 25
if: matrix.otp != '25.3'
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
@@ -58,23 +58,34 @@ jobs:
wget https://github.com/processone/ejabberd/raw/21.12/rebar3
chmod +x rebar3
- name: Install MS SQL Server
run: |
docker run -d -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=ejabberd_Test1" \
-v $(pwd)/test/docker/db/mssql/initdb/initdb_mssql.sql:/initdb_mssql.sql:ro \
-v $(pwd)/sql/mssql.sql:/mssql.sql:ro \
-v $(pwd)/sql/mssql.new.sql:/mssql.new.sql:ro \
-p 1433:1433 --name ejabberd-mssql "mcr.microsoft.com/mssql/server:2019-latest"
sleep 10
- name: Prepare databases
run: |
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
sudo systemctl start mysql.service
sudo systemctl start postgresql.service
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "CREATE USER 'ejabberd_test'@'localhost'
IDENTIFIED BY 'ejabberd_test';"
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
mysql -u root -proot ejabberd_test < sql/mysql.sql
mysql -u ejabberd_test -pejabberd_test ejabberd_test < sql/mysql.sql
pg_isready
sudo -u postgres psql -c "CREATE DATABASE ejabberd_test;"
sudo -u postgres psql -c "CREATE USER ejabberd_test
WITH PASSWORD 'ejabberd_test';"
sudo -u postgres psql -c "CREATE DATABASE ejabberd_test;"
sudo -u postgres psql ejabberd_test -f sql/pg.sql
sudo -u postgres psql -c "GRANT ALL PRIVILEGES
ON DATABASE ejabberd_test TO ejabberd_test;"
PGPASSWORD="ejabberd_test" psql -h localhost -U ejabberd_test ejabberd_test -f sql/pg.sql
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
TABLES IN SCHEMA public
TO ejabberd_test;"
@@ -100,8 +111,7 @@ jobs:
eimp, epam, esip, ezlib, fast_tls, fast_xml, fast_yaml,
mqtree, p1_acme, p1_mysql, p1_oauth2, p1_pgsql, p1_utils, pkix,
sqlite3, stringprep, stun, xmpp, yconf]} ]}.' >>rebar.config
echo '{ct_extra_params, "-verbosity 20"}.' >>rebar.config
echo "{ct_opts, [{verbosity, 20}, {keep_logs, 20}]}." >>rebar.config
echo "{ct_opts, [{keep_logs, 20}]}." >>rebar.config
- name: Remove syntax_tools from release
run: sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
@@ -114,7 +124,7 @@ jobs:
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
- name: Download test logs
if: matrix.otp == 25 && github.repository == 'processone/ejabberd'
if: matrix.otp == '25.3' && github.repository == 'processone/ejabberd'
continue-on-error: true
run: |
mkdir -p _build/test
@@ -139,6 +149,7 @@ jobs:
- run: make options
- run: make xref
- run: make dialyzer
if: matrix.otp != '26.0-rc3'
- name: Check Production Release
run: |
@@ -166,6 +177,7 @@ jobs:
id: ct
run: |
(cd priv && ln -sf ../sql)
sed -i -e 's/ct:pal/ct:log/' test/suite.erl
COMMIT=`echo $GITHUB_SHA | cut -c 1-7`
DATE=`date +%s`
REF_NAME=`echo $GITHUB_REF_NAME | tr "/" "_"`
@@ -193,7 +205,7 @@ jobs:
find logs/ -name exunit.log -exec cat '{}' ';'
- name: Send to coveralls
if: matrix.otp == 25
if: matrix.otp == '25.3'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
@@ -221,20 +233,60 @@ jobs:
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@v2
id: filter
with:
filters: |
sql:
- 'sql/**'
- 'src/mod_admin_update_sql.erl'
- name: Prepare for schema upgrade test
id: prepupgradetest
if: ${{ steps.filter.outputs.sql == 'true' }}
run: |
[[ -d logs ]] && rm -rf logs
[[ -d _build/test/logs ]] && rm -rf _build/test/logs || true
sed -i 's|update_sql, false|update_sql, true|g' test/suite.erl
- name: Run DB tests on upgraded schema (mssql, mysql, pgsql)
run: CT_BACKENDS=mssql,mysql,pgsql make test
if: always() && steps.prepupgradetest.outcome != 'skipped'
id: ctupgradedschema
- name: Check results
if: always() && steps.ctupgradedschema.outcome != 'skipped'
run: |
[[ -d _build ]] && ln -s _build/test/logs/last/ logs || true
ln `find logs/ -name suite.log` logs/suite.log
grep 'TEST COMPLETE' logs/suite.log
grep -q 'TEST COMPLETE,.* 0 failed' logs/suite.log
test $(find logs/ -empty -name error.log)
- name: View logs failures
if: failure() && steps.ctupgradedschema.outcome != 'skipped'
run: |
cat logs/suite.log | awk \
'BEGIN{RS="\n=case";FS="\n"} /=result\s*failed/ {print "=case" $0}'
find logs/ -name error.log -exec cat '{}' ';'
find logs/ -name exunit.log -exec cat '{}' ';'
- name: Prepare new schema
run: |
[[ -d logs ]] && rm -rf logs
[[ -d _build/test/logs ]] && rm -rf _build/test/logs || true
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
mysql -u root -proot -e "DROP DATABASE ejabberd_test;"
sudo -u postgres psql -c "DROP DATABASE ejabberd_test;"
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
mysql -u root -proot ejabberd_test < sql/mysql.new.sql
mysql -u ejabberd_test -pejabberd_test ejabberd_test < sql/mysql.new.sql
sudo -u postgres psql -c "CREATE DATABASE ejabberd_test;"
sudo -u postgres psql ejabberd_test -f sql/pg.new.sql
sudo -u postgres psql -c "GRANT ALL PRIVILEGES
ON DATABASE ejabberd_test TO ejabberd_test;"
PGPASSWORD="ejabberd_test" psql -h localhost -U ejabberd_test ejabberd_test -f sql/pg.new.sql
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
TABLES IN SCHEMA public
TO ejabberd_test;"
@@ -242,7 +294,8 @@ jobs:
SEQUENCES IN SCHEMA public
TO ejabberd_test;"
sed -i 's|new_schema, false|new_schema, true|g' test/suite.erl
- run: CT_BACKENDS=mysql,pgsql make test
- name: Run DB tests on new schema (mssql, mysql, pgsql)
run: CT_BACKENDS=mssql,mysql,pgsql make test
id: ctnewschema
- name: Check results
if: always() && steps.ctnewschema.outcome != 'skipped'
@@ -259,3 +312,17 @@ jobs:
'BEGIN{RS="\n=case";FS="\n"} /=result\s*failed/ {print "=case" $0}'
find logs/ -name error.log -exec cat '{}' ';'
find logs/ -name exunit.log -exec cat '{}' ';'
- name: Upload CT logs
if: failure()
uses: actions/upload-artifact@v3
with:
name: ejabberd-ct-logs-${{matrix.otp}}
#
# Appending the wildcard character ("*") is a trick to make
# "ejabberd-packages" the root directory of the uploaded ZIP file:
#
# https://github.com/actions/upload-artifact#upload-using-multiple-paths-and-exclusions
#
path: _build/test/logs
retention-days: 14
+50 -2
View File
@@ -1,6 +1,8 @@
name: Container
on:
schedule:
- cron: '22 2 */6 * *' # every 6 days to avoid gha cache being evicted
push:
paths-ignore:
- '.devcontainer/**'
@@ -21,12 +23,57 @@ jobs:
permissions:
packages: write
steps:
- name: Check out repository code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache build directory
uses: actions/cache@v3
with:
path: ~/build/
key: ${{runner.os}}-ctr-ct-ng-1.25.0
- name: Get erlang/OTP version for bootstrapping
run: |
echo "OTP_VSN=$(awk '/^otp_vsn=/ {{gsub(/[^0-9.]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV
echo "ELIXIR_VSN=$(awk '/^elixir_vsn=/ {{gsub(/[^0-9.]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV
- name: Install prerequisites
run: |
sudo apt-get -qq update
sudo apt-get -qq install makeself
# https://github.com/crosstool-ng/crosstool-ng/blob/master/testing/docker/ubuntu21.10/Dockerfile
sudo apt-get -qq install build-essential autoconf bison flex gawk
sudo apt-get -qq install help2man libncurses5-dev libtool libtool-bin
sudo apt-get -qq install python3-dev texinfo unzip
- name: Install erlang/OTP
uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VSN }}
elixir-version: ${{ env.ELIXIR_VSN }}
version-type: strict
- name: Remove Elixir Matchers
run: |
echo "::remove-matcher owner=elixir-mixCompileWarning::"
echo "::remove-matcher owner=elixir-credoOutputDefault::"
echo "::remove-matcher owner=elixir-mixCompileError::"
echo "::remove-matcher owner=elixir-mixTestFailure::"
echo "::remove-matcher owner=elixir-dialyzerOutputDefault::"
- name: Build musl-libc based binary archives
run: |
sed -i "s|targets='.*'|targets='x86_64-linux-musl aarch64-linux-musl'|" tools/make-binaries
mv .github/container/ejabberdctl.template .
CHECK_DEPS=false tools/make-binaries
- name: Collect packages
run: |
mkdir tarballs
mv ejabberd-*.tar.gz tarballs
- name: Checkout ejabberd-contrib
uses: actions/checkout@v3
with:
@@ -61,9 +108,10 @@ jobs:
uses: docker/setup-buildx-action@v2
- name: Build and push Docker image
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
with:
build-args: |
METHOD=package
VERSION=${{ steps.gitdescribe.outputs.ver }}
cache-from: type=gha
cache-to: type=gha,mode=max
+4 -1
View File
@@ -31,8 +31,11 @@ jobs:
strategy:
fail-fast: false
matrix:
otp: ['19.3', '20.3', '24.3', '25']
otp: ['20.3', '25.3', '26']
rebar: ['rebar', 'rebar3']
exclude:
- otp: '26'
rebar: 'rebar'
runs-on: ubuntu-latest
container:
image: erlang:${{ matrix.otp }}
+87 -3
View File
@@ -1,3 +1,87 @@
# Version 23.04
General:
- New `s2s_out_bounce_packet` hook
- Re-allow anonymous connection for connection without client certificates ([#3985](https://github.com/processone/ejabberd/issues/3985))
- Stop `ejabberd_system_monitor` before stopping node
- `captcha_url` option now accepts `auto` value, and it's the default
- `mod_mam`: Add support for XEP-0425: Message Moderation
- `mod_mam_sql`: Fix problem with results of mam queries using rsm with max and before
- `mod_muc_rtbl`: New module for Real-Time Block List for MUC rooms ([#4017](https://github.com/processone/ejabberd/issues/4017))
- `mod_roster`: Set roster name from XEP-0172, or the stored one ([#1611](https://github.com/processone/ejabberd/issues/1611))
- `mod_roster`: Preliminary support to store extra elements in subscription request ([#840](https://github.com/processone/ejabberd/issues/840))
- `mod_pubsub`: Pubsub xdata fields `max_item/item_expira/children_max` use `max` not `infinity`
- `mod_vcard_xupdate`: Invalidate `vcard_xupdate` cache on all nodes when vcard is updated
Admin:
- `ext_mod`: Improve support for loading `*.so` files from `ext_mod` dependencies
- Improve output in `gen_html_doc_for_commands` command
- Fix ejabberdctl output formatting ([#3979](https://github.com/processone/ejabberd/issues/3979))
- Log HTTP handler exceptions
MUC:
- New command `get_room_history`
- Persist `none` role for outcasts
- Try to populate room history from mam when unhibernating
- Make `mod_muc_room:set_opts` process persistent flag first
- Allow passing affiliations and subscribers to `create_room_with_opts` command
- Store state in db in `mod_muc:create_room()`
- Make subscribers members by default
SQL schemas:
- Fix a long standing bug in new schema migration
- `update_sql` command: Many improvements in new schema migration
- `update_sql` command: Add support to migrate MySQL too
- Change PostgreSQL SERIAL to BIGSERIAL columns
- Fix minor SQL schema inconsistencies
- Remove unnecessary indexes
- New SQL schema migrate fix
MS SQL:
- MS SQL schema fixes
- Add `new` schema for MS SQL
- Add MS SQL support for new schema migration
- Minor MS SQL improvements
- Fix MS SQL error caused by `ORDER BY` in subquery
SQL Tests:
- Add support for running tests on MS SQL
- Add ability to run tests on upgraded DB
- Un-deprecate `ejabberd_config:set_option/2`
- Use python3 to run `extauth.py` for tests
- Correct README for creating test docker MS SQL DB
- Fix TSQLlint warnings in MSSQL test script
Testing:
- Fix Shellcheck warnings in shell scripts
- Fix Remark-lint warnings
- Fix Prospector and Pylint warnings in test `extauth.py`
- Stop testing ejabberd with Erlang/OTP 19.3, as Github Actions no longer supports ubuntu-18.04
- Test only with oldest OTP supported (20.0), newest stable (25.3) and bleeding edge (26.0-rc2)
- Upload Common Test logs as artifact in case of failure
`ecs` container image:
- Update Alpine to 3.17 to get Erlang/OTP 25 and Elixir 1.14
- Add `tini` as runtime init
- Set `ERLANG_NODE` fixed to `ejabberd@localhost`
- Upload images as artifacts to Github Actions
- Publish tag images automatically to ghcr.io
`ejabberd` container image:
- Update Alpine to 3.17 to get Erlang/OTP 25 and Elixir 1.14
- Add `METHOD` to build container using packages ([#3983](https://github.com/processone/ejabberd/issues/3983))
- Add `tini` as runtime init
- Detect runtime dependencies automatically
- Remove unused Mix stuff: ejabberd script and static COOKIE
- Copy captcha scripts to `/opt/ejabberd-*/lib` like the installers
- Expose only `HOME` volume, it contains all the required subdirs
- ejabberdctl: Don't use `.../releases/COOKIE`, it's no longer included
Installers:
- make-binaries: Bump versions, e.g. erlang/otp to 25.3
- make-binaries: Fix building with erlang/otp v25.x
- make-packages: Fix for installers workflow, which didn't find lynx
# Version 23.01
General:
@@ -486,7 +570,7 @@ Translations:
changed to logging disabled
- Increase default shaper limits (this should help with delays for
clients that are using jingle)
- Fix couple compatibility problems which prevented working on
- Fix couple compatibility problems which prevented working on
erlang R19
- Fix sending presence unavailable when session terminates for
clients that only send directed presences (helps with sometimes
@@ -501,7 +585,7 @@ Translations:
- Add support of ssl connection when connection to mysql
database (configured with `sql_ssl: true` option)
- Experimental support for cockroachdb when configured
with postgres connector
with postgres connector
- Add cache and optimize queries issued by `mod_shared_roster`,
this should greatly improve performance of this module when
used with `sql` backend
@@ -798,6 +882,6 @@ Translations:
# Version 18.12
* MAM data store compression
* Proxy protocol support (http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
* Proxy protocol support
* MUC Self-Ping optimization (XEP-0410)
* Bookmarks conversion (XEP-0411)
+1 -1
View File
@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at conduct@process-one.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at the email address: conduct AT process-one.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+11 -11
View File
@@ -15,20 +15,20 @@ Requirements
To compile ejabberd you need:
- GNU Make
- GCC
- Libexpat ≥ 1.95
- Libyaml ≥ 0.1.4
- Erlang/OTP ≥ 19.3
- OpenSSL ≥ 1.0.0
- GNU Make
- GCC
- Libexpat ≥ 1.95
- Libyaml ≥ 0.1.4
- Erlang/OTP ≥ 19.3
- OpenSSL ≥ 1.0.0
Other optional libraries are:
- Zlib ≥ 1.2.3, for Stream Compression support (XEP-0138)
- PAM library, for Pluggable Authentication Modules (PAM)
- ImageMagick's Convert program and Ghostscript fonts, for CAPTCHA
challenges
- Elixir ≥ 1.10.3, to support Elixir, and alternative to rebar/rebar3
- Zlib ≥ 1.2.3, for Stream Compression support (XEP-0138)
- PAM library, for Pluggable Authentication Modules (PAM)
- ImageMagick's Convert program and Ghostscript fonts, for CAPTCHA
challenges
- Elixir ≥ 1.10.3, to support Elixir, and alternative to rebar/rebar3
If your system splits packages in libraries and development headers,
install the development packages too.
+52 -28
View File
@@ -17,17 +17,16 @@ that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service.
[mqtt]: https://mqtt.org/
[sip]: https://en.wikipedia.org/wiki/Session_Initiation_Protocol
This document explains how to use the
[ejabberd container images](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
available in the GitHub Container Registry,
This document explains how to use the `ejabberd` container image available in
[ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd),
built using the files in `.github/container/`.
Alternatively, there are also
[ejabberd-ecs Docker images](https://hub.docker.com/r/ejabberd/ecs/)
available in Docker Hub,
Alternatively, there is also the `ecs` container image available in
[docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/),
built using the
[docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs)
repository.
Check the [differences between `ejabberd` and `ecs` images](https://github.com/processone/docker-ejabberd/blob/master/ecs/HUB-README.md#alternative-image-in-github).
If you are using a Windows operating system, check the tutorials mentioned in
[ejabberd Docs > Docker Image](https://docs.ejabberd.im/admin/installation/#docker-image).
@@ -154,10 +153,9 @@ Now update your ejabberd configuration file, for example:
docker exec -it ejabberd vi conf/ejabberd.yml
```
and add the required options:
```
captcha_cmd: /opt/ejabberd-22.04/lib/ejabberd-22.04/priv/bin/captcha.sh
captcha_url: https://localhost:5443/captcha
and add this option:
```yaml
captcha_cmd: /opt/ejabberd-22.04/lib/captcha.sh
```
Finally, reload the configuration file or restart the container:
@@ -165,6 +163,18 @@ Finally, reload the configuration file or restart the container:
docker exec ejabberd ejabberdctl reload_config
```
If the CAPTCHA image is not visible, there may be a problem generating it
(the ejabberd log file may show some error message);
or the image URL may not be correctly detected by ejabberd,
in that case you can set the correct URL manually, for example:
```yaml
captcha_url: https://localhost:5443/captcha
```
For more details about CAPTCHA options, please check the
[CAPTCHA](https://docs.ejabberd.im/admin/configuration/basic/#captcha)
documentation section.
Advanced Container Configuration
================================
@@ -206,7 +216,7 @@ explains how to install an additional module using docker-compose.
## Commands on start
The ejabberdctl script reads the `CTL_ON_CREATE` environment variable
the first time the docker container is started,
the first time the container is started,
and reads `CTL_ON_START` every time the container is started.
Those variables can contain one ejabberdctl command,
or several commands separated with the blankspace and `;` characters.
@@ -259,11 +269,10 @@ Example using environment variables (see full example [docker-compose.yml](https
```
Generating a Container Image
============================
Build a Container Image
=======================
This container image includes ejabberd as a standalone OTP release built using Elixir.
That OTP release is configured with:
- `mix.exs`: Customize ejabberd release
@@ -271,27 +280,18 @@ That OTP release is configured with:
- `config/runtime.exs`: Customize ejabberd paths
- `ejabberd.yml.template`: ejabberd default config file
Build ejabberd Community Server base image from ejabberd master on GitHub:
## Direct build
Build ejabberd Community Server container image from ejabberd master git repository:
```bash
docker build \
docker buildx build \
-t personal/ejabberd \
-f .github/container/Dockerfile \
.
```
Build ejabberd Community Server base image for a given ejabberd version,
both for amd64 and arm64 architectures:
```bash
VERSION=22.05
git checkout $VERSION
docker buildx build \
--platform=linux/amd64,linux/arm64
-t personal/ejabberd:$VERSION \
-f .github/container/Dockerfile \
.
```
## Podman build
It's also possible to use podman instead of docker, just notice:
- `EXPOSE 4369-4399` port range is not supported, remove that in Dockerfile
@@ -312,6 +312,30 @@ podman exec -it eja1 sh
podman stop eja1
```
## Package build for `arm64`
By default, `.github/container/Dockerfile` builds this container by directly compiling ejabberd,
it is a fast and direct method.
However, a problem with QEMU prevents building the container in QEMU using Erlang/OTP 25
for the `arm64` architecture.
Providing `--build-arg METHOD=package` is an alternate method to build the container
used by the Github Actions workflow that provides `amd64` and `arm64` container images.
It first builds an ejabberd binary package, and later installs it in the image.
That method avoids using QEMU, so it can build `arm64` container images, but is extremely
slow the first time it's used, and consequently not recommended for general use.
In this case, to build the ejabberd container image for arm64 architecture:
```bash
docker buildx build \
--build-arg METHOD=package \
--platform linux/arm64 \
-t personal/ejabberd:$VERSION \
-f .github/container/Dockerfile \
.
```
Composer Examples
=================
+2 -3
View File
@@ -34,9 +34,9 @@ To save your and our time, we will systematically close all issues that are requ
support and redirect people to the section you are reading right now.
Other channels for support are:
- [ejabberd Mailing List][list]
- [ejabberd XMPP room][muc]: ejabberd@conference.process-one.net
- ejabberd XMPP room: [ejabberd@conference.process-one.net][muc]
- [ejabberd XMPP room logs][logs]
- [ejabberd Mailing List][list]
### <a name="issue"></a> Found an Issue or Bug?
@@ -147,4 +147,3 @@ gives us the option to relicense the code with a more permissive license in the
[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
[license]: https://github.com/processone/ejabberd/blob/master/COPYING
+2 -3
View File
@@ -73,7 +73,7 @@ or in your local machine as explained in [Localization][localization].
Documentation for developers is available in [ejabberd docs: Developers][docs-dev].
Security reports or concerns should preferably be reported privately,
please send an email to the address: contact [at] process-one [dot] net
please send an email to the address: contact at process-one dot net
or some other method from [ProcessOne Contact][p1contact].
For commercial offering and support, including [ejabberd Business Edition][p1home]
@@ -85,7 +85,7 @@ Community
There are several places to get in touch with other ejabberd developers and administrators:
- [ejabberd XMPP chatroom][muc]: ejabberd@conference.process-one.net
- ejabberd XMPP chatroom: [ejabberd@conference.process-one.net][muc]
- [Mailing list][list]
- [GitHub Discussions][discussions]
- [Stack Overflow][stackoverflow]
@@ -105,7 +105,6 @@ and [ejabberd translations](https://github.com/processone/ejabberd-po/) under MI
[erlang]: https://www.erlang.org/
[features]: https://docs.ejabberd.im/admin/introduction/
[fluux]: https://fluux.io/
[github]: https://github.com/processone/ejabberd
[homebrew]: https://docs.ejabberd.im/admin/installation/#homebrew
[hubecs]: https://hub.docker.com/r/ejabberd/ecs/
[im]: https://ejabberd.im/
+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 23.01` | 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 23.04` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
REQUIRE_ERLANG_MIN="8.3 (Erlang/OTP 19.3)"
REQUIRE_ERLANG_MAX="100.0.0 (No Max)"
+9
View File
@@ -665,6 +665,15 @@
<xmpp:note>mod_private</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0425.html"/>
<xmpp:version>0.2.1</xmpp:version>
<xmpp:since>23.04</xmpp:since>
<xmpp:status></xmpp:status>
<xmpp:note>mod_mam</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0441.html"/>
+70 -19
View File
@@ -2,12 +2,12 @@
.\" Title: ejabberd.yml
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\" Date: 01/16/2023
.\" Date: 04/17/2023
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "EJABBERD\&.YML" "5" "01/16/2023" "\ \&" "\ \&"
.TH "EJABBERD\&.YML" "5" "04/17/2023" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -82,7 +82,7 @@ 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/23\&.01/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/23\&.04/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"
@@ -566,7 +566,13 @@ A maximum number of items (not memory!) in cache\&. The rule of thumb, for all t
.RS 4
Full path to a script that generates
CAPTCHA
images\&. @VERSION@ is replaced with ejabberd version number in XX\&.YY format\&. @SEMVER@ is replaced with ejabberd version number in semver format when compiled with Elixir\(cqs mix, or XX\&.YY format otherwise\&. Alternatively, it can be the name of a module that implements ejabberd CAPTCHA support\&. There is no default value: when this option is not set, CAPTCHA functionality is completely disabled\&.
images\&.
\fI@VERSION@\fR
is replaced with ejabberd version number in
\fIXX\&.YY\fR
format\&.
\fI@SEMVER@\fR
is replaced with ejabberd version number in semver format when compiled with Elixir\(cqs mix, or XX\&.YY format otherwise\&. Alternatively, it can be the name of a module that implements ejabberd CAPTCHA support\&. There is no default value: when this option is not set, CAPTCHA functionality is completely disabled\&.
.sp
When using the ejabberd installers or container image, the example captcha scripts can be used like this:
.sp
@@ -595,8 +601,10 @@ CAPTCHA
generated images per minute for any given JID\&. The option is intended to protect the server from CAPTCHA DoS\&. The default value is
\fIinfinity\fR\&.
.RE
.sp
\fINote\fR about the next option: improved in 23\&.04:
.PP
\fBcaptcha_url\fR: \fIURL\fR
\fBcaptcha_url\fR: \fIURL | auto | undefined\fR
.RS 4
An URL where
CAPTCHA
@@ -604,7 +612,14 @@ requests should be sent\&. NOTE: you need to configure
\fIrequest_handlers\fR
for
\fIejabberd_http\fR
listener as well\&. There is no default value\&.
listener as well\&. If set to
\fIauto\fR, it builds the URL using a
\fIrequest_handler\fR
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
\fIauto\fR\&.
.RE
.PP
\fBcertfiles\fR: \fI[Path, \&.\&.\&.]\fR
@@ -1100,7 +1115,7 @@ This option can be used to tune tick time parameter of
Whether to use
\fInew\fR
SQL schema\&. All schemas are located at
https://github\&.com/processone/ejabberd/tree/23\&.01/sql\&. There are two schemas available\&. The default legacy schema allows to store one XMPP domain into one ejabberd database\&. The
https://github\&.com/processone/ejabberd/tree/23\&.04/sql\&. There are two schemas available\&. The default legacy schema allows to store one XMPP domain into one ejabberd database\&. The
\fInew\fR
schema allows to handle several XMPP domains in a single ejabberd database\&. Using this
\fInew\fR
@@ -1216,7 +1231,7 @@ percents\&.
.RS 4
Specify which address families to try, in what order\&. The default is
\fI[ipv6, ipv4]\fR
which means it first tries connecting with IPv6, if that fails it tries using IPv4\&.This option is obsolete and irrelevant when using ejabberd 23\&.01 and Erlang/OTP 22, or newer versions of them\&.
which means it first tries connecting with IPv6, if that fails it tries using IPv4\&. This option is obsolete and irrelevant when using ejabberd 23\&.01 and Erlang/OTP 22, or newer versions of them\&.
.RE
.sp
\fINote\fR about the next option: added in 20\&.12:
@@ -1660,10 +1675,13 @@ An interval to make a dummy SQL request to keep alive the connections to the dat
.PP
\fBsql_odbc_driver\fR: \fIPath\fR
.RS 4
Path to the ODBC driver to use to connect to a Microsoft SQL Server database\&. This option is only valid if the
Path to the ODBC driver to use to connect to a Microsoft SQL Server database\&. This option only applies if the
\fIsql_type\fR
option is set to
\fImssql\fR\&. The default value is:
\fImssql\fR
and
\fIsql_server\fR
is not an ODBC connection string\&. The default value is:
\fIlibtdsodbc\&.so\fR
.RE
.PP
@@ -1719,7 +1737,12 @@ if the latter is not set\&.
.PP
\fBsql_server\fR: \fIHost\fR
.RS 4
A hostname or an IP address of the SQL server\&. The default value is
The hostname or IP address of the SQL server\&. For
\fIsql_type\fR
\fImssql\fR
or
\fIodbc\fR
this can also be an ODBC connection string\&. The default value is
\fIlocalhost\fR\&.
.RE
.sp
@@ -1727,7 +1750,7 @@ A hostname or an IP address of the SQL server\&. The default value is
.PP
\fBsql_ssl\fR: \fItrue | false\fR
.RS 4
Whether to use SSL encrypted connections to the SQL server\&. The option is only available for MySQL and PostgreSQL\&. The default value is
Whether to use SSL encrypted connections to the SQL server\&. The option is only available for MySQL, MS SQL and PostgreSQL\&. The default value is
\fIfalse\fR\&.
.RE
.PP
@@ -1738,7 +1761,7 @@ A path to a file with CA root certificates that will be used to verify SQL conne
and
\fIsql_ssl_verify\fR
options are set to
\fItrue\fR\&. There is no default which means certificate verification is disabled\&.
\fItrue\fR\&. There is no default which means certificate verification is disabled\&. This option has no effect for MS SQL\&.
.RE
.PP
\fBsql_ssl_certfile\fR: \fIPath\fR
@@ -1746,7 +1769,7 @@ options are set to
A path to a certificate file that will be used for SSL connections to the SQL server\&. Implies
\fIsql_ssl\fR
option is set to
\fItrue\fR\&. There is no default which means ejabberd won\(cqt provide a client certificate to the SQL server\&.
\fItrue\fR\&. There is no default which means ejabberd won\(cqt provide a client certificate to the SQL server\&. This option has no effect for MS SQL\&.
.RE
.PP
\fBsql_ssl_verify\fR: \fItrue | false\fR
@@ -1756,7 +1779,7 @@ Whether to verify SSL connection to the SQL server against CA root certificates
option\&. Implies
\fIsql_ssl\fR
option is set to
\fItrue\fR\&. The default value is
\fItrue\fR\&. This option has no effect for MS SQL\&. The default value is
\fIfalse\fR\&.
.RE
.PP
@@ -1971,7 +1994,7 @@ ejabberdctl srg\-create g1 example\&.org "\*(AqGroup number 1\*(Aq" this_is_g1 g
.RE
.SS "mod_admin_update_sql"
.sp
This module can be used to update existing SQL database from the default to the new schema\&. Check the section Default and New Schemas for details\&. Please note that only PostgreSQL is supported\&. When the module is loaded use \fIupdate_sql\fR API\&.
This module can be used to update existing SQL database from the default to the new schema\&. Check the section Default and New Schemas for details\&. Please note that only MS SQL, MySQL, and PostgreSQL are supported\&. When the module is loaded use \fIupdate_sql\fR API\&.
.sp
The module has no options\&.
.SS "mod_announce"
@@ -3866,7 +3889,7 @@ or
\fIsubscribe\fR
or both, and
\fIauthentication\fR
section with username/password field or certfile pointing to client certifcate\&. Accepted urls can use schema mqtt, mqtts (mqtt with tls), mqtt5, mqtt5s (both to trigger v5 protocol), ws, wss, ws5, wss5\&. Certifcate authentication can be only used with mqtts, mqtt5s, wss, wss5\&.
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\&. Certifcate authentication can be only used with mqtts, mqtt5s, wss, wss5\&.
.RE
.RE
.sp
@@ -4652,6 +4675,34 @@ or a conference JID is appended to the
otherwise\&. There is no default value\&.
.RE
.RE
.SS "mod_muc_rtbl"
.sp
This module implement Real\-time blocklists for MUC rooms\&.
.sp
It works by observing remote pubsub node conforming with specification described in https://xmppbl\&.org/\&.
.sp
This module is available since ejabberd 23\&.04\&.
.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
\fBrtbl_node\fR: \fIPubsubNodeName\fR
.RS 4
Name of pubsub node that should be used to track blocked users\&. The default value is
\fImuc_bans_sha256\fR\&.
.RE
.PP
\fBrtbl_server\fR: \fIDomain\fR
.RS 4
Domain of xmpp server that serves block list\&. The default value is
\fIxmppbl\&.org\fR
.RE
.RE
.SS "mod_multicast"
.sp
This module implements a service for XEP\-0033: Extended Stanza Addressing\&.
@@ -7697,13 +7748,13 @@ TODO
ProcessOne\&.
.SH "VERSION"
.sp
This document describes the configuration file of ejabberd 23\&.01\&. Configuration options of other ejabberd versions may differ significantly\&.
This document describes the configuration file of ejabberd 23\&.04\&. 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/23\&.01/ejabberd\&.yml\&.example
Default configuration file: https://github\&.com/processone/ejabberd/blob/23\&.04/ejabberd\&.yml\&.example
.sp
Main site: https://ejabberd\&.im
.sp
+1 -1
View File
@@ -114,7 +114,7 @@ defmodule Ejabberd.MixProject do
{:p1_utils, "~> 1.0"},
{:pkix, "~> 1.0"},
{:stringprep, ">= 1.0.26"},
{:xmpp, ">= 1.6.0"},
{:xmpp, ">= 1.6.2"},
{:yconf, "~> 1.0"}]
++ cond_deps()
end
+4 -4
View File
@@ -1,12 +1,12 @@
%{
"base64url": {:hex, :base64url, "1.0.1", "f8c7f2da04ca9a5d0f5f50258f055e1d699f0e8bf4cfdb30b750865368403cf6", [:rebar3], [], "hexpm", "f9b3add4731a02a9b0410398b475b33e7566a695365237a6bdee1bb447719f5c"},
"cache_tab": {:hex, :cache_tab, "1.0.30", "6d35eecfb65fbe5fc85988503a27338d32de01243f3fc8ea3ee7161af08725a4", [:rebar3], [{:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "6d8a5e00d8f84c42627706a6dbedb02e34d58495f3ed61935c8475ca0531cda0"},
"earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
"eimp": {:hex, :eimp, "1.0.22", "fa9b376ef0b50e8455db15c7c11dea4522c6902e04412288aab436d26335f6eb", [:rebar3], [{:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "b3b9ffb1d9a5f4a2ba88ac418a819164932d9a9d3a2fc3d32ca338ce855c4392"},
"epam": {:hex, :epam, "1.0.12", "2a5625d4133bca4b3943791a3f723ba764455a461ae9b6ba5debb262efcf4b40", [:rebar3], [], "hexpm", "54c166c4459cef72f2990a3d89a8f0be27180fe0ab0f24b28ddcc3b815f49f7f"},
"eredis": {:hex, :eredis, "1.2.0", "0b8e9cfc2c00fa1374cd107ea63b49be08d933df2cf175e6a89b73dd9c380de4", [:rebar3], [], "hexpm", "d9b5abef2c2c8aba8f32aa018203e0b3dc8b1157773b254ab1d4c2002317f1e1"},
"esip": {:hex, :esip, "1.0.49", "7949c288d1e094cb44bff5499231939e34c2ace06de8bef950a341edb1743357", [:rebar3], [{:fast_tls, "1.1.16", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.7", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "a1379ced50c3a2a8f82a77b3184e94c3b87782e90e5ddc0d2baf5b654ecfaa11"},
"ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"},
"ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"},
"ezlib": {:hex, :ezlib, "1.0.12", "ffe906ba10d03aaee7977e1e0e81d9ffc3bb8b47fb9cd8e2e453507a2e56221f", [:rebar3], [{:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "30e94355fb42260aab6e12582cb0c56bf233515e655c8aeaf48760e7561e4ebb"},
"fast_tls": {:hex, :fast_tls, "1.1.16", "85fa7f3112ea4ff5ccb4f3abadc130a8c855ad74eb00869487399cb0c322d208", [:rebar3], [{:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "aa08cca89b4044e74f1f12e399817d8beaeae3ee006c98a893c0bfb1d81fba51"},
"fast_xml": {:hex, :fast_xml, "1.1.49", "67d9bfcadd04efd930e0ee1412b5ea09d3e791f1fdbd4d3e9a8c8f29f8bfed8c", [:rebar3], [{:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "01da064d2f740818956961036637fee2475c17bf8aab9442217f90dc77883593"},
@@ -23,13 +23,13 @@
"p1_acme": {:hex, :p1_acme, "1.0.22", "b40a8031ef0f4592e97e6a8e08e53dbd31a2198cb8377b249f0caea4f8025a1d", [:rebar3], [{:base64url, "1.0.1", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "1.11.5", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "1.0.15", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "c2b25a7b295a435dac4f278a73d8417ff2b0020c45e1683504e8692ef03e2057"},
"p1_mysql": {:hex, :p1_mysql, "1.0.21", "5972add935e7b1b03d981fa88a0d01e96de357443eaf96ca2fb62e465a717f47", [:rebar3], [], "hexpm", "16f197adb99dab034139c429b256d65948a4057d3e4d553adbe5ce3236c4aabf"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.11", "96b4e85c08355720523c2f892011a81a07994d15c179ce4dd82d704fecad15b2", [:rebar3], [], "hexpm", "9c3c6ae59382b9525473bb02a32949889808f33f95f6db10594fd92acd1f63db"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.20", "0231de1a427a561afbea89212a61d2409f1a42696eeca16d0085305aee07717a", [:rebar3], [{:xmpp, "1.6.1", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "240b40fb3fd7e330fdf1d0beff2db0cb090ae5a6eef08a0a157ebb7251ff361c"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.22", "f2ca59b87e8c5dbbbe84d08e307c21f078384232e8fb78a783dbeffa6d37da28", [:rebar3], [{:xmpp, "1.6.2", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "bbc38d3878c7b58ab86c257a2a2ce1bacbd68a5034ebea2735db6a70c1aa12bc"},
"p1_utils": {:hex, :p1_utils, "1.0.25", "2d39b5015a567bbd2cc7033eeb93a7c60d8c84efe1ef69a3473faa07fa268187", [:rebar3], [], "hexpm", "9219214428f2c6e5d3187ff8eb9a8783695c2427420be9a259840e07ada32847"},
"pkix": {:hex, :pkix, "1.0.9", "eb20b2715d71a23b4fe7e754dae9281a964b51113d0bba8adf9da72bf9d65ac2", [:rebar3], [], "hexpm", "daab2c09cdd4eda05c9b45a5c00e994a1a5f27634929e1377e2e59b707103e3a"},
"sqlite3": {:hex, :sqlite3, "1.1.14", "f9ea0cff8540865fdfdb7e24eef34dc46677364b1c070896e99b5bf08c8a7fd7", [:rebar3], [], "hexpm", "85054b6ca297343c159ed6794a473ff2c8eeabd854b6fe02f711c0bfd373ce86"},
"stringprep": {:hex, :stringprep, "1.0.29", "02f23e8c3a219a3dfe40a22e908bece3a2f68af0ff599ea8a7b714ecb21e62ee", [:rebar3], [{:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "928eba304c3006eb1512110ebd7b87db163b00859a09375a1e4466152c6c462a"},
"stun": {:hex, :stun, "1.2.7", "d6bdcf0aa72c927fbe8b779fc4ef1f3916c5450b2ff136c800a7a0361fb1ddff", [:rebar3], [{:fast_tls, "1.1.16", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "3fb1f07aaa630b2276e83d267557d1ceb3d2ce52d1145de71864160210655852"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
"xmpp": {:hex, :xmpp, "1.6.1", "4075de3c1bb63c7838dc6c8d06167ffba2e39fd285e2a295287f26c1d8f64707", [:rebar3], [{:ezlib, "1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.1.16", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.49", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "6.0.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", "87fee84f805a151f4d85c1c11c16a738716dfaae353cb88898c0254f05df81c0"},
"xmpp": {:hex, :xmpp, "1.6.2", "8045dfea83e8996415b9a5161f685cb97dc3c40c0b9c46763a5eca2408017221", [:rebar3], [{:ezlib, "1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.1.16", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.49", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "6.0.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", "db2ee6115961fe159bc2629093797ac4535083176817cdbe2ae186a0ff540fde"},
"yconf": {:hex, :yconf, "1.0.15", "e22998b3d7728270bdd06162a9515bd142b14fae8927cbdbd3ef639c32aa6f7a", [:rebar3], [{:fast_yaml, "1.0.36", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "7ff2ab24d3c9833842716b9aaaa01a8f96641a7695cbb701b03445c4def01117"},
}
-2
View File
@@ -398,7 +398,6 @@
{"Password:","Contrasenya:"}.
{"Path to Dir","Ruta al directori"}.
{"Path to File","Ruta al fitxer"}.
{"Payload type","Tipus de payload"}.
{"Pending","Pendent"}.
{"Period: ","Període: "}.
{"Persist items to storage","Persistir elements al guardar"}.
@@ -564,7 +563,6 @@
{"The sender of the last received message","Qui ha enviat l'ultim missatge rebut"}.
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","El paquet DEU contindre només un element <active/>, un element <default/>, o un element <list/>"}.
{"The subscription identifier associated with the subscription request","L'identificador de subscripció associat amb la petició de subscripció"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","El tipus de dades al node, usualment especificat pel namespace del payload (si n'hi ha)"}.
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","La URL de uns transformació XSL que pot ser aplicada als payloads per a generar un element apropiat de contingut de missatge."}.
{"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","La URL de una transformació XSL que pot ser aplicada al format de payload per a generar un resultat valid de Data Forms, que el client puga mostrar usant un métode generic de Data Forms"}.
{"There was an error changing the password: ","Hi ha hagut un error canviant la contrasenya: "}.
-2
View File
@@ -396,7 +396,6 @@
{"Password:","Passwort:"}.
{"Path to Dir","Pfad zum Verzeichnis"}.
{"Path to File","Pfad zur Datei"}.
{"Payload type","Nutzdatentyp"}.
{"Pending","Ausstehend"}.
{"Period: ","Zeitraum: "}.
{"Persist items to storage","Items dauerhaft speichern"}.
@@ -562,7 +561,6 @@
{"The sender of the last received message","Der Absender der letzten erhaltenen Nachricht"}.
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","Das Stanza darf nur ein <active/>-Element, ein <default/>-Element oder ein <list/>-Element enthalten"}.
{"The subscription identifier associated with the subscription request","Die mit der Abonnement-Anforderung verknüpfte Abonnement-Bezeichnung"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","Die Art der Knotendaten, üblicherweise vom Namensraum der Nutzdaten angegeben (gegebenenfalls)"}.
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","Die URL einer XSL-Transformation welche auf Nutzdaten angewendet werden kann, um ein geeignetes Nachrichtenkörper-Element zu generieren."}.
{"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","Die URL einer XSL-Transformation welche auf das Nutzdaten-Format angewendet werden kann, um ein gültiges Data Forms-Ergebnis zu generieren das der Client mit Hilfe einer generischen Data Forms-Rendering-Engine anzeigen könnte"}.
{"There was an error changing the password: ","Es trat ein Fehler beim Ändern des Passwortes auf: "}.
-2
View File
@@ -377,7 +377,6 @@
{"Password:","Κωδικός πρόσβασης:"}.
{"Path to Dir","Τοποθεσία κατάλογου αρχείων"}.
{"Path to File","Τοποθεσία Αρχείου"}.
{"Payload type","Τύπος φόρτου εργασιών"}.
{"Pending","Εκκρεμεί"}.
{"Period: ","Περίοδος: "}.
{"Persist items to storage","Μόνιμη αποθήκευση στοιχείων"}.
@@ -538,7 +537,6 @@
{"The sender of the last received message","Ο αποστολέας του τελευταίου εισερχομένου μηνύματος"}.
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","Η stanza ΠΡΕΠΕΙ να περιέχει μόνο ένα στοιχείο <active />, ένα στοιχείο <default /> ή ένα στοιχείο <list />"}.
{"The subscription identifier associated with the subscription request","Το αναγνωριστικό συνδρομής συσχετίστηκε με το αίτημα συνδρομής"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","Ο τύπος των δεδομένων του κόμβου συνήθως προσδιορίζεται από το namespace του φόρτου εργασιών (αν υπάρχουν)"}.
{"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"}.
{"There was an error changing the password: ","Παρουσιάστηκε σφάλμα κατά την αλλαγή του κωδικού πρόσβασης: "}.
-2
View File
@@ -398,7 +398,6 @@
{"Password:","Contraseña:"}.
{"Path to Dir","Ruta al directorio"}.
{"Path to File","Ruta al fichero"}.
{"Payload type","Tipo de payload"}.
{"Pending","Pendiente"}.
{"Period: ","Periodo: "}.
{"Persist items to storage","Persistir elementos al almacenar"}.
@@ -564,7 +563,6 @@
{"The sender of the last received message","El emisor del último mensaje recibido"}.
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","El paquete DEBE contener solo un elemento <active/>, un elemento <default/>, o un elemento <list/>"}.
{"The subscription identifier associated with the subscription request","El identificador de suscripción asociado con la petición de suscripción"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","El tipo de datos del nodo, usualmente especificado por el namespace del payload (en caso de haberlo)"}.
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","La URL de una transformación XSL que puede aplicarse a payloads para generar un elemento de contenido del mensaje apropiado."}.
{"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","La URL de una transformación XSL que puede aplicarse al formato de payload para generar un resultado de Formulario de Datos válido, que el cliente pueda mostrar usando un mecanismo de dibujado genérico de Formulario de Datos"}.
{"There was an error changing the password: ","Hubo uno error al cambiar la contaseña: "}.
-1
View File
@@ -337,7 +337,6 @@
{"The collections with which a node is affiliated","האוספים עמם צומת מסונף"}.
{"The password is too weak","הסיסמה חלשה מדי"}.
{"the password is","הסיסמה היא"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","סוג מידע ממסר, לרוב מצוין לפי מרחב־שמות של מטען הייעוד (אם בכלל)"}.
{"There was an error creating the account: ","אירעה שגיאה ביצירת החשבון: "}.
{"There was an error deleting the account: ","אירעה שגיאה במחיקת החשבון: "}.
{"This room is not anonymous","חדר זה אינו אנונימי"}.
-1
View File
@@ -289,7 +289,6 @@
{"Password","Sandi"}.
{"Path to Dir","Jalur ke Dir"}.
{"Path to File","Jalur ke File"}.
{"Payload type","Tipe payload"}.
{"Pending","Tertunda"}.
{"Period: ","Periode: "}.
{"Persist items to storage","Pertahankan item ke penyimpanan"}.
-2
View File
@@ -398,7 +398,6 @@
{"Password:","Senha:"}.
{"Path to Dir","Caminho para o diretório"}.
{"Path to File","Caminho do arquivo"}.
{"Payload type","Tipo da carga útil"}.
{"Pending","Pendente"}.
{"Period: ","Período: "}.
{"Persist items to storage","Persistir elementos ao armazenar"}.
@@ -564,7 +563,6 @@
{"The sender of the last received message","O remetente da última mensagem que foi recebida"}.
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","A instância DEVE conter apenas um elemento <active/>, um elemento <default/>, ou um elemento <list/>"}.
{"The subscription identifier associated with the subscription request","O identificador da assinatura associado à solicitação da assinatura"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","O tipo dos dados do nó, normalmente definido pelo espaço dos nomes da carga útil (caso haja)"}.
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","O URL da transformação XSL que pode ser aplicada nas cargas úteis para gerar um elemento apropriado no corpo da mensagem."}.
{"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","A URL de uma transformação XSL que pode ser aplicada ao formato de carga útil para gerar um Formulário de Dados válido onde o cliente possa exibir usando um mecanismo genérico de renderização do Formulários de Dados"}.
{"There was an error changing the password: ","Houve um erro ao alterar a senha: "}.
+20 -3
View File
@@ -3,7 +3,7 @@
%% To improve translations please read:
%% https://docs.ejabberd.im/developer/extending-ejabberd/localization/
{" (Add * to the end of field to match substring)"," (Adicione * no final do campo para combinar com a substring)"}.
{" (Add * to the end of field to match substring)"," (Adicione * no final do campo para combinar com a sub-cadeia)"}.
{" has set the subject to: "," colocou o tópico: "}.
{"# participants","# participantes"}.
{"A description of the node","Uma descrição do nó"}.
@@ -79,6 +79,7 @@
{"Changing role/affiliation is not allowed","Não é permitida a alteração da função/afiliação"}.
{"Channel already exists","O canal já existe"}.
{"Channel does not exist","O canal não existe"}.
{"Channel JID","Canal JID"}.
{"Channels","Canais"}.
{"Characters not allowed:","Caracteres não aceitos:"}.
{"Chatroom configuration modified","Configuração da sala de bate-papo modificada"}.
@@ -98,6 +99,7 @@
{"Configuration","Configuração"}.
{"Connected Resources:","Recursos conectados:"}.
{"Contact Addresses (normally, room owner or owners)","Endereços de contato (normalmente, o proprietário ou os proprietários da sala)"}.
{"Contrib Modules","Módulos contrib"}.
{"Country","País"}.
{"CPU Time:","Tempo da CPU:"}.
{"Current Discussion Topic","Assunto em discussão"}.
@@ -172,6 +174,8 @@
{"Full List of Room Admins","Lista completa dos administradores das salas"}.
{"Full List of Room Owners","Lista completa dos proprietários das salas"}.
{"Full Name","Nome completo"}.
{"Get List of Online Users","Obter a lista de utilizadores online"}.
{"Get List of Registered Users","Obter a lista de utilizadores registados"}.
{"Get Number of Online Users","Obter quantidade de utilizadores online"}.
{"Get Number of Registered Users","Obter quantidade de utilizadores registados"}.
{"Get Pending","Obter os pendentes"}.
@@ -213,6 +217,8 @@
{"Incorrect value of 'action' attribute","Valor incorreto do atributo 'action'"}.
{"Incorrect value of 'action' in data form","Valor incorreto de 'action' no formulário de dados"}.
{"Incorrect value of 'path' in data form","Valor incorreto de 'path' no formulário de dados"}.
{"Installed Modules:","Módulos instalados:"}.
{"Install","Instalar"}.
{"Insufficient privilege","Privilégio insuficiente"}.
{"Internal server error","Erro interno do servidor"}.
{"Invalid 'from' attribute in forwarded message","Atributo 'from' inválido na mensagem reenviada"}.
@@ -229,6 +235,8 @@
{"January","Janeiro"}.
{"JID normalization denied by service policy","Normalização JID negada por causa da política de serviços"}.
{"JID normalization failed","A normalização JID falhou"}.
{"Joined MIX channels of ~ts","Entrou no canais MIX do ~ts"}.
{"Joined MIX channels:","Uniu-se aos canais MIX:"}.
{"joins the room","Entrar na sala"}.
{"July","Julho"}.
{"June","Junho"}.
@@ -349,6 +357,7 @@
{"Number of registered users","Quantidade de utilizadores registados"}.
{"Number of seconds after which to automatically purge items, or `max` for no specific limit other than a server imposed maximum","Quantidade de segundos após limpar automaticamente os itens ou `max` para nenhum limite específico que não seja um servidor imposto máximo"}.
{"Occupants are allowed to invite others","As pessoas estão autorizadas a convidar outras pessoas"}.
{"Occupants are allowed to query others","Os ocupantes estão autorizados a consultar os outros"}.
{"Occupants May Change the Subject","As pessoas talvez possam alterar o assunto"}.
{"October","Outubro"}.
{"Offline Messages","Mensagens offline"}.
@@ -375,11 +384,13 @@
{"Only those on a whitelist may subscribe and retrieve items","Apenas aqueles presentes numa lista branca podem se inscrever e recuperar os itens"}.
{"Organization Name","Nome da organização"}.
{"Organization Unit","Unidade da organização"}.
{"Other Modules Available:","Outros módulos disponíveis:"}.
{"Outgoing s2s Connections","Conexões s2s de Saída"}.
{"Outgoing s2s Connections:","Saída das conexões s2s:"}.
{"Owner privileges required","São necessários privilégios de dono"}.
{"Packet relay is denied by service policy","A retransmissão de pacote é negada por causa da política de serviço"}.
{"Packet","Pacote"}.
{"Participant ID","ID do participante"}.
{"Participant","Participante"}.
{"Password Verification:","Verificação da Palavra-passe:"}.
{"Password Verification","Verificação de Palavra-passe"}.
@@ -387,7 +398,6 @@
{"Password:","Palavra-chave:"}.
{"Path to Dir","Caminho para o directório"}.
{"Path to File","Caminho do ficheiro"}.
{"Payload type","Tipo da carga útil"}.
{"Pending","Pendente"}.
{"Period: ","Período: "}.
{"Persist items to storage","Persistir elementos ao armazenar"}.
@@ -482,6 +492,7 @@
{"Shut Down Service","Parar Serviço"}.
{"SOCKS5 Bytestreams","Bytestreams SOCKS5"}.
{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","Alguns clientes XMPP podem armazenar a sua palavra-passe no seu computador, só faça isso no seu computador particular por questões de segurança."}.
{"Sources Specs:","Especificações das fontes:"}.
{"Specify the access model","Especificar os modelos de acesso"}.
{"Specify the event message type","Especificar o tipo de mensagem para o evento"}.
{"Specify the publisher model","Especificar o modelo do publicante"}.
@@ -527,6 +538,8 @@
{"The JIDs of those to contact with questions","Os JIDs daqueles para entrar em contato com perguntas"}.
{"The JIDs of those with an affiliation of owner","Os JIDs daqueles com uma afiliação de proprietário"}.
{"The JIDs of those with an affiliation of publisher","Os JIDs daqueles com uma afiliação de editor"}.
{"The list of all online users","A lista de todos os utilizadores online"}.
{"The list of all users","A lista de todos os utilizadores"}.
{"The list of JIDs that may associate leaf nodes with a collection","A lista dos JIDs que podem associar as páginas dos nós numa coleção"}.
{"The maximum number of child nodes that can be associated with a collection, or `max` for no specific limit other than a server imposed maximum","A quantidade máxima de nós relacionados que podem ser associados a uma coleção ou `máximo` para nenhum limite específico que não seja um servidor imposto no máximo"}.
{"The minimum number of milliseconds between sending any two notification digests","A quantidade mínima de milissegundos entre o envio do resumo das duas notificações"}.
@@ -550,7 +563,6 @@
{"The sender of the last received message","O remetente da última mensagem que foi recebida"}.
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","A instância DEVE conter apenas um elemento <active/>, um elemento <default/>, ou um elemento <list/>"}.
{"The subscription identifier associated with the subscription request","O identificador da assinatura associado à solicitação da assinatura"}.
{"The type of node data, usually specified by the namespace of the payload (if any)","O tipo dos dados do nó, normalmente definido pelo espaço dos nomes da carga útil (caso haja)"}.
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","O URL da transformação XSL que pode ser aplicada nas cargas úteis para gerar um elemento apropriado no corpo da mensagem."}.
{"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","A URL de uma transformação XSL que pode ser aplicada ao formato de carga útil para gerar um Formulário de Dados válido onde o cliente possa exibir usando um mecanismo genérico de renderização do Formulários de Dados"}.
{"There was an error changing the password: ","Houve um erro ao alterar a palavra-passe: "}.
@@ -591,6 +603,7 @@
{"Unauthorized","Não Autorizado"}.
{"Unexpected action","Ação inesperada"}.
{"Unexpected error condition: ~p","Condição de erro inesperada: ~p"}.
{"Uninstall","Desinstalar"}.
{"Unregister an XMPP account","Excluir uma conta XMPP"}.
{"Unregister","Deletar registo"}.
{"Unselect All","Desmarcar todos"}.
@@ -601,7 +614,10 @@
{"Update ~p","Atualizar ~p"}.
{"Update plan","Plano de atualização"}.
{"Update script","Script de atualização"}.
{"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"}.
{"Update","Actualizar"}.
{"Upgrade","Atualização"}.
{"Uptime:","Tempo de atividade:"}.
{"URL for Archived Discussion Logs","A URL para o arquivamento dos registos da discussão"}.
{"User already exists","Utilizador já existe"}.
@@ -624,6 +640,7 @@
{"Value of '~s' should be integer","Valor de '~s' deveria ser um inteiro"}.
{"Value 'set' of 'type' attribute is not allowed","Valor 'set' não permitido para atributo 'type'"}.
{"vCard User Search","Busca de Utilizador vCard"}.
{"View joined MIX channels","Exibir os canais MIX aderidos"}.
{"View Queue","Exibir a fila"}.
{"View Roster","Ver a lista"}.
{"Virtual Hosts","Hosts virtuais"}.
-1
View File
@@ -253,7 +253,6 @@
{"Password:","Fjalëkalim:"}.
{"Path to Dir","Shteg për te Drejtori"}.
{"Path to File","Shteg për te Kartelë"}.
{"Payload type","Lloj ngarkese"}.
{"Pending","Pezull"}.
{"Period: ","Periudhë: "}.
{"Ping","Ping"}.
-2
View File
@@ -398,7 +398,6 @@
{"Password:","密码:"}.
{"Path to Dir","目录的路径"}.
{"Path to File","文件路径"}.
{"Payload type","有效载荷类型"}.
{"Pending","挂起"}.
{"Period: ","持续时间: "}.
{"Persist items to storage","持久化内容条目"}.
@@ -564,7 +563,6 @@
{"The sender of the last received message","最后收到的消息的发送者"}.
{"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 type of node data, usually specified by the namespace of the payload (if any)","节点数据的类型, 如果有, 通常由有效负载的名称空间指定"}.
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","XSL转换的URL,可以将其应用于有效负载以生成适当的消息正文元素。"}.
{"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","XSL转换的URL, 可以将其应用于有效负载格式, 以生成有效的数据表单结果, 客户端可以使用通用数据表单呈现引擎来显示该结果"}.
{"There was an error changing the password: ","修改密码出错: "}.
+2 -2
View File
@@ -62,7 +62,7 @@
{p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.21"}}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.11"}}},
{if_var_true, pgsql,
{p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.20"}}}},
{p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.22"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.25"}}},
{pkix, ".*", {git, "https://github.com/processone/pkix", {tag, "1.0.9"}}},
{if_not_rebar3, %% Needed because modules are not fully migrated to new structure and mix
@@ -73,7 +73,7 @@
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.29"}}},
{if_var_true, stun,
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.2.7"}}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.6.1"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.6.2"}}},
{yconf, ".*", {git, "https://github.com/processone/yconf", {tag, "1.0.15"}}}
]}.
+5 -6
View File
@@ -1,25 +1,24 @@
echo -n "===> Preparing dev configuration files: "
printf "===> Preparing dev configuration files: "
PWD_DIR=`pwd`
PWD_DIR=$(pwd)
REL_DIR=$PWD_DIR/_build/dev/rel/ejabberd/
CON_DIR=$REL_DIR/conf/
[ -z "$REL_DIR_TEMP" ] && REL_DIR_TEMP=$REL_DIR
CON_DIR_TEMP=$REL_DIR_TEMP/conf/
BIN_DIR_TEMP=$REL_DIR_TEMP/bin/
cd $CON_DIR_TEMP
cd $CON_DIR_TEMP || exit
sed -i "s|# certfiles:|certfiles:\n - $CON_DIR/cert.pem|g" ejabberd.yml.example
sed -i "s|certfiles:|ca_file: $CON_DIR/ca.pem\ncertfiles:|g" ejabberd.yml.example
sed -i 's|^acl:$|acl:\n admin: [user: admin]|g' ejabberd.yml.example
[ ! -f "$CON_DIR/ejabberd.yml" ] \
&& echo -n "ejabberd.yml " \
&& printf "ejabberd.yml " \
&& mv ejabberd.yml.example ejabberd.yml
sed -i "s|#' POLL|EJABBERD_BYPASS_WARNINGS=true\n\n#' POLL|g" ejabberdctl.cfg.example
[ ! -f "$CON_DIR/ejabberdctl.cfg" ] \
&& echo -n "ejabberdctl.cfg " \
&& printf "ejabberdctl.cfg " \
&& mv ejabberdctl.cfg.example ejabberdctl.cfg
echo ""
+5 -5
View File
@@ -1,4 +1,4 @@
PWD_DIR=`pwd`
PWD_DIR=$(pwd)
REL_DIR=$PWD_DIR/_build/relive/
CON_DIR=$REL_DIR/conf/
@@ -15,17 +15,17 @@ cp ejabberd.yml.example $CON_DIR/ejabberd.yml.example
cp test/ejabberd_SUITE_data/ca.pem $CON_DIR
cp test/ejabberd_SUITE_data/cert.pem $CON_DIR
cd $CON_DIR_TEMP
cd $CON_DIR_TEMP || exit
sed -i "s|# certfiles:|certfiles:\n - $CON_DIR/cert.pem|g" ejabberd.yml.example
sed -i "s|certfiles:|ca_file: $CON_DIR/ca.pem\ncertfiles:|g" ejabberd.yml.example
sed -i 's|^acl:$|acl:\n admin: [user: admin]|g' ejabberd.yml.example
[ ! -f "$CON_DIR/ejabberd.yml" ] \
&& echo -n "ejabberd.yml " \
&& printf "ejabberd.yml " \
&& mv ejabberd.yml.example ejabberd.yml
sed -i "s|#' POLL|EJABBERD_BYPASS_WARNINGS=true\n\n#' POLL|g" ejabberdctl.cfg.example
[ ! -f "$CON_DIR/ejabberdctl.cfg" ] \
&& echo -n "ejabberdctl.cfg " \
&& printf "ejabberdctl.cfg " \
&& mv ejabberdctl.cfg.example ejabberdctl.cfg \
|| echo -n
|| printf
+1 -12
View File
@@ -52,7 +52,6 @@ CREATE TABLE rosterusers (
);
CREATE UNIQUE INDEX i_rosteru_sh_user_jid ON rosterusers (server_host, username, jid);
CREATE INDEX i_rosteru_sh_username ON rosterusers (server_host, username);
CREATE INDEX i_rosteru_sh_jid ON rosterusers (server_host, jid);
@@ -84,7 +83,6 @@ CREATE TABLE sr_user (
);
CREATE UNIQUE INDEX i_sr_user_sh_jid_grp ON sr_user (server_host, jid, grp);
CREATE INDEX i_sr_user_sh_jid ON sr_user (server_host, jid);
CREATE INDEX i_sr_user_sh_grp ON sr_user (server_host, grp);
CREATE TABLE spool (
@@ -190,7 +188,6 @@ CREATE TABLE privacy_list (
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX i_privacy_list_sh_username ON privacy_list (server_host, username);
CREATE UNIQUE INDEX i_privacy_list_sh_username_name ON privacy_list (server_host, username, name);
CREATE TABLE privacy_list_data (
@@ -215,9 +212,6 @@ CREATE TABLE private_storage (
PRIMARY KEY (server_host, username, namespace)
);
CREATE INDEX i_private_storage_sh_username ON private_storage (server_host, username);
CREATE TABLE roster_version (
username text NOT NULL,
server_host text NOT NULL,
@@ -319,7 +313,6 @@ CREATE TABLE muc_online_users (
);
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users (username, server);
CREATE TABLE muc_room_subscribers (
room text NOT NULL,
@@ -389,7 +382,6 @@ CREATE TABLE route (
);
CREATE UNIQUE INDEX i_route ON route(domain, server_host, node, pid);
CREATE INDEX i_route_domain ON route(domain);
CREATE TABLE bosh (
sid text NOT NULL,
@@ -422,6 +414,7 @@ CREATE TABLE push_session (
);
CREATE UNIQUE INDEX i_push_session_susn ON push_session (server_host, username, service, node);
CREATE INDEX i_push_session_sh_username_timestamp ON push_session (server_host, username, timestamp);
CREATE TABLE mix_channel (
channel text NOT NULL,
@@ -449,7 +442,6 @@ CREATE TABLE mix_participant (
);
CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel, service, username, domain);
CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel, service);
CREATE TABLE mix_subscription (
channel text NOT NULL,
@@ -461,9 +453,7 @@ CREATE TABLE mix_subscription (
);
CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel, service, username, domain, node);
CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel, service, username, domain);
CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel, service, node);
CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel, service);
CREATE TABLE mix_pam (
username text NOT NULL,
@@ -475,7 +465,6 @@ CREATE TABLE mix_pam (
);
CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username, server_host, channel, service);
CREATE INDEX i_mix_pam_us ON mix_pam (username, server_host);
CREATE TABLE mqtt_pub (
username text NOT NULL,
-10
View File
@@ -47,7 +47,6 @@ CREATE TABLE rosterusers (
);
CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers (username, jid);
CREATE INDEX i_rosteru_username ON rosterusers (username);
CREATE INDEX i_rosteru_jid ON rosterusers (jid);
@@ -74,7 +73,6 @@ CREATE TABLE sr_user (
);
CREATE UNIQUE INDEX i_sr_user_jid_grp ON sr_user (jid, grp);
CREATE INDEX i_sr_user_jid ON sr_user (jid);
CREATE INDEX i_sr_user_grp ON sr_user (grp);
CREATE TABLE spool (
@@ -169,7 +167,6 @@ CREATE TABLE privacy_list (
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX i_privacy_list_username ON privacy_list (username);
CREATE UNIQUE INDEX i_privacy_list_username_name ON privacy_list (username, name);
CREATE TABLE privacy_list_data (
@@ -192,7 +189,6 @@ CREATE TABLE private_storage (
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX i_private_storage_username ON private_storage (username);
CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage (username, namespace);
@@ -291,7 +287,6 @@ CREATE TABLE muc_online_users (
);
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users (username, server);
CREATE TABLE muc_room_subscribers (
room text NOT NULL,
@@ -358,7 +353,6 @@ CREATE TABLE route (
);
CREATE UNIQUE INDEX i_route ON route(domain, server_host, node, pid);
CREATE INDEX i_route_domain ON route(domain);
CREATE TABLE bosh (
sid text NOT NULL,
@@ -417,7 +411,6 @@ CREATE TABLE mix_participant (
);
CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel, service, username, domain);
CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel, service);
CREATE TABLE mix_subscription (
channel text NOT NULL,
@@ -429,9 +422,7 @@ CREATE TABLE mix_subscription (
);
CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel, service, username, domain, node);
CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel, service, username, domain);
CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel, service, node);
CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel, service);
CREATE TABLE mix_pam (
username text NOT NULL,
@@ -442,7 +433,6 @@ CREATE TABLE mix_pam (
);
CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username, channel, service);
CREATE INDEX i_mix_pam_us ON mix_pam (username);
CREATE TABLE mqtt_pub (
username text NOT NULL,
+646
View File
@@ -0,0 +1,646 @@
--
-- ejabberd, Copyright (C) 2002-2023 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.
--
SET ANSI_PADDING OFF;
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
SET ANSI_PADDING ON;
CREATE TABLE [dbo].[archive] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[timestamp] [bigint] NOT NULL,
[peer] [varchar] (250) NOT NULL,
[bare_peer] [varchar] (250) NOT NULL,
[xml] [ntext] NOT NULL,
[txt] [ntext] NULL,
[id] [bigint] IDENTITY(1,1) NOT NULL,
[kind] [varchar] (10) NULL,
[nick] [varchar] (250) NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [archive_PK] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [archive_sh_username_timestamp] ON [archive] (server_host, username, timestamp)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [archive_sh_username_peer] ON [archive] (server_host, username, peer)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [archive_sh_username_bare_peer] ON [archive] (server_host, username, bare_peer)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [archive_sh_timestamp] ON [archive] (server_host, timestamp)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[archive_prefs] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[def] [text] NOT NULL,
[always] [text] NOT NULL,
[never] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [archive_prefs_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[caps_features] (
[node] [varchar] (250) NOT NULL,
[subnode] [varchar] (250) NOT NULL,
[feature] [text] NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE CLUSTERED INDEX [caps_features_node_subnode] ON [caps_features] (node, subnode)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[last] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[seconds] [text] NOT NULL,
[state] [text] NOT NULL,
CONSTRAINT [last_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[motd] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[xml] [text] NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [motd_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[muc_registered] (
[jid] [varchar] (255) NOT NULL,
[host] [varchar] (255) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[nick] [varchar] (255) NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
);
CREATE INDEX [muc_registered_nick] ON [muc_registered] (nick)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE CLUSTERED INDEX [muc_registered_jid_host] ON [muc_registered] (jid, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_room] (
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[opts] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [muc_room_name_host] ON [muc_room] (name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [muc_room_host_created_at] ON [muc_registered] (host, nick)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_online_room] (
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[node] [varchar] (250) NOT NULL,
[pid] [varchar] (100) NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [muc_online_room_name_host] ON [muc_online_room] (name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_online_users] (
[username] [varchar] (250) NOT NULL,
[server] [varchar] (250) NOT NULL,
[resource] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[node] [varchar] (250) NOT NULL
);
CREATE UNIQUE INDEX [muc_online_users_i] ON [muc_online_users] (username, server, resource, name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_room_subscribers] (
[room] [varchar] (191) NOT NULL,
[host] [varchar] (191) NOT NULL,
[jid] [varchar] (191) NOT NULL,
[nick] [text] NOT NULL,
[nodes] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
);
CREATE UNIQUE CLUSTERED INDEX [muc_room_subscribers_host_room_jid] ON [muc_room_subscribers] (host, room, jid);
CREATE INDEX [muc_room_subscribers_host_jid] ON [muc_room_subscribers] (host, jid);
CREATE INDEX [muc_room_subscribers_jid] ON [muc_room_subscribers] (jid);
CREATE TABLE [dbo].[privacy_default_list] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
CONSTRAINT [privacy_default_list_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
);
CREATE TABLE [dbo].[privacy_list] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
[id] [bigint] IDENTITY(1,1) NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [privacy_list_PK] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
);
CREATE UNIQUE INDEX [privacy_list_sh_username_name] ON [privacy_list] (server_host, username, name)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[privacy_list_data] (
[id] [bigint] NULL,
[t] [char] (1) NOT NULL,
[value] [text] NOT NULL,
[action] [char] (1) NOT NULL,
[ord] [smallint] NOT NULL,
[match_all] [smallint] NOT NULL,
[match_iq] [smallint] NOT NULL,
[match_message] [smallint] NOT NULL,
[match_presence_in] [smallint] NOT NULL,
[match_presence_out] [smallint] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE CLUSTERED INDEX [privacy_list_data_id] ON [privacy_list_data] (id)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[private_storage] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[namespace] [varchar] (250) NOT NULL,
[data] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [private_storage_sh_username_namespace] ON [private_storage] (server_host, username, namespace)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_item] (
[nodeid] [bigint] NULL,
[itemid] [varchar] (255) NOT NULL,
[publisher] [varchar] (250) NOT NULL,
[creation] [varchar] (32) NOT NULL,
[modification] [varchar] (32) NOT NULL,
[payload] [text] NOT NULL DEFAULT ''
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [pubsub_item_itemid] ON [pubsub_item] (itemid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE CLUSTERED INDEX [pubsub_item_nodeid_itemid] ON [pubsub_item] (nodeid, itemid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_node_option] (
[nodeid] [bigint] NULL,
[name] [varchar] (250) NOT NULL,
[val] [varchar] (250) NOT NULL
);
CREATE CLUSTERED INDEX [pubsub_node_option_nodeid] ON [pubsub_node_option] (nodeid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_node_owner] (
[nodeid] [bigint] NULL,
[owner] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE CLUSTERED INDEX [pubsub_node_owner_nodeid] ON [pubsub_node_owner] (nodeid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_state] (
[nodeid] [bigint] NULL,
[jid] [varchar] (255) NOT NULL,
[affiliation] [char] (1) NOT NULL,
[subscriptions] [text] NOT NULL DEFAULT '',
[stateid] [bigint] IDENTITY(1,1) NOT NULL,
CONSTRAINT [pubsub_state_PRIMARY] PRIMARY KEY CLUSTERED
(
[stateid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [pubsub_state_jid] ON [pubsub_state] (jid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE INDEX [pubsub_state_nodeid_jid] ON [pubsub_state] (nodeid, jid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_subscription_opt] (
[subid] [varchar] (255) NOT NULL,
[opt_name] [varchar] (32) NOT NULL,
[opt_value] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [pubsub_subscription_opt_subid_opt_name] ON [pubsub_subscription_opt] (subid, opt_name)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_node] (
[host] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[parent] [varchar] (255) NOT NULL DEFAULT '',
[plugin] [varchar] (32) NOT NULL,
[nodeid] [bigint] IDENTITY(1,1) NOT NULL,
CONSTRAINT [pubsub_node_PRIMARY] PRIMARY KEY CLUSTERED
(
[nodeid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
);
CREATE INDEX [pubsub_node_parent] ON [pubsub_node] (parent)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE INDEX [pubsub_node_host_node] ON [pubsub_node] (host, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[roster_version] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[version] [text] NOT NULL,
CONSTRAINT [roster_version_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[rostergroups] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL,
[grp] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE CLUSTERED INDEX [rostergroups_sh_username_jid] ON [rostergroups] ([server_host], [username], [jid])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[rosterusers] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL,
[nick] [text] NOT NULL,
[subscription] [char] (1) NOT NULL,
[ask] [char] (1) NOT NULL,
[askmessage] [text] NOT NULL,
[server] [char] (1) NOT NULL,
[subscribe] [text] NOT NULL,
[type] [text] NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [rosterusers_sh_username_jid] ON [rosterusers] ([server_host], [username], [jid])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [rosterusers_sh_jid] ON [rosterusers] ([server_host], [jid])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[sm] (
[usec] [bigint] NOT NULL,
[pid] [varchar] (100) NOT NULL,
[node] [varchar] (255) NOT NULL,
[username] [varchar] (255) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[resource] [varchar] (255) NOT NULL,
[priority] [text] NOT NULL,
[info] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [sm_sid] ON [sm] (usec, pid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [sm_node] ON [sm] (node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [sm_sh_username] ON [sm] (server_host, username)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[spool] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[xml] [text] NOT NULL,
[seq] [bigint] IDENTITY(1,1) NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [spool_PK] PRIMARY KEY CLUSTERED
(
[seq] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [spool_sh_username] ON [spool] (server_host, username)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [spool_created_at] ON [spool] (created_at)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
;
CREATE TABLE [dbo].[sr_group] (
[name] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[opts] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [sr_group_sh_name] ON [sr_group] ([server_host], [name])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[sr_user] (
[jid] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[grp] [varchar] (250) NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
);
CREATE UNIQUE CLUSTERED INDEX [sr_user_sh_jid_group] ON [sr_user] ([server_host], [jid], [grp])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [sr_user_sh_grp] ON [sr_user] ([server_host], [grp])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[users] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[password] [text] NOT NULL,
[serverkey] [text] NOT NULL DEFAULT '',
[salt] [text] NOT NULL DEFAULT '',
[iterationcount] [smallint] NOT NULL DEFAULT 0,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[vcard] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[vcard] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [vcard_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[vcard_search] (
[username] [varchar] (250) NOT NULL,
[lusername] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[fn] [text] NOT NULL,
[lfn] [varchar] (250) NOT NULL,
[family] [text] NOT NULL,
[lfamily] [varchar] (250) NOT NULL,
[given] [text] NOT NULL,
[lgiven] [varchar] (250) NOT NULL,
[middle] [text] NOT NULL,
[lmiddle] [varchar] (250) NOT NULL,
[nickname] [text] NOT NULL,
[lnickname] [varchar] (250) NOT NULL,
[bday] [text] NOT NULL,
[lbday] [varchar] (250) NOT NULL,
[ctry] [text] NOT NULL,
[lctry] [varchar] (250) NOT NULL,
[locality] [text] NOT NULL,
[llocality] [varchar] (250) NOT NULL,
[email] [text] NOT NULL,
[lemail] [varchar] (250) NOT NULL,
[orgname] [text] NOT NULL,
[lorgname] [varchar] (250) NOT NULL,
[orgunit] [text] NOT NULL,
[lorgunit] [varchar] (250) NOT NULL,
CONSTRAINT [vcard_search_PRIMARY] PRIMARY KEY CLUSTERED
(
[server_host] ASC,
[lusername] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [vcard_search_sh_lfn] ON [vcard_search] (server_host, lfn)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lfamily] ON [vcard_search] (server_host, lfamily)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lgiven] ON [vcard_search] (server_host, lgiven)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lmiddle] ON [vcard_search] (server_host, lmiddle)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lnickname] ON [vcard_search] (server_host, lnickname)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lbday] ON [vcard_search] (server_host, lbday)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lctry] ON [vcard_search] (server_host, lctry)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_llocality] ON [vcard_search] (server_host, llocality)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lemail] ON [vcard_search] (server_host, lemail)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lorgname] ON [vcard_search] (server_host, lorgname)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [vcard_search_sh_lorgunit] ON [vcard_search] (server_host, lorgunit)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
ALTER TABLE [dbo].[pubsub_item] WITH CHECK ADD CONSTRAINT [pubsub_item_ibfk_1] FOREIGN KEY([nodeid])
REFERENCES [dbo].[pubsub_node] ([nodeid])
ON DELETE CASCADE;
ALTER TABLE [dbo].[pubsub_item] CHECK CONSTRAINT [pubsub_item_ibfk_1];
ALTER TABLE [dbo].[pubsub_node_option] WITH CHECK ADD CONSTRAINT [pubsub_node_option_ibfk_1] FOREIGN KEY([nodeid])
REFERENCES [dbo].[pubsub_node] ([nodeid])
ON DELETE CASCADE;
ALTER TABLE [dbo].[pubsub_node_option] CHECK CONSTRAINT [pubsub_node_option_ibfk_1];
ALTER TABLE [dbo].[pubsub_node_owner] WITH CHECK ADD CONSTRAINT [pubsub_node_owner_ibfk_1] FOREIGN KEY([nodeid])
REFERENCES [dbo].[pubsub_node] ([nodeid])
ON DELETE CASCADE;
ALTER TABLE [dbo].[pubsub_node_owner] CHECK CONSTRAINT [pubsub_node_owner_ibfk_1];
ALTER TABLE [dbo].[pubsub_state] WITH CHECK ADD CONSTRAINT [pubsub_state_ibfk_1] FOREIGN KEY([nodeid])
REFERENCES [dbo].[pubsub_node] ([nodeid])
ON DELETE CASCADE;
ALTER TABLE [dbo].[pubsub_state] CHECK CONSTRAINT [pubsub_state_ibfk_1];
CREATE TABLE [dbo].[oauth_token] (
[token] [varchar] (250) NOT NULL,
[jid] [text] NOT NULL,
[scope] [text] NOT NULL,
[expire] [bigint] NOT NULL,
CONSTRAINT [oauth_token_PRIMARY] PRIMARY KEY CLUSTERED
(
[token] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[route] (
[domain] [varchar] (255) NOT NULL,
[server_host] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[pid] [varchar](100) NOT NULL,
[local_hint] [text] NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [route_i] ON [route] (domain, server_host, node, pid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[bosh] (
[sid] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[pid] [varchar](100) NOT NULL
CONSTRAINT [bosh_PRIMARY] PRIMARY KEY CLUSTERED
(
[sid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
);
CREATE TABLE [dbo].[push_session] (
[username] [varchar] (255) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[timestamp] [bigint] NOT NULL,
[service] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[xml] [varchar] (255) NOT NULL
);
CREATE UNIQUE NONCLUSTERED INDEX [push_session_susn] ON [push_session] (server_host, username, service, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [push_session_sh_username_timestamp] ON [push_session] (server_host, username, timestamp)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_channel] (
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[username] [varchar] (250) NOT NULL,
[domain] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL,
[hidden] [smallint] NOT NULL,
[hmac_key] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [mix_channel] ON [mix_channel] (channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_channel_serv] ON [mix_channel] (service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_participant] (
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[username] [varchar] (250) NOT NULL,
[domain] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL,
[id] [text] NOT NULL,
[nick] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE INDEX [mix_participant] ON [mix_participant] (channel, service, username, domain)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_participant_chan_serv] ON [mix_participant] (channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_subscription] (
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[username] [varchar] (250) NOT NULL,
[domain] [varchar] (250) NOT NULL,
[node] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL
);
CREATE UNIQUE INDEX [mix_subscription] ON [mix_subscription] (channel, service, username, domain, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_subscription_chan_serv_ud] ON [mix_subscription] (channel, service, username, domain)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_subscription_chan_serv_node] ON [mix_subscription] (channel, service, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_subscription_chan_serv] ON [mix_subscription] (channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_pam] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[id] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE NONCLUSTERED INDEX [mix_pam] ON [mix_pam] (username, server_host, channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mqtt_pub] (
[username] [varchar] (250) NOT NULL,
[server_host] [varchar] (250) NOT NULL,
[resource] [varchar] (250) NOT NULL,
[topic] [varchar] (250) NOT NULL,
[qos] [tinyint] NOT NULL,
[payload] [varbinary](max) NOT NULL,
[payload_format] [tinyint] NOT NULL,
[content_type] [text] NOT NULL,
[response_topic] [text] NOT NULL,
[correlation_data] [varbinary](max) NOT NULL,
[user_properties] [varbinary](max) NOT NULL,
[expiry] [int] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [mqtt_topic_server] ON [mqtt_pub] (topic, server_host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+95 -50
View File
@@ -118,10 +118,10 @@ CREATE INDEX [muc_room_host_created_at] ON [muc_registered] (host, nick)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_online_room] (
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
[node] [text] NOT NULL,
[pid] [text] NOT NULL
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
[node] [varchar] (250) NOT NULL,
[pid] [varchar] (100) NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [muc_online_room_name_host] ON [muc_online_room] (name, host)
@@ -133,13 +133,11 @@ CREATE TABLE [dbo].[muc_online_users] (
[resource] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
node text NOT NULL
[node] [varchar] (250) NOT NULL
);
CREATE UNIQUE INDEX [muc_online_users_i] ON [muc_online_users] (username, server, resource, name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_us] ON [muc_online_users] (username, server)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_room_subscribers] (
[room] [varchar] (191) NOT NULL,
@@ -174,9 +172,6 @@ CREATE TABLE [dbo].[privacy_list] (
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
);
CREATE INDEX [privacy_list_username] ON [privacy_list] (username)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE INDEX [privacy_list_username_name] ON [privacy_list] (username, name)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
@@ -203,9 +198,6 @@ CREATE TABLE [dbo].[private_storage] (
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [private_storage_username] ON [private_storage] (username)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE CLUSTERED INDEX [private_storage_username_namespace] ON [private_storage] (username, namespace)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
@@ -226,9 +218,9 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[pubsub_node_option] (
[nodeid] [bigint] NULL,
[name] [text] NOT NULL,
[val] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
[name] [varchar] (250) NOT NULL,
[val] [varchar] (250) NOT NULL
);
CREATE CLUSTERED INDEX [pubsub_node_option_nodeid] ON [pubsub_node_option] (nodeid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
@@ -272,13 +264,13 @@ CREATE TABLE [dbo].[pubsub_node] (
[host] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[parent] [varchar] (255) NOT NULL DEFAULT '',
[plugin] [text] NOT NULL,
[plugin] [varchar] (32) NOT NULL,
[nodeid] [bigint] IDENTITY(1,1) NOT NULL,
CONSTRAINT [pubsub_node_PRIMARY] PRIMARY KEY CLUSTERED
(
[nodeid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
);
CREATE INDEX [pubsub_node_parent] ON [pubsub_node] (parent)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
@@ -320,9 +312,6 @@ CREATE TABLE [dbo].[rosterusers] (
CREATE UNIQUE CLUSTERED INDEX [rosterusers_username_jid] ON [rosterusers] ([username], [jid])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [rosterusers_username] ON [rosterusers] ([username])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [rosterusers_jid] ON [rosterusers] ([jid])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
@@ -366,13 +355,12 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[sr_group] (
[name] [varchar] (250) NOT NULL,
[opts] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [sr_group_PRIMARY] PRIMARY KEY CLUSTERED
(
[name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [sr_group_name] ON [sr_group] ([name])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[sr_user] (
[jid] [varchar] (250) NOT NULL,
[grp] [varchar] (250) NOT NULL,
@@ -382,9 +370,6 @@ CREATE TABLE [dbo].[sr_user] (
CREATE UNIQUE CLUSTERED INDEX [sr_user_jid_group] ON [sr_user] ([jid], [grp])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [sr_user_jid] ON [sr_user] ([jid])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [sr_user_grp] ON [sr_user] ([grp])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
@@ -521,9 +506,6 @@ CREATE TABLE [dbo].[route] (
CREATE UNIQUE CLUSTERED INDEX [route_i] ON [route] (domain, server_host, node, pid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [route_domain] ON [route] (domain)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[bosh] (
[sid] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
@@ -545,25 +527,88 @@ CREATE TABLE [dbo].[push_session] (
CREATE UNIQUE CLUSTERED INDEX [i_push_usn] ON [push_session] (username, service, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE INDEX [i_push_ut] ON [push_session] (username, timestamp)
CREATE INDEX [i_push_ut] ON [push_session] (username, timestamp)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_channel] (
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[username] [varchar] (250) NOT NULL,
[domain] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL,
[hidden] [smallint] NOT NULL,
[hmac_key] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [mix_channel] ON [mix_channel] (channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_channel_serv] ON [mix_channel] (service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_participant] (
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[username] [varchar] (250) NOT NULL,
[domain] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL,
[id] [text] NOT NULL,
[nick] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE INDEX [mix_participant] ON [mix_participant] (channel, service, username, domain)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_participant_chan_serv] ON [mix_participant] (channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_subscription] (
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[username] [varchar] (250) NOT NULL,
[domain] [varchar] (250) NOT NULL,
[node] [varchar] (250) NOT NULL,
[jid] [varchar] (250) NOT NULL
);
CREATE UNIQUE INDEX [mix_subscription] ON [mix_subscription] (channel, service, username, domain, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_subscription_chan_serv_ud] ON [mix_subscription] (channel, service, username, domain)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_subscription_chan_serv_node] ON [mix_subscription] (channel, service, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [mix_subscription_chan_serv] ON [mix_subscription] (channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mix_pam] (
[username] [varchar] (250) NOT NULL,
[channel] [varchar] (250) NOT NULL,
[service] [varchar] (250) NOT NULL,
[id] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [mix_pam] ON [mix_pam] (username, channel, service)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[mqtt_pub] (
[username] [varchar](191) NOT NULL,
[server_host] [varchar](191) NOT NULL,
[resource] [varchar](191) NOT NULL,
[topic] [varchar](191) NOT NULL,
[qos] [tinyint] NOT NULL,
[payload] [varbinary](max) NOT NULL,
[payload_format] [tinyint] NOT NULL,
[content_type] [text] NOT NULL,
[response_topic] [text] NOT NULL,
[correlation_data] [varbinary](max) NOT NULL,
[user_properties] [varbinary](max) NOT NULL,
[expiry] [int] NOT NULL,
CONSTRAINT [i_mqtt_topic_server] PRIMARY KEY CLUSTERED
(
[topic] ASC,
[server_host] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
[username] [varchar] (250) NOT NULL,
[resource] [varchar] (250) NOT NULL,
[topic] [varchar] (250) NOT NULL,
[qos] [tinyint] NOT NULL,
[payload] [varbinary](max) NOT NULL,
[payload_format] [tinyint] NOT NULL,
[content_type] [text] NOT NULL,
[response_topic] [text] NOT NULL,
[correlation_data] [varbinary](max) NOT NULL,
[user_properties] [varbinary](max) NOT NULL,
[expiry] [int] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [mqtt_topic] ON [mqtt_pub] (topic)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+4 -13
View File
@@ -56,7 +56,6 @@ CREATE TABLE rosterusers (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_rosteru_sh_user_jid ON rosterusers(server_host(191), username(75), jid(75));
CREATE INDEX i_rosteru_sh_username ON rosterusers(server_host(191), username);
CREATE INDEX i_rosteru_sh_jid ON rosterusers(server_host(191), jid);
CREATE TABLE rostergroups (
@@ -86,8 +85,7 @@ CREATE TABLE sr_user (
PRIMARY KEY (server_host(191), jid, grp)
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_sr_user_sh_jid_group ON sr_user(server_host(191), jid, grp);
CREATE INDEX i_sr_user_sh_jid ON sr_user(server_host(191), jid);
CREATE UNIQUE INDEX i_sr_user_sh_jid_grp ON sr_user(server_host(191), jid, grp);
CREATE INDEX i_sr_user_sh_grp ON sr_user(server_host(191), grp);
CREATE TABLE spool (
@@ -195,7 +193,6 @@ CREATE TABLE privacy_list (
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_privacy_list_sh_username USING BTREE ON privacy_list(server_host(191), username);
CREATE UNIQUE INDEX i_privacy_list_sh_username_name USING BTREE ON privacy_list (server_host(191), username(75), name(75));
CREATE TABLE privacy_list_data (
@@ -218,11 +215,10 @@ CREATE TABLE private_storage (
server_host varchar(191) NOT NULL,
namespace varchar(191) NOT NULL,
data text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (server_host(191), username, namespace)
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_private_storage_sh_username USING BTREE ON private_storage(server_host(191), username);
CREATE UNIQUE INDEX i_private_storage_sh_sername_namespace USING BTREE ON private_storage(server_host(191), username, namespace);
-- Not tested in mysql
CREATE TABLE roster_version (
@@ -335,7 +331,6 @@ CREATE TABLE muc_online_users (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75));
CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75));
CREATE TABLE muc_room_subscribers (
room varchar(191) NOT NULL,
@@ -405,7 +400,6 @@ CREATE TABLE route (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_route ON route(domain(75), server_host(75), node(75), pid(75));
CREATE INDEX i_route_domain ON route(domain(75));
CREATE TABLE bosh (
sid text NOT NULL,
@@ -438,6 +432,7 @@ CREATE TABLE push_session (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_push_session_susn ON push_session (server_host(191), username(191), service(191), node(191));
CREATE INDEX i_push_session_sh_username_timestamp ON push_session (server_host, username(191), timestamp);
CREATE TABLE mix_channel (
channel text NOT NULL,
@@ -465,7 +460,6 @@ CREATE TABLE mix_participant (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel(191), service(191), username(191), domain(191));
CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel(191), service(191));
CREATE TABLE mix_subscription (
channel text NOT NULL,
@@ -477,9 +471,7 @@ CREATE TABLE mix_subscription (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel(153), service(153), username(153), domain(153), node(153));
CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel(191), service(191), username(191), domain(191));
CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel(191), service(191), node(191));
CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel(191), service(191));
CREATE TABLE mix_pam (
username text NOT NULL,
@@ -491,7 +483,6 @@ CREATE TABLE mix_pam (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username(191), server_host(191), channel(191), service(191));
CREATE INDEX i_mix_pam_us ON mix_pam (username(191), server_host(191));
CREATE TABLE mqtt_pub (
username varchar(191) NOT NULL,
+2 -7
View File
@@ -17,6 +17,7 @@ BEGIN
ALTER TABLE `push_session` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `push_session` ADD PRIMARY KEY (`server_host`, `username`(191), `timestamp`);
ALTER TABLE `push_session` ADD UNIQUE INDEX `i_push_session_susn` (`server_host`, `username`(191), `service`(191), `node`(191));
ALTER TABLE `push_session` ADD INDEX `i_push_session_sh_username_timestamp` (`server_host`, `username`(191), `timestamp`);
ALTER TABLE `roster_version` DROP PRIMARY KEY;
ALTER TABLE `roster_version` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `roster_version` ALTER COLUMN `server_host` DROP DEFAULT;
@@ -33,14 +34,12 @@ BEGIN
ALTER TABLE `rosterusers` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `rosterusers` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `rosterusers` ADD UNIQUE INDEX `i_rosteru_sh_user_jid` (`server_host`, `username`(75), `jid`(75));
ALTER TABLE `rosterusers` ADD INDEX `i_rosteru_sh_username` (`server_host`, `username`);
ALTER TABLE `rosterusers` ADD INDEX `i_rosteru_sh_jid` (`server_host`, `jid`);
ALTER TABLE `private_storage` DROP INDEX `i_private_storage_username_namespace`;
ALTER TABLE `private_storage` DROP INDEX `i_private_storage_username`;
ALTER TABLE `private_storage` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `private_storage` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `private_storage` ADD PRIMARY KEY (`server_host`, `username`, `namespace`);
ALTER TABLE `private_storage` ADD INDEX `i_private_storage_sh_username` USING BTREE (`server_host`, `username`);
ALTER TABLE `mqtt_pub` DROP INDEX `i_mqtt_topic`;
ALTER TABLE `mqtt_pub` ADD COLUMN `server_host` VARCHAR (191) NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `mqtt_pub` ALTER COLUMN `server_host` DROP DEFAULT;
@@ -75,10 +74,10 @@ BEGIN
ALTER TABLE `last` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `last` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `last` ADD PRIMARY KEY (`server_host`, `username`);
ALTER TABLE `sr_group` DROP INDEX `i_sr_group_name`;
ALTER TABLE `sr_group` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `name`;
ALTER TABLE `sr_group` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `sr_group` ADD UNIQUE INDEX `i_sr_group_sh_name` (`server_host`, `name`);
ALTER TABLE `sr_group` ADD PRIMARY KEY (`server_host`, `name`);
ALTER TABLE `muc_registered` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `host`;
ALTER TABLE `muc_registered` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `sm` DROP INDEX `i_node`;
@@ -94,16 +93,13 @@ BEGIN
ALTER TABLE `privacy_list` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `privacy_list` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `privacy_list` ADD UNIQUE INDEX `i_privacy_list_sh_username_name` USING BTREE (`server_host`, `username`(75), `name`(75));
ALTER TABLE `privacy_list` ADD INDEX `i_privacy_list_sh_username` USING BTREE (`server_host`, `username`);
ALTER TABLE `sr_user` DROP INDEX `i_sr_user_jid`;
ALTER TABLE `sr_user` DROP INDEX `i_sr_user_grp`;
ALTER TABLE `sr_user` DROP INDEX `i_sr_user_jid_group`;
ALTER TABLE `sr_user` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `jid`;
ALTER TABLE `sr_user` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `sr_user` ADD UNIQUE INDEX `i_sr_user_sh_jid_group` (`server_host`, `jid`, `grp`);
ALTER TABLE `sr_user` ADD INDEX `i_sr_user_sh_jid` (`server_host`, `jid`);
ALTER TABLE `sr_user` ADD INDEX `i_sr_user_sh_grp` (`server_host`, `grp`);
ALTER TABLE `sr_user` ADD PRIMARY KEY (`server_host`, `jid`, `grp`);
ALTER TABLE `muc_online_users` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `host`;
ALTER TABLE `muc_online_users` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `vcard` DROP PRIMARY KEY;
@@ -119,7 +115,6 @@ BEGIN
ALTER TABLE `mix_pam` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
ALTER TABLE `mix_pam` ALTER COLUMN `server_host` DROP DEFAULT;
ALTER TABLE `mix_pam` ADD UNIQUE INDEX `i_mix_pam` (`username`(191), `server_host`, `channel`(191), `service`(191));
ALTER TABLE `mix_pam` ADD INDEX `i_mix_pam_us` (`username`(191), `server_host`);
ALTER TABLE `route` CHANGE COLUMN `server_host` `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL;
ALTER TABLE `users` DROP PRIMARY KEY;
ALTER TABLE `users` ADD COLUMN `server_host` VARCHAR (191) COLLATE `utf8mb4_unicode_ci` NOT NULL DEFAULT @DEFAULT_HOST AFTER `username`;
-10
View File
@@ -51,7 +51,6 @@ CREATE TABLE rosterusers (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers(username(75), jid(75));
CREATE INDEX i_rosteru_username ON rosterusers(username);
CREATE INDEX i_rosteru_jid ON rosterusers(jid);
CREATE TABLE rostergroups (
@@ -77,7 +76,6 @@ CREATE TABLE sr_user (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_sr_user_jid_group ON sr_user(jid(75), grp(75));
CREATE INDEX i_sr_user_jid ON sr_user(jid);
CREATE INDEX i_sr_user_grp ON sr_user(grp);
CREATE TABLE spool (
@@ -174,7 +172,6 @@ CREATE TABLE privacy_list (
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_privacy_list_username USING BTREE ON privacy_list(username);
CREATE UNIQUE INDEX i_privacy_list_username_name USING BTREE ON privacy_list (username(75), name(75));
CREATE TABLE privacy_list_data (
@@ -199,7 +196,6 @@ CREATE TABLE private_storage (
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username);
CREATE UNIQUE INDEX i_private_storage_username_namespace USING BTREE ON private_storage(username(75), namespace(75));
-- Not tested in mysql
@@ -307,7 +303,6 @@ CREATE TABLE muc_online_users (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75));
CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75));
CREATE TABLE muc_room_subscribers (
room varchar(191) NOT NULL,
@@ -374,7 +369,6 @@ CREATE TABLE route (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_route ON route(domain(75), server_host(75), node(75), pid(75));
CREATE INDEX i_route_domain ON route(domain(75));
CREATE TABLE bosh (
sid text NOT NULL,
@@ -433,7 +427,6 @@ CREATE TABLE mix_participant (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel(191), service(191), username(191), domain(191));
CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel(191), service(191));
CREATE TABLE mix_subscription (
channel text NOT NULL,
@@ -445,9 +438,7 @@ CREATE TABLE mix_subscription (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel(153), service(153), username(153), domain(153), node(153));
CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel(191), service(191), username(191), domain(191));
CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel(191), service(191), node(191));
CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel(191), service(191));
CREATE TABLE mix_pam (
username text NOT NULL,
@@ -458,7 +449,6 @@ CREATE TABLE mix_pam (
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username(191), channel(191), service(191));
CREATE INDEX i_mix_pam_u ON mix_pam (username(191));
CREATE TABLE mqtt_pub (
username varchar(191) NOT NULL,
+14 -38
View File
@@ -30,10 +30,8 @@
-- ALTER TABLE rosterusers ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_rosteru_user_jid;
-- DROP INDEX i_rosteru_username;
-- DROP INDEX i_rosteru_jid;
-- CREATE UNIQUE INDEX i_rosteru_sh_user_jid ON rosterusers USING btree (server_host, username, jid);
-- CREATE INDEX i_rosteru_sh_username ON rosterusers USING btree (server_host, username);
-- CREATE INDEX i_rosteru_sh_jid ON rosterusers USING btree (server_host, jid);
-- ALTER TABLE rosterusers ALTER COLUMN server_host DROP DEFAULT;
@@ -43,15 +41,15 @@
-- ALTER TABLE rostergroups ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE sr_group ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_sr_group_name;
-- ALTER TABLE sr_group ADD PRIMARY KEY (server_host, name);
-- CREATE UNIQUE INDEX i_sr_group_sh_name ON sr_group USING btree (server_host, name);
-- ALTER TABLE sr_group ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE sr_user ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_sr_user_jid_grp;
-- DROP INDEX i_sr_user_jid;
-- DROP INDEX i_sr_user_grp;
-- ALTER TABLE sr_user ADD PRIMARY KEY (server_host, jid, grp);
-- CREATE INDEX i_sr_user_sh_jid ON sr_user USING btree (server_host, jid);
-- CREATE INDEX i_sr_user_sh_grp ON sr_user USING btree (server_host, grp);
-- ALTER TABLE sr_user ALTER COLUMN server_host DROP DEFAULT;
@@ -94,7 +92,7 @@
-- DROP INDEX i_vcard_search_lemail;
-- DROP INDEX i_vcard_search_lorgname;
-- DROP INDEX i_vcard_search_lorgunit;
-- ALTER TABLE vcard_search ADD PRIMARY KEY (server_host, username);
-- ALTER TABLE vcard_search ADD PRIMARY KEY (server_host, lusername);
-- CREATE INDEX i_vcard_search_sh_lfn ON vcard_search(server_host, lfn);
-- CREATE INDEX i_vcard_search_sh_lfamily ON vcard_search(server_host, lfamily);
-- CREATE INDEX i_vcard_search_sh_lgiven ON vcard_search(server_host, lgiven);
@@ -114,17 +112,13 @@
-- ALTER TABLE privacy_default_list ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE privacy_list ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_privacy_list_username;
-- DROP INDEX i_privacy_list_username_name;
-- CREATE INDEX i_privacy_list_sh_username ON privacy_list USING btree (server_host, username);
-- CREATE UNIQUE INDEX i_privacy_list_sh_username_name ON privacy_list USING btree (server_host, username, name);
-- ALTER TABLE privacy_list ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE private_storage ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_private_storage_username;
-- DROP INDEX i_private_storage_username_namespace;
-- ALTER TABLE private_storage ADD PRIMARY KEY (server_host, username, namespace);
-- CREATE INDEX i_private_storage_sh_username ON private_storage USING btree (server_host, username);
-- ALTER TABLE private_storage ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE roster_version ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
@@ -161,20 +155,14 @@
-- DROP INDEX i_push_ut;
-- ALTER TABLE push_session ADD PRIMARY KEY (server_host, username, timestamp);
-- CREATE UNIQUE INDEX i_push_session_susn ON push_session USING btree (server_host, username, service, node);
-- CREATE INDEX i_push_session_sh_username_timestamp ON push_session USING btree (server_host, username, timestamp);
-- ALTER TABLE push_session ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE mix_pam ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_mix_pam;
-- DROP INDEX i_mix_pam_us;
-- CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username, server_host, channel, service);
-- CREATE INDEX i_mix_pam_us ON mix_pam (username, server_host);
-- ALTER TABLE mix_pam ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE route ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_route;
-- CREATE UNIQUE INDEX i_route ON route USING btree (domain, server_host, node, pid);
-- ALTER TABLE i_route ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE mqtt_pub ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- DROP INDEX i_mqtt_topic;
-- CREATE UNIQUE INDEX i_mqtt_topic_server ON mqtt_pub (topic, server_host);
@@ -221,7 +209,6 @@ CREATE TABLE rosterusers (
);
CREATE UNIQUE INDEX i_rosteru_sh_user_jid ON rosterusers USING btree (server_host, username, jid);
CREATE INDEX i_rosteru_sh_username ON rosterusers USING btree (server_host, username);
CREATE INDEX i_rosteru_sh_jid ON rosterusers USING btree (server_host, jid);
@@ -238,8 +225,7 @@ CREATE TABLE sr_group (
name text NOT NULL,
server_host text NOT NULL,
opts text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now(),
PRIMARY KEY (server_host, name)
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX i_sr_group_sh_name ON sr_group USING btree (server_host, name);
@@ -248,19 +234,17 @@ CREATE TABLE sr_user (
jid text NOT NULL,
server_host text NOT NULL,
grp text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now(),
PRIMARY KEY (server_host, jid, grp)
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX i_sr_user_sh_jid_grp ON sr_user USING btree (server_host, jid, grp);
CREATE INDEX i_sr_user_sh_jid ON sr_user USING btree (server_host, jid);
CREATE INDEX i_sr_user_sh_grp ON sr_user USING btree (server_host, grp);
CREATE TABLE spool (
username text NOT NULL,
server_host text NOT NULL,
xml text NOT NULL,
seq SERIAL,
seq BIGSERIAL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
@@ -274,7 +258,7 @@ CREATE TABLE archive (
bare_peer text NOT NULL,
xml text NOT NULL,
txt text,
id SERIAL,
id BIGSERIAL,
kind text,
nick text,
created_at TIMESTAMP NOT NULL DEFAULT now()
@@ -355,11 +339,10 @@ CREATE TABLE privacy_list (
username text NOT NULL,
server_host text NOT NULL,
name text NOT NULL,
id SERIAL UNIQUE,
id BIGSERIAL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE INDEX i_privacy_list_sh_username ON privacy_list USING btree (server_host, username);
CREATE UNIQUE INDEX i_privacy_list_sh_username_name ON privacy_list USING btree (server_host, username, name);
CREATE TABLE privacy_list_data (
@@ -382,12 +365,10 @@ CREATE TABLE private_storage (
server_host text NOT NULL,
namespace text NOT NULL,
data text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now(),
PRIMARY KEY (server_host, username, namespace)
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE INDEX i_private_storage_sh_username ON private_storage USING btree (server_host, username);
CREATE UNIQUE INDEX i_private_storage_sh_username_namespace ON private_storage USING btree (server_host, username, namespace);
CREATE TABLE roster_version (
username text NOT NULL,
@@ -413,7 +394,7 @@ CREATE TABLE pubsub_node (
node text NOT NULL,
parent text NOT NULL DEFAULT '',
plugin text NOT NULL,
nodeid SERIAL UNIQUE
nodeid BIGSERIAL UNIQUE
);
CREATE INDEX i_pubsub_node_parent ON pubsub_node USING btree (parent);
CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node USING btree (host, node);
@@ -436,7 +417,7 @@ CREATE TABLE pubsub_state (
jid text NOT NULL,
affiliation character(1),
subscriptions text NOT NULL DEFAULT '',
stateid SERIAL UNIQUE
stateid BIGSERIAL UNIQUE
);
CREATE INDEX i_pubsub_state_jid ON pubsub_state USING btree (jid);
CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state USING btree (nodeid, jid);
@@ -502,7 +483,6 @@ CREATE TABLE muc_online_users (
);
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
CREATE TABLE muc_room_subscribers (
room text NOT NULL,
@@ -574,7 +554,6 @@ CREATE TABLE route (
);
CREATE UNIQUE INDEX i_route ON route USING btree (domain, server_host, node, pid);
CREATE INDEX i_route_domain ON route USING btree (domain);
CREATE TABLE bosh (
sid text NOT NULL,
@@ -607,6 +586,7 @@ CREATE TABLE push_session (
);
CREATE UNIQUE INDEX i_push_session_susn ON push_session USING btree (server_host, username, service, node);
CREATE INDEX i_push_session_sh_username_timestamp ON push_session USING btree (server_host, username, timestamp);
CREATE TABLE mix_channel (
channel text NOT NULL,
@@ -634,7 +614,6 @@ CREATE TABLE mix_participant (
);
CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel, service, username, domain);
CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel, service);
CREATE TABLE mix_subscription (
channel text NOT NULL,
@@ -646,9 +625,7 @@ CREATE TABLE mix_subscription (
);
CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel, service, username, domain, node);
CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel, service, username, domain);
CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel, service, node);
CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel, service);
CREATE TABLE mix_pam (
username text NOT NULL,
@@ -660,7 +637,6 @@ CREATE TABLE mix_pam (
);
CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username, server_host, channel, service);
CREATE INDEX i_mix_pam_us ON mix_pam (username, server_host);
CREATE TABLE mqtt_pub (
username text NOT NULL,
+6 -16
View File
@@ -51,7 +51,6 @@ CREATE TABLE rosterusers (
);
CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers USING btree (username, jid);
CREATE INDEX i_rosteru_username ON rosterusers USING btree (username);
CREATE INDEX i_rosteru_jid ON rosterusers USING btree (jid);
@@ -78,13 +77,12 @@ CREATE TABLE sr_user (
);
CREATE UNIQUE INDEX i_sr_user_jid_grp ON sr_user USING btree (jid, grp);
CREATE INDEX i_sr_user_jid ON sr_user USING btree (jid);
CREATE INDEX i_sr_user_grp ON sr_user USING btree (grp);
CREATE TABLE spool (
username text NOT NULL,
xml text NOT NULL,
seq SERIAL,
seq BIGSERIAL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
@@ -97,7 +95,7 @@ CREATE TABLE archive (
bare_peer text NOT NULL,
xml text NOT NULL,
txt text,
id SERIAL,
id BIGSERIAL,
kind text,
nick text,
created_at TIMESTAMP NOT NULL DEFAULT now()
@@ -169,11 +167,10 @@ CREATE TABLE privacy_default_list (
CREATE TABLE privacy_list (
username text NOT NULL,
name text NOT NULL,
id SERIAL UNIQUE,
id BIGSERIAL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE INDEX i_privacy_list_username ON privacy_list USING btree (username);
CREATE UNIQUE INDEX i_privacy_list_username_name ON privacy_list USING btree (username, name);
CREATE TABLE privacy_list_data (
@@ -198,7 +195,6 @@ CREATE TABLE private_storage (
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE INDEX i_private_storage_username ON private_storage USING btree (username);
CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace);
@@ -224,7 +220,7 @@ CREATE TABLE pubsub_node (
node text NOT NULL,
parent text NOT NULL DEFAULT '',
plugin text NOT NULL,
nodeid SERIAL UNIQUE
nodeid BIGSERIAL UNIQUE
);
CREATE INDEX i_pubsub_node_parent ON pubsub_node USING btree (parent);
CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node USING btree (host, node);
@@ -247,7 +243,7 @@ CREATE TABLE pubsub_state (
jid text NOT NULL,
affiliation character(1),
subscriptions text NOT NULL DEFAULT '',
stateid SERIAL UNIQUE
stateid BIGSERIAL UNIQUE
);
CREATE INDEX i_pubsub_state_jid ON pubsub_state USING btree (jid);
CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state USING btree (nodeid, jid);
@@ -309,7 +305,6 @@ CREATE TABLE muc_online_users (
);
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
CREATE TABLE muc_room_subscribers (
room text NOT NULL,
@@ -378,7 +373,6 @@ CREATE TABLE route (
);
CREATE UNIQUE INDEX i_route ON route USING btree (domain, server_host, node, pid);
CREATE INDEX i_route_domain ON route USING btree (domain);
CREATE TABLE bosh (
sid text NOT NULL,
@@ -409,7 +403,7 @@ CREATE TABLE push_session (
);
CREATE UNIQUE INDEX i_push_usn ON push_session USING btree (username, service, node);
CREATE UNIQUE INDEX i_push_ut ON push_session USING btree (username, timestamp);
CREATE INDEX i_push_ut ON push_session USING btree (username, timestamp);
CREATE TABLE mix_channel (
channel text NOT NULL,
@@ -437,7 +431,6 @@ CREATE TABLE mix_participant (
);
CREATE UNIQUE INDEX i_mix_participant ON mix_participant (channel, service, username, domain);
CREATE INDEX i_mix_participant_chan_serv ON mix_participant (channel, service);
CREATE TABLE mix_subscription (
channel text NOT NULL,
@@ -449,9 +442,7 @@ CREATE TABLE mix_subscription (
);
CREATE UNIQUE INDEX i_mix_subscription ON mix_subscription (channel, service, username, domain, node);
CREATE INDEX i_mix_subscription_chan_serv_ud ON mix_subscription (channel, service, username, domain);
CREATE INDEX i_mix_subscription_chan_serv_node ON mix_subscription (channel, service, node);
CREATE INDEX i_mix_subscription_chan_serv ON mix_subscription (channel, service);
CREATE TABLE mix_pam (
username text NOT NULL,
@@ -462,7 +453,6 @@ CREATE TABLE mix_pam (
);
CREATE UNIQUE INDEX i_mix_pam ON mix_pam (username, channel, service);
CREATE INDEX i_mix_pam_us ON mix_pam (username);
CREATE TABLE mqtt_pub (
username text NOT NULL,
+1
View File
@@ -103,6 +103,7 @@ prep_stop(State) ->
ejabberd_sm:stop(),
ejabberd_service:stop(),
ejabberd_s2s:stop(),
ejabberd_system_monitor:stop(),
gen_mod:stop(),
State.
+54 -1
View File
@@ -441,18 +441,37 @@ do_create_image(Key, FileName) when is_binary(FileName) ->
get_prog_name() ->
case ejabberd_option:captcha_cmd() of
undefined ->
?DEBUG("The option captcha_cmd is not configured, "
?WARNING_MSG("The option captcha_cmd is not configured, "
"but some module wants to use the CAPTCHA "
"feature.",
[]),
false;
FileName ->
maybe_warning_norequesthandler(),
FileName
end.
maybe_warning_norequesthandler() ->
Host = hd(ejabberd_option:hosts()),
URL = get_auto_url(any, ?MODULE, Host),
case URL of
undefined ->
?WARNING_MSG("The option captcha_cmd is configured, "
"but there is NO request_handler in listen option "
"configured with ejabberd_captcha. Please check "
"https://docs.ejabberd.im/admin/configuration/basic/#captcha",
[]);
_ ->
ok
end.
-spec get_url(binary()) -> binary().
get_url(Str) ->
case ejabberd_option:captcha_url() of
auto ->
Host = ejabberd_config:get_myname(),
URL = get_auto_url(any, ?MODULE, Host),
<<URL/binary, $/, Str/binary>>;
undefined ->
URL = parse_captcha_host(),
<<URL/binary, "/captcha/", Str/binary>>;
@@ -477,6 +496,40 @@ parse_captcha_host() ->
<<"http://", (ejabberd_config:get_myname())/binary>>
end.
get_auto_url(Tls, Module, Host) ->
case find_handler_port_path(Tls, Module) of
[] -> undefined;
TPPs ->
{ThisTls, Port, Path} = case lists:keyfind(true, 1, TPPs) of
false ->
lists:keyfind(false, 1, TPPs);
TPP ->
TPP
end,
Protocol = case ThisTls of
false -> <<"http">>;
true -> <<"https">>
end,
<<Protocol/binary,
"://", Host/binary, ":",
(integer_to_binary(Port))/binary,
"/",
(str:join(Path, <<"/">>))/binary>>
end.
find_handler_port_path(Tls, Module) ->
lists:filtermap(
fun({{Port, _, _},
ejabberd_http,
#{tls := ThisTls, request_handlers := Handlers}})
when (Tls == any) or (Tls == ThisTls) ->
case lists:keyfind(Module, 2, Handlers) of
false -> false;
{Path, Module} -> {true, {ThisTls, Port, Path}}
end;
(_) -> false
end, ets:tab2list(ejabberd_listener)).
get_transfer_protocol(PortString) ->
PortNumber = binary_to_integer(PortString),
PortListeners = get_port_listeners(PortNumber),
+22 -22
View File
@@ -33,9 +33,11 @@
-include("ejabberd_commands.hrl").
-define(RAW(V), if HTMLOutput -> fxml:crypt(iolist_to_binary(V)); true -> iolist_to_binary(V) end).
-define(TAG(N), if HTMLOutput -> [<<"<", ??N, "/>">>]; true -> md_tag(N, <<"">>) end).
-define(TAG(N, V), if HTMLOutput -> [<<"<", ??N, ">">>, V, <<"</", ??N, ">">>]; true -> md_tag(N, V) end).
-define(TAG(N, C, V), if HTMLOutput -> [<<"<", ??N, " class='", C, "'>">>, V, <<"</", ??N, ">">>]; true -> md_tag(N, V) end).
-define(TAG_BIN(N), (atom_to_binary(N, latin1))/binary).
-define(TAG_STR(N), atom_to_list(N)).
-define(TAG(N), if HTMLOutput -> [<<"<", ?TAG_BIN(N), "/>">>]; true -> md_tag(N, <<"">>) end).
-define(TAG(N, V), if HTMLOutput -> [<<"<", ?TAG_BIN(N), ">">>, V, <<"</", ?TAG_BIN(N), ">">>]; true -> md_tag(N, V) end).
-define(TAG(N, C, V), if HTMLOutput -> [<<"<", ?TAG_BIN(N), " class='", C, "'>">>, V, <<"</", ?TAG_BIN(N), ">">>]; true -> md_tag(N, V) end).
-define(TAG_R(N, V), ?TAG(N, ?RAW(V))).
-define(TAG_R(N, C, V), ?TAG(N, C, ?RAW(V))).
-define(SPAN(N, V), ?TAG_R(span, ??N, V)).
@@ -413,14 +415,19 @@ gen_doc(#ejabberd_commands{name=Name, tags=Tags, desc=Desc, longdesc=LongDesc,
"" -> [];
_ -> ?TAG('div', "note-down", ?RAW(Note))
end,
{NotePre, NotePost} =
if HTMLOutput -> {[], NoteEl};
true -> {NoteEl, []}
end,
[NoteEl,
[NotePre,
?TAG(h1, atom_to_list(Name)),
?TAG(p, ?RAW(Desc)),
case LongDesc of
"" -> [];
_ -> ?TAG(p, ?RAW(LongDesc))
end,
NotePost,
?TAG(h2, <<"Arguments:">>), ArgsText,
?TAG(h2, <<"Result:">>), ResultText,
?TAG(h2, <<"Tags:">>), ?TAG(p, TagsText)]
@@ -434,24 +441,17 @@ gen_doc(#ejabberd_commands{name=Name, tags=Tags, desc=Desc, longdesc=LongDesc,
end.
find_commands_definitions() ->
case code:lib_dir(ejabberd, ebin) of
{error, _} ->
lists:map(fun({N, _, _}) ->
ejabberd_commands:get_command_definition(N)
end, ejabberd_commands:list_commands());
Path ->
lists:flatmap(fun(P) ->
Mod = list_to_atom(filename:rootname(P)),
code:ensure_loaded(Mod),
Cs = case erlang:function_exported(Mod, get_commands_spec, 0) of
true ->
apply(Mod, get_commands_spec, []);
_ ->
[]
end,
[C#ejabberd_commands{definer = Mod} || C <- Cs]
end, filelib:wildcard("*.beam", Path))
end.
lists:flatmap(
fun(Mod) ->
code:ensure_loaded(Mod),
Cs = case erlang:function_exported(Mod, get_commands_spec, 0) of
true ->
apply(Mod, get_commands_spec, []);
_ ->
[]
end,
[C#ejabberd_commands{definer = Mod} || C <- Cs]
end, ejabberd_config:beams(all)).
generate_html_output(File, RegExp, Languages) ->
Cmds = find_commands_definitions(),
+2 -2
View File
@@ -37,13 +37,13 @@
-export([beams/1, validators/1, globals/0, may_hide_data/1]).
-export([dump/0, dump/1, convert_to_yaml/1, convert_to_yaml/2]).
-export([callback_modules/1]).
-export([set_option/2]).
%% Deprecated functions
-export([get_option/2, set_option/2]).
-export([get_option/2]).
-export([get_version/0, get_myhosts/0]).
-export([get_mylang/0, get_lang/1]).
-deprecated([{get_option, 2},
{set_option, 2},
{get_version, 0},
{get_myhosts, 0},
{get_mylang, 0},
+1 -1
View File
@@ -498,7 +498,7 @@ is_supported_args(Args) ->
%% Commands are Bold
-define(B1, "\e[1m").
-define(B2, "\e[21m").
-define(B2, "\e[22m").
-define(C(S), case ShCode of true -> [?B1, S, ?B2]; false -> S end).
%% Arguments are Dim
+10 -1
View File
@@ -39,6 +39,7 @@
-include("logger.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_stacktrace.hrl").
-include_lib("kernel/include/file.hrl").
-record(state, {sockmod,
@@ -370,7 +371,15 @@ process(Handlers, Request) ->
HandlerModule:socket_handoff(
LocalPath, Request, HandlerOpts);
false ->
HandlerModule:process(LocalPath, Request)
try
HandlerModule:process(LocalPath, Request)
catch
?EX_RULE(Class, Reason, Stack) ->
?ERROR_MSG(
"HTTP handler crashed: ~s",
[misc:format_exception(2, Class, Reason, ?EX_STACK(Stack))]),
erlang:raise(Class, Reason, ?EX_STACK(Stack))
end
end,
ejabberd_hooks:run(http_request_debug, [{LocalPath, Request}]),
R;
+1 -1
View File
@@ -329,7 +329,7 @@ captcha_host() ->
captcha_limit() ->
ejabberd_config:get_option({captcha_limit, global}).
-spec captcha_url() -> 'undefined' | binary().
-spec captcha_url() -> 'auto' | 'undefined' | binary().
captcha_url() ->
ejabberd_config:get_option({captcha_url, global}).
+4 -2
View File
@@ -123,7 +123,9 @@ opt_type(captcha_host) ->
opt_type(captcha_limit) ->
econf:pos_int(infinity);
opt_type(captcha_url) ->
econf:url();
econf:either(
econf:url(),
econf:enum([auto, undefined]));
opt_type(certfiles) ->
econf:list(econf:binary());
opt_type(cluster_backend) ->
@@ -546,7 +548,7 @@ options() ->
{captcha_cmd, undefined},
{captcha_host, <<"">>},
{captcha_limit, infinity},
{captcha_url, undefined},
{captcha_url, auto},
{certfiles, undefined},
{cluster_backend, mnesia},
{cluster_nodes, []},
+21 -11
View File
@@ -458,8 +458,8 @@ doc() ->
note => "improved in 23.01",
desc =>
?T("Full path to a script that generates http://../basic/#captcha[CAPTCHA] images. "
"@VERSION@ is replaced with ejabberd version number in XX.YY format. "
"@SEMVER@ is replaced with ejabberd version number in semver format "
"'@VERSION@' is replaced with ejabberd version number in 'XX.YY' format. "
"'@SEMVER@' is replaced with ejabberd version number in semver format "
"when compiled with Elixir's mix, or XX.YY format otherwise. "
"Alternatively, it can be the name of a module that implements ejabberd CAPTCHA support. "
"There is no default value: when this option is not "
@@ -477,11 +477,17 @@ doc() ->
#{value => "String",
desc => ?T("Deprecated. Use _`captcha_url`_ instead.")}},
{captcha_url,
#{value => ?T("URL"),
#{value => ?T("URL | auto | undefined"),
note => "improved in 23.04",
desc =>
?T("An URL where http://../basic/#captcha[CAPTCHA] requests should be sent. NOTE: you need "
"to configure 'request_handlers' for 'ejabberd_http' listener "
"as well. There is no default value.")}},
"as well. "
"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 default value is 'auto'.")}},
{certfiles,
#{value => "[Path, ...]",
desc =>
@@ -1293,9 +1299,9 @@ doc() ->
note => "added in 20.12",
desc =>
?T("Path to the ODBC driver to use to connect to a Microsoft SQL "
"Server database. This option is only valid if the _`sql_type`_ "
"option is set to 'mssql'. "
"The default value is: 'libtdsodbc.so'")}},
"Server database. This option only applies if the _`sql_type`_ "
"option is set to 'mssql' and _`sql_server`_ is not an ODBC "
"connection string. The default value is: 'libtdsodbc.so'")}},
{sql_password,
#{value => ?T("Password"),
desc =>
@@ -1334,14 +1340,15 @@ doc() ->
{sql_server,
#{value => ?T("Host"),
desc =>
?T("A hostname or an IP address of the SQL server. "
?T("The hostname or IP address of the SQL server. For _`sql_type`_ "
"'mssql' or 'odbc' this can also be an ODBC connection string. "
"The default value is 'localhost'.")}},
{sql_ssl,
#{value => "true | false",
note => "improved in 20.03",
desc =>
?T("Whether to use SSL encrypted connections to the "
"SQL server. The option is only available for MySQL and "
"SQL server. The option is only available for MySQL, MS SQL and "
"PostgreSQL. The default value is 'false'.")}},
{sql_ssl_cafile,
#{value => ?T("Path"),
@@ -1350,7 +1357,8 @@ doc() ->
"be used to verify SQL connections. Implies _`sql_ssl`_ "
"and _`sql_ssl_verify`_ options are set to 'true'. "
"There is no default which means "
"certificate verification is disabled.")}},
"certificate verification is disabled. "
"This option has no effect for MS SQL.")}},
{sql_ssl_certfile,
#{value => ?T("Path"),
desc =>
@@ -1358,13 +1366,15 @@ doc() ->
"for SSL connections to the SQL server. Implies _`sql_ssl`_ "
"option is set to 'true'. There is no default which means "
"ejabberd won't provide a client certificate to the SQL "
"server.")}},
"server. "
"This option has no effect for MS SQL.")}},
{sql_ssl_verify,
#{value => "true | false",
desc =>
?T("Whether to verify SSL connection to the SQL server against "
"CA root certificates defined in _`sql_ssl_cafile`_ option. "
"Implies _`sql_ssl`_ option is set to 'true'. "
"This option has no effect for MS SQL. "
"The default value is 'false'.")}},
{sql_start_interval,
#{value => "timeout()",
+11 -4
View File
@@ -360,10 +360,17 @@ bounce_message_queue(FromTo, State) ->
-spec bounce_packet(xmpp_element(), state()) -> state().
bounce_packet(Pkt, State) when ?is_stanza(Pkt) ->
Lang = xmpp:get_lang(Pkt),
Err = mk_bounce_error(Lang, State),
ejabberd_router:route_error(Pkt, Err),
State;
#{server_host := Host} = State,
case ejabberd_hooks:run_fold(
s2s_out_bounce_packet, Host, State, [Pkt]) of
ignore ->
State;
State2 ->
Lang = xmpp:get_lang(Pkt),
Err = mk_bounce_error(Lang, State2),
ejabberd_router:route_error(Pkt, Err),
State2
end;
bounce_packet(_, State) ->
State.
+29 -4
View File
@@ -1159,9 +1159,19 @@ db_opts(Host) ->
SSLOpts = get_ssl_opts(Transport, Host),
case Type of
mssql ->
[mssql, <<"DRIVER=ODBC;SERVER=", Server/binary, ";UID=", User/binary,
";DATABASE=", DB/binary ,";PWD=", Pass/binary,
";PORT=", (integer_to_binary(Port))/binary ,";CLIENT_CHARSET=UTF-8;">>, Timeout];
case odbc_server_is_connstring(Server) of
true ->
[mssql, Server, Timeout];
false ->
Encryption = case Transport of
tcp -> <<"">>;
ssl -> <<";ENCRYPTION=require;ENCRYPT=yes">>
end,
[mssql, <<"DRIVER=ODBC;SERVER=", Server/binary, ";DATABASE=", DB/binary,
";UID=", User/binary, ";PWD=", Pass/binary,
";PORT=", (integer_to_binary(Port))/binary, Encryption/binary,
";CLIENT_CHARSET=UTF-8;">>, Timeout]
end;
_ ->
[Type, Server, Port, DB, User, Pass, Timeout, Transport, SSLOpts]
end
@@ -1171,6 +1181,8 @@ warn_if_ssl_unsupported(tcp, _) ->
ok;
warn_if_ssl_unsupported(ssl, pgsql) ->
ok;
warn_if_ssl_unsupported(ssl, mssql) ->
ok;
warn_if_ssl_unsupported(ssl, mysql) ->
ok;
warn_if_ssl_unsupported(ssl, Type) ->
@@ -1203,7 +1215,7 @@ get_ssl_opts(ssl, Host) ->
get_ssl_opts(tcp, _) ->
[].
init_mssql(Host) ->
init_mssql_odbcinst(Host) ->
Driver = ejabberd_option:sql_odbc_driver(Host),
ODBCINST = io_lib:fwrite("[ODBC]~n"
"Driver = ~s~n", [Driver]),
@@ -1225,6 +1237,19 @@ init_mssql(Host) ->
Err
end.
init_mssql(Host) ->
Server = ejabberd_option:sql_server(Host),
case odbc_server_is_connstring(Server) of
true -> ok;
false -> init_mssql_odbcinst(Host)
end.
odbc_server_is_connstring(Server) ->
case binary:match(Server, <<"=">>) of
nomatch -> false;
_ -> true
end.
write_file_if_new(File, Payload) ->
case filelib:is_file(File) of
true -> ok;
+7 -2
View File
@@ -30,7 +30,7 @@
-author('ekhramtsov@process-one.net').
%% API
-export([start/0, config_reloaded/0]).
-export([start/0, config_reloaded/0, stop/0]).
%% gen_event callbacks
-export([init/1, handle_event/2, handle_call/2,
@@ -68,6 +68,10 @@ start() ->
ejabberd:start_app(os_mon),
set_oom_watermark().
-spec stop() -> term().
stop() ->
gen_event:delete_handler(alarm_handler, ?MODULE, []).
excluded_apps() ->
[os_mon, mnesia, sasl, stdlib, kernel].
@@ -115,7 +119,8 @@ handle_info(Info, State) ->
?WARNING_MSG("unexpected info: ~p~n", [Info]),
{ok, State}.
terminate(_Reason, _State) ->
terminate(_Reason, State) ->
misc:cancel_timer(State#state.tref),
ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 50).
code_change(_OldVsn, State, _Extra) ->
+15 -12
View File
@@ -66,7 +66,7 @@ init([]) ->
{ok, #state{}}.
add_paths() ->
[code:add_patha(module_ebin_dir(Module))
[code:add_pathsz([module_ebin_dir(Module)|module_deps_dirs(Module)])
|| {Module, _} <- installed()].
handle_call(Request, From, State) ->
@@ -229,7 +229,7 @@ install(Package) when is_binary(Package) ->
Module = misc:binary_to_atom(Package),
case compile_and_install(Module, Attrs) of
ok ->
code:add_patha(module_ebin_dir(Module)),
code:add_pathsz([module_ebin_dir(Module)|module_deps_dirs(Module)]),
ejabberd_config:reload(),
copy_commit_json(Package, Attrs),
case erlang:function_exported(Module, post_install, 0) of
@@ -256,7 +256,7 @@ uninstall(Package) when is_binary(Package) ->
|| Host <- ejabberd_option:hosts()],
code:purge(Module),
code:delete(Module),
code:del_path(module_ebin_dir(Module)),
[code:del_path(PathDelete) || PathDelete <- [module_ebin_dir(Module)|module_deps_dirs(Module)]],
delete_path(module_lib_dir(Module)),
ejabberd_config:reload();
false ->
@@ -654,11 +654,12 @@ install(Module, Spec, SrcDir, LibDir) ->
Files1 = [{File, copy(File, filename:join(LibDir, File))}
|| File <- filelib:wildcard("{ebin,priv,conf,include}/**")],
Files2 = [{File, copy(File, filename:join(LibDir, filename:join(lists:nthtail(2,filename:split(File)))))}
|| File <- filelib:wildcard("deps/*/{ebin,priv}/**")],
|| File <- filelib:wildcard("deps/*/ebin/**")],
Files3 = [{File, copy(File, filename:join(LibDir, File))}
|| File <- filelib:wildcard("deps/*/priv/**")],
Errors = lists:dropwhile(fun({_, ok}) -> true;
(_) -> false
end, Files1++Files2),
copy_priv_files(LibDir),
end, Files1++Files2++Files3),
inform_module_configuration(Module, LibDir, Files1),
Result = case Errors of
[{F, {error, E}}|_] ->
@@ -671,12 +672,6 @@ install(Module, Spec, SrcDir, LibDir) ->
file:set_cwd(CurDir),
Result.
copy_priv_files(LibDir) ->
file:set_cwd(LibDir),
EjabberdLibDir = code:lib_dir(ejabberd),
[{File, copy(File, filename:join(EjabberdLibDir, File))}
|| File <- filelib:wildcard("{priv}/**")].
inform_module_configuration(Module, LibDir, Files1) ->
Res = lists:filter(fun({[$c, $o, $n, $f |_], ok}) -> true;
(_) -> false
@@ -736,6 +731,14 @@ rebar_dep({App, _, {git, Url, Ref}}) ->
"; (cd "++filename:basename(App)++
"; git checkout -q "++Ref++")"}.
module_deps_dirs(Module) ->
SrcDir = module_src_dir(Module),
LibDir = module_lib_dir(Module),
DepsDir = filename:join(LibDir, "deps"),
Deps = rebar_deps(filename:join(SrcDir, "rebar.config"))
++ rebar_deps(filename:join(SrcDir, "rebar.config.script")),
[filename:join(DepsDir, App) || {App, _Cmd} <- Deps].
%% -- YAML spec parser
consult(File) ->
+414 -159
View File
@@ -34,6 +34,8 @@
% Commands API
-export([update_sql/0]).
% For testing
-export([update_sql/1]).
-include("logger.hrl").
-include("ejabberd_commands.hrl").
@@ -63,7 +65,8 @@ depends(_Host, _Opts) ->
get_commands_spec() ->
[#ejabberd_commands{name = update_sql, tags = [sql],
desc = "Convert PostgreSQL DB to the new format",
desc = "Convert MS SQL, MySQL or PostgreSQL DB to the new format",
note = "improved in 23.04",
module = ?MODULE, function = update_sql,
args = [],
args_example = [],
@@ -93,6 +96,8 @@ update_sql(Host) ->
DBType = ejabberd_option:sql_type(LHost),
IsSupported =
case DBType of
mssql -> true;
mysql -> true;
pgsql -> true;
_ -> false
end,
@@ -110,189 +115,316 @@ update_sql(Host) ->
State = #state{host = LHost,
dbtype = DBType,
escape = Escape},
update_tables(State)
update_tables(State),
check_config()
end.
check_config() ->
case ejabberd_sql:use_new_schema() of
true -> ok;
false ->
ejabberd_config:set_option(new_sql_schema, true),
io:format('~nNOTE: you must add "new_sql_schema: true" to ejabberd.yml before next restart~n~n', [])
end.
update_tables(State) ->
add_sh_column(State, "users"),
drop_pkey(State, "users"),
add_pkey(State, "users", ["server_host", "username"]),
drop_sh_default(State, "users"),
case add_sh_column(State, "users") of
true ->
drop_pkey(State, "users"),
add_pkey(State, "users", ["server_host", "username"]),
drop_sh_default(State, "users");
false ->
ok
end,
add_sh_column(State, "last"),
drop_pkey(State, "last"),
add_pkey(State, "last", ["server_host", "username"]),
drop_sh_default(State, "last"),
case add_sh_column(State, "last") of
true ->
drop_pkey(State, "last"),
add_pkey(State, "last", ["server_host", "username"]),
drop_sh_default(State, "last");
false ->
ok
end,
add_sh_column(State, "rosterusers"),
drop_index(State, "i_rosteru_user_jid"),
drop_index(State, "i_rosteru_username"),
drop_index(State, "i_rosteru_jid"),
create_unique_index(State, "rosterusers", "i_rosteru_sh_user_jid", ["server_host", "username", "jid"]),
create_index(State, "rosterusers", "i_rosteru_sh_username", ["server_host", "username"]),
create_index(State, "rosterusers", "i_rosteru_sh_jid", ["server_host", "jid"]),
drop_sh_default(State, "rosterusers"),
case add_sh_column(State, "rosterusers") of
true ->
drop_index(State, "rosterusers", "i_rosteru_user_jid"),
drop_index(State, "rosterusers", "i_rosteru_username"),
drop_index(State, "rosterusers", "i_rosteru_jid"),
create_unique_index(State, "rosterusers", "i_rosteru_sh_user_jid", ["server_host", "username", "jid"]),
create_index(State, "rosterusers", "i_rosteru_sh_jid", ["server_host", "jid"]),
drop_sh_default(State, "rosterusers");
false ->
ok
end,
add_sh_column(State, "rostergroups"),
drop_index(State, "pk_rosterg_user_jid"),
create_index(State, "rostergroups", "i_rosterg_sh_user_jid", ["server_host", "username", "jid"]),
drop_sh_default(State, "rostergroups"),
case add_sh_column(State, "rostergroups") of
true ->
drop_index(State, "rostergroups", "pk_rosterg_user_jid"),
create_index(State, "rostergroups", "i_rosterg_sh_user_jid", ["server_host", "username", "jid"]),
drop_sh_default(State, "rostergroups");
false ->
ok
end,
add_sh_column(State, "sr_group"),
add_pkey(State, "sr_group", ["server_host", "name"]),
create_unique_index(State, "sr_group", "i_sr_group_sh_name", ["server_host", "name"]),
drop_sh_default(State, "sr_group"),
case add_sh_column(State, "sr_group") of
true ->
drop_index(State, "sr_group", "i_sr_group_name"),
create_unique_index(State, "sr_group", "i_sr_group_sh_name", ["server_host", "name"]),
drop_sh_default(State, "sr_group");
false ->
ok
end,
add_sh_column(State, "sr_user"),
drop_index(State, "i_sr_user_jid_grp"),
drop_index(State, "i_sr_user_jid"),
drop_index(State, "i_sr_user_grp"),
add_pkey(State, "sr_user", ["server_host", "jid", "grp"]),
create_unique_index(State, "sr_user", "i_sr_user_sh_jid_grp", ["server_host", "jid", "grp"]),
create_index(State, "sr_user", "i_sr_user_sh_jid", ["server_host", "jid"]),
create_index(State, "sr_user", "i_sr_user_sh_grp", ["server_host", "grp"]),
drop_sh_default(State, "sr_user"),
case add_sh_column(State, "sr_user") of
true ->
drop_index(State, "sr_user", "i_sr_user_jid_grp"),
drop_index(State, "sr_user", "i_sr_user_jid"),
drop_index(State, "sr_user", "i_sr_user_grp"),
create_unique_index(State, "sr_user", "i_sr_user_sh_jid_grp", ["server_host", "jid", "grp"]),
create_index(State, "sr_user", "i_sr_user_sh_grp", ["server_host", "grp"]),
drop_sh_default(State, "sr_user");
false ->
ok
end,
add_sh_column(State, "spool"),
drop_index(State, "i_despool"),
create_index(State, "spool", "i_spool_sh_username", ["server_host", "username"]),
drop_sh_default(State, "spool"),
case add_sh_column(State, "spool") of
true ->
drop_index(State, "spool", "i_despool"),
create_index(State, "spool", "i_spool_sh_username", ["server_host", "username"]),
drop_sh_default(State, "spool");
false ->
ok
end,
add_sh_column(State, "archive"),
drop_index(State, "i_username"),
drop_index(State, "i_username_timestamp"),
drop_index(State, "i_timestamp"),
drop_index(State, "i_peer"),
drop_index(State, "i_bare_peer"),
drop_index(State, "i_username_peer"),
drop_index(State, "i_username_bare_peer"),
create_index(State, "archive", "i_archive_sh_username_timestamp", ["server_host", "username", "timestamp"]),
create_index(State, "archive", "i_archive_sh_timestamp", ["server_host", "timestamp"]),
create_index(State, "archive", "i_archive_sh_username_peer", ["server_host", "username", "peer"]),
create_index(State, "archive", "i_archive_sh_username_bare_peer", ["server_host", "username", "bare_peer"]),
drop_sh_default(State, "archive"),
case add_sh_column(State, "archive") of
true ->
drop_index(State, "archive", "i_username"),
drop_index(State, "archive", "i_username_timestamp"),
drop_index(State, "archive", "i_timestamp"),
drop_index(State, "archive", "i_peer"),
drop_index(State, "archive", "i_bare_peer"),
drop_index(State, "archive", "i_username_peer"),
drop_index(State, "archive", "i_username_bare_peer"),
create_index(State, "archive", "i_archive_sh_username_timestamp", ["server_host", "username", "timestamp"]),
create_index(State, "archive", "i_archive_sh_timestamp", ["server_host", "timestamp"]),
create_index(State, "archive", "i_archive_sh_username_peer", ["server_host", "username", "peer"]),
create_index(State, "archive", "i_archive_sh_username_bare_peer", ["server_host", "username", "bare_peer"]),
drop_sh_default(State, "archive");
false ->
ok
end,
add_sh_column(State, "archive_prefs"),
drop_pkey(State, "archive_prefs"),
add_pkey(State, "archive_prefs", ["server_host", "username"]),
drop_sh_default(State, "archive_prefs"),
case add_sh_column(State, "archive_prefs") of
true ->
drop_pkey(State, "archive_prefs"),
add_pkey(State, "archive_prefs", ["server_host", "username"]),
drop_sh_default(State, "archive_prefs");
false ->
ok
end,
add_sh_column(State, "vcard"),
drop_pkey(State, "vcard"),
add_pkey(State, "vcard", ["server_host", "username"]),
drop_sh_default(State, "vcard"),
case add_sh_column(State, "vcard") of
true ->
drop_pkey(State, "vcard"),
add_pkey(State, "vcard", ["server_host", "username"]),
drop_sh_default(State, "vcard");
false ->
ok
end,
add_sh_column(State, "vcard_search"),
drop_pkey(State, "vcard_search"),
drop_index(State, "i_vcard_search_lfn"),
drop_index(State, "i_vcard_search_lfamily"),
drop_index(State, "i_vcard_search_lgiven"),
drop_index(State, "i_vcard_search_lmiddle"),
drop_index(State, "i_vcard_search_lnickname"),
drop_index(State, "i_vcard_search_lbday"),
drop_index(State, "i_vcard_search_lctry"),
drop_index(State, "i_vcard_search_llocality"),
drop_index(State, "i_vcard_search_lemail"),
drop_index(State, "i_vcard_search_lorgname"),
drop_index(State, "i_vcard_search_lorgunit"),
add_pkey(State, "vcard_search", ["server_host", "username"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lfn", ["server_host", "lfn"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lfamily", ["server_host", "lfamily"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lgiven", ["server_host", "lgiven"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lmiddle", ["server_host", "lmiddle"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lnickname", ["server_host", "lnickname"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lbday", ["server_host", "lbday"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lctry", ["server_host", "lctry"]),
create_index(State, "vcard_search", "i_vcard_search_sh_llocality", ["server_host", "llocality"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lemail", ["server_host", "lemail"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lorgname", ["server_host", "lorgname"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lorgunit", ["server_host", "lorgunit"]),
drop_sh_default(State, "vcard_search"),
case add_sh_column(State, "vcard_search") of
true ->
drop_pkey(State, "vcard_search"),
drop_index(State, "vcard_search", "i_vcard_search_lfn"),
drop_index(State, "vcard_search", "i_vcard_search_lfamily"),
drop_index(State, "vcard_search", "i_vcard_search_lgiven"),
drop_index(State, "vcard_search", "i_vcard_search_lmiddle"),
drop_index(State, "vcard_search", "i_vcard_search_lnickname"),
drop_index(State, "vcard_search", "i_vcard_search_lbday"),
drop_index(State, "vcard_search", "i_vcard_search_lctry"),
drop_index(State, "vcard_search", "i_vcard_search_llocality"),
drop_index(State, "vcard_search", "i_vcard_search_lemail"),
drop_index(State, "vcard_search", "i_vcard_search_lorgname"),
drop_index(State, "vcard_search", "i_vcard_search_lorgunit"),
add_pkey(State, "vcard_search", ["server_host", "lusername"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lfn", ["server_host", "lfn"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lfamily", ["server_host", "lfamily"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lgiven", ["server_host", "lgiven"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lmiddle", ["server_host", "lmiddle"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lnickname", ["server_host", "lnickname"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lbday", ["server_host", "lbday"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lctry", ["server_host", "lctry"]),
create_index(State, "vcard_search", "i_vcard_search_sh_llocality", ["server_host", "llocality"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lemail", ["server_host", "lemail"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lorgname", ["server_host", "lorgname"]),
create_index(State, "vcard_search", "i_vcard_search_sh_lorgunit", ["server_host", "lorgunit"]),
drop_sh_default(State, "vcard_search");
false ->
ok
end,
add_sh_column(State, "privacy_default_list"),
drop_pkey(State, "privacy_default_list"),
add_pkey(State, "privacy_default_list", ["server_host", "username"]),
drop_sh_default(State, "privacy_default_list"),
case add_sh_column(State, "privacy_default_list") of
true ->
drop_pkey(State, "privacy_default_list"),
add_pkey(State, "privacy_default_list", ["server_host", "username"]),
drop_sh_default(State, "privacy_default_list");
false ->
ok
end,
add_sh_column(State, "privacy_list"),
drop_index(State, "i_privacy_list_username"),
drop_index(State, "i_privacy_list_username_name"),
create_index(State, "privacy_list", "i_privacy_list_sh_username", ["server_host", "username"]),
create_unique_index(State, "privacy_list", "i_privacy_list_sh_username_name", ["server_host", "username", "name"]),
drop_sh_default(State, "privacy_list"),
case add_sh_column(State, "privacy_list") of
true ->
drop_index(State, "privacy_list", "i_privacy_list_username"),
drop_index(State, "privacy_list", "i_privacy_list_username_name"),
create_unique_index(State, "privacy_list", "i_privacy_list_sh_username_name", ["server_host", "username", "name"]),
drop_sh_default(State, "privacy_list");
false ->
ok
end,
add_sh_column(State, "private_storage"),
drop_index(State, "i_private_storage_username"),
drop_index(State, "i_private_storage_username_namespace"),
add_pkey(State, "private_storage", ["server_host", "username", "namespace"]),
create_index(State, "private_storage", "i_private_storage_sh_username", ["server_host", "username"]),
drop_sh_default(State, "private_storage"),
case add_sh_column(State, "private_storage") of
true ->
drop_index(State, "private_storage", "i_private_storage_username"),
drop_index(State, "private_storage", "i_private_storage_username_namespace"),
add_pkey(State, "private_storage", ["server_host", "username", "namespace"]),
drop_sh_default(State, "private_storage");
false ->
ok
end,
add_sh_column(State, "roster_version"),
drop_pkey(State, "roster_version"),
add_pkey(State, "roster_version", ["server_host", "username"]),
drop_sh_default(State, "roster_version"),
case add_sh_column(State, "roster_version") of
true ->
drop_pkey(State, "roster_version"),
add_pkey(State, "roster_version", ["server_host", "username"]),
drop_sh_default(State, "roster_version");
false ->
ok
end,
add_sh_column(State, "muc_room"),
drop_sh_default(State, "muc_room"),
case add_sh_column(State, "muc_room") of
true ->
drop_sh_default(State, "muc_room");
false ->
ok
end,
add_sh_column(State, "muc_registered"),
drop_sh_default(State, "muc_registered"),
case add_sh_column(State, "muc_registered") of
true ->
drop_sh_default(State, "muc_registered");
false ->
ok
end,
add_sh_column(State, "muc_online_room"),
drop_sh_default(State, "muc_online_room"),
case add_sh_column(State, "muc_online_room") of
true ->
drop_sh_default(State, "muc_online_room");
false ->
ok
end,
add_sh_column(State, "muc_online_users"),
drop_sh_default(State, "muc_online_users"),
case add_sh_column(State, "muc_online_users") of
true ->
drop_sh_default(State, "muc_online_users");
false ->
ok
end,
add_sh_column(State, "motd"),
drop_pkey(State, "motd"),
add_pkey(State, "motd", ["server_host", "username"]),
drop_sh_default(State, "motd"),
case add_sh_column(State, "motd") of
true ->
drop_pkey(State, "motd"),
add_pkey(State, "motd", ["server_host", "username"]),
drop_sh_default(State, "motd");
false ->
ok
end,
add_sh_column(State, "sm"),
drop_index(State, "i_sm_sid"),
drop_index(State, "i_sm_username"),
add_pkey(State, "sm", ["usec", "pid"]),
create_index(State, "sm", "i_sm_sh_username", ["server_host", "username"]),
drop_sh_default(State, "sm"),
case add_sh_column(State, "sm") of
true ->
drop_index(State, "sm", "i_sm_sid"),
drop_index(State, "sm", "i_sm_username"),
add_pkey(State, "sm", ["usec", "pid"]),
create_index(State, "sm", "i_sm_sh_username", ["server_host", "username"]),
drop_sh_default(State, "sm");
false ->
ok
end,
add_sh_column(State, "push_session"),
drop_index(State, "i_push_usn"),
drop_index(State, "i_push_ut"),
add_pkey(State, "push_session", ["server_host", "username", "timestamp"]),
create_unique_index(State, "push_session", "i_push_session_susn", ["server_host", "username", "service", "node"]),
drop_sh_default(State, "push_session"),
case add_sh_column(State, "push_session") of
true ->
drop_index(State, "push_session", "i_push_usn"),
drop_index(State, "push_session", "i_push_ut"),
create_unique_index(State, "push_session", "i_push_session_susn", ["server_host", "username", "service", "node"]),
create_index(State, "push_session", "i_push_session_sh_username_timestamp", ["server_host", "username", "timestamp"]),
drop_sh_default(State, "push_session");
false ->
ok
end,
add_sh_column(State, "mix_pam"),
drop_index(State, "i_mix_pam"),
drop_index(State, "i_mix_pam_us"),
create_unique_index(State, "mix_pam", "i_mix_pam", ["username", "server_host", "channel", "service"]),
create_index(State, "mix_pam", "i_mix_pam_us", ["username", "server_host"]),
drop_sh_default(State, "mix_pam"),
case add_sh_column(State, "mix_pam") of
true ->
drop_index(State, "mix_pam", "i_mix_pam"),
drop_index(State, "mix_pam", "i_mix_pam_u"),
drop_index(State, "mix_pam", "i_mix_pam_us"),
create_unique_index(State, "mix_pam", "i_mix_pam", ["username", "server_host", "channel", "service"]),
drop_sh_default(State, "mix_pam");
false ->
ok
end,
add_sh_column(State, "route"),
drop_index(State, "i_route"),
create_unique_index(State, "route", "i_route", ["domain", "server_host", "node", "pid"]),
drop_sh_default(State, "route"),
add_sh_column(State, "mqtt_pub"),
drop_index(State, "i_mqtt_topic"),
create_unique_index(State, "mqtt_pub", "i_mqtt_topic_server", ["topic", "server_host"]),
drop_sh_default(State, "mqtt_pub"),
case add_sh_column(State, "mqtt_pub") of
true ->
drop_index(State, "mqtt_pub", "i_mqtt_topic"),
create_unique_index(State, "mqtt_pub", "i_mqtt_topic_server", ["topic", "server_host"]),
drop_sh_default(State, "mqtt_pub");
false ->
ok
end,
ok.
add_sh_column(#state{dbtype = pgsql} = State, Table) ->
check_sh_column(#state{dbtype = mysql} = State, Table) ->
DB = ejabberd_option:sql_database(State#state.host),
sql_query(
State#state.host,
["SELECT 1 FROM information_schema.columns ",
"WHERE table_name = '", Table, "' AND column_name = 'server_host' ",
"AND table_schema = '", (State#state.escape)(DB), "' ",
"GROUP BY table_name, column_name;"], false);
check_sh_column(State, Table) ->
DB = ejabberd_option:sql_database(State#state.host),
sql_query(
State#state.host,
["SELECT 1 FROM information_schema.columns ",
"WHERE table_name = '", Table, "' AND column_name = 'server_host' ",
"AND table_catalog = '", (State#state.escape)(DB), "' ",
"GROUP BY table_name, column_name;"], false).
add_sh_column(State, Table) ->
case check_sh_column(State, Table) of
true -> false;
false ->
do_add_sh_column(State, Table),
true
end.
do_add_sh_column(#state{dbtype = pgsql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ADD COLUMN server_host text NOT NULL DEFAULT '",
(State#state.escape)(State#state.host),
"';"]);
add_sh_column(#state{dbtype = mysql} = State, Table) ->
do_add_sh_column(#state{dbtype = mssql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ADD COLUMN server_host text NOT NULL DEFAULT '",
["ALTER TABLE [", Table, "] ADD [server_host] varchar (250) NOT NULL ",
"CONSTRAINT [server_host_default] DEFAULT '",
(State#state.escape)(State#state.host),
"';"]);
do_add_sh_column(#state{dbtype = mysql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ADD COLUMN server_host varchar(191) NOT NULL DEFAULT '",
(State#state.escape)(State#state.host),
"';"]).
@@ -300,6 +432,10 @@ drop_pkey(#state{dbtype = pgsql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " DROP CONSTRAINT ", Table, "_pkey;"]);
drop_pkey(#state{dbtype = mssql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE [", Table, "] DROP CONSTRAINT [", Table, "_PRIMARY];"]);
drop_pkey(#state{dbtype = mysql} = State, Table) ->
sql_query(
State#state.host,
@@ -310,8 +446,16 @@ add_pkey(#state{dbtype = pgsql} = State, Table, Cols) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ADD PRIMARY KEY (", SCols, ");"]);
add_pkey(#state{dbtype = mssql} = State, Table, Cols) ->
SCols = string:join(Cols, "], ["),
sql_query(
State#state.host,
["ALTER TABLE [", Table, "] ADD CONSTRAINT [", Table, "_PRIMARY] PRIMARY KEY CLUSTERED ([", SCols, "]) ",
"WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ",
"ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY];"]);
add_pkey(#state{dbtype = mysql} = State, Table, Cols) ->
SCols = string:join(Cols, ", "),
Cols2 = [C ++ mysql_keylen(Table, C) || C <- Cols],
SCols = string:join(Cols2, ", "),
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ADD PRIMARY KEY (", SCols, ");"]).
@@ -320,19 +464,56 @@ drop_sh_default(#state{dbtype = pgsql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ALTER COLUMN server_host DROP DEFAULT;"]);
drop_sh_default(#state{dbtype = mssql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE [", Table, "] DROP CONSTRAINT [server_host_default];"]);
drop_sh_default(#state{dbtype = mysql} = State, Table) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " ALTER COLUMN server_host DROP DEFAULT;"]).
drop_index(#state{dbtype = pgsql} = State, Index) ->
check_index(#state{dbtype = pgsql} = State, Table, Index) ->
sql_query(
State#state.host,
["SELECT 1 FROM pg_indexes WHERE tablename = '", Table,
"' AND indexname = '", Index, "';"], false);
check_index(#state{dbtype = mssql} = State, Table, Index) ->
sql_query(
State#state.host,
["SELECT 1 FROM sys.tables t ",
"INNER JOIN sys.indexes i ON i.object_id = t.object_id ",
"WHERE i.index_id > 0 ",
"AND i.name = '", Index, "' ",
"AND t.name = '", Table, "';"], false);
check_index(#state{dbtype = mysql} = State, Table, Index) ->
DB = ejabberd_option:sql_database(State#state.host),
sql_query(
State#state.host,
["SELECT 1 FROM information_schema.statistics ",
"WHERE table_name = '", Table, "' AND index_name = '", Index, "' ",
"AND table_schema = '", (State#state.escape)(DB), "' ",
"GROUP BY table_name, index_name;"], false).
drop_index(State, Table, Index) ->
OldIndex = old_index_name(State#state.dbtype, Index),
case check_index(State, Table, OldIndex) of
true -> do_drop_index(State, Table, OldIndex);
false -> ok
end.
do_drop_index(#state{dbtype = pgsql} = State, _Table, Index) ->
sql_query(
State#state.host,
["DROP INDEX ", Index, ";"]);
drop_index(#state{dbtype = mysql} = State, Index) ->
do_drop_index(#state{dbtype = mssql} = State, Table, Index) ->
sql_query(
State#state.host,
["DROP INDEX ", Index, ";"]).
["DROP INDEX [", Index, "] ON [", Table, "];"]);
do_drop_index(#state{dbtype = mysql} = State, Table, Index) ->
sql_query(
State#state.host,
["ALTER TABLE ", Table, " DROP INDEX ", Index, ";"]).
create_unique_index(#state{dbtype = pgsql} = State, Table, Index, Cols) ->
SCols = string:join(Cols, ", "),
@@ -340,8 +521,17 @@ create_unique_index(#state{dbtype = pgsql} = State, Table, Index, Cols) ->
State#state.host,
["CREATE UNIQUE INDEX ", Index, " ON ", Table, " USING btree (",
SCols, ");"]);
create_unique_index(#state{dbtype = mssql} = State, Table, "i_privacy_list_sh_username_name" = Index, Cols) ->
create_index(State, Table, Index, Cols);
create_unique_index(#state{dbtype = mssql} = State, Table, Index, Cols) ->
SCols = string:join(Cols, ", "),
sql_query(
State#state.host,
["CREATE UNIQUE ", mssql_clustered(Index), "INDEX [", new_index_name(State#state.dbtype, Index), "] ",
"ON [", Table, "] (", SCols, ") ",
"WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);"]);
create_unique_index(#state{dbtype = mysql} = State, Table, Index, Cols) ->
Cols2 = [C ++ "(75)" || C <- Cols],
Cols2 = [C ++ mysql_keylen(Index, C) || C <- Cols],
SCols = string:join(Cols2, ", "),
sql_query(
State#state.host,
@@ -349,25 +539,90 @@ create_unique_index(#state{dbtype = mysql} = State, Table, Index, Cols) ->
SCols, ");"]).
create_index(#state{dbtype = pgsql} = State, Table, Index, Cols) ->
NewIndex = new_index_name(State#state.dbtype, Index),
SCols = string:join(Cols, ", "),
sql_query(
State#state.host,
["CREATE INDEX ", Index, " ON ", Table, " USING btree (",
["CREATE INDEX ", NewIndex, " ON ", Table, " USING btree (",
SCols, ");"]);
create_index(#state{dbtype = mssql} = State, Table, Index, Cols) ->
NewIndex = new_index_name(State#state.dbtype, Index),
SCols = string:join(Cols, ", "),
sql_query(
State#state.host,
["CREATE INDEX [", NewIndex, "] ON [", Table, "] (", SCols, ") ",
"WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);"]);
create_index(#state{dbtype = mysql} = State, Table, Index, Cols) ->
Cols2 = [C ++ "(75)" || C <- Cols],
NewIndex = new_index_name(State#state.dbtype, Index),
Cols2 = [C ++ mysql_keylen(NewIndex, C) || C <- Cols],
SCols = string:join(Cols2, ", "),
sql_query(
State#state.host,
["CREATE INDEX ", Index, " ON ", Table, "(",
["CREATE INDEX ", NewIndex, " ON ", Table, "(",
SCols, ");"]).
old_index_name(mssql, "i_bare_peer") -> "archive_bare_peer";
old_index_name(mssql, "i_peer") -> "archive_peer";
old_index_name(mssql, "i_timestamp") -> "archive_timestamp";
old_index_name(mssql, "i_username") -> "archive_username";
old_index_name(mssql, "i_username_bare_peer") -> "archive_username_bare_peer";
old_index_name(mssql, "i_username_peer") -> "archive_username_peer";
old_index_name(mssql, "i_username_timestamp") -> "archive_username_timestamp";
old_index_name(mssql, "i_push_usn") -> "i_push_usn";
old_index_name(mssql, "i_push_ut") -> "i_push_ut";
old_index_name(mssql, "pk_rosterg_user_jid") -> "rostergroups_username_jid";
old_index_name(mssql, "i_rosteru_jid") -> "rosterusers_jid";
old_index_name(mssql, "i_rosteru_username") -> "rosterusers_username";
old_index_name(mssql, "i_rosteru_user_jid") -> "rosterusers_username_jid";
old_index_name(mssql, "i_despool") -> "spool_username";
old_index_name(mssql, "i_sr_user_jid_grp") -> "sr_user_jid_group";
old_index_name(mssql, Index) -> string:substr(Index, 3);
old_index_name(_Type, Index) -> Index.
new_index_name(mssql, "i_rosterg_sh_user_jid") -> "rostergroups_sh_username_jid";
new_index_name(mssql, "i_rosteru_sh_jid") -> "rosterusers_sh_jid";
new_index_name(mssql, "i_rosteru_sh_user_jid") -> "rosterusers_sh_username_jid";
new_index_name(mssql, "i_sr_user_sh_jid_grp") -> "sr_user_sh_jid_group";
new_index_name(mssql, Index) -> string:substr(Index, 3);
new_index_name(_Type, Index) -> Index.
mssql_clustered("i_mix_pam") -> "";
mssql_clustered("i_push_session_susn") -> "";
mssql_clustered(_) -> "CLUSTERED ".
mysql_keylen(_, "bare_peer") -> "(191)";
mysql_keylen(_, "channel") -> "(191)";
mysql_keylen(_, "domain") -> "(75)";
mysql_keylen(_, "jid") -> "(75)";
mysql_keylen(_, "name") -> "(75)";
mysql_keylen(_, "node") -> "(75)";
mysql_keylen(_, "peer") -> "(191)";
mysql_keylen(_, "pid") -> "(75)";
mysql_keylen(_, "server_host") -> "(191)";
mysql_keylen(_, "service") -> "(191)";
mysql_keylen(_, "topic") -> "(191)";
mysql_keylen("i_privacy_list_sh_username_name", "username") -> "(75)";
mysql_keylen("i_rosterg_sh_user_jid", "username") -> "(75)";
mysql_keylen("i_rosteru_sh_user_jid", "username") -> "(75)";
mysql_keylen(_, "username") -> "(191)";
mysql_keylen(_, _) -> "".
sql_query(Host, Query) ->
io:format("executing \"~ts\" on ~ts~n", [Query, Host]),
sql_query(Host, Query, true).
sql_query(Host, Query, Log) ->
case Log of
true -> io:format("executing \"~ts\" on ~ts~n", [Query, Host]);
false -> ok
end,
case ejabberd_sql:sql_query(Host, Query) of
{selected, _Cols, []} ->
false;
{selected, _Cols, [_Rows]} ->
true;
{error, Error} ->
io:format("error: ~p~n", [Error]),
ok;
false;
_ ->
ok
end.
@@ -379,5 +634,5 @@ mod_doc() ->
?T("This module can be used to update existing SQL database "
"from the default to the new schema. Check the section "
"http://../database/#default-and-new-schemas[Default and New Schemas] for details. "
"Please note that only PostgreSQL is supported. "
"Please note that only MS SQL, MySQL, and PostgreSQL are supported. "
"When the module is loaded use _`update_sql`_ API.")}.
+18 -2
View File
@@ -28,6 +28,7 @@
-protocol({xep, 313, '0.6.1', '15.06', "", ""}).
-protocol({xep, 334, '0.2'}).
-protocol({xep, 359, '0.5.0'}).
-protocol({xep, 425, '0.2.1', '23.04', "", ""}).
-protocol({xep, 441, '0.2.0'}).
-behaviour(gen_mod).
@@ -44,7 +45,8 @@
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,
delete_old_messages_batch/5, delete_old_messages_status/1, delete_old_messages_abort/1]).
delete_old_messages_batch/5, delete_old_messages_status/1, delete_old_messages_abort/1,
remove_message_from_archive/3]).
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
@@ -352,6 +354,19 @@ remove_mam_for_user_with_peer(User, Server, Peer) ->
{error, <<"Invalid peer JID">>}
end.
-spec remove_message_from_archive(User :: binary(), Server :: binary(), StanzaId :: integer()) ->
ok | {error, binary()}.
remove_message_from_archive(User, Server, StanzaId) ->
Mod = gen_mod:db_mod(Server, ?MODULE),
case Mod:remove_from_archive(User, Server, StanzaId) of
ok ->
ok;
{error, Bin} when is_binary(Bin) ->
{error, Bin};
{error, _} ->
{error, <<"Db returned error">>}
end.
get_module_host(LServer) ->
try gen_mod:db_mod(LServer, ?MODULE)
catch error:{module_not_loaded, ?MODULE, LServer} ->
@@ -1316,8 +1331,9 @@ msg_to_el(#archive_msg{timestamp = TS, packet = El, nick = Nick,
end,
Pkt3 = maybe_update_from_to(
Pkt2, JidRequestor, JidArchive, Peer, MsgType, Nick),
Pkt4 = xmpp:put_meta(Pkt3, archive_nick, Nick),
Delay = #delay{stamp = TS, from = jid:make(LServer)},
{ok, #forwarded{sub_els = [Pkt3], delay = Delay}}
{ok, #forwarded{sub_els = [Pkt4], delay = Delay}}
catch _:{xmpp_codec, Why} ->
?ERROR_MSG("Failed to decode raw element ~p from message "
"archive of user ~ts: ~ts",
+17 -1
View File
@@ -81,7 +81,7 @@ remove_from_archive(LUser, LServer, none) ->
{atomic, _} -> ok;
{aborted, Reason} -> {error, Reason}
end;
remove_from_archive(LUser, LServer, WithJid) ->
remove_from_archive(LUser, LServer, #jid{} = WithJid) ->
US = {LUser, LServer},
Peer = jid:remove_resource(jid:split(WithJid)),
F = fun () ->
@@ -96,6 +96,22 @@ remove_from_archive(LUser, LServer, WithJid) ->
case mnesia:transaction(F) of
{atomic, _} -> ok;
{aborted, Reason} -> {error, Reason}
end;
remove_from_archive(LUser, LServer, StanzaId) ->
Timestamp = misc:usec_to_now(StanzaId),
US = {LUser, LServer},
F = fun () ->
Msgs = mnesia:select(
archive_msg,
ets:fun2ms(
fun(#archive_msg{us = US1, timestamp = Timestamp1} = Msg)
when US1 == US, Timestamp1 == Timestamp -> Msg
end)),
lists:foreach(fun mnesia:delete_object/1, Msgs)
end,
case mnesia:transaction(F) of
{atomic, _} -> ok;
{aborted, Reason} -> {error, Reason}
end.
delete_old_messages(global, TimeStamp, Type) ->
+13 -2
View File
@@ -64,12 +64,18 @@ remove_from_archive(LUser, LServer, none) ->
{error, Reason} -> {error, Reason};
_ -> ok
end;
remove_from_archive(LUser, LServer, WithJid) ->
remove_from_archive(LUser, LServer, #jid{} = WithJid) ->
Peer = jid:encode(jid:remove_resource(WithJid)),
case ejabberd_sql:sql_query(LServer,
?SQL("delete from archive where username=%(LUser)s and %(LServer)H and bare_peer=%(Peer)s")) of
{error, Reason} -> {error, Reason};
_ -> ok
end;
remove_from_archive(LUser, LServer, StanzaId) ->
case ejabberd_sql:sql_query(LServer,
?SQL("delete from archive where username=%(LUser)s and %(LServer)H and timestamp=%(StanzaId)d")) of
{error, Reason} -> {error, Reason};
_ -> ok
end.
count_messages_to_delete(ServerHost, TimeStamp, Type) ->
@@ -441,6 +447,11 @@ make_sql_query(User, LServer, MAMQuery, RSM, ExtraUsernames) ->
true ->
[]
end,
SubOrderClause = if LimitClause /= []; TopClause /= [] ->
<<" ORDER BY timestamp DESC ">>;
true ->
[]
end,
WithTextClause = if is_binary(WithText), WithText /= <<>> ->
[<<" and match (txt) against (">>,
ToString(WithText), <<")">>];
@@ -528,7 +539,7 @@ make_sql_query(User, LServer, MAMQuery, RSM, ExtraUsernames) ->
% XEP-0059: Result Set Management
% 2.5 Requesting the Last Page in a Result Set
[<<"SELECT">>, UserSel, <<" timestamp, xml, peer, kind, nick FROM (">>,
Query, <<" ORDER BY timestamp DESC ">>,
Query, SubOrderClause,
LimitClause, <<") AS t ORDER BY timestamp ASC;">>];
_ ->
[Query, <<" ORDER BY timestamp ASC ">>,
+11 -5
View File
@@ -1214,7 +1214,13 @@ authenticate(#connect{password = Pass, properties = Props} = Pkt, State) ->
true ->
{ok, JID, pkix};
false ->
{error, 'not-authorized'}
{error, 'not-authorized'};
no_cert ->
case ejabberd_auth:check_password_with_authmodule(
LUser, <<>>, LServer, Pass) of
{true, AuthModule} -> {ok, JID, AuthModule};
false -> {error, 'not-authorized'}
end
end;
_ ->
case ejabberd_auth:check_password_with_authmodule(
@@ -1228,9 +1234,9 @@ authenticate(#connect{password = Pass, properties = Props} = Pkt, State) ->
Err
end.
-spec tls_auth(jid:jid(), state()) -> boolean().
-spec tls_auth(jid:jid(), state()) -> boolean() | no_cert.
tls_auth(_JID, #state{tls_verify = false}) ->
false;
no_cert;
tls_auth(JID, State) ->
case State#state.socket of
{fast_tls, Sock} ->
@@ -1251,10 +1257,10 @@ tls_auth(JID, State) ->
false
end;
error ->
false
no_cert
end;
_ ->
false
no_cert
end.
get_cert_jid(Cert) ->
+11
View File
@@ -317,6 +317,15 @@ create_room(Host, Name, Opts) ->
store_room(ServerHost, Host, Name, Opts) ->
store_room(ServerHost, Host, Name, Opts, undefined).
maybe_store_new_room(ServerHost, Host, Name, Opts) ->
case {proplists:get_bool(persistent, Opts), proplists:get_value(subscribers, Opts, [])} of
{false, []} ->
{atomic, ok};
{_, Subs} ->
Changes = [{add_subscription, JID, Nick, Nodes} || {JID, Nick, Nodes} <- Subs],
store_room(ServerHost, Host, Name, Opts, Changes)
end.
store_room(ServerHost, Host, Name, Opts, ChangesHints) ->
LServer = jid:nameprep(ServerHost),
Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -417,6 +426,7 @@ handle_call({create, Room, Host, Opts}, _From,
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
case start_room(RMod, Host, ServerHost, Room, NewOpts) of
{ok, _} ->
maybe_store_new_room(ServerHost, Host, Room, NewOpts),
ejabberd_hooks:run(create_room, ServerHost, [ServerHost, Room, Host]),
{reply, ok, State};
Err ->
@@ -432,6 +442,7 @@ handle_call({create, Room, Host, From, Nick, Opts}, _From,
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
case start_room(RMod, Host, ServerHost, Room, NewOpts, From, Nick) of
{ok, _} ->
maybe_store_new_room(ServerHost, Host, Room, NewOpts),
ejabberd_hooks:run(create_room, ServerHost, [ServerHost, Room, Host]),
{reply, ok, State};
Err ->
+93 -13
View File
@@ -46,7 +46,7 @@
web_page_host/3,
mod_opt_type/1, mod_options/1,
get_commands_spec/0, find_hosts/1, room_diagnostics/2,
get_room_pid/2]).
get_room_pid/2, get_room_history/2]).
-include("logger.hrl").
-include_lib("xmpp/include/xmpp.hrl").
@@ -162,9 +162,14 @@ get_commands_spec() ->
result = {res, rescode}},
#ejabberd_commands{name = create_room_with_opts, tags = [muc_room],
desc = "Create a MUC room name@service in host with given options",
longdesc = "To set affilitions string value must have format 'Type:JID,Type:JID' "
"for example 'owner:bob@example.com,member:peter@example.com'. Subscribers can be "
"define with string 'JID:Nick:Node1:Node2,JID:Nick:Node3' for example "
"'bob@example.com:Bob:messages:subject,anne@example.com:Anne:messages'.",
module = ?MODULE, function = create_room_with_opts,
args_desc = ["Room name", "MUC service", "Server host", "List of options"],
args_example = ["room1", "muc.example.com", "localhost", [{"members_only","true"}]],
args_example = ["room1", "muc.example.com", "localhost",
[{"members_only","true"}, {"subscribers", "bob@example.com:Bob:messages"}]],
args = [{name, binary}, {service, binary},
{host, binary},
{options, {list,
@@ -405,7 +410,18 @@ get_commands_spec() ->
result_desc = "Affiliation of the user",
result_example = member,
args = [{name, binary}, {service, binary}, {jid, binary}],
result = {affiliation, atom}}
result = {affiliation, atom}},
#ejabberd_commands{name = get_room_history, tags = [muc_room],
desc = "Get history of messages stored inside MUC room state",
note = "added in 23.04",
module = ?MODULE, function = get_room_history,
args_desc = ["Room name", "MUC service"],
args_example = ["room1", "muc.example.com"],
args = [{name, binary}, {service, binary}],
result = {history, {list,
{entry, {tuple,
[{timestamp, string},
{message, string}]}}}}}
].
@@ -721,7 +737,7 @@ create_room_with_opts(Name1, Host1, ServerHost1, CustomRoomOpts) ->
lists:keysort(1, DefRoomOpts)),
case mod_muc:create_room(Host, Name, RoomOpts) of
ok ->
maybe_store_room(ServerHost, Host, Name, RoomOpts);
ok;
{error, _} ->
throw({error, "Unable to start room"})
end;
@@ -732,15 +748,6 @@ create_room_with_opts(Name1, Host1, ServerHost1, CustomRoomOpts) ->
end
end.
maybe_store_room(ServerHost, Host, Name, RoomOpts) ->
case proplists:get_bool(persistent, RoomOpts) of
true ->
{atomic, _} = mod_muc:store_room(ServerHost, Host, Name, RoomOpts),
ok;
false ->
ok
end.
%% Create the room only in the database.
%% It is required to restart the MUC service for the room to appear.
muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) ->
@@ -1163,10 +1170,66 @@ format_room_option(OptionString, ValueString) ->
ValueString;
lang -> ValueString;
pubsub -> ValueString;
affiliations ->
[parse_affiliation_string(Opt) || Opt <- str:tokens(ValueString, <<",">>)];
subscribers ->
[parse_subscription_string(Opt) || Opt <- str:tokens(ValueString, <<",">>)];
_ -> misc:binary_to_atom(ValueString)
end,
{Option, Value}.
parse_affiliation_string(String) ->
{Type, JidS} = case String of
<<"owner:", Jid/binary>> -> {owner, Jid};
<<"admin:", Jid/binary>> -> {admin, Jid};
<<"member:", Jid/binary>> -> {member, Jid};
<<"outcast:", Jid/binary>> -> {outcast, Jid};
_ -> throw({error, "Invalid 'affiliation'"})
end,
try jid:decode(JidS) of
#jid{luser = U, lserver = S, lresource = R} ->
{{U, S, R}, {Type, <<>>}}
catch _:{bad_jid, _} ->
throw({error, "Malformed JID in affiliation"})
end.
parse_subscription_string(String) ->
case str:tokens(String, <<":">>) of
[_] ->
throw({error, "Invalid 'subscribers' - missing nick"});
[_, _] ->
throw({error, "Invalid 'subscribers' - missing nodes"});
[JidS, Nick | Nodes] ->
Nodes2 = parse_nodes(Nodes, []),
try jid:decode(JidS) of
Jid ->
{Jid, Nick, Nodes2}
catch _:{bad_jid, _} ->
throw({error, "Malformed JID in 'subscribers'"})
end
end.
parse_nodes([], Acc) ->
Acc;
parse_nodes([<<"presence">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_PRESENCE | Acc]);
parse_nodes([<<"messages">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_MESSAGES | Acc]);
parse_nodes([<<"participants">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_PARTICIPANTS | Acc]);
parse_nodes([<<"affiliations">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_AFFILIATIONS | Acc]);
parse_nodes([<<"subject">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_SUBJECT | Acc]);
parse_nodes([<<"config">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_CONFIG | Acc]);
parse_nodes([<<"system">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_SYSTEM | Acc]);
parse_nodes([<<"subscribers">> | Rest], Acc) ->
parse_nodes(Rest, [?NS_MUCSUB_NODES_SUBSCRIBERS | Acc]);
parse_nodes(_, _) ->
throw({error, "Invalid 'subscribers' - unknown node name used"}).
%% @doc Get the Pid of an existing MUC room, or 'room_not_found'.
-spec get_room_pid(binary(), binary()) -> pid() | room_not_found | invalid_service.
get_room_pid(Name, Service) ->
@@ -1290,6 +1353,23 @@ get_room_affiliations(Name, Service) ->
throw({error, "The room does not exist."})
end.
get_room_history(Name, Service) ->
case get_room_pid(Name, Service) of
Pid when is_pid(Pid) ->
case mod_muc_room:get_state(Pid) of
{ok, StateData} ->
History = p1_queue:to_list((StateData#state.history)#lqueue.queue),
lists:map(
fun({_Nick, Packet, _HaveSubject, TimeStamp, _Size}) ->
{xmpp_util:encode_timestamp(TimeStamp), fxml:element_to_binary(xmpp:encode(Packet))}
end, History);
_ ->
throw({error, "Unable to fetch room state."})
end;
_ ->
throw({error, "The room does not exist."})
end.
%%----------------------------
%% Get Room Affiliation
%%----------------------------
+217 -46
View File
@@ -294,15 +294,15 @@ init([Host, ServerHost, Access, Room, HistorySize,
process_flag(trap_exit, true),
Shaper = ejabberd_shaper:new(RoomShaper),
RoomQueue = room_queue_new(ServerHost, Shaper, QueueType),
State = set_affiliation(Creator, owner,
#state{host = Host, server_host = ServerHost,
access = Access, room = Room,
history = lqueue_new(HistorySize, QueueType),
jid = jid:make(Room, Host),
just_created = true,
room_queue = RoomQueue,
room_shaper = Shaper}),
State1 = set_opts(DefRoomOpts, State),
State = set_opts(DefRoomOpts,
#state{host = Host, server_host = ServerHost,
access = Access, room = Room,
history = lqueue_new(HistorySize, QueueType),
jid = jid:make(Room, Host),
just_created = true,
room_queue = RoomQueue,
room_shaper = Shaper}),
State1 = set_affiliation(Creator, owner, State),
store_room(State1),
?INFO_MSG("Created MUC room ~ts@~ts by ~ts",
[Room, Host, jid:encode(Creator)]),
@@ -316,20 +316,40 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts, QueueType])
process_flag(trap_exit, true),
Shaper = ejabberd_shaper:new(RoomShaper),
RoomQueue = room_queue_new(ServerHost, Shaper, QueueType),
Jid = jid:make(Room, Host),
State = set_opts(Opts, #state{host = Host,
server_host = ServerHost,
access = Access,
room = Room,
history = lqueue_new(HistorySize, QueueType),
jid = jid:make(Room, Host),
jid = Jid,
room_queue = RoomQueue,
room_shaper = Shaper}),
add_to_log(room_existence, started, State),
ejabberd_hooks:run(start_room, ServerHost, [ServerHost, Room, Host]),
State1 = cleanup_affiliations(State),
State2 =
case {lists:keyfind(hibernation_time, 1, Opts),
(State1#state.config)#config.mam,
(State1#state.history)#lqueue.max} of
{{_, V}, true, L} when is_integer(V), L > 0 ->
{Msgs, _, _} = mod_mam:select(ServerHost, Jid, Jid, [],
#rsm_set{max = L, before = <<"9999999999999999">>},
groupchat, only_messages),
Hist2 =
lists:foldl(
fun({_, TS, #forwarded{sub_els = [#message{meta = #{archive_nick := Nick}} = Msg]}}, Hist) ->
Pkt = xmpp:set_from_to(Msg, jid:replace_resource(Jid, Nick), Jid),
Size = element_size(Pkt),
lqueue_in({Nick, Pkt, false, misc:usec_to_now(TS), Size}, Hist)
end, State1#state.history, Msgs),
State1#state{history = Hist2};
_ ->
State1
end,
erlang:send_after(?CLEAN_ROOM_TIMEOUT, self(),
close_room_if_temporary_and_empty),
{ok, normal_state, reset_hibernate_timer(State1)}.
{ok, normal_state, reset_hibernate_timer(State2)}.
normal_state({route, <<"">>,
#message{from = From, type = Type, lang = Lang} = Packet},
@@ -454,6 +474,8 @@ normal_state({route, <<"">>,
[StateData]) of
ignore ->
{next_state, normal_state, StateData};
{ignore, StateData2} ->
{next_state, normal_state, StateData2};
#iq{type = T} = IQRes when T == error; T == result ->
ejabberd_router:route(IQRes),
{next_state, normal_state, StateData};
@@ -479,6 +501,15 @@ normal_state({route, <<"">>,
process_iq_captcha(From, IQ, StateData);
#adhoc_command{} ->
process_iq_adhoc(From, IQ, StateData);
#fasten_apply_to{} = ApplyTo ->
case xmpp:get_subtag(ApplyTo, #message_moderate{}) of
#message_moderate{} = Moderate ->
process_iq_moderate(From, IQ, ApplyTo, Moderate, StateData);
_ ->
Txt = ?T("The feature requested is not "
"supported by the conference"),
{error, xmpp:err_service_unavailable(Txt, Lang)}
end;
_ ->
Txt = ?T("The feature requested is not "
"supported by the conference"),
@@ -1002,12 +1033,8 @@ process_groupchat_message(#message{from = From, lang = Lang} = Packet, StateData
not Moderated, IsSubscriber} of
{true, _} -> true;
{_, true} ->
case get_default_role(get_affiliation(From, StateData),
StateData) of
moderator -> true;
participant -> true;
_ -> false
end;
% We assume all subscribers are at least members
true;
_ ->
false
end,
@@ -1043,24 +1070,26 @@ process_groupchat_message(#message{from = From, lang = Lang} = Packet, StateData
drop ->
{next_state, normal_state, StateData};
NewPacket1 ->
NewPacket = xmpp:put_meta(xmpp:remove_subtag(NewPacket1, #nick{}),
NewPacket = xmpp:put_meta(xmpp:remove_subtag(
add_stanza_id(NewPacket1, StateData), #nick{}),
muc_sender_real_jid, From),
Node = if Subject == [] -> ?NS_MUCSUB_NODES_MESSAGES;
true -> ?NS_MUCSUB_NODES_SUBJECT
end,
NewStateData2 = check_message_for_retractions(NewPacket1, NewStateData1),
send_wrapped_multiple(
jid:replace_resource(StateData#state.jid, FromNick),
get_users_and_subscribers_with_node(Node, StateData),
NewPacket, Node, NewStateData1),
NewStateData2 = case has_body_or_subject(NewPacket) of
NewPacket, Node, NewStateData2),
NewStateData3 = case has_body_or_subject(NewPacket) of
true ->
add_message_to_history(FromNick, From,
NewPacket,
NewStateData1);
NewStateData2);
false ->
NewStateData1
NewStateData2
end,
{next_state, normal_state, NewStateData2}
{next_state, normal_state, NewStateData3}
end;
_ ->
Err = case (StateData#state.config)#config.allow_change_subj of
@@ -1092,6 +1121,58 @@ process_groupchat_message(#message{from = From, lang = Lang} = Packet, StateData
{next_state, normal_state, StateData}
end.
-spec check_message_for_retractions(Packet :: message(), State :: state()) -> state().
check_message_for_retractions(Packet,
#state{config = Config, jid = JID, server_host = Server} = State) ->
case xmpp:get_subtag(Packet, #fasten_apply_to{}) of
#fasten_apply_to{id = ID} = F ->
case xmpp:get_subtag(F, #message_retract{}) of
#message_retract{} ->
#jid{luser = U, lserver = S} = xmpp:get_from(Packet),
case remove_from_history({U, S}, ID, State) of
{NewState, StanzaId} when is_integer(StanzaId) ->
case Config#config.mam of
true ->
JIDs = jid:encode(JID),
mod_mam:remove_message_from_archive(JIDs, Server, StanzaId),
NewState;
_ ->
NewState
end;
{NewState, _} ->
NewState
end;
_ ->
State
end;
_ ->
State
end.
-spec add_stanza_id(Packet :: message(), State :: state()) -> message().
add_stanza_id(Packet, #state{jid = JID}) ->
{AddId, NewPacket} =
case xmpp:get_meta(Packet, stanza_id, false) of
false ->
GenID = erlang:system_time(microsecond),
{true, xmpp:put_meta(Packet, stanza_id, GenID)};
_ ->
StanzaIds = xmpp:get_subtags(Packet, #stanza_id{by = #jid{}}),
HasOurStanzaId = lists:any(
fun(#stanza_id{by = JID2}) when JID == JID2 -> true;
(_) -> false
end, StanzaIds),
{not HasOurStanzaId, Packet}
end,
if
AddId ->
ID = xmpp:get_meta(NewPacket, stanza_id),
IDs = integer_to_binary(ID),
xmpp:append_subtags(NewPacket, [#stanza_id{by = JID, id = IDs}]);
true ->
Packet
end.
-spec process_normal_message(jid(), message(), state()) -> state().
process_normal_message(From, #message{lang = Lang} = Pkt, StateData) ->
Action = lists:foldl(
@@ -1735,10 +1816,12 @@ set_role(JID, Role, StateData) ->
end, StateData#state.users, LJIDs),
StateData#state.nicks}
end,
Affiliation = get_affiliation(JID, StateData),
Roles = case Role of
%% Don't persist 'none' role: if someone is kicked, they will
%% maintain the same role they had *before* they were kicked
none ->
%% maintain the same role they had *before* they were kicked,
%% unless they were banned
none when Affiliation /= outcast ->
StateData#state.roles;
NewRole ->
maps:put(jid:remove_resource(LJID),
@@ -2101,11 +2184,22 @@ get_priority_from_presence(#presence{priority = Prio}) ->
_ -> Prio
end.
-spec find_nick_by_jid(jid(), state()) -> binary().
-spec find_nick_by_jid(jid() | undefined, state()) -> binary().
find_nick_by_jid(undefined, _StateData) ->
<<>>;
find_nick_by_jid(JID, StateData) ->
LJID = jid:tolower(JID),
#user{nick = Nick} = maps:get(LJID, StateData#state.users),
Nick.
case maps:find(LJID, StateData#state.users) of
{ok, #user{nick = Nick}} ->
Nick;
_ ->
case maps:find(LJID, (StateData#state.muc_subscribers)#muc_subscribers.subscribers) of
{ok, #subscriber{nick = Nick}} ->
Nick;
_ ->
<<>>
end
end.
-spec is_nick_change(jid(), binary(), state()) -> boolean().
is_nick_change(JID, Nick, StateData) ->
@@ -2835,6 +2929,37 @@ add_message_to_history(FromNick, FromJID, Packet, StateData) ->
StateData#state{just_created = erlang:system_time(microsecond)}
end.
remove_from_history(StanzaId, #state{history = #lqueue{queue = Queue} = LQueue} = StateData) ->
NewQ = p1_queue:foldl(
fun({_, Pkt, _, _, _} = Entry, Acc) ->
case xmpp:get_meta(Pkt, stanza_id, missing) of
V when V == StanzaId ->
Acc;
_ ->
p1_queue:in(Entry, Acc)
end
end, p1_queue:new(), Queue),
StateData#state{history = LQueue#lqueue{queue = NewQ}}.
remove_from_history({U1, S1}, OriginId, #state{history = #lqueue{queue = Queue} = LQueue} = StateData) ->
{NewQ, StanzaId} = p1_queue:foldl(
fun({_, Pkt, _, _, _} = Entry, {Q, none}) ->
case jid:tolower(xmpp:get_from(Pkt)) of
{U2, S2, _} when U1 == U2, S1 == S2 ->
case xmpp:get_subtag(Pkt, #origin_id{}) of
#origin_id{id = V} when V == OriginId ->
{Q, xmpp:get_meta(Pkt, stanza_id, missing)};
_ ->
{p1_queue:in(Entry, Q), none}
end;
_ ->
{p1_queue:in(Entry, Q), none}
end;
(Entry, {Q, S}) ->
{p1_queue:in(Entry, Q), S}
end, {p1_queue:new(), none}, Queue),
{StateData#state{history = LQueue#lqueue{queue = NewQ}}, StanzaId}.
-spec send_history(jid(), [lqueue_elem()], state()) -> ok.
send_history(JID, History, StateData) ->
lists:foreach(
@@ -3054,7 +3179,7 @@ process_item_change(Item, SD, UJID) ->
process_iq_mucsub(JID,
#iq{type = set,
sub_els = [#muc_unsubscribe{}]}, SD),
set_affiliation(JID, outcast, set_role(JID, none, SD2), Reason);
set_role(JID, none, set_affiliation(JID, outcast, SD2, Reason));
{JID, affiliation, A, Reason} when (A == admin) or (A == owner) ->
SD1 = set_affiliation(JID, A, SD, Reason),
SD2 = set_role(JID, moderator, SD1),
@@ -3384,7 +3509,7 @@ send_kickban_presence(UJID, JID, Reason, Code, NewAffiliation,
send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
StateData) ->
#user{jid = RealJID, nick = Nick} = maps:get(jid:tolower(UJID), StateData#state.users),
ActorNick = get_actor_nick(MJID, StateData),
ActorNick = find_nick_by_jid(MJID, StateData),
%% TODO: optimize further
UserMap =
maps:merge(
@@ -3427,15 +3552,6 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
end
end, ok, UserMap).
-spec get_actor_nick(undefined | jid(), state()) -> binary().
get_actor_nick(undefined, _StateData) ->
<<"">>;
get_actor_nick(MJID, StateData) ->
try maps:get(jid:tolower(MJID), StateData#state.users) of
#user{nick = ActorNick} -> ActorNick
catch _:{badkey, _} -> <<"">>
end.
-spec convert_legacy_fields([xdata_field()]) -> [xdata_field()].
convert_legacy_fields(Fs) ->
lists:map(
@@ -3866,14 +3982,23 @@ remove_nonmembers(StateData) ->
end, StateData, get_users_and_subscribers(StateData)).
-spec set_opts([{atom(), any()}], state()) -> state().
set_opts([], StateData) ->
set_opts(Opts, StateData) ->
case lists:keytake(persistent, 1, Opts) of
false ->
set_opts2(Opts, StateData);
{value, Tuple, Rest} ->
set_opts2([Tuple | Rest], StateData)
end.
-spec set_opts2([{atom(), any()}], state()) -> state().
set_opts2([], StateData) ->
set_vcard_xupdate(StateData);
set_opts([{vcard, Val} | Opts], StateData)
set_opts2([{vcard, Val} | Opts], StateData)
when is_record(Val, vcard_temp) ->
%% default_room_options is setting a default room vcard
ValRaw = fxml:element_to_binary(xmpp:encode(Val)),
set_opts([{vcard, ValRaw} | Opts], StateData);
set_opts([{Opt, Val} | Opts], StateData) ->
set_opts2([{vcard, ValRaw} | Opts], StateData);
set_opts2([{Opt, Val} | Opts], StateData) ->
NSD = case Opt of
title ->
StateData#state{config =
@@ -4022,7 +4147,7 @@ set_opts([{Opt, Val} | Opts], StateData) ->
end, muc_subscribers_new(), Val),
StateData#state{muc_subscribers = MUCSubscribers};
affiliations ->
StateData#state{affiliations = maps:from_list(Val)};
set_affiliations(maps:from_list(Val), StateData);
roles ->
StateData#state{roles = maps:from_list(Val)};
subject ->
@@ -4042,7 +4167,7 @@ set_opts([{Opt, Val} | Opts], StateData) ->
?INFO_MSG("Unknown MUC room option, will be discarded: ~p", [Other]),
StateData
end,
set_opts(Opts, NSD).
set_opts2(Opts, NSD).
-spec set_vcard_xupdate(state()) -> state().
set_vcard_xupdate(#state{config =
@@ -4210,7 +4335,7 @@ maybe_forget_room(StateData) ->
make_disco_info(_From, StateData) ->
Config = StateData#state.config,
Feats = [?NS_VCARD, ?NS_MUC, ?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
?NS_COMMANDS,
?NS_COMMANDS, ?NS_MESSAGE_MODERATE, ?NS_MESSAGE_RETRACT,
?CONFIG_OPT_TO_FEATURE((Config#config.public),
<<"muc_public">>, <<"muc_hidden">>),
?CONFIG_OPT_TO_FEATURE((Config#config.persistent),
@@ -4964,6 +5089,52 @@ add_presence_hats(JID, Pres, StateData) ->
Pres
end.
-spec process_iq_moderate(jid(), iq(), fasten_apply_to(), message_moderate(), state()) ->
{result, undefined, state()} |
{error, stanza_error()}.
process_iq_moderate(_From, #iq{type = get}, _ApplyTo, _Moderate, _StateData) ->
{error, xmpp:err_bad_request()};
process_iq_moderate(From, #iq{type = set, lang = Lang},
#fasten_apply_to{id = Id},
#message_moderate{reason = Reason},
#state{config = Config, jid = JID, server_host = Server} = StateData) ->
FAffiliation = get_affiliation(From, StateData),
FRole = get_role(From, StateData),
IsModerator = FRole == moderator orelse FAffiliation == owner orelse
FAffiliation == admin,
case IsModerator of
false ->
{error, xmpp:err_forbidden(
?T("Only moderators are allowed to retract messages"), Lang)};
_ ->
try binary_to_integer(Id) of
StanzaId ->
case Config#config.mam of
true ->
JIDs = jid:encode(JID),
mod_mam:remove_message_from_archive(JIDs, Server, StanzaId);
_ ->
ok
end,
By = jid:replace_resource(JID, find_nick_by_jid(From, StateData)),
Packet = #message{type = groupchat,
sub_els = [
#fasten_apply_to{id = Id, sub_els = [
#message_moderated{by = By, reason = Reason,
retract = #message_retract{}}
]}]},
send_wrapped_multiple(JID,
get_users_and_subscribers_with_node(?NS_MUCSUB_NODES_MESSAGES, StateData),
Packet, ?NS_MUCSUB_NODES_MESSAGES, StateData),
NSD = add_message_to_history(<<"">>,
StateData#state.jid, Packet, StateData),
{result, undefined, remove_from_history(StanzaId, NSD)}
catch _:_ ->
{error, xmpp:err_bad_request(
?T("Stanza id is not valid"), Lang)}
end
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Voice request support
+236
View File
@@ -0,0 +1,236 @@
%%%----------------------------------------------------------------------
%%% File : mod_muc_rtbl.erl
%%% Author : Paweł Chmielowski <pawel@process-one.net>
%%% Purpose :
%%% Created : 17 kwi 2023 by Paweł Chmielowski <pawel@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2023 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_muc_rtbl).
-author("pawel@process-one.net").
-behaviour(gen_mod).
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
-include("mod_muc_room.hrl").
%% API
-export([start/2, stop/1, mod_opt_type/1, mod_options/1, mod_doc/0, depends/2]).
-export([pubsub_event_handler/1, muc_presence_filter/3, muc_process_iq/2]).
-record(muc_rtbl, {host_id, blank = blank}).
start(Host, _Opts) ->
ejabberd_mnesia:create(?MODULE, muc_rtbl,
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, muc_rtbl)},
{type, set}]),
ejabberd_hooks:add(local_send_to_resource_hook, Host,
?MODULE, pubsub_event_handler, 50),
ejabberd_hooks:add(muc_filter_presence, Host,
?MODULE, muc_presence_filter, 50),
ejabberd_hooks:add(muc_process_iq, Host,
?MODULE, muc_process_iq, 50),
request_initial_items(Host).
stop(Host) ->
ejabberd_hooks:delete(local_send_to_resource_hook, Host,
?MODULE, pubsub_event_handler, 50),
ejabberd_hooks:delete(muc_filter_presence, Host,
?MODULE, muc_presence_filter, 50),
ejabberd_hooks:delete(muc_process_iq, Host,
?MODULE, muc_process_iq, 50),
Jid = service_jid(Host),
IQ = #iq{type = set, from = Jid, to = jid:make(mod_muc_rtbl_opt:rtbl_server(Host)),
sub_els = [
#pubsub{unsubscribe =
#ps_unsubscribe{jid = Jid, node = mod_muc_rtbl_opt:rtbl_node(Host)}}]},
ejabberd_router:route_iq(IQ, fun parse_subscribe_result/1).
request_initial_items(Host) ->
IQ = #iq{type = get, from = service_jid(Host),
to = jid:make(mod_muc_rtbl_opt:rtbl_server(Host)),
sub_els = [
#pubsub{items = #ps_items{node = mod_muc_rtbl_opt:rtbl_node(Host)}}]},
ejabberd_router:route_iq(IQ, fun parse_initial_items/1).
parse_initial_items(#iq{type = error} = IQ) ->
?WARNING_MSG("Fetching initial list failed: ~p", [xmpp:format_stanza_error(xmpp:get_error(IQ))]);
parse_initial_items(#iq{from = From, to = #jid{lserver = Host} = To, type = result} = IQ) ->
case xmpp:get_subtag(IQ, #pubsub{}) of
#pubsub{items = #ps_items{node = Node, items = Items}} ->
Added = lists:foldl(
fun(#ps_item{id = ID}, Acc) ->
mnesia:dirty_write(#muc_rtbl{host_id = {Host, ID}}),
maps:put(ID, true, Acc)
end, #{}, Items),
SubIQ = #iq{type = set, from = To, to = From,
sub_els = [
#pubsub{subscribe = #ps_subscribe{jid = To, node = Node}}]},
ejabberd_router:route_iq(SubIQ, fun parse_subscribe_result/1),
notify_rooms(Host, Added);
_ ->
?WARNING_MSG("Fetching initial list failed: invalid result payload", [])
end.
parse_subscribe_result(#iq{type = error} = IQ) ->
?WARNING_MSG("Subscription error: ~p", [xmpp:format_stanza_error(xmpp:get_error(IQ))]);
parse_subscribe_result(_) ->
ok.
pubsub_event_handler(#message{from = #jid{luser = <<>>, lserver = SServer},
to = #jid{luser = <<>>, lserver = Server,
lresource = <<"rtbl-", _/binary>>}} = Msg) ->
SServer2 = mod_muc_rtbl_opt:rtbl_server(Server),
SNode = mod_muc_rtbl_opt:rtbl_node(Server),
if SServer == SServer2 ->
case xmpp:get_subtag(Msg, #ps_event{}) of
#ps_event{items = #ps_items{node = Node, retract = Retract}} when Node == SNode,
is_binary(Retract) ->
mnesia:dirty_delete(muc_rtbl, {Server, Retract});
#ps_event{items = #ps_items{node = Node, items = Items}} when Node == SNode ->
Added = lists:foldl(
fun(#ps_item{id = ID}, Acc) ->
mnesia:dirty_write(#muc_rtbl{host_id = {Server, ID}}),
maps:put(ID, true, Acc)
end, #{}, Items),
case maps:size(Added) of
0 -> ok;
_ -> notify_rooms(Server, Added)
end;
_ ->
ok
end;
true ->
ok
end,
stop;
pubsub_event_handler(_) ->
ok.
muc_presence_filter(#presence{from = #jid{lserver = Server} = From, lang = Lang} = Packet, _State, _Nick) ->
Blocked =
case mnesia:dirty_read(muc_rtbl, {Server, sha256(Server)}) of
[] ->
JIDs = sha256(jid:encode(jid:tolower(jid:remove_resource(From)))),
case mnesia:dirty_read(muc_rtbl, {Server, JIDs}) of
[] -> false;
_ -> true
end;
_ -> true
end,
case Blocked of
false -> Packet;
_ ->
ErrText = ?T("You have been banned from this room"),
Err = xmpp:err_forbidden(ErrText, Lang),
ejabberd_router:route_error(Packet, Err),
drop
end.
muc_process_iq(#iq{type = set, sub_els = [{rtbl_update, Items}]}, #state{users = Users} = State0) ->
{NewState, _} =
maps:fold(
fun(_, #user{role = moderator}, {State, HostHashes}) ->
{State, HostHashes};
({_, S, _} = LJid, #user{jid = JID}, {State, HostHashes}) ->
{Ban, HH2} =
case maps:find(S, HostHashes) of
{ok, Sha} ->
{maps:is_key(Sha, Items), HostHashes};
_ ->
Sha = sha256(S),
{maps:is_key(Sha, Items), maps:put(S, Sha, HostHashes)}
end,
Ban2 =
case Ban of
false ->
Sha2 = sha256(jid:encode(jid:remove_resource(LJid))),
maps:is_key(Sha2, Items);
_ ->
true
end,
case Ban2 of
true ->
{_, _, State2} = mod_muc_room:handle_event({process_item_change,
{JID, role, none, <<"Banned by RTBL">>},
undefined},
normal_state, State),
{State2, HH2};
_ ->
{State, HH2}
end
end, {State0, #{}}, Users),
{stop, {ignore, NewState}};
muc_process_iq(IQ, _State) ->
IQ.
sha256(Data) ->
Bin = crypto:hash(sha256, Data),
str:to_hexlist(Bin).
notify_rooms(Host, Items) ->
IQ = #iq{type = set, to = jid:make(Host), sub_els = [{rtbl_update, Items}]},
lists:foreach(
fun(CHost) ->
lists:foreach(
fun({_, _, Pid}) when node(Pid) == node() ->
mod_muc_room:route(Pid, IQ);
(_) ->
ok
end, mod_muc:get_online_rooms(CHost))
end, mod_muc_admin:find_hosts(Host)).
service_jid(Host) ->
jid:make(<<>>, Host, <<"rtbl-", (ejabberd_cluster:node_id())/binary>>).
mod_opt_type(rtbl_server) ->
econf:domain();
mod_opt_type(rtbl_node) ->
econf:non_empty(econf:binary()).
mod_options(_Host) ->
[{rtbl_server, <<"xmppbl.org">>},
{rtbl_node, <<"muc_bans_sha256">>}].
mod_doc() ->
#{desc =>
[?T("This module implement Real-time blocklists for MUC rooms."), "",
?T("It works by observing remote pubsub node conforming with "
"specification described in https://xmppbl.org/."), "",
?T("This module is available since ejabberd 23.04.")],
opts =>
[{rtbl_server,
#{value => ?T("Domain"),
desc =>
?T("Domain of xmpp server that serves block list. "
"The default value is 'xmppbl.org'")}},
{rtbl_node,
#{value => "PubsubNodeName",
desc =>
?T("Name of pubsub node that should be used to track blocked users. "
"The default value is 'muc_bans_sha256'.")}}]}.
depends(_, _) ->
[{mod_muc, hard}, {mod_pubsub, soft}].
+20
View File
@@ -0,0 +1,20 @@
%% Generated automatically
%% DO NOT EDIT: run `make options` instead
-module(mod_muc_rtbl_opt).
-export([rtbl_node/1]).
-export([rtbl_server/1]).
-spec rtbl_node(gen_mod:opts() | global | binary()) -> binary().
rtbl_node(Opts) when is_map(Opts) ->
gen_mod:get_opt(rtbl_node, Opts);
rtbl_node(Host) ->
gen_mod:get_module_opt(Host, mod_muc_rtbl, rtbl_node).
-spec rtbl_server(gen_mod:opts() | global | binary()) -> binary().
rtbl_server(Opts) when is_map(Opts) ->
gen_mod:get_opt(rtbl_server, Opts);
rtbl_server(Host) ->
gen_mod:get_module_opt(Host, mod_muc_rtbl, rtbl_server).
+4
View File
@@ -3456,6 +3456,10 @@ get_configure_xfields(_Type, Options, Lang, Groups) ->
{true, {roster_groups_allowed, Value, Groups}};
({sql, _}) -> false;
({rsm, _}) -> false;
({Item, infinity}) when Item == max_items;
Item == item_expire;
Item == children_max ->
{true, {Item, max}};
(_) -> true
end, Options),
Lang).
+14 -4
View File
@@ -567,24 +567,25 @@ transaction(LUser, LServer, LJIDs, F) ->
-spec in_subscription(boolean(), presence()) -> boolean().
in_subscription(_, #presence{from = JID, to = To,
sub_els = SubEls,
type = Type, status = Status}) ->
#jid{user = User, server = Server} = To,
Reason = if Type == subscribe -> xmpp:get_text(Status);
true -> <<"">>
end,
process_subscription(in, User, Server, JID, Type,
Reason).
Reason, SubEls).
-spec out_subscription(presence()) -> boolean().
out_subscription(#presence{from = From, to = JID, type = Type}) ->
#jid{user = User, server = Server} = From,
process_subscription(out, User, Server, JID, Type, <<"">>).
process_subscription(out, User, Server, JID, Type, <<"">>, []).
-spec process_subscription(in | out, binary(), binary(), jid(),
subscribe | subscribed | unsubscribe | unsubscribed,
binary()) -> boolean().
binary(), [fxml:xmlel()]) -> boolean().
process_subscription(Direction, User, Server, JID1,
Type, Reason) ->
Type, Reason, SubEls) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
LJID = jid:tolower(jid:remove_resource(JID1)),
@@ -618,6 +619,8 @@ process_subscription(Direction, User, Server, JID1,
{Subscription, Pending} ->
NewItem = Item#roster{subscription = Subscription,
ask = Pending,
name = get_nick_subels(SubEls, Item#roster.name),
xs = SubEls,
askmessage = AskMessage},
roster_subscribe_t(LUser, LServer, LJID, NewItem),
case mod_roster_opt:store_current_id(LServer) of
@@ -655,6 +658,12 @@ process_subscription(Direction, User, Server, JID1,
false
end.
get_nick_subels(SubEls, Default) ->
case xmpp:get_subtag(#presence{sub_els = SubEls}, #nick{}) of
{nick, N} -> N;
_ -> Default
end.
%% in_state_change(Subscription, Pending, Type) -> NewState
%% NewState = none | {NewSubscription, NewPending}
-ifdef(ROSTER_GATEWAY_WORKAROUND).
@@ -983,6 +992,7 @@ resend_pending_subscriptions(#{jid := JID} = State) ->
Sub = #presence{from = jid:make(R#roster.jid),
to = BareJID,
type = subscribe,
sub_els = R#roster.xs,
status = xmpp:mk_text(Status)},
ejabberd_c2s:send(AccState, Sub);
(_, AccState) ->
+2 -2
View File
@@ -107,7 +107,7 @@ user_send_packet(Acc) ->
-spec vcard_set(iq()) -> iq().
vcard_set(#iq{from = #jid{luser = LUser, lserver = LServer}} = IQ) ->
ets_cache:delete(?VCARD_XUPDATE_CACHE, {LUser, LServer}),
ets_cache:delete(?VCARD_XUPDATE_CACHE, {LUser, LServer}, ejabberd_cluster:get_nodes()),
ejabberd_sm:force_update_presence({LUser, LServer}),
IQ;
vcard_set(Acc) ->
@@ -117,7 +117,7 @@ vcard_set(Acc) ->
remove_user(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
ets_cache:delete(?VCARD_XUPDATE_CACHE, {LUser, LServer}).
ets_cache:delete(?VCARD_XUPDATE_CACHE, {LUser, LServer}, ejabberd_cluster:get_nodes()).
%%====================================================================
%% Storage
+1 -1
View File
@@ -21,7 +21,7 @@ The following commands will create the necessary login, user and database, will
```
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
```
## Running tests
+10 -2
View File
@@ -1,8 +1,16 @@
USE [master]
SET ANSI_NULLS ON;
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
USE [master];
GO
-- prevent creation when already exists
IF DB_ID('ejabberd_test') IS NOT NULL
set noexec on -- prevent creation when already exists
BEGIN
SET NOEXEC ON;
END
CREATE DATABASE ejabberd_test;
GO
+1
View File
@@ -24,6 +24,7 @@ services:
- mssqldata:/var/opt/mssql
- ./db/mssql/initdb/initdb_mssql.sql:/initdb_mssql.sql:ro
- ../../sql/mssql.sql:/mssql.sql:ro
- ../../sql/mssql.new.sql:/mssql.new.sql:ro
restart: always
ports:
- 1433:1433
+30 -29
View File
@@ -99,7 +99,8 @@ do_init_per_group(mysql, Config) ->
case catch ejabberd_sql:sql_query(?MYSQL_VHOST, [<<"select 1;">>]) of
{selected, _, _} ->
mod_muc:shutdown_rooms(?MYSQL_VHOST),
clear_sql_tables(mysql, ?config(base_dir, Config)),
clear_sql_tables(mysql, Config),
update_sql(?MYSQL_VHOST, Config),
set_opt(server, ?MYSQL_VHOST, Config);
Err ->
{skip, {mysql_not_available, Err}}
@@ -108,7 +109,8 @@ do_init_per_group(mssql, Config) ->
case catch ejabberd_sql:sql_query(?MSSQL_VHOST, [<<"select 1;">>]) of
{selected, _, _} ->
mod_muc:shutdown_rooms(?MSSQL_VHOST),
clear_sql_tables(mssql, ?config(base_dir, Config)),
clear_sql_tables(mssql, Config),
update_sql(?MSSQL_VHOST, Config),
set_opt(server, ?MSSQL_VHOST, Config);
Err ->
{skip, {mssql_not_available, Err}}
@@ -117,7 +119,8 @@ do_init_per_group(pgsql, Config) ->
case catch ejabberd_sql:sql_query(?PGSQL_VHOST, [<<"select 1;">>]) of
{selected, _, _} ->
mod_muc:shutdown_rooms(?PGSQL_VHOST),
clear_sql_tables(pgsql, ?config(base_dir, Config)),
clear_sql_tables(pgsql, Config),
update_sql(?PGSQL_VHOST, Config),
set_opt(server, ?PGSQL_VHOST, Config);
Err ->
{skip, {pgsql_not_available, Err}}
@@ -1011,37 +1014,35 @@ bookmark_conference() ->
'$handle_undefined_function'(_, _) ->
erlang:error(undef).
%%%===================================================================
%%% SQL stuff
%%%===================================================================
clear_sql_tables(sqlite, _BaseDir) ->
update_sql(Host, Config) ->
case ?config(update_sql, Config) of
true ->
mod_admin_update_sql:update_sql(Host);
false -> ok
end.
schema_suffix(Config) ->
case ejabberd_sql:use_new_schema() of
true ->
case ?config(update_sql, Config) of
true -> ".sql";
_ -> ".new.sql"
end;
_ -> ".sql"
end.
clear_sql_tables(sqlite, _Config) ->
ok;
clear_sql_tables(Type, BaseDir) ->
clear_sql_tables(Type, Config) ->
BaseDir = ?config(base_dir, Config),
{VHost, File} = case Type of
mysql ->
Path = case ejabberd_sql:use_new_schema() of
true ->
"mysql.new.sql";
false ->
"mysql.sql"
end,
{?MYSQL_VHOST, Path};
mssql ->
Path = case ejabberd_sql:use_new_schema() of
true ->
"mssql.new.sql";
false ->
"mssql.sql"
end,
{?MSSQL_VHOST, Path};
pgsql ->
Path = case ejabberd_sql:use_new_schema() of
true ->
"pg.new.sql";
false ->
"pg.sql"
end,
{?PGSQL_VHOST, Path}
mysql -> {?MYSQL_VHOST, "mysql" ++ schema_suffix(Config)};
mssql -> {?MSSQL_VHOST, "mssql" ++ schema_suffix(Config)};
pgsql -> {?PGSQL_VHOST, "pg" ++ schema_suffix(Config)}
end,
SQLFile = filename:join([BaseDir, "sql", File]),
CreationQueries = read_sql_queries(SQLFile),
+1 -1
View File
@@ -64,7 +64,7 @@
{host_config, "localhost", [{auth_method, internal}]}.
{host_config, "extauth.localhost",
[{auth_method, external},
{extauth_program, "python extauth.py"}]}.
{extauth_program, "python3 extauth.py"}]}.
{host_config, "mnesia.localhost",
[{auth_method, internal},
{{add, modules}, [{mod_announce, [{db_type, internal}]},
@@ -1,5 +1,5 @@
define_macro:
EXTAUTH_CONFIG:
queue_type: ram
extauth_program: "python extauth.py"
extauth_program: "python3 extauth.py"
auth_method: external
+1
View File
@@ -108,6 +108,7 @@ max_fsm_queue: 1000
queue_type: file
modules:
mod_adhoc: []
mod_admin_update_sql: []
mod_announce: []
mod_configure: []
mod_disco: []
+18 -13
View File
@@ -1,51 +1,56 @@
"""extauth dummy script for ejabberd testing."""
import sys
import struct
def read_from_stdin(bytes):
if hasattr(sys.stdin, 'buffer'):
return sys.stdin.buffer.read(bytes)
else:
return sys.stdin.read(bytes)
def read_from_stdin(read_bytes):
"""Read buffer from standard input."""
if hasattr(sys.stdin, 'buffer'):
return sys.stdin.buffer.read(read_bytes)
return sys.stdin.read(read_bytes)
def read():
"""Read input and process the command."""
(pkt_size,) = struct.unpack('>H', read_from_stdin(2))
pkt = sys.stdin.read(pkt_size)
cmd = pkt.split(':')[0]
if cmd == 'auth':
u, s, p = pkt.split(':', 3)[1:]
if u == "wrong":
user, _, _ = pkt.split(':', 3)[1:]
if user == "wrong":
write(False)
else:
write(True)
elif cmd == 'isuser':
u, s = pkt.split(':', 2)[1:]
if u == "wrong":
user, _ = pkt.split(':', 2)[1:]
if user == "wrong":
write(False)
else:
write(True)
elif cmd == 'setpass':
u, s, p = pkt.split(':', 3)[1:]
user, _, _ = pkt.split(':', 3)[1:]
write(True)
elif cmd == 'tryregister':
u, s, p = pkt.split(':', 3)[1:]
user, _, _ = pkt.split(':', 3)[1:]
write(True)
elif cmd == 'removeuser':
u, s = pkt.split(':', 2)[1:]
user, _ = pkt.split(':', 2)[1:]
write(True)
elif cmd == 'removeuser3':
u, s, p = pkt.split(':', 3)[1:]
user, _, _ = pkt.split(':', 3)[1:]
write(True)
else:
write(False)
read()
def write(result):
"""write result to standard output."""
if result:
sys.stdout.write('\x00\x02\x00\x01')
else:
sys.stdout.write('\x00\x02\x00\x00')
sys.stdout.flush()
if __name__ == "__main__":
try:
read()
+12 -1
View File
@@ -642,7 +642,8 @@ query_rsm_after(Config, From, To, NS) ->
query_rsm_before(Config, From, To) ->
lists:foreach(
fun(NS) ->
query_rsm_before(Config, From, To, NS)
query_rsm_before(Config, From, To, NS),
query_last_message(Config, From, To, NS)
end, ?VERSIONS).
query_rsm_before(Config, From, To, NS) ->
@@ -661,6 +662,16 @@ query_rsm_before(Config, From, To, NS) ->
Last
end, <<"">>, lists:reverse([lists:seq(1, N) || N <- lists:seq(0, 5)])).
query_last_message(Config, From, To, NS) ->
ct:comment("Retrieving last message", []),
QID = p1_rand:get_string(),
Query = #mam_query{xmlns = NS, id = QID,
rsm = #rsm_set{before = <<>>, max = 1}},
ID = send_query(Config, Query),
recv_archived_messages(Config, From, To, QID, [5]),
RSM = ?match(#rsm_set{} = RSM, recv_fin(Config, ID, QID, NS, false), RSM),
match_rsm_count(RSM, 5).
match_rsm_count(#rsm_set{count = undefined}, _) ->
%% The backend doesn't support counting
ok;
+4 -2
View File
@@ -131,6 +131,7 @@ init_config(Config) ->
{resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{update_sql, false},
{password, Password},
{backends, Backends}
|Config].
@@ -546,10 +547,11 @@ decode_stream_element(NS, El) ->
decode(El, NS, []).
format_element(El) ->
case erlang:function_exported(ct, log, 5) of
Bin = case erlang:function_exported(ct, log, 5) of
true -> ejabberd_web_admin:pretty_print_xml(El);
false -> io_lib:format("~p~n", [El])
end.
end,
binary:replace(Bin, <<"<">>, <<"&lt;">>, [global]).
decode(El, NS, Opts) ->
try
+3 -2
View File
@@ -31,6 +31,7 @@
recv_presence/1, recv/1]).
-include("suite.hrl").
-include_lib("stdlib/include/assert.hrl").
%%%===================================================================
%%% API
@@ -83,9 +84,9 @@ get_set(Config) ->
"personal website: http://www.saint-andre.com/">>},
#iq{type = result, sub_els = []} =
send_recv(Config, #iq{type = set, sub_els = [VCard]}),
%% TODO: check if VCard == VCard1.
#iq{type = result, sub_els = [_VCard1]} =
#iq{type = result, sub_els = [VCard1]} =
send_recv(Config, #iq{type = get, sub_els = [#vcard_temp{}]}),
?assertEqual(VCard, VCard1),
disconnect(Config).
service_vcard(Config) ->
+15 -13
View File
@@ -76,7 +76,7 @@ write_rfcs()
int=$(echo $1 | sed 's/^0*//')
imp=$(grep "\-protocol({rfc, $int," $BASE/src/* | sed "s/.*src\/\(.*\).erl.*'\([0-9.-]*\)'.*/\1 \2/")
[ "$imp" == "" ] && imp="NA 0.0"
[ "$imp" = "" ] && imp="NA 0.0"
echo " <implements rdf:resource=\"https://www.rfc-editor.org/info/$rfc\"/>" >>$out
}
@@ -88,7 +88,7 @@ write_xeps()
comments2=""
int=$(echo $1 | sed 's/^0*//')
imp=$(grep "\-protocol({xep, $int," $BASE/src/* | sed "s/.*src\/\(.*\).erl.*'\([0-9.-]*\)'.*/\1 \2/")
[ "$imp" == "" ] && imp="NA 0.0"
[ "$imp" = "" ] && imp="NA 0.0"
sourcefiles=$(grep "\-protocol({xep, $int," $BASE/src/* | sed "s/.*src\/\(.*\).erl.*'\([0-9.-]*\)'.*/\1/" | tr '\012' ',' | sed 's|,$||' | sed 's|,|, |g' | sed 's|^ejabberd$||')
@@ -103,15 +103,17 @@ write_xeps()
[ -n "$comments" ] && comments2=", $comments"
note="$sourcefiles$comments2"
echo " <implements>" >>$out
echo " <xmpp:SupportedXep>" >>$out
echo " <xmpp:xep rdf:resource=\"https://xmpp.org/extensions/$xep.html\"/>" >>$out
echo " <xmpp:version>$versions</xmpp:version>" >>$out
echo " <xmpp:since>$since</xmpp:since>" >>$out
echo " <xmpp:status>$status</xmpp:status>" >>$out
echo " <xmpp:note>$note</xmpp:note>" >>$out
echo " </xmpp:SupportedXep>" >>$out
echo " </implements>" >>$out
{
echo " <implements>"
echo " <xmpp:SupportedXep>"
echo " <xmpp:xep rdf:resource=\"https://xmpp.org/extensions/$xep.html\"/>"
echo " <xmpp:version>$versions</xmpp:version>"
echo " <xmpp:since>$since</xmpp:since>"
echo " <xmpp:status>$status</xmpp:status>"
echo " <xmpp:note>$note</xmpp:note>"
echo " </xmpp:SupportedXep>"
echo " </implements>"
} >>$out
}
[ $# -eq 1 ] && BASE="$1" || BASE="$PWD"
@@ -121,13 +123,13 @@ final=ejabberd.doap
write_doap_head $final
for x_num in $(grep "\-protocol({rfc" $BASE/src/* | sed "s/,//" | awk '{printf("%04d\n", $2)}' | sort -u)
grep "\-protocol({rfc" $BASE/src/* | sed "s/,//" | awk '{printf("%04d\n", $2)}' | sort -u | while IFS= read -r x_num
do
write_rfcs $x_num $temp
done
echo "" >>$temp
for x_num in $(grep "\-protocol({xep" $BASE/src/* | sed "s/,//" | awk '{printf("%04d\n", $2)}' | sort -u)
grep "\-protocol({xep" $BASE/src/* | sed "s/,//" | awk '{printf("%04d\n", $2)}' | sort -u | while IFS= read -r x_num
do
write_xeps $x_num $temp
done
+80 -37
View File
@@ -67,19 +67,19 @@ rel_vsn=$(git describe --tags | sed -e 's/-g.*//' -e 's/-/./' | tr -d '[:space:]
mix_vsn=$(mix_version "$rel_vsn")
crosstool_vsn='1.25.0'
termcap_vsn='1.3.1'
expat_vsn='2.4.9'
expat_vsn='2.5.0'
zlib_vsn='1.2.13'
yaml_vsn='0.2.5'
ssl_vsn='1.1.1q'
otp_vsn='24.3.4.5'
elixir_vsn='1.14.0'
ssl_vsn='1.1.1t'
otp_vsn='25.3'
elixir_vsn='1.14.3'
pam_vsn='1.5.2'
png_vsn='1.6.38'
png_vsn='1.6.39'
jpeg_vsn='9e'
webp_vsn='1.2.4'
webp_vsn='1.3.0'
gd_vsn='2.3.3'
odbc_vsn='2.3.11'
sqlite_vsn='3390300'
sqlite_vsn='3410100'
root_dir="${BUILD_DIR:-$HOME/build}"
bootstrap_dir="$root_dir/bootstrap"
ct_prefix_dir="$root_dir/x-tools"
@@ -117,7 +117,8 @@ odbc_tar="$odbc_dir.tar.gz"
rel_tar="$rel_name-$mix_vsn.tar.gz"
ct_jobs=$(nproc)
src_dir="$root_dir/src"
platform='x86_64-pc-linux-gnu'
platform=$(gcc -dumpmachine)
platform_libc=$(echo $platform | sed "s/\-/\ /g" | awk '{print $NF}')
targets='x86_64-linux-gnu aarch64-linux-gnu'
build_start=$(date '+%F %T')
have_current_deps='false'
@@ -257,20 +258,49 @@ create_common_config()
CT_CC_LANG_CXX=y
CT_ARCH_64=y
CT_KERNEL_LINUX=y
CT_LINUX_V_3_16=y
CT_GLIBC_V_2_17=y
CT_GLIBC_KERNEL_VERSION_NONE=y
CT_LOG_PROGRESS_BAR=n
EOF
}
#.
#' Create Crosstool-NG configuration file for glibc.
create_gnu_config()
{
local file="$1"
create_common_config "$file"
cat >>"$file" <<-'EOF'
CT_LINUX_V_3_16=y
CT_GLIBC_V_2_19=y
CT_GLIBC_KERNEL_VERSION_NONE=y
EOF
}
#.
#' Create Crosstool-NG configuration file for musl.
create_musl_config()
{
local file="$1"
create_common_config "$file"
cat >>"$file" <<-'EOF'
CT_EXPERIMENTAL=y
CT_LIBC_MUSL=y
CT_MUSL_V_1_2_2=y
EOF
}
#.
#' Create Crosstool-NG configuration file for x64.
create_x64_config()
{
local file="$1"
local libc="$2"
create_common_config "$file"
create_${libc}_config "$file"
cat >>"$file" <<-'EOF'
CT_ARCH_X86=y
@@ -282,8 +312,10 @@ create_x64_config()
create_arm64_config()
{
local file="$1"
local libc="$2"
create_common_config "$file"
create_${libc}_config "$file"
cat >>"$file" <<-'EOF'
CT_ARCH_ARM=y
@@ -319,6 +351,13 @@ add_otp_path()
if [ "$mode" = 'native' ]
then native_otp_bin="$prefix/bin"
# for github runners to build for non-native systems
# https://github.com/marketplace/actions/setup-erlang-otp-with-optional-elixir-and-mix-and-or-rebar3
elif [ ! -z "${INSTALL_DIR_FOR_OTP-}" ] && [ ! -z "${INSTALL_DIR_FOR_ELIXIR-}" ]
then
native_otp_bin="$INSTALL_DIR_FOR_OTP/bin"
native_elixir_bin="$INSTALL_DIR_FOR_ELIXIR/bin"
export PATH="$native_elixir_bin:$PATH"
fi
export PATH="$native_otp_bin:$PATH"
}
@@ -437,8 +476,9 @@ build_toolchain()
{
local target="$1"
local prefix="$2"
local libc="$3"
local arch=$(arch_name "$target")
if [ -d "$prefix" ]
then
info "Using existing toolchain in $prefix ..."
@@ -458,9 +498,9 @@ build_toolchain()
cd "$OLDPWD"
fi
info "Building toolchain for $arch ..."
info "Building toolchain for $arch-$libc ..."
cd "$root_dir"
create_${arch}_config 'defconfig'
create_${arch}_config 'defconfig' "$libc"
ct-ng defconfig
sed -i -e "s|^CT_ZLIB_VERSION=.*|CT_ZLIB_VERSION=\"$zlib_vsn\"|" .config
sed -i -e 's|^CT_ZLIB_MIRRORS=.*|CT_ZLIB_MIRRORS="https://github.com/madler/zlib/releases/download/v${CT_ZLIB_VERSION} https://www.zlib.net/ https://www.zlib.net/fossils/"|' .config
@@ -477,6 +517,7 @@ build_deps()
local mode="$1"
local target="$2"
local prefix="$3"
local libc="$4"
local arch="$(arch_name "$target")"
local target_src_dir="$prefix/src"
local saved_path="$PATH"
@@ -507,7 +548,7 @@ build_deps()
tar -xJf "$src_dir/$pam_tar"
cd "$OLDPWD"
info "Building Termcap $termcap_vsn for $arch ..."
info "Building Termcap $termcap_vsn for $arch-$libc ..."
cd "$target_src_dir/$termcap_dir"
$configure --prefix="$prefix"
cat >'config.h' <<-'EOF'
@@ -535,24 +576,24 @@ build_deps()
make install
cd "$OLDPWD"
info "Building zlib $zlib_vsn for $arch ..."
info "Building zlib $zlib_vsn for $arch-$libc ..."
cd "$target_src_dir/$zlib_dir"
CFLAGS="$CFLAGS -O3 -fPIC" ./configure --prefix="$prefix" --static
make
make install
cd "$OLDPWD"
info "Building OpenSSL $ssl_vsn for $arch ..."
info "Building OpenSSL $ssl_vsn for $arch-$libc ..."
cd "$target_src_dir/$ssl_dir"
CFLAGS="$CFLAGS -O3 -fPIC" ./Configure no-shared no-ui-console \
--prefix="$prefix" \
--openssldir="$prefix" \
"linux-${target%-linux-gnu}"
"linux-${target%-linux-*}"
make build_libs
make install_dev
cd "$OLDPWD"
info "Building Expat $expat_vsn for $arch ..."
info "Building Expat $expat_vsn for $arch-$libc ..."
cd "$target_src_dir/$expat_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
--without-docbook \
@@ -561,7 +602,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building LibYAML $yaml_vsn for $arch ..."
info "Building LibYAML $yaml_vsn for $arch-$libc ..."
cd "$target_src_dir/$yaml_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
CFLAGS="$CFLAGS -O3 -fPIC"
@@ -569,7 +610,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building SQLite $sqlite_vsn for $arch ..."
info "Building SQLite $sqlite_vsn for $arch-$libc ..."
cd "$target_src_dir/$sqlite_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
CFLAGS="$CFLAGS -O3 -fPIC"
@@ -577,7 +618,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building ODBC $odbc_vsn for $arch ..."
info "Building ODBC $odbc_vsn for $arch-$libc ..."
cd "$target_src_dir/$odbc_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
CFLAGS="$CFLAGS -O3 -fPIC"
@@ -594,7 +635,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building libpng $png_vsn for $arch ..."
info "Building libpng $png_vsn for $arch-$libc ..."
cd "$target_src_dir/$png_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
CFLAGS="$CFLAGS -O3 -fPIC"
@@ -602,7 +643,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building JPEG $jpeg_vsn for $arch ..."
info "Building JPEG $jpeg_vsn for $arch-$libc ..."
cd "$target_src_dir/$jpeg_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
CFLAGS="$CFLAGS -O3 -fPIC"
@@ -610,7 +651,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building WebP $webp_vsn for $arch ..."
info "Building WebP $webp_vsn for $arch-$libc ..."
cd "$target_src_dir/$webp_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
CFLAGS="$CFLAGS -O3 -fPIC"
@@ -618,7 +659,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building LibGD $gd_vsn for $arch ..."
info "Building LibGD $gd_vsn for $arch-$libc ..."
cd "$target_src_dir/$gd_dir"
$configure --prefix="$prefix" --enable-static --disable-shared \
--with-zlib="$prefix" \
@@ -640,7 +681,7 @@ build_deps()
make install
cd "$OLDPWD"
info "Building Erlang/OTP $otp_vsn for $arch ..."
info "Building Erlang/OTP $otp_vsn for $arch-$libc ..."
if [ "$mode" = 'cross' ]
then
add_otp_path "$mode" "$prefix"
@@ -669,7 +710,7 @@ build_deps()
fi
cd "$OLDPWD"
info "Building Elixir $elixir_vsn for $arch ..."
info "Building Elixir $elixir_vsn for $arch-$libc ..."
cd "$target_src_dir/$elixir_dir"
make install PREFIX="$prefix"
cd "$OLDPWD"
@@ -684,11 +725,12 @@ build_rel()
local mode="$1"
local target="$2"
local prefix="$3"
local libc="$4"
local arch="$(arch_name "$target")"
local rel_dir="$PWD/_build/prod"
local target_data_dir="$prefix/$rel_name"
local target_dst_dir="$prefix/$rel_name-$rel_vsn"
local target_dst_tar="$rel_name-$rel_vsn-linux-$arch.tar.gz"
local target_dst_tar="$rel_name-$rel_vsn-linux-$libc-$arch.tar.gz"
local saved_path="$PATH"
#
@@ -715,7 +757,7 @@ build_rel()
export CFLAGS="-g0 -O2 -pipe -fomit-frame-pointer -static-libgcc $CPPFLAGS"
export CXXFLAGS="$CFLAGS -static-libstdc++"
export LDFLAGS="-L$prefix/lib -static-libgcc -static-libstdc++"
export ERL_COMPILER_OPTIONS='[deterministic, no_debug_info]'
export ERL_COMPILER_OPTIONS='[no_debug_info]' # Building 25.x fails with 'deterministic'.
if [ "$mode" = 'cross' ]
then configure="./configure --host=$target --build=$platform"
@@ -723,7 +765,7 @@ build_rel()
fi
if [ $have_current_deps = false ]
then build_deps "$mode" "$target" "$prefix"
then build_deps "$mode" "$target" "$prefix" "$libc"
fi
add_otp_path "$mode" "$prefix"
@@ -738,7 +780,7 @@ build_rel()
info "Removing old $rel_name builds"
rm -rf '_build' 'deps'
info "Building $rel_name $rel_vsn for $arch ..."
info "Building $rel_name $rel_vsn for $arch-$libc ..."
./autogen.sh
eimp_cflags='-fcommon'
eimp_libs='-lwebp -ljpeg -lpng -lz -lm'
@@ -782,7 +824,7 @@ build_rel()
unset host_alias build_alias
fi
info "Putting together $rel_name $rel_vsn archive for $arch ..."
info "Putting together $rel_name $rel_vsn archive for $arch-$libc ..."
mkdir "$target_dst_dir"
tar -C "$target_dst_dir" -xzf "$rel_dir/$rel_tar"
create_data_dir "$target_dst_dir" "$target_data_dir"
@@ -870,15 +912,16 @@ export LC_ALL='C.UTF-8' # Elixir insists on a UTF-8 environment.
for target in $targets
do
prefix="$build_dir/$(arch_name "$target")"
libc="$(echo $target | sed "s/\-/\ /g" | awk '{print $NF}')"
prefix="$build_dir/$(arch_name "$target")-$libc"
toolchain_dir="$ct_prefix_dir/$target"
if [ "$(uname -m)-linux-gnu" = "$target" ]
if [ "$(uname -m)-linux-$platform_libc" = "$target" ]
then mode='native'
else mode='cross'
fi
build_toolchain "$target" "$toolchain_dir"
build_rel "$mode" "$target" "$prefix"
build_toolchain "$target" "$toolchain_dir" "$libc"
build_rel "$mode" "$target" "$prefix" "$libc"
done
save_built_dep_vsns
+2 -2
View File
@@ -80,7 +80,7 @@ create_help_file()
local file="$1"
cat >"$file" <<-EOF
This is the $rel_name $rel_vsn-$iteration installer for linux-$arch
This is the $rel_name $rel_vsn-$iteration installer for linux-gnu-$arch
Visit:
$home_url
@@ -354,7 +354,7 @@ create_setup_script()
for arch in $architectures
do
tar_name="$rel_name-$rel_vsn-linux-$arch.tar.gz"
tar_name="$rel_name-$rel_vsn-linux-gnu-$arch.tar.gz"
installer_name="$rel_name-$rel_vsn-$iteration-linux-$arch.run"
test -e "$tar_name" || tools/make-binaries
+1 -1
View File
@@ -203,7 +203,7 @@ make_package()
for arch in $architectures
do
tar_name="$rel_name-$rel_vsn-linux-$arch.tar.gz"
tar_name="$rel_name-$rel_vsn-linux-gnu-$arch.tar.gz"
arch_dir="$tmp_dir/$arch"
opt_dir="$arch_dir/opt"
etc_dir="$arch_dir/etc"
+21 -19
View File
@@ -32,7 +32,7 @@ extract_lang_po2msg ()
MSGSTR_PATH=$PO_PATH.msgstr
MSGS_PATH=$LANG_CODE.msg
cd $PO_DIR
cd $PO_DIR || exit
# Check PO has correct ~
# Let's convert to C format so we can use msgfmt
@@ -48,11 +48,13 @@ extract_lang_po2msg ()
msgattrib $PO_PATH --translated --no-fuzzy --no-obsolete --no-location --no-wrap | grep "^msg" | tail --lines=+3 >$MS_PATH
grep "^msgid" $PO_PATH.ms | sed 's/^msgid //g' >$MSGID_PATH
grep "^msgstr" $PO_PATH.ms | sed 's/^msgstr //g' >$MSGSTR_PATH
echo "%% Generated automatically" >$MSGS_PATH
echo "%% DO NOT EDIT: run \`make translations\` instead" >>$MSGS_PATH
echo "%% To improve translations please read:" >>$MSGS_PATH
echo "%% https://docs.ejabberd.im/developer/extending-ejabberd/localization/" >>$MSGS_PATH
echo "" >>$MSGS_PATH
{
echo "%% Generated automatically"
echo "%% DO NOT EDIT: run \`make translations\` instead"
echo "%% To improve translations please read:"
echo "%% https://docs.ejabberd.im/developer/extending-ejabberd/localization/"
echo ""
} >>$MSGS_PATH
paste $MSGID_PATH $MSGSTR_PATH --delimiter=, | awk '{print "{" $0 "}."}' | sort -g >>$MSGS_PATH
rm $MS_PATH
@@ -68,29 +70,29 @@ extract_lang_updateall ()
echo "Generating POT..."
extract_lang_src2pot
cd $MSGS_DIR
cd $MSGS_DIR || exit
echo ""
echo -e "File Missing (fuzzy) Language Last translator"
echo -e "---- ------- ------- -------- ---------------"
for i in $( ls *.msg ) ; do
echo "File Missing (fuzzy) Language Last translator"
echo "---- ------- ------- -------- ---------------"
for i in *.msg ; do
LANG_CODE=${i%.msg}
echo -n $LANG_CODE | awk '{printf "%-6s", $1 }'
printf "%s" "$LANG_CODE" | awk '{printf "%-6s", $1 }'
PO=$PO_DIR/$LANG_CODE.po
extract_lang_popot2po $LANG_CODE
extract_lang_po2msg $LANG_CODE
MISSING=`msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4+$7 }'`
echo -n " $MISSING"
MISSING=$(msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4+$7 }')
printf " %s" "$MISSING"
FUZZY=`msgfmt --statistics $PO 2>&1 | awk '{printf "%7s", $4 }'`
echo -n " $FUZZY"
FUZZY=$(msgfmt --statistics $PO 2>&1 | awk '{printf "%7s", $4 }')
printf " %s" "$FUZZY"
LANGUAGE=`grep "X-Language:" $PO | sed 's/\"X-Language: //g' | sed 's/\\\\n\"//g' | awk '{printf "%-12s", $1}'`
echo -n " $LANGUAGE"
LANGUAGE=$(grep "X-Language:" $PO | sed 's/\"X-Language: //g' | sed 's/\\n\"//g' | awk '{printf "%-12s", $1}')
printf " %s" "$LANGUAGE"
LASTAUTH=`grep "Last-Translator" $PO | sed 's/\"Last-Translator: //g' | sed 's/\\\\n\"//g'`
LASTAUTH=$(grep "Last-Translator" $PO | sed 's/\"Last-Translator: //g' | sed 's/\\n\"//g')
echo " $LASTAUTH"
done
echo ""
@@ -101,7 +103,7 @@ extract_lang_updateall ()
cd ..
}
EJA_DIR=`pwd`
EJA_DIR=$(pwd)
PROJECT=ejabberd
DEPS_DIR=$1
MSGS_DIR=$EJA_DIR/priv/msgs