diff --git a/.github/container/Dockerfile b/.github/container/Dockerfile
index 94a9422f2..1d238339a 100644
--- a/.github/container/Dockerfile
+++ b/.github/container/Dockerfile
@@ -1,20 +1,22 @@
#' Define default build variables
-## specifc ARGs for METHOD='direct'
-ARG OTP_VSN='25.3'
-ARG ELIXIR_VSN='1.14.4'
-## specifc ARGs for METHOD='package'
-ARG ALPINE_VSN='3.17'
-## general ARGs
+ARG OTP_VSN='27.3.4.3'
+ARG ELIXIR_VSN='1.18.4'
ARG UID='9000'
ARG USER='ejabberd'
ARG HOME="opt/$USER"
-ARG METHOD='direct'
ARG BUILD_DIR="/$USER"
ARG VERSION='master'
################################################################################
-#' METHOD='direct' - build and install ejabberd directly from source
-FROM docker.io/erlang:${OTP_VSN}-alpine AS direct
+#' Compile ejabberdapi
+FROM docker.io/golang:1.25-alpine AS api
+RUN go install -v \
+ github.com/processone/ejabberd-api/cmd/ejabberd@master \
+ && mv bin/ejabberd bin/ejabberdapi
+
+################################################################################
+#' build and install ejabberd directly from source
+FROM docker.io/erlang:${OTP_VSN}-alpine AS ejabberd
RUN apk -U add --no-cache \
autoconf \
@@ -39,7 +41,8 @@ ARG ELIXIR_VSN
RUN wget -O - https://github.com/elixir-lang/elixir/archive/v$ELIXIR_VSN.tar.gz \
| tar -xzf -
-WORKDIR elixir-$ELIXIR_VSN
+WORKDIR /elixir-$ELIXIR_VSN
+ENV ERL_FLAGS="+JPperf true"
RUN make install clean
RUN mix local.hex --force \
@@ -50,6 +53,7 @@ COPY / $BUILD_DIR/
WORKDIR $BUILD_DIR
RUN mv .github/container/ejabberdctl.template . \
+ && mv .github/container/ejabberd.yml.example . \
&& ./autogen.sh \
&& ./configure --with-rebar=mix --enable-all \
&& make deps \
@@ -67,36 +71,18 @@ RUN cp -p $BUILD_DIR/tools/captcha*.sh $HOME-$VERSION/lib
RUN find "$HOME-$VERSION/bin" -name 'ejabberd' -delete \
&& find "$HOME-$VERSION/releases" -name 'COOKIE' -delete
-RUN wget -O "$HOME/conf/cacert.pem" 'https://curl.se/ca/cacert.pem' \
- && sed -i '/^loglevel:/a \ \
- \nca_file: /opt/ejabberd/conf/cacert.pem \
- \ncertfiles: \
- \n - /opt/ejabberd/conf/server.pem' "$HOME/conf/ejabberd.yml"
+RUN wget -O "$HOME/conf/cacert.pem" 'https://curl.se/ca/cacert.pem'
-################################################################################
-#' METHOD='package' - install ejabberd from binary tarball package
-FROM docker.io/alpine:${ALPINE_VSN} AS package
-COPY tarballs/ejabberd-*-linux-musl-*.tar.gz /tmp/
-WORKDIR /rootfs
-ARG HOME
-RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \
- && mkdir -p $home_root_dir \
- && ARCH=$(uname -m | sed -e 's/x86_64/x64/;s/aarch64/arm64/') \
- && tar -xzf /tmp/ejabberd-*-linux-musl-$ARCH.tar.gz -C $home_root_dir
-
-################################################################################
#' Prepare ejabberd for runtime
-FROM ${METHOD} AS ejabberd
RUN apk -U add --no-cache \
git \
libcap \
openssl
-WORKDIR /rootfs
-ARG HOME
RUN mkdir -p usr/local/bin $HOME/conf $HOME/database $HOME/logs $HOME/upload
-ARG BUILD_DIR
+COPY --from=api /go/bin/ejabberdapi usr/local/bin/
+
RUN if [ ! -d $HOME/.ejabberd-modules ]; \
then \
if [ -d $BUILD_DIR/.ejabberd-modules ]; \
@@ -116,11 +102,35 @@ RUN export PEM=$HOME/conf/server.pem \
-days 3650 \
-subj "/CN=localhost"
+RUN sed -i 's|^#CTL_OVER_HTTP=|CTL_OVER_HTTP=../|' "$HOME/conf/ejabberdctl.cfg"
+
RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \
&& setcap 'cap_net_bind_service=+ep' $(find $home_root_dir -name beam.smp) \
&& echo -e \
"#!/bin/sh \
\n[ -z \$ERLANG_NODE_ARG ] && export ERLANG_NODE_ARG=ejabberd@localhost \
+ \nexport EMA=\"\$EJABBERD_MACRO_ADMIN\" \
+ \nexport HOST=\"\${EJABBERD_MACRO_HOST:-localhost}\" \
+ \nif [ -n \"\$EMA\" ] \
+ \nthen \
+ \n if [ \"\$EMA\" != \"\${EMA%%@*}\" ] \
+ \n then \
+ \n export USERNAME=\"\${EMA%%@*}\" \
+ \n export HOST=\"\${EMA##*@}\" \
+ \n else \
+ \n export USERNAME=\"\$EMA\" \
+ \n export SHOW_WARNING=\"true\" \
+ \n fi \
+ \nelif [ -n \"\$REGISTER_ADMIN_PASSWORD\" ] \
+ \nthen \
+ \n export USERNAME=\"admin\" \
+ \nelse \
+ \n export USERNAME=\"\$(od -A n -N 8 -t x8 /dev/urandom)\" \
+ \nfi \
+ \nexport EJABBERD_MACRO_ADMIN=\"\$USERNAME@\$HOST\" \
+ \n[ -n \"\$SHOW_WARNING\" ] && echo \"WARNING: The EJABBERD_MACRO_ADMIN environment variable was set to '\$EMA', but it should include the host... I'll overwrite it to become '\$EJABBERD_MACRO_ADMIN'.\" \
+ \n[ -n \"\$CTL_ON_CREATE\" ] && export SEPARATOR=\";\" \
+ \n[ -n \"\$REGISTER_ADMIN_PASSWORD\" ] && export CTL_ON_CREATE=\"register \${EJABBERD_MACRO_ADMIN%%@*} \${EJABBERD_MACRO_ADMIN##*@} \$REGISTER_ADMIN_PASSWORD \$SEPARATOR \$CTL_ON_CREATE\" \
\nexport CONFIG_DIR=/$HOME/conf \
\nexport LOGS_DIR=/$HOME/logs \
\nexport SPOOL_DIR=/$HOME/database \
@@ -137,28 +147,28 @@ RUN home_root_dir=$(echo $HOME | sed 's|\(.*\)/.*|\1 |') \
ARG UID
RUN chown -R $UID:$UID $HOME
+RUN cp /rootfs/$HOME-$VERSION/lib/captcha*.sh usr/local/bin/
+RUN mkdir $HOME/sql \
+ && find /rootfs/$HOME-$VERSION/lib/ -name *.sql -exec cp {} $HOME/sql \; -exec cp {} $HOME/database \;
+
################################################################################
-#' METHOD='direct' - Remove erlang/OTP & rebar3
-FROM docker.io/erlang:${OTP_VSN}-alpine AS runtime-direct
+#' Remove erlang/OTP & rebar3
+FROM docker.io/erlang:${OTP_VSN}-alpine AS runtime
RUN apk del .erlang-rundeps \
&& rm -f $(which rebar3) \
&& find /usr -type d -name 'erlang' -exec rm -rf {} + \
&& find /usr -type l -exec test ! -e {} \; -delete
-################################################################################
-#' METHOD='package' - define runtime base image
-FROM docker.io/alpine:${ALPINE_VSN} AS runtime-package
-
-################################################################################
#' Update alpine, finalize runtime environment
-FROM runtime-${METHOD} AS runtime
COPY --from=ejabberd /tmp/runDeps /tmp/runDeps
RUN apk -U upgrade --available --no-cache \
&& apk add --no-cache \
$(cat /tmp/runDeps) \
so:libcap.so.2 \
so:libtdsodbc.so.0 \
+ curl \
tini \
+ && rm /tmp/runDeps \
&& ln -fs /usr/lib/libtdsodbc.so.0 /usr/lib/libtdsodbc.so
ARG USER
@@ -167,9 +177,13 @@ ARG HOME
RUN addgroup $USER -g $UID \
&& adduser -s /sbin/nologin -D -u $UID -h /$HOME -G $USER $USER
+RUN ln -fs /usr/local/bin/ /opt/ejabberd/bin
+RUN rm -rf /home \
+ && ln -fs /opt /home
+
################################################################################
#' Build together production image
-FROM scratch AS prod
+FROM scratch
ARG USER
ARG HOME
@@ -186,7 +200,7 @@ HEALTHCHECK \
WORKDIR /$HOME
USER $USER
VOLUME ["/$HOME"]
-EXPOSE 1883 4369-4399 5210 5222 5269 5280 5443
+EXPOSE 1880 1883 4369-4399 5210 5222 5269 5280 5443
ENTRYPOINT ["/sbin/tini","--","ejabberdctl"]
CMD ["foreground"]
diff --git a/.github/container/ejabberd.yml.example b/.github/container/ejabberd.yml.example
new file mode 100644
index 000000000..2f63a2b64
--- /dev/null
+++ b/.github/container/ejabberd.yml.example
@@ -0,0 +1,278 @@
+###
+### ejabberd configuration file
+###
+### The parameters used in this configuration file are explained at
+###
+### https://docs.ejabberd.im/admin/configuration
+###
+### The configuration file is written in YAML.
+### *******************************************************
+### ******* !!! WARNING !!! *******
+### ******* YAML IS INDENTATION SENSITIVE *******
+### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY *******
+### *******************************************************
+### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
+###
+
+define_macro:
+ HOST: localhost
+ ## ADMIN: ... # set by /usr/local/bin/ejabberdctl
+ PORT_C2S: 5222
+ PORT_C2S_TLS: 5223
+ PORT_S2S: 5269
+ PORT_HTTP_TLS: 5443
+ PORT_HTTP: 5280
+ PORT_BROWSER: 1880
+ PORT_STUN: 5478
+ PORT_MQTT: 1883
+ PORT_PROXY65: 7777
+
+hosts:
+ - HOST
+
+loglevel: info
+
+## If you already have certificates, list them here
+# certfiles:
+# - /etc/letsencrypt/live/domain.tld/fullchain.pem
+# - /etc/letsencrypt/live/domain.tld/privkey.pem
+
+ca_file: /opt/ejabberd/conf/cacert.pem
+certfiles:
+ - /opt/ejabberd/conf/server.pem
+
+listen:
+ -
+ port: PORT_C2S
+ ip: "::"
+ module: ejabberd_c2s
+ max_stanza_size: 262144
+ shaper: c2s_shaper
+ access: c2s
+ starttls_required: true
+ -
+ port: PORT_C2S_TLS
+ ip: "::"
+ module: ejabberd_c2s
+ max_stanza_size: 262144
+ shaper: c2s_shaper
+ access: c2s
+ tls: true
+ -
+ port: PORT_S2S
+ ip: "::"
+ module: ejabberd_s2s_in
+ max_stanza_size: 524288
+ shaper: s2s_shaper
+ -
+ port: PORT_HTTP_TLS
+ ip: "::"
+ module: ejabberd_http
+ tls: true
+ request_handlers:
+ /admin: ejabberd_web_admin
+ /api: mod_http_api
+ /bosh: mod_bosh
+ /captcha: ejabberd_captcha
+ /upload: mod_http_upload
+ /ws: ejabberd_http_ws
+ -
+ port: PORT_HTTP
+ ip: "::"
+ module: ejabberd_http
+ request_handlers:
+ /admin: ejabberd_web_admin
+ /.well-known/acme-challenge: ejabberd_acme
+ -
+ port: PORT_BROWSER
+ ip: "::"
+ module: ejabberd_http
+ request_handlers:
+ /: ejabberd_web_admin
+ -
+ port: "unix:../sockets/ctl_over_http.sock"
+ module: ejabberd_http
+ unix_socket:
+ mode: '0600'
+ request_handlers:
+ /ctl: ejabberd_ctl
+ -
+ port: PORT_STUN
+ ip: "::"
+ transport: udp
+ module: ejabberd_stun
+ use_turn: true
+ ## The server's public IPv4 address:
+ # turn_ipv4_address: "203.0.113.3"
+ ## The server's public IPv6 address:
+ # turn_ipv6_address: "2001:db8::3"
+ -
+ port: PORT_MQTT
+ ip: "::"
+ module: mod_mqtt
+ backlog: 1000
+
+s2s_use_starttls: optional
+
+acl:
+ local:
+ user_regexp: ""
+ loopback:
+ ip:
+ - 127.0.0.0/8
+ - ::1/128
+ admin:
+ user:
+ - ADMIN
+
+access_rules:
+ local:
+ allow: local
+ c2s:
+ deny: blocked
+ allow: all
+ announce:
+ allow: admin
+ configure:
+ allow: admin
+ muc_create:
+ allow: local
+ pubsub_createnode:
+ allow: local
+ trusted_network:
+ allow: loopback
+
+api_permissions:
+ "console commands":
+ from: ejabberd_ctl
+ who: all
+ what: "*"
+ "webadmin commands":
+ from: ejabberd_web_admin
+ who: admin
+ what: "*"
+ "admin access":
+ who:
+ access:
+ allow:
+ - acl: loopback
+ - acl: admin
+ oauth:
+ scope: "ejabberd:admin"
+ access:
+ allow:
+ - acl: loopback
+ - acl: admin
+ what:
+ - "*"
+ - "!stop"
+ - "!start"
+ "public commands":
+ who:
+ ip: 127.0.0.1/8
+ what:
+ - status
+ - connected_users_number
+
+shaper:
+ normal:
+ rate: 3000
+ burst_size: 20000
+ fast: 100000
+
+shaper_rules:
+ max_user_sessions: 10
+ max_user_offline_messages:
+ 5000: admin
+ 100: all
+ c2s_shaper:
+ none: admin
+ normal: all
+ s2s_shaper: fast
+
+modules:
+ mod_adhoc: {}
+ mod_admin_extra: {}
+ mod_announce:
+ access: announce
+ mod_avatar: {}
+ mod_blocking: {}
+ mod_bosh: {}
+ mod_caps: {}
+ mod_carboncopy: {}
+ mod_client_state: {}
+ mod_configure: {}
+ mod_disco: {}
+ mod_fail2ban: {}
+ mod_http_api: {}
+ mod_http_upload:
+ put_url: https://@HOST_URL_ENCODE@:5443/upload
+ custom_headers:
+ "Access-Control-Allow-Origin": "https://@HOST@"
+ "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
+ "Access-Control-Allow-Headers": "Content-Type"
+ mod_last: {}
+ mod_mam:
+ ## Mnesia is limited to 2GB, better to use an SQL backend
+ ## For small servers SQLite is a good fit and is very easy
+ ## to configure. Uncomment this when you have SQL configured:
+ ## db_type: sql
+ assume_mam_usage: true
+ default: always
+ mod_mqtt: {}
+ mod_muc:
+ access:
+ - allow
+ access_admin:
+ - allow: admin
+ access_create: muc_create
+ access_persistent: muc_create
+ access_mam:
+ - allow
+ default_room_options:
+ mam: true
+ mod_muc_admin: {}
+ mod_offline:
+ access_max_user_messages: max_user_offline_messages
+ mod_ping: {}
+ mod_privacy: {}
+ mod_private: {}
+ mod_proxy65:
+ access: local
+ max_connections: 5
+ port: PORT_PROXY65
+ mod_pubsub:
+ access_createnode: pubsub_createnode
+ plugins:
+ - flat
+ - pep
+ force_node_config:
+ ## Avoid buggy clients to make their bookmarks public
+ storage:bookmarks:
+ access_model: whitelist
+ mod_push: {}
+ mod_push_keepalive: {}
+ mod_register:
+ ## Only accept registration requests from the "trusted"
+ ## network (see access_rules section above).
+ ## Think twice before enabling registration from any
+ ## address. See the Jabber SPAM Manifesto for details:
+ ## https://github.com/ge0rg/jabber-spam-fighting-manifesto
+ ip_access: trusted_network
+ mod_roster:
+ versioning: true
+ mod_s2s_bidi: {}
+ mod_s2s_dialback: {}
+ mod_shared_roster: {}
+ mod_stream_mgmt:
+ resend_on_timeout: if_offline
+ mod_stun_disco: {}
+ mod_vcard: {}
+ mod_vcard_xupdate: {}
+ mod_version:
+ show_os: false
+
+### Local Variables:
+### mode: yaml
+### End:
+### vim: set filetype=yaml tabstop=8
diff --git a/.github/container/ejabberdctl.template b/.github/container/ejabberdctl.template
index 1a8df3e12..b1f1d2179 100755
--- a/.github/container/ejabberdctl.template
+++ b/.github/container/ejabberdctl.template
@@ -15,8 +15,8 @@ SCRIPT_DIR="$(cd "$(dirname "$SCRIPT")" && pwd -P)"
# shellcheck disable=SC2034
ERTS_VSN="{{erts_vsn}}"
ERL="{{erl}}"
-IEX="{{bindir}}/iex"
EPMD="{{epmd}}"
+IEX="{{iexpath}}"
COOKIE_FILE="$HOME"/.erlang.cookie
[ -n "$ERLANG_COOKIE" ] && [ ! -f "$COOKIE_FILE" ] && echo "$ERLANG_COOKIE" > "$COOKIE_FILE" && chmod 400 "$COOKIE_FILE"
@@ -60,7 +60,6 @@ done
# define ejabberd variables if not already defined from the command line
: "${CONFIG_DIR:="{{config_dir}}"}"
: "${LOGS_DIR:="{{logs_dir}}"}"
-: "${SPOOL_DIR:="{{spool_dir}}"}"
: "${EJABBERD_CONFIG_PATH:="$CONFIG_DIR/ejabberd.yml"}"
: "${EJABBERDCTL_CONFIG_PATH:="$CONFIG_DIR/ejabberdctl.cfg"}"
# Allows passing extra Erlang command-line arguments in vm.args file
@@ -69,8 +68,13 @@ done
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
[ -n "$ERLANG_NODE_ARG" ] && ERLANG_NODE="$ERLANG_NODE_ARG"
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
+: "${SPOOL_DIR:="{{spool_dir}}"}"
: "${EJABBERD_LOG_PATH:="$LOGS_DIR/ejabberd.log"}"
+# backward support for old mnesia spool dir path
+: "${SPOOL_DIR_OLD:="$SPOOL_DIR/$ERLANG_NODE"}"
+[ -r "$SPOOL_DIR_OLD/schema.DAT" ] && [ ! -r "$SPOOL_DIR/schema.DAT" ] && SPOOL_DIR="$SPOOL_DIR_OLD"
+
# define erl parameters
ERLANG_OPTS="+K $POLL +P $ERL_PROCESSES $ERL_OPTIONS"
if [ -n "$FIREWALL_WINDOW" ] ; then
@@ -79,6 +83,9 @@ fi
if [ -n "$INET_DIST_INTERFACE" ] ; then
INET_DIST_INTERFACE2=$("$ERL" $ERLANG_OPTS -noshell -eval 'case inet:parse_address("'$INET_DIST_INTERFACE'") of {ok,IP} -> io:format("~p",[IP]); _ -> ok end.' -s erlang halt)
if [ -n "$INET_DIST_INTERFACE2" ] ; then
+ if [ "$(echo "$INET_DIST_INTERFACE2" | grep -o "," | wc -l)" -eq 7 ] ; then
+ INET_DIST_INTERFACE2="$INET_DIST_INTERFACE2 -proto_dist inet6_tcp"
+ fi
ERLANG_OPTS="$ERLANG_OPTS -kernel inet_dist_use_interface $INET_DIST_INTERFACE2"
fi
fi
@@ -90,11 +97,12 @@ ERL_CRASH_DUMP="$LOGS_DIR"/erl_crash_$(date "+%Y%m%d-%H%M%S").dump
ERL_INETRC="$CONFIG_DIR"/inetrc
# define ejabberd parameters
-EJABBERD_OPTS="$EJABBERD_OPTS\
-$(sed '/^log_rotate_size/!d;s/:[ \t]*\([0-9]\{1,\}\).*/ \1/;s/:[ \t]*\(infinity\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
-$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
-$(sed '/^log_burst_limit_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
-$(sed '/^log_burst_limit_window_time/!d;s/:[ \t]*\([0-9]*[a-z]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")"
+EJABBERD_OPTS="\
+$(sed '/^log_rotate_size/!d;s/:[ \t]*\([0-9]\{1,\}\).*/ \1/;s/:[ \t]*\(infinity\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$(sed '/^log_burst_limit_count/!d;s/:[ \t]*\([0-9]*\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$(sed '/^log_burst_limit_window_time/!d;s/:[ \t]*\([0-9]*[a-z]*\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$EJABBERD_OPTS"
[ -n "$EJABBERD_OPTS" ] && EJABBERD_OPTS="-ejabberd $EJABBERD_OPTS"
EJABBERD_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS $EJABBERD_OPTS -s ejabberd"
@@ -187,8 +195,10 @@ livewarning()
echo "Please be extremely cautious with your actions,"
echo "and exit immediately if you are not completely sure."
echo ""
- echo "To exit this LIVE mode and stop ejabberd, press:"
- echo " q(). and press the Enter key"
+ echo "To stop ejabberd gracefully:"
+ echo " ejabberd:stop()."
+ echo "To quit erlang immediately, press:"
+ echo " control+g and then q"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
@@ -199,6 +209,39 @@ livewarning()
fi
}
+check_etop_result()
+{
+ result=$?
+ if [ $result -eq 1 ] ; then
+ echo ""
+ echo "It seems there was some problem running 'ejabberdctl etop'."
+ echo "Is the error message something like this?"
+ echo " Failed to load module 'etop' because it cannot be found..."
+ echo "Then probably ejabberd was compiled with development tools disabled."
+ echo "To use 'etop', recompile ejabberd with: ./configure --enable-tools"
+ echo ""
+ exit $result
+ fi
+}
+
+check_iex_result()
+{
+ result=$?
+ if [ $result -eq 127 ] ; then
+ echo ""
+ echo "It seems there was some problem finding 'iex' binary from Elixir."
+ echo "Probably ejabberd was compiled with Rebar3 and Elixir disabled, like:"
+ echo " ./configure"
+ echo "which is equivalent to:"
+ echo " ./configure --with-rebar=rebar3 --disable-elixir"
+ echo "To use 'iex', recompile ejabberd enabling Elixir or using Mix:"
+ echo " ./configure --enable-elixir"
+ echo " ./configure --with-rebar=mix"
+ echo ""
+ exit $result
+ fi
+}
+
help()
{
echo ""
@@ -227,16 +270,34 @@ help()
}
# dynamic node name helper
-uid()
-{
- uuid=$(uuidgen 2>/dev/null)
- random=$(awk 'BEGIN { srand(); print int(rand()*32768) }' /dev/null)
- [ -z "$uuid" ] && [ -f /proc/sys/kernel/random/uuid ] && uuid=$(cat /proc/sys/kernel/random/uuid)
- [ -z "$uuid" ] && uuid=$(printf "%X" "${random:-$$}$(date +%M%S)")
- uuid=$(printf '%s' $uuid | sed 's/^\(...\).*$/\1/')
- [ $# -eq 0 ] && echo "${uuid}-${ERLANG_NODE}"
- [ $# -eq 1 ] && echo "${uuid}-${1}-${ERLANG_NODE}"
- [ $# -eq 2 ] && echo "${uuid}-${1}@${2}"
+uid() {
+ ERTSVERSION="$("$ERL" -version 2>&1 | sed 's|.* \([0-9]*[0-9]\).*|\1|g')"
+ if [ $ERTSVERSION -lt 11 ] ; then # otp 23.0 includes erts 11.0
+ # Erlang/OTP lower than 23, which doesn's support dynamic node code
+ N=1
+ PF=$(( $$ % 97 ))
+ while
+ case $# in
+ 0) NN="${PF}-${N}-${ERLANG_NODE}"
+ ;;
+ 1) NN="${PF}-${N}-${1}-${ERLANG_NODE}"
+ ;;
+ 2) NN="${PF}-${N}-${1}@${2}"
+ ;;
+ esac
+ N=$(( N + 1 + ( $$ % 5 ) ))
+ "$EPMD" -names 2>/dev/null | grep -q " ${NN%@*} "
+ do :; done
+ echo $NN
+ else
+ # Erlang/OTP 23 or higher: use native dynamic node code
+ # https://www.erlang.org/patches/otp-23.0#OTP-13812
+ if [ "$ERLANG_NODE" != "${ERLANG_NODE%.*}" ]; then
+ echo "undefined@${ERLANG_NODE#*@}"
+ else
+ echo "undefined"
+ fi
+ fi
}
# stop epmd if there is no other running node
@@ -250,6 +311,8 @@ stop_epmd()
# if all ok, ensure runtime directory exists and make it current directory
check_start()
{
+ ECSIMAGE_DBPATH=$HOME/database/$ERLANG_NODE
+ [ ! -d "$ECSIMAGE_DBPATH" ] && ln -s $HOME/database $HOME/database/$ERLANG_NODE
[ -n "$ERL_DIST_PORT" ] && return
"$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && {
pgrep -f "$ERLANG_NODE" >/dev/null && {
@@ -283,13 +346,18 @@ post_waiter_loop()
LIST=$@
HEAD=${LIST%% ; *}
TAIL=${LIST#* ; }
- echo ":> ejabberdctl $HEAD"
- $0 $HEAD
+ HEAD2=${HEAD#\! *}
+ echo ":> ejabberdctl $HEAD2"
+ $0 $HEAD2
ctlstatus=$?
if [ $ctlstatus -ne 0 ] ; then
- echo ":> FAILURE in command '$HEAD' !!! Stopping ejabberd..."
- $0 halt > /dev/null
- exit $ctlstatus
+ if [ "$HEAD" != "$HEAD2" ] ; then
+ echo ":> FAILURE in command '$HEAD2' !!! Ignoring result"
+ else
+ echo ":> FAILURE in command '$HEAD' !!! Stopping ejabberd..."
+ $0 halt > /dev/null
+ exit $ctlstatus
+ fi
fi
[ "$HEAD" = "$TAIL" ] || post_waiter_loop $TAIL
}
@@ -297,6 +365,13 @@ post_waiter_loop()
# allow sync calls
wait_status()
{
+ wait_status_node "$ERLANG_NODE" $1 $2 $3
+}
+
+wait_status_node()
+{
+ CONNECT_NODE=$1
+ shift
# args: status try delay
# return: 0 OK, 1 KO
timeout="$2"
@@ -307,14 +382,71 @@ wait_status()
if [ $timeout -eq 0 ] ; then
status="$1"
else
- run_erl "$(uid ctl)" -hidden -noinput -s ejabberd_ctl \
- -extra "$ERLANG_NODE" $NO_TIMEOUT status > /dev/null
+ run_erl "$(uid ctl)" -hidden -noinput \
+ -eval 'net_kernel:connect_node('"'$CONNECT_NODE'"')' \
+ -s ejabberd_ctl \
+ -extra "$CONNECT_NODE" $NO_TIMEOUT status > /dev/null
status="$?"
fi
done
[ $timeout -gt 0 ]
}
+exec_other_command()
+{
+ exec_other_command_node $ERLANG_NODE "$@"
+}
+
+exec_other_command_node()
+{
+ CONNECT_NODE=$1
+ shift
+ if [ -z "$CTL_OVER_HTTP" ] || [ ! -S "$CTL_OVER_HTTP" ] \
+ || [ ! -x "$(command -v curl)" ] || [ -z "$1" ] || [ "$1" = "help" ] \
+ || [ "$1" = "mnesia_info_ctl" ]|| [ "$1" = "print_sql_schema" ] ; then
+ run_erl "$(uid ctl)" -hidden -noinput \
+ -eval 'net_kernel:connect_node('"'$CONNECT_NODE'"')' \
+ -s ejabberd_ctl \
+ -extra "$CONNECT_NODE" $NO_TIMEOUT "$@"
+ result=$?
+ case $result in
+ 3) help;;
+ *) :;;
+ esac
+ return $result
+ else
+ exec_ctl_over_http_socket "$@"
+ fi
+}
+
+exec_ctl_over_http_socket()
+{
+ COMMAND=${1}
+ CARGS=""
+ while [ $# -gt 0 ]; do
+ [ -z "$CARGS" ] && CARGS="[" || CARGS="${CARGS}, "
+ CARGS="${CARGS}\"$1\""
+ shift
+ done
+ CARGS="${CARGS}]"
+ TEMPHEADERS=temp-headers.log
+ curl \
+ --unix-socket ${CTL_OVER_HTTP} \
+ --header "Content-Type: application/json" \
+ --header "Accept: application/json" \
+ --data "${CARGS}" \
+ --dump-header ${TEMPHEADERS} \
+ --no-progress-meter \
+ "http://localhost/ctl/${COMMAND}"
+ result=$(sed -n 's/.*status-code: \([0-9]*\).*/\1/p' < $TEMPHEADERS)
+ rm ${TEMPHEADERS}
+ case $result in
+ 2|3) exec_other_command help ${COMMAND};;
+ *) :;;
+ esac
+ exit $result
+}
+
# ensure we can change current directory to SPOOL_DIR
[ -f "$SPOOL_DIR/schema.DAT" ] || FIRST_RUN=true
[ -d "$SPOOL_DIR" ] || run_cmd mkdir -p "$SPOOL_DIR"
@@ -323,6 +455,103 @@ cd "$SPOOL_DIR" || {
exit 6
}
+printe()
+{
+ printf "\n"
+ printf "\e[1;40;32m==> %s\e[0m\n" "$1"
+}
+
+## Function copied from tools/make-installers
+user_agrees()
+{
+ question="$*"
+
+ if [ -t 0 ]
+ then
+ printe "$question (y/n) [n]"
+ read -r response
+ case "$response" in
+ [Yy]|[Yy][Ee][Ss])
+ return 0
+ ;;
+ [Nn]|[Nn][Oo]|'')
+ return 1
+ ;;
+ *)
+ echo 'Please respond with "yes" or "no".'
+ user_agrees "$question"
+ ;;
+ esac
+ else # Assume 'yes' if not running interactively.
+ return 0
+ fi
+}
+
+mnesia_change()
+{
+ ERLANG_NODE_OLD="$1"
+ [ "$ERLANG_NODE_OLD" = "" ] \
+ && echo "Error: Please provide the old erlang node name, for example:" \
+ && echo " ejabberdctl mnesia_change ejabberd@oldmachine" \
+ && exit 1
+
+ SPOOL_DIR_BACKUP=$SPOOL_DIR/$ERLANG_NODE_OLD-backup/
+ OLDFILE=$SPOOL_DIR_BACKUP/$ERLANG_NODE_OLD.backup
+ NEWFILE=$SPOOL_DIR_BACKUP/$ERLANG_NODE.backup
+
+ printe "This changes your mnesia database from node name '$ERLANG_NODE_OLD' to '$ERLANG_NODE'"
+
+ [ -d "$SPOOL_DIR_BACKUP" ] && printe "WARNING! A backup of old node already exists in $SPOOL_DIR_BACKUP"
+
+ if ! user_agrees "Do you want to proceed?"
+ then
+ echo 'Operation aborted.'
+ exit 1
+ fi
+
+ printe "Starting ejabberd with old node name $ERLANG_NODE_OLD ..."
+ exec_erl "$ERLANG_NODE_OLD" $EJABBERD_OPTS -detached
+ wait_status_node $ERLANG_NODE_OLD 0 30 2
+ result=$?
+ case $result in
+ 1) echo "There was a problem starting ejabberd with the old erlang node name. " \
+ && echo "Check for log errors in $EJABBERD_LOG_PATH" \
+ && exit $result;;
+ *) :;;
+ esac
+ exec_other_command_node $ERLANG_NODE_OLD "status"
+
+ printe "Making backup of old database to file $OLDFILE ..."
+ mkdir $SPOOL_DIR_BACKUP
+ exec_other_command_node $ERLANG_NODE_OLD backup "$OLDFILE"
+
+ printe "Changing node name in new backup file $NEWFILE ..."
+ exec_other_command_node $ERLANG_NODE_OLD mnesia_change_nodename "$ERLANG_NODE_OLD" "$ERLANG_NODE" "$OLDFILE" "$NEWFILE"
+
+ printe "Stopping old ejabberd..."
+ exec_other_command_node $ERLANG_NODE_OLD "stop"
+ wait_status_node $ERLANG_NODE_OLD 3 30 2 && stop_epmd
+
+ printe "Moving old mnesia spool files to backup subdirectory $SPOOL_DIR_BACKUP ..."
+ mv $SPOOL_DIR/*.DAT $SPOOL_DIR_BACKUP
+ mv $SPOOL_DIR/*.DCD $SPOOL_DIR_BACKUP
+ mv $SPOOL_DIR/*.LOG $SPOOL_DIR_BACKUP
+
+ printe "Starting ejabberd with new node name $ERLANG_NODE ..."
+ exec_erl "$ERLANG_NODE" $EJABBERD_OPTS -detached
+ wait_status 0 30 2
+ exec_other_command "status"
+
+ printe "Installing fallback of new mnesia..."
+ exec_other_command install_fallback "$NEWFILE"
+
+ printe "Stopping new ejabberd..."
+ exec_other_command "stop"
+ wait_status 3 30 2 && stop_epmd
+
+ printe "Finished, now you can start ejabberd normally"
+}
+
# main
case $1 in
start)
@@ -350,24 +579,31 @@ case $1 in
;;
etop)
set_dist_client
- exec_erl "$(uid top)" -hidden -node "$ERLANG_NODE" -s etop \
- -s erlang halt -output text
+ exec_erl "$(uid top)" -hidden -remsh "$ERLANG_NODE" \
+ -eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \
+ -s etop \
+ -output text
+ check_etop_result
;;
iexdebug)
debugwarning
set_dist_client
exec_iex "$(uid debug)" --remsh "$ERLANG_NODE"
+ check_iex_result
;;
iexlive)
livewarning
exec_iex "$ERLANG_NODE" --erl "$EJABBERD_OPTS"
+ check_iex_result
;;
ping)
PEER=${2:-$ERLANG_NODE}
[ "$PEER" = "${PEER%.*}" ] && PS="-s"
set_dist_client
exec_cmd "$ERL" ${PS:--}name "$(uid ping "$(hostname $PS)")" $ERLANG_OPTS \
- -noinput -hidden -eval 'io:format("~p~n",[net_adm:ping('"'$PEER'"')])' \
+ -noinput -hidden \
+ -eval 'net_kernel:connect_node('"'$PEER'"')' \
+ -eval 'io:format("~p~n",[net_adm:ping('"'$PEER'"')])' \
-s erlang halt -output text
;;
started)
@@ -378,18 +614,14 @@ case $1 in
set_dist_client
wait_status 3 30 2 && stop_epmd # wait 30x2s before timeout
;;
+ mnesia_change)
+ mnesia_change $2
+ ;;
post_waiter)
post_waiter_waiting
;;
*)
set_dist_client
- run_erl "$(uid ctl)" -hidden -noinput -s ejabberd_ctl \
- -extra "$ERLANG_NODE" $NO_TIMEOUT "$@"
- result=$?
- case $result in
- 2|3) help;;
- *) :;;
- esac
- exit $result
+ exec_other_command "$@"
;;
esac
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b71dbccfa..ebf9da68c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,20 +25,20 @@ jobs:
strategy:
fail-fast: false
matrix:
- otp: ['20.0', '25.3', '26.1']
- runs-on: ubuntu-20.04
+ otp: ['25', '26', '27', '28']
+ runs-on: ubuntu-24.04
services:
redis:
- image: redis
+ image: public.ecr.aws/docker/library/redis
ports:
- 6379:6379
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Test shell scripts
- if: matrix.otp == '25.3'
+ if: matrix.otp == '27'
run: |
shellcheck test/ejabberd_SUITE_data/gencerts.sh
shellcheck tools/captcha.sh
@@ -46,18 +46,10 @@ jobs:
shellcheck -x ejabberdctl.template
- name: Get specific Erlang/OTP
- if: matrix.otp != '25.3'
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
- - name: Get a compatible Rebar3
- if: matrix.otp <= '21.3'
- run: |
- rm rebar3
- 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" \
@@ -69,8 +61,8 @@ jobs:
- name: Prepare databases
run: |
- docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
- docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
+ docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
+ docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
sudo systemctl start mysql.service
sudo systemctl start postgresql.service
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
@@ -78,14 +70,14 @@ jobs:
IDENTIFIED BY 'ejabberd_test';"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
- 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 "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 -c "GRANT ALL ON SCHEMA public TO ejabberd_test;"
+ sudo -u postgres psql -c "ALTER DATABASE ejabberd_test OWNER TO ejabberd_test;"
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
TABLES IN SCHEMA public
TO ejabberd_test;"
@@ -103,22 +95,13 @@ jobs:
- 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
+ - name: Cache Hex.pm
+ uses: actions/cache@v4
with:
path: |
~/.cache/rebar3/
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
- - name: Download test logs
- if: matrix.otp == '25.3' && github.repository == 'processone/ejabberd'
- continue-on-error: true
- run: |
- mkdir -p _build/test
- curl -sSL https://github.com/processone/ecil/tarball/gh-pages |
- tar -C _build/test --strip-components=1 --wildcards -xzf -
- rm -rf _build/test/logs/last/
-
- name: Compile
run: |
./autogen.sh
@@ -128,7 +111,6 @@ jobs:
--disable-elixir \
--disable-mssql \
--disable-odbc
- make update
make
- run: make install -s
@@ -136,6 +118,9 @@ jobs:
- run: make options
- run: make xref
- run: make dialyzer
+ - run: make test-eunit
+ - run: make elvis
+ if: matrix.otp >= '26'
- name: Check Production Release
run: |
@@ -148,12 +133,30 @@ jobs:
cat $RE/logs/ejabberd.log
grep -q "is stopped in" $RE/logs/ejabberd.log
- - name: Check Development Release
+ - name: Start Development Release
run: |
make dev
RE=_build/dev/rel/ejabberd
+ sed -i 's/starttls_required: true/starttls_required: false/g' $RE/conf/ejabberd.yml
$RE/bin/ejabberdctl start
$RE/bin/ejabberdctl started
+ $RE/bin/ejabberdctl register admin localhost admin
+ grep -q "is started in" $RE/logs/ejabberd.log
+
+ - name: Run XMPP Interoperability Tests against CI server.
+ if: matrix.otp == '27'
+ continue-on-error: true
+ uses: XMPP-Interop-Testing/xmpp-interop-tests-action@v1.6.1
+ with:
+ domain: 'localhost'
+ adminAccountUsername: 'admin'
+ adminAccountPassword: 'admin'
+ disabledSpecifications: RFC6121,XEP-0030,XEP-0045,XEP-0054,XEP-0060,XEP-0080,XEP-0115,XEP-0118,XEP-0215,XEP-0347,XEP-0363,XEP-0384
+
+ - name: Stop Development Release
+ if: always()
+ run: |
+ RE=_build/dev/rel/ejabberd
$RE/bin/ejabberdctl stop
$RE/bin/ejabberdctl stopped
cat $RE/logs/ejabberd.log
@@ -173,7 +176,7 @@ jobs:
./rebar3 cover
- name: Check results
- if: always() && (steps.ct.outcome != 'skipped' || steps.ct2.outcome != 'skipped')
+ if: always() && (steps.ct.outcome != 'skipped')
id: ctresults
run: |
[[ -d _build ]] && ln -s _build/test/logs/last/ logs || true
@@ -191,7 +194,7 @@ jobs:
find logs/ -name exunit.log -exec cat '{}' ';'
- name: Send to coveralls
- if: matrix.otp == '25.3'
+ if: matrix.otp == '27'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
@@ -203,24 +206,8 @@ jobs:
"payload":{"build_num":$GITHUB_RUN_ID,
"status":"done"}}'
- - name: Upload test logs
- if: always() && steps.ct.outcome == 'failure' && github.repository == 'processone/ejabberd'
- uses: peaceiris/actions-gh-pages@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: Check for changes to trigger schema upgrade test
- uses: dorny/paths-filter@v2
+ uses: dorny/paths-filter@v3
id: filter
with:
filters: |
@@ -259,20 +246,20 @@ jobs:
run: |
[[ -d logs ]] && rm -rf logs
[[ -d _build/test/logs ]] && rm -rf _build/test/logs || true
- docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
- docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
+ docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
+ docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
mysql -u root -proot -e "DROP DATABASE ejabberd_test;"
sudo -u postgres psql -c "DROP DATABASE ejabberd_test;"
- docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
- docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
+ docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
+ docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
- 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 -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 -c "GRANT ALL ON SCHEMA public TO ejabberd_test;"
+ sudo -u postgres psql -c "ALTER DATABASE ejabberd_test OWNER TO ejabberd_test;"
sudo -u postgres psql ejabberd_test -c "GRANT ALL PRIVILEGES ON ALL
TABLES IN SCHEMA public
TO ejabberd_test;"
@@ -301,7 +288,7 @@ jobs:
- name: Upload CT logs
if: failure()
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ejabberd-ct-logs-${{matrix.otp}}
#
diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml
index 0461cb9b8..0bb169ccc 100644
--- a/.github/workflows/container.yml
+++ b/.github/workflows/container.yml
@@ -1,8 +1,6 @@
name: Container
on:
- schedule:
- - cron: '22 2 */6 * *' # every 6 days to avoid gha cache being evicted
push:
paths-ignore:
- '.devcontainer/**'
@@ -19,63 +17,17 @@ env:
jobs:
container:
name: Container
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
permissions:
packages: write
steps:
- name: Check out repository code
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
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@v4
+ uses: actions/checkout@v5
with:
repository: processone/ejabberd-contrib
path: .ejabberd-modules/sources/ejabberd-contrib
@@ -108,10 +60,9 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v6
with:
build-args: |
- METHOD=package
VERSION=${{ steps.gitdescribe.outputs.ver }}
cache-from: type=gha
cache-to: type=gha,mode=max
diff --git a/.github/workflows/installers.yml b/.github/workflows/installers.yml
index 4a026c31c..37c8983b4 100644
--- a/.github/workflows/installers.yml
+++ b/.github/workflows/installers.yml
@@ -21,13 +21,13 @@ on:
jobs:
binaries:
name: Binaries
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- name: Cache build directory
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/build/
- key: ${{runner.os}}-ct-ng-1.26.0
+ key: ${{runner.os}}-ct-ng-1.27.0
- name: Install prerequisites
run: |
sudo apt-get -qq update
@@ -41,7 +41,7 @@ jobs:
gem install --no-document --user-install fpm
echo $HOME/.local/share/gem/ruby/*/bin >> $GITHUB_PATH
- name: Check out repository code
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Build binary archives
@@ -55,7 +55,7 @@ jobs:
mkdir ejabberd-packages
mv ejabberd_*.deb ejabberd-*.rpm ejabberd-*.run ejabberd-packages
- name: Upload packages
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ejabberd-packages
#
@@ -70,15 +70,15 @@ jobs:
release:
name: Release
needs: [binaries]
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
if: github.ref_type == 'tag'
steps:
- name: Download packages
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v5
with:
name: ejabberd-packages
- name: Draft Release
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v2
with:
draft: true
files: ejabberd-packages/*
diff --git a/.github/workflows/runtime.yml b/.github/workflows/runtime.yml
index 4b62858f8..cd599fe83 100644
--- a/.github/workflows/runtime.yml
+++ b/.github/workflows/runtime.yml
@@ -31,139 +31,197 @@ jobs:
strategy:
fail-fast: false
matrix:
- otp: ['20.3', '25.3', '26']
+ otp: ['24', '25', '26', '27', '28']
rebar: ['rebar', 'rebar3']
exclude:
- - otp: '26'
+ - otp: '24'
rebar: 'rebar'
- runs-on: ubuntu-latest
+ - otp: '27'
+ rebar: 'rebar'
+ - otp: '28'
+ rebar: 'rebar'
+ runs-on: ubuntu-24.04
container:
- image: erlang:${{ matrix.otp }}
+ image: public.ecr.aws/docker/library/erlang:${{ matrix.otp }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
+
+ - name: Get old compatible Rebar binaries
+ if: matrix.otp < 24
+ run: |
+ rm rebar
+ rm rebar3
+ wget https://github.com/processone/ejabberd/raw/21.12/rebar
+ wget https://github.com/processone/ejabberd/raw/21.12/rebar3
+ chmod +x rebar
+ chmod +x rebar3
+
+ - name: Get recent compatible Rebar binaries
+ if: matrix.otp > 23 && matrix.otp < 25
+ run: |
+ rm rebar
+ rm rebar3
+ wget https://github.com/processone/ejabberd/raw/24.12/rebar
+ wget https://github.com/processone/ejabberd/raw/24.12/rebar3
+ chmod +x rebar
+ chmod +x rebar3
- name: Prepare libraries
run: |
apt-get -qq update
- apt-get purge -y libgd3
+ apt-get purge -y libgd3 nginx
apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
libsqlite3-dev libwebp-dev libyaml-dev
+ - name: Cache Hex.pm
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cache/rebar3/
+ key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
+
+ - name: Unlock eredis dependency
+ if: matrix.rebar == 'rebar3' && matrix.otp < 21
+ run: rebar3 unlock eredis
+
- name: Compile
run: |
./autogen.sh
- ./configure --with-rebar=`which ${{ matrix.rebar }}` \
+ ./configure --with-rebar=./${{ matrix.rebar }} \
--prefix=/tmp/ejabberd \
+ --with-min-erlang=9.0.5 \
--enable-all \
--disable-elixir \
+ --disable-tools \
--disable-odbc
- make update
make
- run: make xref
- - name: Test rel (rebar2)
+ - run: make dialyzer
+
+ - name: Prepare rel (rebar2)
if: matrix.rebar == 'rebar'
run: |
- make rel
- rel/ejabberd/bin/ejabberdctl start \
- && rel/ejabberd/bin/ejabberdctl started
- rel/ejabberd/bin/ejabberdctl register user1 localhost s0mePass
- rel/ejabberd/bin/ejabberdctl registered_users localhost
- cat rel/ejabberd/logs/*
+ mkdir -p _build/prod && ln -s `pwd`/rel/ _build/prod/rel
+ mkdir -p _build/dev && ln -s `pwd`/rel/ _build/dev/rel
- - name: Test rel
- if: matrix.rebar != 'rebar'
+ - name: Run rel
run: |
make rel
_build/prod/rel/ejabberd/bin/ejabberdctl start \
&& _build/prod/rel/ejabberd/bin/ejabberdctl started
_build/prod/rel/ejabberd/bin/ejabberdctl register user1 localhost s0mePass
- _build/prod/rel/ejabberd/bin/ejabberdctl registered_users localhost
+ _build/prod/rel/ejabberd/bin/ejabberdctl registered_users localhost > registered.log
_build/prod/rel/ejabberd/bin/ejabberdctl stop \
&& _build/prod/rel/ejabberd/bin/ejabberdctl stopped
- cat _build/prod/rel/ejabberd/logs/*
- - name: Test dev
- if: matrix.rebar != 'rebar'
+ - name: Run dev
run: |
make dev
_build/dev/rel/ejabberd/bin/ejabberdctl start \
&& _build/dev/rel/ejabberd/bin/ejabberdctl started
- _build/dev/rel/ejabberd/bin/ejabberdctl register user1 localhost s0mePass
- _build/dev/rel/ejabberd/bin/ejabberdctl registered_users localhost
+ _build/dev/rel/ejabberd/bin/ejabberdctl register user2 localhost s0mePass
+ _build/dev/rel/ejabberd/bin/ejabberdctl registered_users localhost >> registered.log
_build/dev/rel/ejabberd/bin/ejabberdctl stop \
&& _build/dev/rel/ejabberd/bin/ejabberdctl stopped
- cat _build/dev/rel/ejabberd/logs/*
- mix:
- name: Mix
+ - name: Run install
+ run: |
+ make install
+ /tmp/ejabberd/sbin/ejabberdctl start \
+ && /tmp/ejabberd/sbin/ejabberdctl started
+ /tmp/ejabberd/sbin/ejabberdctl register user3 localhost s0mePass
+ /tmp/ejabberd/sbin/ejabberdctl registered_users localhost >> registered.log
+ /tmp/ejabberd/sbin/ejabberdctl stop \
+ && /tmp/ejabberd/sbin/ejabberdctl stopped
+
+ - name: View logs
+ run: |
+ echo "===> Registered:"
+ cat registered.log
+ echo "===> Prod:"
+ cat _build/prod/rel/ejabberd/logs/*
+ echo "===> Dev:"
+ cat _build/dev/rel/ejabberd/logs/*
+ echo "===> Install:"
+ cat /tmp/ejabberd/var/log/ejabberd/*
+
+ - name: Check logs
+ run: |
+ grep -q '^user1$' registered.log
+ grep -q '^user2$' registered.log
+ grep -q '^user3$' registered.log
+ grep -q 'is started' _build/prod/rel/ejabberd/logs/ejabberd.log
+ grep -q 'is stopped' _build/prod/rel/ejabberd/logs/ejabberd.log
+ test $(find _build/prod/rel/ -empty -name error.log)
+ grep -q 'is started' _build/dev/rel/ejabberd/logs/ejabberd.log
+ grep -q 'is stopped' _build/dev/rel/ejabberd/logs/ejabberd.log
+ test $(find _build/dev/rel/ -empty -name error.log)
+ grep -q 'is started' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ grep -q 'is stopped' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ test $(find /tmp/ejabberd/var/log/ejabberd/ -empty -name error.log)
+
+ - name: View logs failures
+ if: always()
+ run: |
+ cat _build/prod/rel/ejabberd/logs/ejabberd.log
+ cat _build/prod/rel/ejabberd/logs/error.log
+ cat _build/dev/rel/ejabberd/logs/ejabberd.log
+ cat _build/dev/rel/ejabberd/logs/error.log
+ cat /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ cat /tmp/ejabberd/var/log/ejabberd/error.log
+
+ rebar3-elixir:
+ name: Rebar3+Elixir
strategy:
fail-fast: false
matrix:
- otp: ['21.3', '25.0', '26']
- elixir: ['1.10.3', '1.11.4', '1.12.3', '1.13.4', '1.14.5', '1.15']
- exclude:
- - otp: '21.3'
- elixir: '1.12.3'
- - otp: '21.3'
- elixir: '1.13.4'
- - otp: '21.3'
- elixir: '1.14.5'
- - otp: '21.3'
- elixir: '1.15'
- - otp: '25.0'
- elixir: '1.10.3'
- - otp: '25.0'
- elixir: '1.11.4'
- - otp: '25.0'
- elixir: '1.12.3'
- - otp: '26'
- elixir: '1.10.3'
- - otp: '26'
- elixir: '1.11.4'
- - otp: '26'
- elixir: '1.12.3'
- - otp: '26'
- elixir: '1.13.4'
- runs-on: ubuntu-20.04
+ elixir: ['1.14', '1.15', '1.16', '1.17', '1.18']
+ runs-on: ubuntu-24.04
+ container:
+ image: public.ecr.aws/docker/library/elixir:${{ matrix.elixir }}
steps:
- - uses: actions/checkout@v4
-
- - name: Get specific Erlang/OTP
- uses: erlef/setup-beam@v1
- with:
- otp-version: ${{matrix.otp}}
- elixir-version: ${{matrix.elixir}}
+ - uses: actions/checkout@v5
- name: Prepare libraries
run: |
- sudo apt-get -qq update
- sudo apt-get -y purge libgd3 nginx
- sudo apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
- libsqlite3-dev libwebp-dev libyaml-dev
+ apt-get -qq update
+ apt-get -y purge libgd3 nginx
+ apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
+ libsqlite3-dev libwebp-dev libyaml-dev
- - name: Remove Elixir Matchers
+ - name: Enable Module.Example and an Elixir dependency
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::"
+ sed -i "s|^modules:|modules:\n 'Ejabberd.Module.Example': {}|g" ejabberd.yml.example
+ cat ejabberd.yml.example
+ sed -i 's|^{deps, \[\(.*\)|{deps, [{decimal, ".*", {git, "https://github.com/ericmj/decimal", {branch, "main"}}},\n \1|g' rebar.config
+ cat rebar.config
+
+ - name: Cache Hex.pm
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cache/rebar3/
+ key: ${{matrix.elixir}}-${{hashFiles('rebar.config')}}
+
+ - name: Install Hex and Rebar3 manually on older Elixir
+ if: matrix.elixir <= '1.14'
+ run: |
+ mix local.hex --force
+ mix local.rebar --force
- name: Compile
run: |
./autogen.sh
- ./configure --with-rebar=mix \
+ ./configure --with-rebar=./rebar3 \
--prefix=/tmp/ejabberd \
--enable-all \
- --disable-elixir \
--disable-odbc
- mix deps.get
make
- run: make xref
@@ -188,17 +246,46 @@ jobs:
_build/dev/rel/ejabberd/bin/ejabberdctl stop \
&& _build/dev/rel/ejabberd/bin/ejabberdctl stopped
- - name: Check rel
+ - name: Run install
+ run: |
+ make install
+ /tmp/ejabberd/sbin/ejabberdctl start \
+ && /tmp/ejabberd/sbin/ejabberdctl started
+ /tmp/ejabberd/sbin/ejabberdctl register user3 localhost s0mePass
+ /tmp/ejabberd/sbin/ejabberdctl registered_users localhost >> registered.log
+ /tmp/ejabberd/sbin/ejabberdctl stop \
+ && /tmp/ejabberd/sbin/ejabberdctl stopped
+
+ - name: View logs
+ if: always()
+ run: |
+ echo "===> Registered:"
+ cat registered.log
+ echo "===> Prod:"
+ cat _build/prod/rel/ejabberd/logs/*
+ echo "===> Dev:"
+ cat _build/dev/rel/ejabberd/logs/*
+ echo "===> Install:"
+ cat /tmp/ejabberd/var/log/ejabberd/*
+
+ - name: Check logs
if: always()
run: |
grep -q '^user1$' registered.log
grep -q '^user2$' registered.log
+ grep -q '^user3$' registered.log
grep -q 'is started' _build/prod/rel/ejabberd/logs/ejabberd.log
grep -q 'is stopped' _build/prod/rel/ejabberd/logs/ejabberd.log
+ grep -q 'Stopping Ejabberd.Module.Example' _build/prod/rel/ejabberd/logs/ejabberd.log
test $(find _build/prod/ -empty -name error.log)
grep -q 'is started' _build/dev/rel/ejabberd/logs/ejabberd.log
grep -q 'is stopped' _build/dev/rel/ejabberd/logs/ejabberd.log
+ grep -q 'Stopping Ejabberd.Module.Example' _build/dev/rel/ejabberd/logs/ejabberd.log
test $(find _build/dev/ -empty -name error.log)
+ grep -q 'is started' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ grep -q 'is stopped' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ grep -q 'Stopping Ejabberd.Module.Example' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ test $(find /tmp/ejabberd/var/log/ejabberd/ -empty -name error.log)
- name: View logs failures
if: failure()
@@ -207,3 +294,139 @@ jobs:
cat _build/prod/rel/ejabberd/logs/error.log
cat _build/dev/rel/ejabberd/logs/ejabberd.log
cat _build/dev/rel/ejabberd/logs/error.log
+ cat /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ cat /tmp/ejabberd/var/log/ejabberd/error.log
+
+ mix:
+ name: Mix
+ strategy:
+ fail-fast: false
+ matrix:
+ elixir: ['1.14', '1.15', '1.16', '1.17', '1.18']
+ runs-on: ubuntu-24.04
+ container:
+ image: public.ecr.aws/docker/library/elixir:${{ matrix.elixir }}
+
+ steps:
+
+ - uses: actions/checkout@v5
+
+ - name: Prepare libraries
+ run: |
+ apt-get -qq update
+ apt-get -y purge libgd3 nginx
+ apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
+ libsqlite3-dev libwebp-dev libyaml-dev
+
+ - name: Remove Elixir Matchers
+ run: |
+ 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: Enable Module.Example and an Elixir dependency
+ run: |
+ sed -i "s|^modules:|modules:\n 'Ejabberd.Module.Example': {}|g" ejabberd.yml.example
+ cat ejabberd.yml.example
+ sed -i 's|^{deps, \(.*\)|{deps, \1\n {decimal, ".*", {git, "https://github.com/ericmj/decimal", {branch, "main"}}}, |g' rebar.config
+ cat rebar.config
+
+ - name: Cache Hex.pm
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.hex/
+ key: ${{matrix.elixir}}-${{hashFiles('mix.exs')}}
+
+ - name: Install Hex and Rebar3 manually on older Elixir
+ if: matrix.elixir <= '1.14'
+ run: |
+ mix local.hex --force
+ mix local.rebar --force
+
+ - name: Compile
+ run: |
+ ./autogen.sh
+ ./configure --with-rebar=mix \
+ --prefix=/tmp/ejabberd \
+ --enable-all
+ make
+
+ - run: make xref
+
+ - run: make dialyzer
+
+ - run: make edoc
+
+ - name: Run rel
+ run: |
+ make rel
+ _build/prod/rel/ejabberd/bin/ejabberdctl start \
+ && _build/prod/rel/ejabberd/bin/ejabberdctl started
+ _build/prod/rel/ejabberd/bin/ejabberdctl register user1 localhost s0mePass
+ _build/prod/rel/ejabberd/bin/ejabberdctl registered_users localhost > registered.log
+ _build/prod/rel/ejabberd/bin/ejabberdctl stop \
+ && _build/prod/rel/ejabberd/bin/ejabberdctl stopped
+
+ - name: Run dev
+ run: |
+ make dev
+ _build/dev/rel/ejabberd/bin/ejabberdctl start \
+ && _build/dev/rel/ejabberd/bin/ejabberdctl started
+ _build/dev/rel/ejabberd/bin/ejabberdctl register user2 localhost s0mePass
+ _build/dev/rel/ejabberd/bin/ejabberdctl registered_users localhost >> registered.log
+ _build/dev/rel/ejabberd/bin/ejabberdctl stop \
+ && _build/dev/rel/ejabberd/bin/ejabberdctl stopped
+
+ - name: Run install
+ run: |
+ make install
+ /tmp/ejabberd/sbin/ejabberdctl start \
+ && /tmp/ejabberd/sbin/ejabberdctl started
+ /tmp/ejabberd/sbin/ejabberdctl register user3 localhost s0mePass
+ /tmp/ejabberd/sbin/ejabberdctl registered_users localhost >> registered.log
+ /tmp/ejabberd/sbin/ejabberdctl stop \
+ && /tmp/ejabberd/sbin/ejabberdctl stopped
+
+ - name: View logs
+ if: always()
+ run: |
+ echo "===> Registered:"
+ cat registered.log
+ echo "===> Prod:"
+ cat _build/prod/rel/ejabberd/logs/*
+ echo "===> Dev:"
+ cat _build/dev/rel/ejabberd/logs/*
+ echo "===> Install:"
+ cat /tmp/ejabberd/var/log/ejabberd/*
+
+ - name: Check logs
+ if: always()
+ run: |
+ grep -q '^user1$' registered.log
+ grep -q '^user2$' registered.log
+ grep -q '^user3$' registered.log
+ grep -q 'is started' _build/prod/rel/ejabberd/logs/ejabberd.log
+ grep -q 'is stopped' _build/prod/rel/ejabberd/logs/ejabberd.log
+ grep -q 'Stopping Ejabberd.Module.Example' _build/prod/rel/ejabberd/logs/ejabberd.log
+ test $(find _build/prod/ -empty -name error.log)
+ grep -q 'is started' _build/dev/rel/ejabberd/logs/ejabberd.log
+ grep -q 'is stopped' _build/dev/rel/ejabberd/logs/ejabberd.log
+ grep -q 'Stopping Ejabberd.Module.Example' _build/dev/rel/ejabberd/logs/ejabberd.log
+ test $(find _build/dev/ -empty -name error.log)
+ grep -q 'is started' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ grep -q 'is stopped' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ grep -q 'Stopping Ejabberd.Module.Example' /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ test $(find /tmp/ejabberd/var/log/ejabberd/ -empty -name error.log)
+
+ - name: View logs failures
+ if: failure()
+ run: |
+ cat _build/prod/rel/ejabberd/logs/ejabberd.log
+ cat _build/prod/rel/ejabberd/logs/error.log
+ cat _build/dev/rel/ejabberd/logs/ejabberd.log
+ cat _build/dev/rel/ejabberd/logs/error.log
+ cat /tmp/ejabberd/var/log/ejabberd/ejabberd.log
+ cat /tmp/ejabberd/var/log/ejabberd/error.log
diff --git a/.gitignore b/.gitignore
index 4e8bc1de3..0f69a0aa3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,12 +34,14 @@
/priv/bin/captcha*sh
/priv/sql
/rel/ejabberd
+/recompile.log
/_build
/database/
/.rebar
-/rebar.lock
/log/
Mnesia.nonode@nohost/
+/TAGS
+/tags
# Binaries created with tools/make-{binaries,installers,packages}:
/ejabberd_*.deb
/ejabberd-*.rpm
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 6e9fd45ae..78cdf45ae 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -2,7 +2,24 @@
"version": "0.2.0",
"configurations": [
{
- "name": "Relive",
+ "name": "Relive (Vim)",
+ "type": "erlang",
+ "request": "launch",
+ "runinterminal": [
+ "./rebar3", "shell",
+ "--apps", "ejabberd",
+ "--config", "rel/relive.config",
+ "--script", "rel/relive.escript",
+ "--name", "ejabberd@localhost",
+ "--setcookie", "COOKIE"
+ ],
+ "projectnode": "ejabberd@localhost",
+ "cookie": "COOKIE",
+ "timeout": 900,
+ "cwd": "."
+ },
+ {
+ "name": "Relive (VSCode)",
"type": "erlang",
"request": "launch",
"runinterminal": [
diff --git a/.vscode/relive.sh b/.vscode/relive.sh
index 6a0394955..b10b83fb0 100755
--- a/.vscode/relive.sh
+++ b/.vscode/relive.sh
@@ -1,6 +1,6 @@
[ ! -f Makefile ] \
&& ./autogen.sh \
- && ./configure --with-rebar=./rebar3 \
- && make deps
+ && ./configure --with-rebar=rebar3 \
+ && make
make relive
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd8fcb055..cadfc1c74 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,644 @@
-# Version 23.10
+## Version 25.08
+
+#### API Commands
+
+- `ban_account`: Run `sm_kick_user` event when kicking account ([#4415](https://github.com/processone/ejabberd/issues/4415))
+- `ban_account`: No need to change password ([#4415](https://github.com/processone/ejabberd/issues/4415))
+- `mnesia_change`: New command in `ejabberdctl` script that helps changing the mnesia node name
+
+#### Configuration
+
+- Rename `auth_password_types_hidden_in_scram1` option to `auth_password_types_hidden_in_sasl1`
+- `econf`: If a host in configuration is encoded IDNA, decode it ([#3519](https://github.com/processone/ejabberd/issues/3519))
+- `ejabberd_config`: New predefined keyword `HOST_URL_ENCODE`
+- `ejabberd.yml.example`: Use `HOST_URL_ENCODE` to handle case when vhost is non-latin1
+- `mod_conversejs`: Add option `conversejs_plugins` ([#4413](https://github.com/processone/ejabberd/issues/4413))
+- `mod_matrix_gw`: Add `leave_timeout` option ([#4386](https://github.com/processone/ejabberd/issues/4386))
+
+#### Documentation and Tests
+
+- `COMPILE.md`: Mention dependencies and add link to Docs ([#4431](https://github.com/processone/ejabberd/issues/4431))
+- `ejabberd_doc`: Document commands tags for modules
+- CI: bump XMPP-Interop-Testing/xmpp-interop-tests-action ([#4425](https://github.com/processone/ejabberd/issues/4425))
+- Runtime: Raise the minimum Erlang tested to Erlang/OTP 24
+
+#### Installers and Container
+
+- Bump Erlang/OTP version to 27.3.4.2
+- Bump OpenSSL version to 3.5.2
+- `make-binaries`: Disable Linux-PAM's `logind` support
+
+#### Core and Modules
+
+- Bump `p1_acme` to fix `'AttributePKCS-10'` and OTP 28 ([processone/p1_acme#4](https://github.com/processone/p1_acme/issues/4))
+- Prevent loops in `xml_compress:decode` with corrupted data
+- `ejabberd_auth_mnesia`: Fix issue with filtering duplicates in `get_users()`
+- `ejabberd_listener`: Add secret in temporary unix domain socket path ([#4422](https://github.com/processone/ejabberd/issues/4422))
+- `ejabberd_listener`: Log error when cannot set definitive unix socket ([#4422](https://github.com/processone/ejabberd/issues/4422))
+- `ejabberd_listener`: Try to create provisional socket in final directory ([#4422](https://github.com/processone/ejabberd/issues/4422))
+- `ejabberd_logger`: Print log lines colorized in console when using rebar3
+- `mod_conversejs`: Ensure assets_path ends in `/` as required by Converse ([#4414](https://github.com/processone/ejabberd/issues/4414))
+- `mod_conversejs`: Ensure plugins URL is separated with `/` ([#4413](https://github.com/processone/ejabberd/issues/4413))
+- `mod_http_upload`: Encode URLs into IDNA when showing to XMPP client ([#3519](https://github.com/processone/ejabberd/issues/3519))
+- `mod_matrix_gw`: Add support for null values in `is_canonical_json` ([#4421](https://github.com/processone/ejabberd/issues/4421))
+- `mod_matrix_gw`: Don't send empty direct Matrix messages ([#4420](https://github.com/processone/ejabberd/issues/4420))
+- `mod_matrix_gw`: Matrix gateway updates
+- `mod_muc`: Report db failures when restoring rooms
+- `mod_muc`: Unsubscribe users from members-only rooms when expelled ([#4412](https://github.com/processone/ejabberd/issues/4412))
+- `mod_providers`: New module to serve easily XMPP Providers files
+- `mod_register`: Don't duplicate welcome subject and message
+- `mod_scram_upgrade`: Fix format of passwords updates
+- `mod_scram_upgrade`: Only offer upgrades to methods that aren't already stored
+
+## Version 25.07
+
+#### Security fix
+
+- `ext_mod`: Add temporary workaround for zip including absolute path
+
+#### Compilation
+
+- Raise the minimum Elixir tested version to 1.14.0 ([#4281](https://github.com/processone/ejabberd/issues/4281))
+- Raise Erlang/OTP minimum requirement to 25.0 ([#4281](https://github.com/processone/ejabberd/issues/4281))
+- `configure.ac`: Allow to specify minimal erlang version using `--with-min-erlang`
+- `Makefile.in`: Add target `test-`
+- `rebar3-format.sh`: Replace csplit with perl
+- Container: Bump Erlang/OTP 27.3.4.1, Elixir 1.18.4
+- Installers: Bump Erlang/OTP 27.3.4.1, Elixir 1.18.4, libexpat 2.7.1, OpenSSL 3.5.1
+
+#### Configuration and Tests
+
+- Add `rest_proxy*` options to configure proxy used by rest module
+- `ejabberd_c2s`: Add `auth_password_types_hidden_in_scram1` option
+- `ejabberd_http`: Remove unused `default_host` option and state element
+- `ejabberd_http`: New option `hosts_alias` and function `resolve_host_alias/1` ([#4400](https://github.com/processone/ejabberd/issues/4400))
+- New predefined keywords: `CONFIG_PATH` and `LOG_PATH`
+- Fix macro used in string options when defined in env var
+- Use auxiliary function to get `$HOME`, use Mnesia directory when not set ([#4402](https://github.com/processone/ejabberd/issues/4402))
+- `ejabberd_config`: Better `lists:uniq` substitute
+- Tests: update readme and compose to work with current sw versions
+- Update Elvis to 4.1.1, fix some warnings and enable their tests
+
+#### Erlang/OTP 28 support
+
+- Add workaround in `p1_acme` for Jose 1.11.10 not supporting OTP 28 `ecPrivkeyVer1` ([#4393](https://github.com/processone/ejabberd/issues/4393))
+- Bump `fast_xml` and `xmpp` for improved Erlang/OTP 28 support
+- Bump `xmpp` and `p1_acme` patched with Erlang/OTP 28 support
+- Fix `make options` in Erlang/OTP 28 ([#4352](https://github.com/processone/ejabberd/issues/4352))
+- Fix crash in `rebar3 cover` with Erlang/OTP 28 ([#4353](https://github.com/processone/ejabberd/issues/4353))
+- Rebar/Rebar3: Update binaries to work with Erlang/OTP 25-28 ([#4354](https://github.com/processone/ejabberd/issues/4354))
+- CI and Runtime: Add Erlang/OTP 28 to the versions matrix
+
+#### SQL
+
+- Fix mnesia to sql exporter after changes to auth tables
+- Update code for switching to new schema type to users table changes
+- Add mssql specific implementation of `delete_old_mam_messages`
+- Make `delete_old_mam_messages_batch` work with sqlite
+- `ejabberd_sm_sql`: Use misc:encode_pid/1
+- `mysql.sql`: Fix typo in commit 7862c6a when creating users table
+- `pg.sql`: Fix missing comma in postgres schema ([#4409](https://github.com/processone/ejabberd/issues/4409))
+
+#### Core and Modules
+
+- `ejabberd_s2s_in`: Allow S2S connections to accept client certificates that have only server purpose ([#4392](https://github.com/processone/ejabberd/issues/4392))
+- `ext_mod`: Recommend to write README.md instead txt (processone/ejabberd-contrib#363)
+- `ext_mod`: Support library path installed from Debian (processone/ejabberd-contrib#363)
+- `ext_mod`: When upgrading module, clean also the compiled directories
+- `gen_mod`: Add support to prepare module stopping before actually stopping any module
+- `mod_antispam`: Imported from ejabberd-contrib and improved ([#4373](https://github.com/processone/ejabberd/issues/4373))
+- `mod_auth_fast`: Clear tokens on kick, change pass and unregister ([#4397](https://github.com/processone/ejabberd/issues/4397))([#4398](https://github.com/processone/ejabberd/issues/4398))([#4399](https://github.com/processone/ejabberd/issues/4399))
+- `mod_conversejs`: Add link in WebAdmin to local Converse if configured
+- `mod_mam`: Present mam full text search in xep-431 compatible way
+- `mod_mam_mnesia`: Handle objects that don't need conversion in `transform/0`
+- `mod_matrix_gw`: Don't send empty messages in Matrix rooms ([#4385](https://github.com/processone/ejabberd/issues/4385))
+- `mod_matrix_gw`: Support older Matrix rooms versions starting from version 4
+- `mod_matrix_gw`: When encoding JSON, handle term that is key-value list ([#4379](https://github.com/processone/ejabberd/issues/4379))
+- `mod_matrix_gw_s2s`: Fix key validation in `check_signature`
+- `mod_mix` and `mod_muc_rtbl`: Support list of IDs in `pubsub-items-retract` (processone/xmpp#100)
+- `mod_pubsub_serverinfo`: Imported module from ejabberd-contrib ([#4408](https://github.com/processone/ejabberd/issues/4408))
+- `mod_register`: Normalize username when determining if user want to change pass
+- `mod_register`: Strip query data when returning errors
+- WebAdmin: New hooks `webadmin_menu_system` to add items to system menu
+
+## Version 25.04
+
+#### Security fixes
+- Fixes issue with handling of user provided occupant-id in messages and presences sent to muc room. Server was replacing
+ just first instance of occupant-id with its own version, leaving other ones untouched. That would mean that depending
+ on order in which clients send occupant-id, they could see value provided by sender, and that could be used to spoof
+ as different sender.
+
+#### Commands API
+- `kick_users`: New command to kick all logged users for a given host
+
+#### Bugfixes
+- Fix issue with sql schema auto upgrade when using `sqlite` database
+- Fix problem with container update, that could ignore previous data stored in `mnesia` database
+- Revert limit of allowed characters in shared roster group names, that will again allow using symbols like `:`
+
+## Version 25.03
+
+#### Commands API
+- `ejabberdctl`: New option `CTL_OVER_HTTP` ([#4340](https://github.com/processone/ejabberd/issues/4340))
+- `ejabberd_web_admin`: Support commands with tuple arguments
+- `mod_adhoc_api`: New module to execute API Commands using Ad-Hoc Commands ([#4357](https://github.com/processone/ejabberd/issues/4357))
+- `mod_http_api`: Sort list elements in a command result
+- Show warning when registering command with an existing name
+- Fix commands unregistration
+- `change_room_option`: Add forgotten support to set `enable_hats` room option
+- `change_room_option`: Verify room option value before setting it ([#4337](https://github.com/processone/ejabberd/issues/4337))
+- `create_room_with_opts`: Recommend using `;` and `=` separators
+- `list_cluster_detailed`: Fix crash when a node is down
+- `mnesia_list_tables`: Allow using this internal command
+- `mnesia_table_change_storage`: Allow using this internal command
+- `status`: Separate command result with newline
+- `update_sql`: Fix updating tables created by ejabberd internally
+- `update_sql`: Fix MySQL support
+
+#### Configuration
+- `acl`: Fix bug matching the acl `shared_group: NAME`
+- `define_keyword`: New option to define keywords ([#4350](https://github.com/processone/ejabberd/issues/4350))
+- `define_macro`: Add option to `globals()` because it's useless inside `host_config`
+- `ejabberd.yml.example`: Enable `mod_muc_occupantid` by default
+- Add support to use keywords in toplevel, listener and modules
+- Show warning also when deprecated listener option is set as disabled ([#4345](https://github.com/processone/ejabberd/issues/4345))
+
+#### Container
+- Bump versions to Erlang/OTP 27.3 and Elixir 1.18.3
+- Add `ERL_FLAGS` to compile elixir on qemu cross-platform
+- Copy files to stable path, add ecs backwards compatibility
+- Fix warning about relative workdir
+- Improve entrypoint script: register account, or set random
+- Link path to Mnesia spool dir for backwards compatibility
+- Place `sockets/` outside `database/`
+- Use again direct METHOD, qemu got fixed ([#4280](https://github.com/processone/ejabberd/issues/4280))
+- `ejabberd.yml.example`: Copy main example configuration file
+- `ejabberd.yml.example`: Define and use macros in the default configuration file
+- `ejabberd.yml.example`: Enable `CTL_OVER_HTTP` by default
+- `ejabberd.yml.example`: Listen for webadmin in a port number lower than any other
+- `ejabberdapi`: Compile during build
+- `CONTAINER.md`: Include documentation for ecs container image
+
+#### Core and Modules
+- `ejabberd_auth`: Add support for `auth_stored_password_types`
+- `ejabberd_router`: Don't rewrite "self-addressed" privileged IQs as results ([#4348](https://github.com/processone/ejabberd/issues/4348))
+- `misc`: Fix json version of `json_encode_with_kv_list` for nested kv lists ([#4338](https://github.com/processone/ejabberd/issues/4338))
+- OAuth: Fix crashes when oauth is feed with invalid jid ([#4355](https://github.com/processone/ejabberd/issues/4355))
+- PubSub: Bubble up db errors in `nodetree_tree_sql:set_node`
+- `mod_configure`: Add option `access` to let configure the access name
+- `mod_mix_pam`: Remove `Channels` roster group of mix channels ([#4297](https://github.com/processone/ejabberd/issues/4297))
+- `mod_muc`: Document MUC room option vcard_xupdate
+- `mod_privilege`: Accept non-privileged IQs from privileged components ([#4341](https://github.com/processone/ejabberd/issues/4341))
+- `mod_private`: Improve exception handling
+- `mod_private`: Don't warn on conversion errors
+- `mod_private`: Handle invalid PEP-native bookmarks
+- `mod_private`: Don't crash on invalid bookmarks
+- `mod_s2s_bidi`: Stop processing other handlers in s2s_in_handle_info ([#4344](https://github.com/processone/ejabberd/issues/4344))
+- `mod_s2s_bidi`: Fix issue with wrong namespace
+
+#### Dependencies
+- `ex_doc`: Bump to 0.37.2
+- `stringprep`: Bump to 1.0.31
+- `provider_asn1`: Bump to 0.4.1
+- `xmpp` Bump to bring fix for ssdp hash calculation
+- `xmpp` Bump to get support for webchat_url ([#3041](https://github.com/processone/ejabberd/issues/3041))
+- `xmpp` Bump to get XEP-0317 Hats namespaces version 0.2.0
+- `xmpp` Bump to bring SSDP to XEP version 0.4
+- `yconf` Bump to support macro inside string
+
+#### Development and Testing
+- `mix.exs`: Keep debug info when building `dev` release
+- `mix.exs`: The `ex_doc` dependency is only relevant for the `edoc` Mix environment
+- `ext_mod`: add `$libdir/include` to include path
+- `ext_mod`: fix greedy include path ([#4359](https://github.com/processone/ejabberd/issues/4359))
+- `gen_mod`: Support registering commands and `hook_subscribe` in `start/2` result
+- `c2s_handle_bind`: New event in `ejabberd_c2s` ([#4356](https://github.com/processone/ejabberd/issues/4356))
+- `muc_disco_info_extras`: New event `mod_muc_room` useful for `mod_muc_webchat_url` ([#3041](https://github.com/processone/ejabberd/issues/3041))
+- VSCode: Fix compiling support
+- Add tests for config features `define_macro` and `define_keyword`
+- Allow test to run using `ct_run`
+- Fixes to handle re-running test after `update_sql`
+- Uninstall `mod_example` when the tests has finished
+
+#### Documentation
+- Add XEPs that are indirectly supported and required by XEP-0479
+- Document that XEP-0474 0.4.0 was recently upgraded
+- Don't use backtick quotes for ejabberd name
+- Fix values allowed in db_type of mod_auth_fast documentation
+- Reword explanation about ACL names and definitions
+- Update moved or broken URLs in documentation
+
+#### Installers
+- Bump Erlang/OTP 27.3 and Elixir 1.18.3
+- Bump OpenSSL 3.4.1
+- Bump crosstool-NG 1.27.0
+- Fix building Termcap and Linux-PAM
+
+#### Matrix Gateway
+- Preserve XMPP message IDs in Matrix rooms
+- Better Matrix room topic and room roles to MUC conversion, support room aliases in invites
+- Add `muc#user` element to presences and an initial empty subject
+- Fix `gen_iq_handler:remove_iq_handler` call
+- Properly handle IQ requests
+- Support Matrix room aliases
+- Fix handling of 3PI events
+
+#### Unix Domain Socket
+- Add support for socket relative path
+- Use `/tmp` for temporary socket, as path is restricted to 107 chars
+- Handle unix socket when logging remote client
+- When stopping listener, delete Unix Domain Socket file
+- `get_auto_url` option: Don't build auto URL if port is unix domain socket ([#4345](https://github.com/processone/ejabberd/issues/4345))
+
+## Version 24.12
+
+#### Miscelanea
+
+- Elixir: support loading Elixir modules for auth ([#4315](https://github.com/processone/ejabberd/issues/4315))
+- Environment variables `EJABBERD_MACRO` to define macros
+- Fix problem starting ejabberd when first host uses SQL, other one mnesia
+- HTTP Websocket: Enable `allow_unencrypted_sasl2` on websockets ([#4323](https://github.com/processone/ejabberd/issues/4323))
+- Relax checks for channels bindings for connections using external encryption
+- Redis: Add support for unix domain socket ([#4318](https://github.com/processone/ejabberd/issues/4318))
+- Redis: Use eredis 1.7.1 from Nordix when using mix/rebar3 and Erlang 21+
+- `mod_auth_fast`: New module with support XEP-0484: Fast Authentication Streamlining Tokens
+- `mod_http_api`: Fix crash when module not enabled (for example, in CT tests)
+- `mod_http_api`: New option `default_version`
+- `mod_muc`: Make rsm handling in disco items, correctly count skipped rooms
+- `mod_offline`: Only delete offline msgs when user has MAM enabled ([#4287](https://github.com/processone/ejabberd/issues/4287))
+- `mod_priviled`: Handle properly roster iq
+- `mod_pubsub`: Send notifications on PEP item retract
+- `mod_s2s_bidi`: Catch extra case in check for s2s bidi element
+- `mod_scram_upgrade`: Don't abort the upgrade
+- `mod_shared_roster`: The name of a new group is lowercased
+- `mod_shared_roster`: Get back support for `groupid@vhost` in `displayed`
+- `mod_stun_disco`: Fix syntax of credentials response
+
+#### Commands API
+
+- Change arguments and result to consistent names (API v3)
+- `create_rooms_file`: Improve to support vhosts with different config
+- `evacuate_kindly`: New command to kick users and prevent login ([#4309](https://github.com/processone/ejabberd/issues/4309))
+- `join_cluster`: Explain that this returns immediately (since 5a34020, 24.06)
+- `mod_muc_admin`: Rename argument `name` to `room` for consistency
+
+#### Documentation
+
+- Fix some documentation syntax, add links to toplevel, modules and API
+- `CONTAINER.md`: Add kubernetes yaml examples to use with podman
+- `SECURITY.md`: Add security policy and reporting guidelines
+- `ejabberd.service`: Disable the systemd watchdog by default
+- `ejabberd.yml.example`: Use non-standard STUN port
+
+#### WebAdmin
+
+- Shared group names are case sensitive, use original case instead of lowercase
+- Use lowercase username and server authentication credentials
+- Fix calculation of node's uptime days
+- Fix link to displayed group when it is from another vhost
+
+## Version 24.10
+
+#### Miscelanea
+
+- `ejabberd_c2s`: Optionally allow unencrypted SASL2
+- `ejabberd_system_monitor`: Handle call by `gen_event:swap_handler` ([#4233](https://github.com/processone/ejabberd/issues/4233))
+- `ejabberd_http_ws`: Remove support for old websocket connection protocol
+- `ejabberd_stun`: Omit `auth_realm` log message
+- `ext_mod`: Handle `info` message when contrib module transfers table ownership
+- `mod_block_strangers`: Add feature announcement to disco-info ([#4039](https://github.com/processone/ejabberd/issues/4039))
+- `mod_mam`: Advertise XEP-0424 feature in server disco-info ([#3340](https://github.com/processone/ejabberd/issues/3340))
+- `mod_muc_admin`: Better handling of malformed jids in `send_direct_invitation` command
+- `mod_muc_rtbl`: Fix call to `gen_server:stop` ([#4260](https://github.com/processone/ejabberd/issues/4260))
+- `mod_privilege`: Support "IQ permission" from XEP-0356 0.4.1 ([#3889](https://github.com/processone/ejabberd/issues/3889))
+- `mod_pubsub`: Don't blindly echo PEP notification
+- `mod_pubsub`: Skip non-delivery errors for local pubsub generated notifications
+- `mod_pubsub`: Fall back to default plugin options
+- `mod_pubsub`: Fix choice of node config defaults
+- `mod_pubsub`: Fix merging of default node options
+- `mod_pubsub`: Fix default node config parsing
+- `mod_register`: Support to block IPs in a vhost using `append_host_config` ([#4038](https://github.com/processone/ejabberd/issues/4038))
+- `mod_s2s_bidi`: Add support for S2S Bidirectional
+- `mod_scram_upgrade`: Add support for SCRAM upgrade tasks
+- `mod_vcard`: Return error stanza when storage doesn't support vcard update ([#4266](https://github.com/processone/ejabberd/issues/4266))
+- `mod_vcard`: Return explicit error stanza when user attempts to modify other's vcard
+- Minor improvements to support `mod_tombstones` (#2456)
+- Update `fast_xml` to use `use_maps` and remove obsolete elixir files
+- Update `fast_tls` and `xmpp` to improve s2s fallback for invalid direct tls connections
+- `make-binaries`: Bump dependency versions: Elixir 1.17.2, OpenSSL 3.3.2, ...
+
+#### Administration
+
+- `ejabberdctl`: If `ERLANG_NODE` lacks host, add hostname ([#4288](https://github.com/processone/ejabberd/issues/4288))
+- `ejabberd_app`: At server start, log Erlang and Elixir versions
+- MySQL: Fix column type in the schema update of `archive` table in schema update
+
+#### Commands API
+
+- `get_mam_count`: New command to get number of archived messages for an account
+- `set_presence`: Return error when session not found
+- `update`: Fix command output
+- Add `mam` and `offline` tags to the related purge commands
+
+#### Code Quality
+
+- Fix warnings about unused macro definitions reported by Erlang LS
+- Fix Elvis report: Fix dollar space syntax
+- Fix Elvis report: Remove spaces in weird places
+- Fix Elvis report: Don't use ignored variables
+- Fix Elvis report: Remove trailing whitespace characters
+- Define the types of options that `opt_type.sh` cannot derive automatically
+- `ejabberd_http_ws`: Fix dialyzer warnings
+- `mod_matrix_gw`: Remove useless option `persist`
+- `mod_privilege`: Replace `try...catch` with a clean alternative
+
+#### Development Help
+
+- `elvis.config`: Fix file syntax, set vim mode, disable many tests
+- `erlang_ls.config`: Let it find paths, update to Erlang 26, enable crossref
+- `hooks_deps`: Hide false-positive warnings about `gen_mod`
+- `Makefile`: Add support for `make elvis` when using rebar3
+- `.vscode/launch.json`: Experimental support for debugging with Neovim
+- CI: Add Elvis tests
+- CI: Add XMPP Interop tests
+- Runtime: Cache hex.pm archive from rebar3 and mix
+
+#### Documentation
+
+- Add links in top-level options documentation to their Docs website sections
+- Document which SQL servers can really use `update_sql_schema`
+- Improve documentation of `ldap_servers` and `ldap_backups` options ([#3977](https://github.com/processone/ejabberd/issues/3977))
+- `mod_register`: Document behavior when `access` is set to `none` ([#4078](https://github.com/processone/ejabberd/issues/4078))
+
+#### Elixir
+
+- Handle case when elixir support is enabled but not available
+- Start ExSync manually to ensure it's started if (and only if) Relive
+- `mix.exs`: Fix `mix release` error: `logger` being regular and included application ([#4265](https://github.com/processone/ejabberd/issues/4265))
+- `mix.exs`: Remove from `extra_applications` the apps already defined in `deps` ([#4265](https://github.com/processone/ejabberd/issues/4265))
+
+#### WebAdmin
+
+- Add links in user page to offline and roster pages
+- Add new "MAM Archive" page to webadmin
+- Improve many pages to handle when modules are disabled
+- `mod_admin_extra`: Move some webadmin pages to their modules
+
+## Version 24.07
+
+#### Core
+
+- `ejabberd_options`: Add trailing `@` to `@VERSION@` parsing
+- `mod_http_api`: Fix problem parsing tuples when using OTP 27 json library ([#4242](https://github.com/processone/ejabberd/issues/4242))
+- `mod_http_api`: Restore args conversion of `{"k":"v"}` to tuple lists
+- `mod_matrix_gw`: Add misc:json_encode_With_kv_lists and use it in matrix sign function
+- `mod_muc`: Output `muc#roominfo_avatarhash` in room disco info as per updated XEP-0486 ([#4234](https://github.com/processone/ejabberd/issues/4234))
+- `mod_muc`: Improve cross version handling of muc retractions
+- `node_pep`: Add missing feature `item-ids` to node_pep
+- `mod_register`: Send welcome message as `chat` too ([#4246](https://github.com/processone/ejabberd/issues/4246))
+- `ejabberd_hooks`: Support for ejabberd hook subscribers, useful for [mod_prometheus](https://github.com/processone/ejabberd-contrib/tree/master/mod_prometheus)
+- `ejabberd.app`: Don't add `iex` to included_applications
+- `make-installers`: Fix path in scripts in regular user install ([#4258](https://github.com/processone/ejabberd/issues/4258))
+- Test: New tests for API commands
+
+#### Documentation
+
+- `mod_matrix_gw`: Fix `matrix_id_as_jid` option documentation
+- `mod_register`: Add example configuration of `welcome_message` option
+- `mix.exs`: Add ejabberd example config files to the hex package
+- Update `CODE_OF_CONDUCT.md`
+
+#### ext_mod
+
+- Fetch dependencies from hex.pm when mix is available
+- files_to_path is deprecated, use compile_to_path
+- Compile all Elixir files in a library with one function call
+- Improve error result when problem compiling elixir file
+- Handle case when contrib module has no `*.ex` and no `*.erl`
+- `mix.exs`: Include Elixir's Logger in the OTP release, useful for [mod_libcluster](https://github.com/processone/ejabberd-contrib/tree/master/mod_libcluster)
+
+#### Logs
+
+- Print message when starting ejabberd application fails
+- Use error_logger when printing startup failure message
+- Use proper format depending on the formatter ([#4256](https://github.com/processone/ejabberd/issues/4256))
+
+#### SQL
+
+- Add option `update_sql_schema_timeout` to allow schema update use longer timeouts
+- Add ability to specify custom timeout for sql operations
+- Allow to configure number of restart in `sql_transaction()`
+- Make sql query in testsuite compatible with pg9.1
+- In `mysql.sql`, fix update instructions for the `archive` table, `origin_id` column ([#4259](https://github.com/processone/ejabberd/issues/4259))
+
+#### WebAdmin
+
+- `ejabberd.yml.example`: Add `api_permissions` group for webadmin ([#4249](https://github.com/processone/ejabberd/issues/4249))
+- Don't use host from url in webadmin, prefer host used for authentication
+- Fix number of accounts shown in the online-users page
+- Fix crash when viewing old shared roster groups ([#4245](https://github.com/processone/ejabberd/issues/4245))
+- Support groupid with spaces when making shared roster result ([#4245](https://github.com/processone/ejabberd/issues/4245))
+
+## Version 24.06
+
+#### Core
+
+- `econf`: Add ability to use additional custom errors when parsing options
+- `ejabberd_logger`: Reloading configuration will update logger settings
+- `gen_mod`: Add support to specify a hook global, not vhost-specific
+- `mod_configure`: Retract `Get User Password` command to update XEP-0133 1.3.0
+- `mod_conversejs`: Simplify support for `@HOST@` in `default_domain` option ([#4167](https://github.com/processone/ejabberd/issues/4167))
+- `mod_mam`: Document that XEP-0441 is implemented as well
+- `mod_mam`: Update support for XEP-0425 version 0.3.0, keep supporting 0.2.1 ([#4193](https://github.com/processone/ejabberd/issues/4193))
+- `mod_matrix_gw`: Fix support for `@HOST@` in `matrix_domain` option ([#4167](https://github.com/processone/ejabberd/issues/4167))
+- `mod_muc_log`: Hide join/leave lines, add method to show them
+- `mod_muc_log`: Support `allowpm` introduced in 2bd61ab
+- `mod_muc_room`: Use ejabberd hooks instead of function calls to `mod_muc_log` ([#4191](https://github.com/processone/ejabberd/issues/4191))
+- `mod_private`): Cope with bookmark decoding errors
+- `mod_vcard_xupdate`: Send hash after avatar get set for first time
+- `prosody2ejabberd`: Handle the `approved` attribute. As feature isn't implemented, discard it ([#4188](https://github.com/processone/ejabberd/issues/4188))
+
+#### SQL
+
+- `update_sql_schema`: Enable this option by default
+- CI: Don't load database schema files for mysql and pgsql
+- Support Unix Domain Socket with updated p1_pgsql and p1_mysql ([#3716](https://github.com/processone/ejabberd/issues/3716))
+- Fix handling of `mqtt_pub` table definition from `mysql.sql` and fix `should_update_schema/1` in `ejabberd_sql_schema.erl`
+- Don't start sql connection pools for unknown hosts
+- Add `update_primary_key` command to sql schema updater
+- Fix crash running `export2sql` when MAM enabled but MUC disabled
+- Improve detection of types in odbc
+
+#### Commands API
+
+- New ban commands use private storage to keep ban information ([#4201](https://github.com/processone/ejabberd/issues/4201))
+- `join_cluster_here`: New command to join a remote node into our local cluster
+- Don't name integer and string results in API examples ([#4198](https://github.com/processone/ejabberd/issues/4198))
+- `get_user_subscriptions`: Fix validation of user field in that command
+- `mod_admin_extra`: Handle case when `mod_private` is not enabled ([#4201](https://github.com/processone/ejabberd/issues/4201))
+- `mod_muc_admin`: Improve validation of arguments in several commands
+
+#### Compile
+
+- `ejabberdctl`: Comment ERTS_VSN variable when not used ([#4194](https://github.com/processone/ejabberd/issues/4194))
+- `ejabberdctl`: Fix iexlive after `make prod` when using Elixir
+- `ejabberdctl`: If `INET_DIST_INTERFACE` is IPv6, set required option ([#4189](https://github.com/processone/ejabberd/issues/4189))
+- `ejabberdctl`: Make native dynamic node names work when using fully qualified domain names
+- `rebar.config.script`: Support relaxed dependency version ([#4192](https://github.com/processone/ejabberd/issues/4192))
+- `rebar.config`: Update deps version to rebar3's relaxed versioning
+- `rebar.lock`: Track file, now that rebar3 uses loose dependency versioning
+- `configure.ac`: When using rebar3, unlock dependencies that are disabled ([#4212](https://github.com/processone/ejabberd/issues/4212))
+- `configure.ac`: When using rebar3 with old Erlang, unlock some dependencies ([#4213](https://github.com/processone/ejabberd/issues/4213))
+- `mix:exs`: Move `xmpp` from `included_applications` to `applications`
+
+#### Dependencies
+
+- Base64url: Use only when using rebar2 and Erlang lower than 24
+- Idna: Bump from 6.0.0 to 6.1.1
+- Jiffy: Use Json module when Erlang/OTP 27, jiffy with older ones
+- Jose: Update to the new 1.11.10 for Erlang/OTP higher than 23
+- Luerl: Update to 1.2.0 when OTP same or higher than 20, simplifies commit a09f222
+- P1_acme: Update to support Jose 1.11.10 and Ipv6 support ([#4170](https://github.com/processone/ejabberd/issues/4170))
+- P1_acme: Update to use Erlang's json library instead of jiffy when OTP 27
+- Port_compiler: Update to 1.15.0 that supports Erlang/OTP 27.0
+
+#### Development Help
+
+- `.gitignore`: Ignore ctags/etags files
+- `make dialyzer`: Add support to run Dialyzer with Mix
+- `make format|indent`: New targets to format and indent source code
+- `make relive`: Add Sync tool with Rebar3, ExSync with Mix
+- `hook_deps`: Use precise name: hooks are added and later deleted, not removed
+- `hook_deps`: Fix to handle FileNo as tuple `{FileNumber, CharacterPosition}`
+- Add support to test also EUnit suite
+- Fix `code:lib_dir` call to work with Erlang/OTP 27.0-rc2
+- Set process flags when Erlang/OTP 27 to help debugging
+- Test retractions in mam_tests
+
+#### Documentation
+
+- Add some XEPs support that was forgotten
+- Fix documentation links to new URLs generated by MkDocs
+- Remove `...` in example configuration: it is assumed and reduces verbosity
+- Support for version note in modules too
+- Mark toplevel options, commands and modules that changed in latest version
+- Now modules themselves can have version annotations in `note`
+
+#### Installers and Container
+
+- make-binaries: Bump Erlang/OTP to 26.2.5 and Elixir 1.16.3
+- make-binaries: Bump OpenSSL to 3.3.1
+- make-binaries: Bump Linux-PAM to 1.6.1
+- make-binaries: Bump Expat to 2.6.2
+- make-binaries: Revert temporarily an OTP commit that breaks MSSQL ([#4178](https://github.com/processone/ejabberd/issues/4178))
+- CONTAINER.md: Invalid `CTL_ON_CREATE` usage in docker-compose example
+
+#### WebAdmin
+
+- ejabberd_ctl: Improve parsing of commas in arguments
+- ejabberd_ctl: Fix output of UTF-8-encoded binaries
+- WebAdmin: Remove webadmin_view for now, as commands allow more fine-grained permissions
+- WebAdmin: Unauthorized response: include some text to direct to the logs
+- WebAdmin: Improve home page
+- WebAdmin: Sort alphabetically the menu items, except the most used ones
+- WebAdmin: New login box in the left menu bar
+- WebAdmin: Add make_command functions to produce HTML command element
+- Document 'any' argument and result type, useful for internal commands
+- Commands with 'internal' tag: don't list and block execution by frontends
+- WebAdmin: Move content to commands; new pages; hook changes; new commands
+
+## Version 24.02
+
+#### Core:
+
+- Added Matrix gateway in `mod_matrix_gw`
+- Support SASL2 and Bind2
+- Support tls-server-end-point channel binding and sasl2 codec
+- Support tls-exporter channel binding
+- Support XEP-0474: SASL SCRAM Downgrade Protection
+- Fix presenting features and returning results of inline bind2 elements
+- `disable_sasl_scram_downgrade_protection`: New option to disable XEP-0474
+- `negotiation_timeout`: Increase default value from 30s to 2m
+- mod_carboncopy: Teach how to interact with bind2 inline requests
+
+#### Other:
+
+- ejabberdctl: Fix startup problem when having set `EJABBERD_OPTS` and logger options
+- ejabberdctl: Set EJABBERD_OPTS back to `""`, and use previous flags as example
+- eldap: Change logic for `eldap tls_verify=soft` and `false`
+- eldap: Don't set `fail_if_no_peer_cert` for eldap ssl client connections
+- Ignore hints when checking for chat states
+- mod_mam: Support XEP-0424 Message Retraction
+- mod_mam: Fix XEP-0425: Message Moderation with SQL storage
+- mod_ping: Support XEP-0198 pings when stream management is enabled
+- mod_pubsub: Normalize pubsub `max_items` node options on read
+- mod_pubsub: PEP nodetree: Fix reversed logic in node fixup function
+- mod_pubsub: Only care about PEP bookmarks options when creating node from scratch
+
+#### SQL:
+
+- MySQL: Support `sha256_password` auth plugin
+- ejabberd_sql_schema: Use the first unique index as a primary key
+- Update SQL schema files for MAM's XEP-0424
+- New option [`sql_flags`](https://docs.ejabberd.im/admin/configuration/toplevel/#sql-flags): right now only useful to enable `mysql_alternative_upsert`
+
+#### Installers and Container:
+
+- Container: Add ability to ignore failures in execution of `CTL_ON_*` commands
+- Container: Update to Erlang/OTP 26.2, Elixir 1.16.1 and Alpine 3.19
+- Container: Update this custom ejabberdctl to match the main one
+- make-binaries: Bump OpenSSL 3.2.1, Erlang/OTP 26.2.2, Elixir 1.16.1
+- make-binaries: Bump many dependency versions
+
+#### Commands API:
+
+- `print_sql_schema`: New command available in ejabberdctl command-line script
+- ejabberdctl: Rework temporary node name generation
+- ejabberdctl: Print argument description, examples and note in help
+- ejabberdctl: Document exclusive ejabberdctl commands like all the others
+- Commands: Add a new `muc_sub` tag to all the relevant commands
+- Commands: Improve syntax of many commands documentation
+- Commands: Use list arguments in many commands that used separators
+- Commands: `set_presence`: switch priority argument from string to integer
+- ejabberd_commands: Add the command API version as [a tag `vX`](https://docs.ejabberd.im/developer/ejabberd-api/admin-tags/#v1)
+- ejabberd_ctl: Add support for list and tuple arguments
+- ejabberd_xmlrpc: Fix support for restuple error response
+- mod_http_api: When no specific API version is requested, use the latest
+
+#### Compilation with Rebar3/Elixir/Mix:
+- Fix compilation with Erlang/OTP 27: don't use the reserved word 'maybe'
+- configure: Fix explanation of `--enable-group` option ([#4135](https://github.com/processone/ejabberd/issues/4135))
+- Add observer and runtime_tools in releases when `--enable-tools`
+- Update "make translations" to reduce build requirements
+- Use Luerl 1.0 for Erlang 20, 1.1.1 for 21-26, and temporary fork for 27
+- Makefile: Add `install-rel` and `uninstall-rel`
+- Makefile: Rename `make rel` to `make prod`
+- Makefile: Update `make edoc` to use ExDoc, requires mix
+- Makefile: No need to use `escript` to run rebar|rebar3|mix
+- configure: If `--with-rebar=rebar3` but rebar3 not system-installed, use local one
+- configure: Use Mix or Rebar3 by default instead of Rebar2 to compile ejabberd
+- ejabberdctl: Detect problem running iex or etop and show explanation
+- Rebar3: Include Elixir files when making a release
+- Rebar3: Workaround to fix protocol consolidation
+- Rebar3: Add support to compile Elixir dependencies
+- Rebar3: Compile explicitly our Elixir files when `--enable-elixir`
+- Rebar3: Provide proper path to `iex`
+- Rebar/Rebar3: Update binaries to work with Erlang/OTP 24-27
+- Rebar/Rebar3: Remove Elixir as a rebar dependency
+- Rebar3/Mix: If `dev` profile/environment, enable tools automatically
+- Elixir: Fix compiling ejabberd as a dependency ([#4128](https://github.com/processone/ejabberd/issues/4128))
+- Elixir: Fix ejabberdctl start/live when installed
+- Elixir: Fix: `FORMATTER ERROR: bad return value` ([#4087](https://github.com/processone/ejabberd/issues/4087))
+- Elixir: Fix: Couldn't find file `Elixir Hex API`
+- Mix: Enable stun by default when `vars.config` not found
+- Mix: New option `vars_config_path` to set path to `vars.config` ([#4128](https://github.com/processone/ejabberd/issues/4128))
+- Mix: Fix ejabberdctl iexlive problem locating iex in an OTP release
+
+## Version 23.10
+
+#### Compilation:
-Compilation:
- Erlang/OTP: Raise the requirement to Erlang/OTP 20.0 as a minimum
- CI: Update tests to Erlang/OTP 26 and recent Elixir
- Move Xref and Dialyzer options from workflows to `rebar.config`
@@ -13,7 +651,8 @@ Compilation:
- Elixir: When building OTP release with mix, keep `ERLANG_NODE=ejabberd@localhost`
- `ejabberdctl`: Pass `ERLANG_OPTS` when calling `erl` to parse the `INET_DIST_INTERFACE` ([#4066](https://github.com/processone/ejabberd/issues/#4066)
-Commands:
+#### Commands:
+
- `create_room_with_opts`: Fix typo and move examples to `args_example` ([#4080](https://github.com/processone/ejabberd/issues/#4080))
- `etop`: Let `ejabberdctl etop` work in a release (if `observer` application is available)
- `get_roster`: Command now returns groups in a list instead of newlines ([#4088](https://github.com/processone/ejabberd/issues/#4088))
@@ -23,7 +662,8 @@ Commands:
- `ejabberdctl`: Support `policy=user` in the help and return proper arguments
- `ejabberdctl`: Document how to stop a debug shell: control+g
-Container:
+#### Container:
+
- Dockerfile: Add missing dependency for mssql databases
- Dockerfile: Reorder stages and steps for consistency
- Dockerfile: Use Alpine as base for `METHOD=package`
@@ -31,7 +671,8 @@ Container:
- Dockerfile: Provide specific OTP and elixir vsn for direct compilation
- Halt ejabberd if a command in `CTL_ON_` fails during ejabberd startup
-Core:
+#### Core:
+
- `auth_external_user_exists_check`: New option ([#3377](https://github.com/processone/ejabberd/issues/#3377))
- `gen_mod`: Extend `gen_mod` API to simplify hooks and IQ handlers registration
- `gen_mod`: Add shorter forms for `gen_mod` hook/`iq_handler` API
@@ -46,14 +687,15 @@ Core:
- Web Admin: In roster page move the `AddJID` textbox to top ([#4067](https://github.com/processone/ejabberd/issues/#4067))
- Web Admin: Show a warning when visiting webadmin with non-privileged account ([#4089](https://github.com/processone/ejabberd/issues/#4089))
-Docs:
+#### Docs:
+
- Example configuration: clarify 5223 tls options; specify s2s shaper
- Make sure that `policy=user` commands have `host` instead of `server` arg in docs
- Improve syntax of many command descriptions for the Docs site
- Move example Perl extauth script from ejabberd git to Docs site
- Remove obsolete example files, and add link in Docs to the archived copies
-Installers (`make-binaries`):
+#### Installers (`make-binaries`):
- Bump Erlang/OTP version to 26.1.1, and other dependencies
- Remove outdated workaround
- Don't build Linux-PAM examples
@@ -65,7 +707,8 @@ Installers (`make-binaries`):
- Set kernel version for all builds
- Let curl fail on HTTP errors
-Modules:
+#### Modules:
+
- `mod_muc_log`: Add trailing backslash to URLs shown in disco info
- `mod_muc_occupantid`: New module with support for XEP-0421 Occupant Id ([#3397](https://github.com/processone/ejabberd/issues/#3397))
- `mod_muc_rtbl`: Better error handling in ([#4050](https://github.com/processone/ejabberd/issues/#4050))
@@ -83,7 +726,8 @@ Modules:
- `mod_register_web`: Make redirect to page that end with `/` ([#3177](https://github.com/processone/ejabberd/issues/#3177))
- `mod_shared_roster_ldap`: Don't crash in `get_member_jid` on empty output ([#3614](https://github.com/processone/ejabberd/issues/#3614))
-MUC:
+#### MUC:
+
- Add support to register nick in a room ([#3455](https://github.com/processone/ejabberd/issues/#3455))
- Convert `allow_private_message` MUC room option to `allowpm` ([#3736](https://github.com/processone/ejabberd/issues/#3736))
- Update xmpp version to send `roomconfig_changesubject` in disco#info ([#4085](https://github.com/processone/ejabberd/issues/#4085))
@@ -96,7 +740,8 @@ MUC:
- Remove existing role information for users that are kicked from room ([#4035](https://github.com/processone/ejabberd/issues/#4035))
- Expand rule "mucsub subscribers are members in members only rooms" to more places
-SQL:
+#### SQL:
+
- Add ability to force alternative upsert implementation in mysql
- Properly parse mysql version even if it doesn't have type tag
- Use prepared statement with mysql
@@ -106,9 +751,10 @@ SQL:
- `mod_privacy_sql`: Optimize `set_list`
- `mod_privacy_sql`: Use more efficient way to calculate changes in `set_privacy_list`
-# Version 23.04
+## Version 23.04
+
+#### General:
-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
@@ -121,13 +767,15 @@ General:
- `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:
+#### 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:
+#### MUC:
+
- New command `get_room_history`
- Persist `none` role for outcasts
- Try to populate room history from mam when unhibernating
@@ -136,7 +784,8 @@ MUC:
- Store state in db in `mod_muc:create_room()`
- Make subscribers members by default
-SQL schemas:
+#### 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
@@ -145,14 +794,16 @@ SQL schemas:
- Remove unnecessary indexes
- New SQL schema migrate fix
-MS SQL:
+#### 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:
+#### 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`
@@ -160,7 +811,8 @@ SQL Tests:
- Correct README for creating test docker MS SQL DB
- Fix TSQLlint warnings in MSSQL test script
-Testing:
+#### Testing:
+
- Fix Shellcheck warnings in shell scripts
- Fix Remark-lint warnings
- Fix Prospector and Pylint warnings in test `extauth.py`
@@ -168,14 +820,14 @@ Testing:
- 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:
+#### `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:
+#### `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
@@ -185,14 +837,16 @@ Testing:
- Expose only `HOME` volume, it contains all the required subdirs
- ejabberdctl: Don't use `.../releases/COOKIE`, it's no longer included
-Installers:
+#### 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
+## Version 23.01
+
+#### General:
-General:
- Add `misc:uri_parse/2` to allow declaring default ports for protocols
- CAPTCHA: Add support to define module instead of path to script
- Clustering: Handle `mnesia_system_event mnesia_up` when other node joins this ([#3842](https://github.com/processone/ejabberd/issues/3842))
@@ -212,7 +866,8 @@ General:
- PubSub: Expose the `pubsub#type` field in `disco#info` query to the node ([#3914](https://github.com/processone/ejabberd/issues/3914))
- Translations: Update German translation
-Admin:
+#### Admin:
+
- `api_permissions`: Fix option crash when doesn't have `who:` section
- `log_modules_fully`: New option to list modules that will log everything
- `outgoing_s2s_families`: Changed option's default to IPv6, and fall back to IPv4
@@ -223,13 +878,15 @@ Admin:
- Silent warning in OTP24 about not specified `cacerts` in SQL connections
- Fix compilation warnings with Elixir 1.14
-DOAP:
+#### DOAP:
+
- Support extended `-protocol` erlang attribute
- Add extended RFCs and XEP details to some protocol attributes
- `tools/generate-doap.sh`: New script to generate DOAP file, add `make doap` ([#3915](https://github.com/processone/ejabberd/issues/3915))
- `ejabberd.doap`: New DOAP file describing ejabberd supported protocols
-MQTT:
+#### MQTT:
+
- Add MQTT bridge module
- Add support for certificate authentication in MQTT bridge
- Implement reload in MQTT bridge
@@ -238,15 +895,17 @@ MQTT:
- `mqtt_publish`: New hook for MQTT publish event
- `mqtt_(un)subscribe`: New hooks for MQTT subscribe & unsubscribe events
-VSCode:
+#### VSCode:
+
- Improve `.devcontainer` to use use devcontainer image and `.vscode`
- Add `.vscode` files to instruct VSCode how to run ejabberd
- Add Erlang LS default configuration
- Add Elvis default configuration
-# Version 22.10
+## Version 22.10
+
+#### Core:
-Core:
- Add `log_burst_limit_*` options ([#3865](https://github.com/processone/ejabberd/issues/3865))
- Support `ERL_DIST_PORT` option to work without epmd
- Auth JWT: Catch all errors from `jose_jwt:verify` and log debugging details ([#3890](https://github.com/processone/ejabberd/issues/3890))
@@ -264,7 +923,8 @@ Core:
- `mod_shared_roster_ldap`: Update roster_get hook to use `#roster_item{}`
- `prosody2ejabberd`: Fix parsing of scram password from prosody
-MIX:
+#### MIX:
+
- Fix MIX's filter_nodes
- Return user jid on join
- `mod_mix_pam`: Add new MIX namespaces to disco features
@@ -279,12 +939,13 @@ MIX:
- `mod_roster`: Adapt to change of mix_annotate type to boolean in roster_query
- `mod_shared_roster`: Fix wrong hook type `#roster{}` (now `#roster_item{}`)
-MUC:
+#### MUC:
+
- Store role, and use it when joining a moderated room ([#3330](https://github.com/processone/ejabberd/issues/3330))
- Don't persist `none` role ([#3330](https://github.com/processone/ejabberd/issues/3330))
- Allow MUC service admins to bypass max_user_conferences limitation
- Show allow_query_users room option in disco info ([#3830](https://github.com/processone/ejabberd/issues/3830))
-- Don't set affiliation to `none` if it's already `none` in `mod_muc_room:process_item_change/3`
+- mod_muc_room: Don't set affiliation to `none` if it's already `none` in `process_item_change/3`
- Fix mucsub unsubscribe notification payload to have muc_unsubcribe in it
- Allow muc_{un}subscribe hooks to modify sent packets
- Pass room state to muc_{un}subscribed hook
@@ -292,7 +953,8 @@ MUC:
- Export `mod_muc_admin:get_room_pid/2`
- Export function for getting room diagnostics
-SQL:
+#### SQL:
+
- Handle errors reported from begin/commit inside transaction
- Make connection close errors bubble up from inside sql transaction
- Make first sql reconnect wait shorter time
@@ -304,7 +966,8 @@ SQL:
- Update mysql library
- Catch mysql connection being close earlier
-Build:
+#### Build:
+
- `make all`: Generate start scripts here, not in `make install` ([#3821](https://github.com/processone/ejabberd/issues/3821))
- `make clean`: Improve this and "distclean"
- `make deps`: Ensure deps configuration is ran when getting deps ([#3823](https://github.com/processone/ejabberd/issues/3823))
@@ -317,7 +980,8 @@ Build:
- Remove unused macro definitions detected by rebar3_hank
- Remove unused header files which content is already in xmpp library
-Container:
+#### Container:
+
- Get ejabberd-contrib sources to include them
- Copy `.ejabberd-modules` directory if available
- Do not clone repo inside container build
@@ -327,7 +991,8 @@ Container:
- Set a less frequent healthcheck to reduce CPU usage ([#3826](https://github.com/processone/ejabberd/issues/3826))
- Fix build instructions, add more podman examples
-Installers:
+#### Installers:
+
- make-binaries: Include CAPTCHA script with release
- make-binaries: Edit rebar.config more carefully
- make-binaries: Fix linking of EIMP dependencies
@@ -341,57 +1006,59 @@ Installers:
- make-installers: Override code on upgrade
- make-installers: Apply cosmetic changes
-External modules:
+#### External modules:
+
- ext_mod: Support managing remote nodes in the cluster
- ext_mod: Handle correctly when COMMIT.json not found
- Don't bother with COMMIT.json user-friendly feature in automated user case
- Handle not found COMMIT.json, for example in GH Actions
- Add WebAdmin page for managing external modules
-Workflows Actions:
+#### Workflows Actions:
+
- Update workflows to Erlang 25
- Update workflows: Ubuntu 18 is deprecated and 22 is added
- CI: Remove syntax_tools from applications, as fast_xml fails Dialyzer
- Runtime: Add Xref options to be as strict as CI
-# Version 22.05
+## Version 22.05
-Core
+#### Core
- C2S: Don't expect that socket will be available in `c2s_terminated` hook
- Event handling process hook tracing
- Guard against `erlang:system_info(logical_processors)` not always returning a number
- `domain_balancing`: Allow for specifying `type` only, without specifying `component_number`
-MQTT
+#### MQTT
- Add TLS certificate authentication for MQTT connections
- Fix login when generating client id, keep connection record (#3593)
- Pass property name as expected in mqtt_codec (fixes login using MQTT 5)
- Support MQTT subscriptions spread over the cluster (#3750)
-MUC
+#### MUC
- Attach meta field with real jid to mucsub subscription events
- Handle user removal
- Stop empty MUC rooms 30 seconds after creation
- `default_room_options`: Update options configurable
- `subscribe_room_many_max_users`: New option in `mod_muc_admin`
-mod_conversejs
+#### mod_conversejs
- Improved options to support `@HOST@` and `auto` values
- Set `auth` and `register` options based on ejabberd configuration
- `conversejs_options`: New option
- `conversejs_resources`: New option
-PubSub
+#### PubSub
- `mod_pubsub`: Allow for limiting `item_expire` value
- `mod_pubsub`: Unsubscribe JID on whitelist removal
- `node_pep`: Add config-node and multi-items features (#3714)
-SQL
+#### SQL
- Improve compatibility with various db engine versions
- Sync old-to-new schema script with reality (#3790)
- Slight improvement in MSSQL testing support, but not yet complete
-Other Modules
+#### Other Modules
- `auth_jwt`: Checking if an user is active in SM for a JWT authenticated user (#3795)
- `mod_configure`: Implement Get List of Registered/Online Users from XEP-0133
- `mod_host_meta`: New module to serve host-meta files, see XEP-0156
@@ -404,7 +1071,7 @@ Other Modules
- `mod_shared_roster`: Normalize JID on unset_presence (#3752)
- `mod_stun_disco`: Fix parsing of IPv6 listeners
-Dependencies
+#### Dependencies
- autoconf: Supported from 2.59 to the new 2.71
- fast_tls: Update to 1.1.14 to support OpenSSL 3
- jiffy: Update to 1.1.1 to support Erlang/OTP 25.0-rc1
@@ -414,7 +1081,7 @@ Dependencies
- rebar3: Updated binary to work from Erlang/OTP 22 to 25
- `make update`: Fix when used with rebar 3.18
-Compile
+#### Compile
- `mix release`: Copy `include/` files for ejabberd, deps and otp, in `mix.exs`
- `rebar3 release`: Fix ERTS path in `ejabberdctl`
- `configure.ac`: Set default ejabberd version number when not using git
@@ -423,7 +1090,7 @@ Compile
- `tools/make-binaries`: New script for building Linux binaries
- `tools/make-installers`: New script for building command line installers
-Start
+#### Start
- New `make relive` similar to `ejabberdctl live` without installing
- `ejabberdctl`: Fix some warnings detected by ShellCheck
- `ejabberdctl`: Mention in the help: `etop`, `ping` and `started`/`stopped`
@@ -431,7 +1098,7 @@ Start
- `mix.exs`: Add `-boot` and `-boot_var` in `ejabberdctl` instead of adding `vm.args`
- `tools/captcha.sh`: Fix some warnings detected by ShellCheck
-Commands
+#### Commands
- Accept more types of ejabberdctl commands arguments as JSON-encoded
- `delete_old_mam_messages_batch`: New command with rate limit
- `delete_old_messages_batch`: New command with rate limit
@@ -443,7 +1110,7 @@ Commands
- `stop|restart`: Terminate ejabberd_sm before everything else to ensure sessions closing (#3641)
- `subscribe_room_many`: New command
-Translations
+#### Translations
- Updated Catalan
- Updated French
- Updated German
@@ -451,7 +1118,7 @@ Translations
- Updated Portuguese (Brazil)
- Updated Spanish
-Workflows
+#### Workflows
- CI: Publish CT logs and Cover on failure to an external GH Pages repo
- CI: Test shell scripts using ShellCheck (#3738)
- Container: New workflow to build and publish containers
@@ -459,14 +1126,14 @@ Workflows
- Installers: New workflow to build binary packages
- Runtime: New workflow to test compilation, rel, starting and ejabberdctl
-# Version 21.12
+## Version 21.12
-Commands
+#### Commands
- `create_room_with_opts`: Fixed when using SQL storage
- `change_room_option`: Add missing fields from config inside `mod_muc_admin:change_options`
- piefxis: Fixed arguments of all commands
-Modules
+#### Modules
- mod_caps: Don't forget caps on XEP-0198 resumption
- mod_conversejs: New module to serve a simple page for Converse.js
- mod_http_upload_quota: Avoid `max_days` race
@@ -481,7 +1148,7 @@ Modules
- mod_register_web: Handle unknown host gracefully
- mod_register_web: Use mod_register configured restrictions
-PubSub
+#### PubSub
- Add `delete_expired_pubsub_items` command
- Add `delete_old_pubsub_items` command
- Optimize publishing on large nodes (SQL)
@@ -492,7 +1159,7 @@ PubSub
- node_flat: Avoid catch-all clauses for RSM
- node_flat_sql: Avoid catch-all clauses for RSM
-SQL
+#### SQL
- Use `INSERT ... ON CONFLICT` in SQL_UPSERT for PostgreSQL >= 9.5
- mod_mam export: assign MUC entries to the MUC service
- MySQL: Fix typo when creating index
@@ -500,15 +1167,15 @@ SQL
- PgSQL: Add missing SQL migration for table `push_session`
- PgSQL: Fix `vcard_search` definition in pgsql new schema
-Other
+#### Other
- `captcha-ng.sh`: "sort -R" command not POSIX, added "shuf" and "cat" as fallback
- Make s2s connection table cleanup more robust
- Update export/import of scram password to XEP-0227 1.1
- Update Jose to 1.11.1 (the last in hex.pm correctly versioned)
-# Version 21.07
+## Version 21.07
-Compilation
+#### Compilation
- Add rebar3 3.15.2 binary
- Add support for mix to: `./configure --enable-rebar=mix`
- Improved `make rel` to work with rebar3 and mix
@@ -520,14 +1187,16 @@ Compilation
- Added experimental support for GitHub Codespaces
- Switch test service from TravisCI to GitHub Actions
-Commands:
+#### Commands:
+
- Display extended error message in ejabberdctl
- Remove SMP option from ejabberdctl.cfg, `-smp` was removed in OTP 21
- `create_room`: After creating room, store in DB if it's persistent
- `help`: Major changes in its usage and output
- `srg_create`: Update to use `label` parameter instead of `name`
-Modules:
+#### Modules:
+
- ejabberd_listener: New `send_timeout` option
- mod_mix: Improvements to update to 0.14.1
- mod_muc_room: Don't leak owner JIDs
@@ -544,7 +1213,8 @@ Modules:
- WebAdmin: New simple pages to view mnesia tables information and content
- WebSocket: Fix typos
-SQL:
+#### SQL:
+
- MySQL Backend Patch for scram-sha512
- SQLite: When exporting for SQLite, use its specific escape options
- SQLite: Minor fixes for new_sql_schema support
@@ -552,16 +1222,18 @@ SQL:
- mod_mqtt: Add mqtt_pub table definition for MSSQL
- mod_shared_roster: Add missing indexes to `sr_group` tables in all SQL databases
-# Version 21.04
+## Version 21.04
+
+#### API Commands:
-API Commands:
- `add_rosteritem/...`: Add argument guards to roster commands
- `get_user_subscriptions`: New command for MUC/Sub
- `remove_mam_for_user_with_peer`: Fix when removing room archive
- `send_message`: Fix bug introduced in ejabberd 21.01
- `set_vcard`: Return modules errors
-Build and setup:
+#### Build and setup:
+
- Allow ejabberd to be compatible as a dependency for an Erlang project using rebar3
- CAPTCHA: New question/answer-based CAPTCHA script
- `--enable-lua`: new configure option for luerl instead of --enable-tools
@@ -569,14 +1241,16 @@ Build and setup:
- Update `sql_query` record to handle the Erlang/OTP 24 compiler reports
- Updated dependencies to fix Dialyzer warnings
-Miscellaneous:
+#### Miscellaneous:
+
- CAPTCHA: Update `FORM_TYPE` from captcha to register
- LDAP: fix eldap certificate verification
- MySQL: Fix for "specified key was too long"
- Translations: updated the Esperanto, Greek, and Japanese translations
- Websocket: Fix PONG responses
-Modules:
+#### Modules:
+
- `mod_block_strangers`: If stanza is type error, allow it passing
- `mod_caps`: Don't request roster when not needed
- `mod_caps`: Skip reading roster in one more case
@@ -590,9 +1264,10 @@ Modules:
- `mod_pubsub`: Fix `gen_pubsub_node:get_state` return value
- `mod_vcard`: Obtain and provide photo type in vCard LDAP
-# Version 21.01
+## Version 21.01
+
+#### Miscellaneous changes:
-Miscellaneous changes:
- `log_rotate_size` option: Fix handling of ‘infinity’ value
- `mod_time`: Fix invalid timezone
- Auth JWT: New `check_decoded_jwt` hook runs the default JWT verifier
@@ -607,7 +1282,8 @@ Miscellaneous changes:
- Stun: Block loopback addresses by default
- Several documentation fixes and clarifications
-Commands:
+#### Commands:
+
- `decide_room`: Use better fallback value for room activity time when skipping room
- `delete_old_message`: Fix when using sqlite spool table
- `module_install`: Make ext_mod compile module with debug_info flags
@@ -615,17 +1291,19 @@ Commands:
- `send_message`: Don’t include empty in messages
- `set_room_affiliation`: Validate affiliations
-Running:
+#### Running:
+
- Docker: New `Dockerfile` and `devcontainer.json`
- New `ejabberdctl foreground-quiet`
- Systemd: Allow for listening on privileged ports
- Systemd: Integrate nicely with systemd
-Translations:
+#### Translations:
+
- Moved gettext PO files to a new `ejabberd-po` repository
- Improved several translations: Catalan, Chinese, German, Greek, Indonesian, Norwegian, Portuguese (Brazil), Spanish.
-# Version 20.12
+## Version 20.12
- Add support for `SCRAM-SHA-{256,512}-{PLUS}` authentication
- Don't use same value in cache for user don't exist and wrong password
@@ -634,13 +1312,13 @@ Translations:
- start_room: new hook runs when a room process is started
- check_decoded_jwt: new hook to check decoded JWT after success authentication
-* Admin
+#### Admin
- Docker: Fix DB initialization
- New sql_odbc_driver option: choose the mssql ODBC driver
- Rebar3: Fully supported. Enable with `./configure --with-rebar=/path/to/rebar3`
- systemd: start ejabberd in foreground
-* Modules:
+#### Modules:
- MAM: Make sure that jid used as base in mam xml_compress is bare
- MAM: Support for MAM Flipped Pages
- MUC: Always show MucSub subscribers nicks
@@ -660,9 +1338,9 @@ Translations:
- WebAdmin: Mark dangerous buttons with CSS
- WebSocket: Make websocket send put back pressure on c2s process
-# Version 20.07
+## Version 20.07
-* Changes in this version
+#### Changes in this version
- Add support for using unix sockets in listeners.
- Make this version compatible with erlang R23
- Make room permissions checks more strict for subscribers
@@ -687,9 +1365,9 @@ Translations:
they were passed to handler modules
- Make stun module work better with ipv6 addresses
-# Version 20.03
+## Version 20.03
-* Changes in this version
+#### Changes in this version
- Add support of ssl connection when connection to mysql
database (configured with `sql_ssl: true` option)
- Experimental support for cockroachdb when configured
@@ -707,9 +1385,9 @@ Translations:
- Fix reporting errors in `send_stanza` command when xml
passed to it couldn't be passed correctly
-# Version 20.02
+## Version 20.02
-* Changes in this version
+#### Changes in this version
- Fix problems when trying to use string format with unicode
values directly in xmpp nodes
- Add missing oauth_client table declaration in lite.new.sql
@@ -725,9 +1403,9 @@ Translations:
override built-in values
- Fix return value of reload_config and dump_config commands
-# Version 20.01
+## Version 20.01
-* New features
+#### New features
- Implement OAUTH authentication in mqtt
- Make logging infrastructure use new logger introduced
in Erlang (requires OTP22)
@@ -742,7 +1420,7 @@ Translations:
- Generate man page automatically
- Implement copy feature in mod_carboncopy
-* Fixes
+#### Fixes
- Make webadmin work with configurable paths
- Fix handling of result in xmlrpc module
- Make webadmin work even when accessed through not declared domain
@@ -758,20 +1436,20 @@ Translations:
failed
- Fix crash in stream management when timeout was not set
-# Version 19.09
+## Version 19.09
-* Admin
+#### Admin
- The minimum required Erlang/OTP version is now 19.3
- Fix API call using OAuth (#2982)
- Rename MUC command arguments from Host to Service (#2976)
-* Webadmin
+#### Webadmin
- Don't treat 'Host' header as a virtual XMPP host (#2989)
- Fix some links to Guide in WebAdmin and add new ones (#3003)
- Use select fields to input host in WebAdmin Backup (#3000)
- Check account auth provided in WebAdmin is a local host (#3000)
-* ACME
+#### ACME
- Improve ACME implementation
- Fix IDA support in ACME requests
- Fix unicode formatting in ACME module
@@ -782,10 +1460,10 @@ Translations:
- Don't auto request certificate for localhost and IP-like domains
- Add listener for ACME challenge in example config
-* Authentication
+#### Authentication
- JWT-only authentication for some users (#3012)
-* MUC
+#### MUC
- Apply default role after revoking admin affiliation (#3023)
- Custom exit message is not broadcast (#3004)
- Revert "Affiliations other than admin and owner cannot invite to members_only rooms" (#2987)
@@ -793,11 +1471,11 @@ Translations:
- Improve rooms_* commands to accept 'global' as MUC service argument (#2976)
- Rename MUC command arguments from Host to Service (#2976)
-* SQL
+#### SQL
- Fix transactions for Microsoft SQL Server (#2978)
- Spawn SQL connections on demand only
-* Misc
+#### Misc
- Add support for XEP-0328: JID Prep
- Added gsfonts for captcha
- Log Mnesia table type on creation
@@ -811,14 +1489,14 @@ Translations:
- Correctly handle unicode in log messages
- Fix unicode processing in ejabberd.yml
-# Version 19.08
+## Version 19.08
-* Administration
+#### Administration
- Improve ejabberd halting procedure
- Process unexpected erlang messages uniformly: logging a warning
- mod_configure: Remove modules management
-* Configuration
+#### Configuration
- Use new configuration validator
- ejabberd_http: Use correct virtual host when consulting trusted_proxies
- Fix Elixir modules detection in the configuration file
@@ -828,7 +1506,7 @@ Translations:
- mod_stream_mgmt: Allow flexible timeout format
- mod_mqtt: Allow flexible timeout format in session_expiry option
-* Misc
+#### Misc
- Fix SQL connections leakage
- New authentication method using JWT tokens
- extauth: Add 'certauth' command
@@ -843,22 +1521,22 @@ Translations:
- mod_privacy: Don't attempt to query 'undefined' active list
- mod_privacy: Fix race condition
-* MUC
+#### MUC
- Add code for hibernating inactive muc_room processes
- Improve handling of unexpected iq in mod_muc_room
- Attach mod_muc_room processes to a supervisor
- Restore room when receiving message or generic iq for not started room
- Distribute routing of MUC messages across all CPU cores
-* PubSub
+#### PubSub
- Fix pending nodes retrieval for SQL backend
- Check access_model when publishing PEP
- Remove deprecated pubsub plugins
- Expose access_model and publish_model in pubsub#metadata
-# Version 19.05
+## Version 19.05
-* Admin
+#### Admin
- The minimum required Erlang/OTP version is now 19.1
- Provide a suggestion when unknown command, module, option or request handler is detected
- Deprecate some listening options: captcha, register, web_admin, http_bind and xmlrpc
@@ -869,19 +1547,19 @@ Translations:
- Improve request_handlers validator
- Fix syntax in example Elixir config file
-* Auth
+#### Auth
- Correctly support cache tags in ejabberd_auth
- Don't process failed EXTERNAL authentication by mod_fail2ban
- Don't call to mod_register when it's not loaded
- Make anonymous auth don't {de}register user when there are other resources
-* Developer
+#### Developer
- Rename listening callback from start/2 to start/3
- New hook called when room gets destroyed: room_destroyed
- New hooks for tracking mucsub subscriptions changes: muc_subscribed, muc_unsubscribed
- Make static hooks analyzer working again
-* MUC
+#### MUC
- Service admins are allowed to recreate room even if archive is nonempty
- New option user_mucsub_from_muc_archive
- Avoid late arrival of get_disco_item response
@@ -890,7 +1568,7 @@ Translations:
- Make get_subscribed_rooms work even for non-persistant rooms
- Allow non-moderator subscribers to get list of room subscribers
-* Offline
+#### Offline
- New option bounce_groupchat: make it not bounce mucsub/groupchat messages
- New option use_mam_for_storage: fetch data from mam instead of spool table
- When applying limit of max msgs in spool check only spool size
@@ -902,27 +1580,27 @@ Translations:
- Return correct value from count_offline_messages with mam storage option
- Make mod_offline put msg ignored by mam in spool when mam storage is on
-* SQL:
+#### SQL:
- Add SQL schemas for MQTT tables
- Report better errors on SQL terms decode failure
- Fix PostgreSQL compatibility in mod_offline_sql:remove_old_messages
- Fix handling of list arguments on pgsql
- Preliminary support for SQL in process_rosteritems command
-* Tests
+#### Tests
- Add tests for user mucsub mam from muc mam
- Add tests for offline with mam storage
- Add tests for offline use_mam_for_storage
- Initial Docker environment to run ejabberd test suite
- Test offline:use_mam_for_storage, mam:user_mucsub_from_muc_archive used together
-* Websocket
+#### Websocket
- Add WebSockets support to mod_mqtt
- Return "Bad request" error when origin in websocket connection doesn't match
- Fix RFC6454 violation on websocket connection when validating Origin header
- Origin header validation on websocket connection
-* Other modules
+#### Other modules
- mod_adhoc: Use xml:lang from stanza when it's missing in element
- mod_announce: Add 'sessionid' attribute when required
- mod_bosh: Don't put duplicate polling attribute in bosh payload
@@ -933,16 +1611,16 @@ Translations:
- mod_mqtt: Support other socket modules
- mod_push: Check for payload in encrypted messages
-# Version 19.02
+## Version 19.02
-* Admin
+#### Admin
- Fix in configure.ac the Erlang/OTP version: from 17.5 to 19.0
- reload_config command: Fix crash when sql_pool_size option is used
- reload_config command: Fix crash when SQL is not configured
- rooms_empty_destroy command: Several fixes to behave more conservative
- Fix serverhost->host parameter name for muc_(un)register_nick API
-* Configuration
+#### Configuration
- Allow specifying tag for listener for api_permission purposes
- Change default ciphers to intermediate
- Define default ciphers/protocol_option in example config
@@ -952,29 +1630,29 @@ Translations:
- mod_muc: New option access_mam to restrict who can modify that room option
- mod_offline: New option store_groupchat to allow storing group chat messages
-* Core
+#### Core
- Add MQTT protocol support
- Fix (un)setting of priority
- Use OTP application startup infrastructure for starting dependencies
- Improve starting order of several dependencies
-* MAM
+#### MAM
- mod_mam_mnesia/sql: Improve check for empty archive
- disallow room creation if archive not empty and clear_archive_on_room_destroy is false
- allow check if archive is empty for or user or room
- Additional checks for database failures
-* MUC
+#### MUC
- Make sure that room_destroyed is called even when some code throws in terminate
- Update muc room state after adding extra access field to it
- MUC/Sub: Send mucsub subscriber notification events with from set to room jid
-* Shared Roster
+#### Shared Roster
- Don't perform roster push for non-local contacts
- Handle versioning result when shared roster group has remote account
- Fix SQL queries
-* Miscelanea
+#### Miscelanea
- CAPTCHA: Add no-store hint to CAPTCHA challenge stanzas
- HTTP: Reject http_api request with malformed Authentication header
- mod_carboncopy: Don't lose carbons on presence change or session resumption
@@ -987,9 +1665,9 @@ Translations:
- Translations: fixed "make translations"
- WebAdmin: Fix support to restart module with new options
-# Version 18.12
+## Version 18.12
-* MAM data store compression
-* Proxy protocol support
-* MUC Self-Ping optimization (XEP-0410)
-* Bookmarks conversion (XEP-0411)
+- MAM data store compression
+- Proxy protocol support
+- MUC Self-Ping optimization (XEP-0410)
+- Bookmarks conversion (XEP-0411)
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index a9145ba2f..e8855889e 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -22,6 +22,21 @@ Examples of unacceptable behavior by participants include:
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
+## Guidelines for Respectful and Efficient Communication on Issues, Discussions, and PRs
+
+To ensure that our maintainers can efficiently manage issues and provide timely updates, we kindly ask that all comments on GitHub tickets remain relevant to the topic of the issue. Please avoid posting comments solely to ping maintainers or ask for updates. If you need information on the status of an issue, consider the following:
+
+- **Check the Issue Timeline:** Review the existing comments and updates on the issue before posting.
+- **Use Reactions:** If you want to show that you are interested in an issue, use GitHub's reaction feature (e.g., thumbs up) instead of commenting.
+- **Be Patient:** Understand that maintainers may be working on multiple tasks and will provide updates as soon as possible.
+
+Additionally, please be aware that:
+
+- **User Responses:** Users who report issues may no longer be using the software, may have switched to other projects, or may simply be busy. It is their right not to respond to follow-up questions or comments.
+- **Maintainer Priorities:** Maintainers have the right to define their own priorities and schedule. They will address issues based on their availability and the project's needs.
+
+By following these guidelines, you help us maintain a productive and respectful environment for everyone involved.
+
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
@@ -40,7 +55,7 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai
## Attribution
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
+[homepage]: https://www.contributor-covenant.org/
+[version]: https://www.contributor-covenant.org/version/1/4/
diff --git a/COMPILE.md b/COMPILE.md
index c6b10800a..2eb8a1739 100644
--- a/COMPILE.md
+++ b/COMPILE.md
@@ -7,7 +7,7 @@ from source code.
For a more detailed explanation, please check the
ejabberd Docs: [Source Code Installation][docs-source].
-[docs-source]: https://docs.ejabberd.im/admin/installation/#source-code
+[docs-source]: https://docs.ejabberd.im/admin/install/source/
Requirements
@@ -19,7 +19,7 @@ To compile ejabberd you need:
- GCC
- Libexpat ≥ 1.95
- Libyaml ≥ 0.1.4
-- Erlang/OTP ≥ 20.0
+- Erlang/OTP ≥ 25.0
- OpenSSL ≥ 1.0.0
Other optional libraries are:
@@ -28,7 +28,7 @@ Other optional libraries are:
- 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
+- Elixir ≥ 1.10.3, for Elixir support. It is recommended Elixir 1.14.0 or higher
If your system splits packages in libraries and development headers,
install the development packages too.
@@ -43,7 +43,7 @@ There are several ways to obtain the ejabberd source code:
- Source code package from [ejabberd GitHub Releases][ghr]
- Latest development code from [ejabberd Git repository][gitrepo]
-[p1dl]: https://www.process-one.net/en/ejabberd/downloads/
+[p1dl]: https://www.process-one.net/download/ejabberd/
[ghr]: https://github.com/processone/ejabberd/releases
[gitrepo]: https://github.com/processone/ejabberd
@@ -65,6 +65,11 @@ To configure the compilation, features, install paths...
./configure --help
+The build tool automatically downloads and compiles the
+erlang libraries that [ejabberd depends on][docs-repo].
+
+[docs-repo]: https://docs.ejabberd.im/developer/repositories/
+
Install in the System
---------------------
@@ -89,13 +94,8 @@ Build an OTP Release
Instead of installing ejabberd in the system, you can build an OTP release
that includes all necessary to run ejabberd in a subdirectory:
- ./configure --with-rebar=rebar3
- make rel
-
-Or, if you have Elixir available and plan to develop Elixir code:
-
- ./configure --with-rebar=mix
- make dev
+ ./configure
+ make prod
Check the full list of targets:
diff --git a/CONTAINER.md b/CONTAINER.md
index 7c7c233ef..e96081112 100644
--- a/CONTAINER.md
+++ b/CONTAINER.md
@@ -1,41 +1,44 @@
[](https://github.com/processone/ejabberd/tags)
-[](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
+[](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
+[](https://hub.docker.com/r/ejabberd/ecs/)
-
-`ejabberd` Container Image
-==========================
+ejabberd Container Images
+=========================
[ejabberd][home] is an open-source,
robust, scalable and extensible realtime platform built using [Erlang/OTP][erlang],
that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service.
-[home]: https://ejabberd.im/
+[home]: https://www.ejabberd.im/
[erlang]: https://www.erlang.org/
[xmpp]: https://xmpp.org/
[mqtt]: https://mqtt.org/
[sip]: https://en.wikipedia.org/wiki/Session_Initiation_Protocol
-This document explains how to use the `ejabberd` container image available in
-[ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd),
-built using the files in `.github/container/`.
-This image is based in Alpine 3.17, includes Erlang/OTP 25.3 and Elixir 1.14.4.
+This page documents those container images ([images comparison](#images-comparison)):
-Alternatively, there is also the `ecs` container image available in
-[docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/),
-built using the
-[docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs)
-repository.
-Check the [differences between `ejabberd` and `ecs` images](https://github.com/processone/docker-ejabberd/blob/master/ecs/HUB-README.md#alternative-image-in-github).
+- [](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
+ published in [ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd),
+ built using [ejabberd](https://github.com/processone/ejabberd/tree/master/.github/container) repository,
+ both for stable ejabberd releases and the `master` branch, in x64 and arm64 architectures.
-If you are using a Windows operating system, check the tutorials mentioned in
-[ejabberd Docs > Docker Image](https://docs.ejabberd.im/admin/installation/#docker-image).
+- [](https://hub.docker.com/r/ejabberd/ecs/)
+ published in [docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/),
+ built using [docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs) repository
+ for ejabberd stable releases in x64 architectures.
+
+For Microsoft Windows, see
+[Docker Desktop for Windows 10](https://www.process-one.net/blog/install-ejabberd-on-windows-10-using-docker-desktop/),
+and [Docker Toolbox for Windows 7](https://www.process-one.net/blog/install-ejabberd-on-windows-7-using-docker-toolbox/).
+
+For Kubernetes Helm, see [help-ejabberd](https://github.com/sando38/helm-ejabberd).
Start ejabberd
-==============
+--------------
-## With default configuration
+### daemon
Start ejabberd in a new container:
@@ -44,13 +47,7 @@ docker run --name ejabberd -d -p 5222:5222 ghcr.io/processone/ejabberd
```
That runs the container as a daemon,
-using ejabberd default configuration file and XMPP domain "localhost".
-
-Stop the running container:
-
-```bash
-docker stop ejabberd
-```
+using ejabberd default configuration file and XMPP domain `localhost`.
Restart the stopped ejabberd container:
@@ -58,60 +55,91 @@ Restart the stopped ejabberd container:
docker restart ejabberd
```
+Stop the running container:
-## Start with Erlang console attached
+```bash
+docker stop ejabberd
+```
-Start ejabberd with an Erlang console attached using the `live` command:
+Remove the ejabberd container:
+
+```bash
+docker rm ejabberd
+```
+
+
+### with Erlang console
+
+Start ejabberd with an interactive Erlang console attached using the `live` command:
```bash
docker run --name ejabberd -it -p 5222:5222 ghcr.io/processone/ejabberd live
```
-That uses the default configuration file and XMPP domain "localhost".
+That uses the default configuration file and XMPP domain `localhost`.
-## Start with your configuration and database
+### with your data
Pass a configuration file as a volume
and share the local directory to store database:
```bash
-mkdir database
-chown ejabberd database
+mkdir conf && cp ejabberd.yml.example conf/ejabberd.yml
-cp ejabberd.yml.example ejabberd.yml
+mkdir database && chown ejabberd database
docker run --name ejabberd -it \
- -v $(pwd)/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml \
+ -v $(pwd)/conf/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml \
-v $(pwd)/database:/opt/ejabberd/database \
-p 5222:5222 ghcr.io/processone/ejabberd live
```
-Notice that ejabberd runs in the container with an account named `ejabberd`,
+Notice that ejabberd runs in the container with an account named `ejabberd`
+with UID 9000 and group `ejabberd` with GID 9000,
and the volumes you mount must grant proper rights to that account.
Next steps
-==========
+----------
-## Register the administrator account
+### Register admin account
-The default ejabberd configuration does not grant admin privileges
-to any account,
-you may want to register a new account in ejabberd
-and grant it admin rights.
+#### [](https://github.com/processone/ejabberd/pkgs/container/ejabberd) [:orange_circle:](#images-comparison)
-Register an account using the `ejabberdctl` script:
+If you set the `REGISTER_ADMIN_PASSWORD` environment variable,
+an account is automatically registered with that password,
+and admin privileges are granted to it.
+The account created depends on what variables you have set:
+
+- `EJABBERD_MACRO_ADMIN=juliet@example.org` -> `juliet@example.org`
+- `EJABBERD_MACRO_HOST=example.org` -> `admin@example.org`
+- None of those variables are set -> `admin@localhost`
+
+The account registration is shown in the container log:
+
+```
+:> ejabberdctl register admin example.org somePassw0rd
+User admin@example.org successfully registered
+```
+
+Alternatively, you can register the account manually yourself
+and edit `conf/ejabberd.yml` and add the ACL as explained in
+[ejabberd Docs: Administration Account](https://docs.ejabberd.im/admin/install/next-steps/#administration-account).
+
+---
+
+#### [](https://hub.docker.com/r/ejabberd/ecs/)
+
+The default ejabberd configuration has already granted admin privilege
+to an account that would be called `admin@localhost`,
+so you just need to register it, for example:
```bash
docker exec -it ejabberd ejabberdctl register admin localhost passw0rd
```
-Then edit conf/ejabberd.yml and add the ACL as explained in
-[ejabberd Docs: Administration Account](https://docs.ejabberd.im/admin/installation/#administration-account)
-
-
-## Check ejabberd log files
+### Check ejabberd log
Check the content of the log files inside the container,
even if you do not put it on a shared persistent drive:
@@ -121,7 +149,7 @@ docker exec -it ejabberd tail -f logs/ejabberd.log
```
-## Inspect the container files
+### Inspect container files
The container uses Alpine Linux. Start a shell inside the container:
@@ -130,7 +158,7 @@ docker exec -it ejabberd sh
```
-## Open ejabberd debug console
+### Open debug console
Open an interactive debug Erlang console attached to a running ejabberd in a running container:
@@ -139,7 +167,7 @@ docker exec -it ejabberd ejabberdctl debug
```
-## CAPTCHA
+### CAPTCHA
ejabberd includes two example CAPTCHA scripts.
If you want to use any of them, first install some additional required libraries:
@@ -155,7 +183,7 @@ docker exec -it ejabberd vi conf/ejabberd.yml
and add this option:
```yaml
-captcha_cmd: /opt/ejabberd-22.04/lib/captcha.sh
+captcha_cmd: "$HOME/bin/captcha.sh"
```
Finally, reload the configuration file or restart the container:
@@ -176,23 +204,25 @@ For more details about CAPTCHA options, please check the
documentation section.
-Advanced Container Configuration
-================================
+Advanced
+--------
-## Ports
+### Ports
-This container image exposes the ports:
+The container image exposes several ports
+(check also [Docs: Firewall Settings](https://docs.ejabberd.im/admin/guide/security/#firewall-settings)):
- `5222`: The default port for XMPP clients.
- `5269`: For XMPP federation. Only needed if you want to communicate with users on other servers.
-- `5280`: For admin interface.
+- `5280`: For admin interface (URL is `admin/`).
+- `1880`: For admin interface (URL is `/`, useful for [podman-desktop](https://podman-desktop.io/) and [docker-desktop](https://www.docker.com/products/docker-desktop/)) [:orange_circle:](#images-comparison)
- `5443`: With encryption, used for admin interface, API, CAPTCHA, OAuth, Websockets and XMPP BOSH.
- `1883`: Used for MQTT
- `4369-4399`: EPMD and Erlang connectivity, used for `ejabberdctl` and clustering
-- `5210`: Erlang connectivity when `ERL_DIST_PORT` is set, alternative to EPMD
+- `5210`: Erlang connectivity when `ERL_DIST_PORT` is set, alternative to EPMD [:orange_circle:](#images-comparison)
-## Volumes
+### Volumes
ejabberd produces two types of data: log files and database spool files (Mnesia).
This is the kind of data you probably want to store on a persistent or local drive (at least the database).
@@ -206,14 +236,29 @@ You should back up or export the content of the directory to persistent storage
- `/opt/ejabberd/logs/`: Directory containing log files
- `/opt/ejabberd/upload/`: Directory containing uploaded files. This should also be backed up.
-All these files are owned by `ejabberd` user inside the container.
+All these files are owned by an account named `ejabberd` with group `ejabberd` in the container.
+Its corresponding `UID:GID` is `9000:9000`.
+If you prefer bind mounts instead of volumes, then
+you need to map this to valid `UID:GID` on your host to get read/write access on
+mounted directories.
-It's possible to install additional ejabberd modules using volumes,
-[this comment](https://github.com/processone/docker-ejabberd/issues/81#issuecomment-1036115146)
-explains how to install an additional module using docker-compose.
+If using Docker, try:
+```bash
+mkdir database
+sudo chown 9000:9000 database
+```
+
+If using Podman, try:
+```bash
+mkdir database
+podman unshare chown 9000:9000 database
+```
+
+It's possible to install additional ejabberd modules using volumes, check
+[this Docs tutorial](https://docs.ejabberd.im/developer/extending-ejabberd/modules/#your-module-in-ejabberd-modules-with-ejabberd-container).
-## Commands on start
+### Commands on start
The ejabberdctl script reads the `CTL_ON_CREATE` environment variable
the first time the container is started,
@@ -221,17 +266,240 @@ 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.
-Example usage (or check the [full example](#customized-example)):
+If any of those commands returns a failure, the container starting gets aborted.
+If there is a command with a result that can be ignored,
+prefix that command with `!`
+
+This example, registers an `admin@localhost` account when the container is first created.
+Everytime the container starts, it shows the list of registered accounts,
+checks that the admin account exists and password is valid,
+changes the password of an account if it exists (ignoring any failure),
+and shows the ejabberd starts (check also the [full example](#customized-example)):
```yaml
environment:
- CTL_ON_CREATE=register admin localhost asd
- CTL_ON_START=stats registeredusers ;
check_password admin localhost asd ;
+ ! change_password bot123 localhost qqq ;
status
```
-## Clustering
+### Macros in environment [:high_brightness:](#images-comparison)
+
+ejabberd reads `EJABBERD_MACRO_*` environment variables
+and uses them to define the corresponding
+[macros](https://docs.ejabberd.im/admin/configuration/file-format/#macros-in-configuration-file),
+overwriting the corresponding macro definition if it was set in the configuration file.
+This is supported since ejabberd 24.12.
+
+For example, if you configure this in `ejabberd.yml`:
+
+```yaml
+acl:
+ admin:
+ user: ADMIN
+```
+
+now you can define the admin account JID using an environment variable:
+```yaml
+ environment:
+ - EJABBERD_MACRO_ADMIN=admin@localhost
+```
+
+Check the [full example](#customized-example) for other example.
+
+
+### ejabberd-contrib
+
+This section addresses those topics related to
+[ejabberd-contrib](https://docs.ejabberd.im/admin/guide/modules/#ejabberd-contrib):
+
+- [Download source code](#download-source-code)
+- [Install a module](#install-a-module)
+- [Install git for dependencies](#install-git-for-dependencies)
+- [Install your module](#install-your-module)
+
+---
+
+#### Download source code
+
+The `ejabberd` container image includes the ejabberd-contrib git repository source code,
+but `ecs` does not, so first download it:
+```bash
+$ docker exec ejabberd ejabberdctl modules_update_specs
+```
+
+#### Install a module
+
+Compile and install any of the contributed modules, for example:
+```bash
+docker exec ejabberd ejabberdctl module_install mod_statsdx
+
+Module mod_statsdx has been installed and started.
+It's configured in the file:
+ /opt/ejabberd/.ejabberd-modules/mod_statsdx/conf/mod_statsdx.yml
+Configure the module in that file, or remove it
+and configure in your main ejabberd.yml
+```
+
+#### Install git for dependencies
+
+Some modules depend on erlang libraries,
+but the container images do not include `git` or `mix` to download them.
+Consequently, when you attempt to install such a module,
+there will be error messages like:
+
+```bash
+docker exec ejabberd ejabberdctl module_install ejabberd_observer_cli
+
+I'll download "recon" using git because I can't use Mix to fetch from hex.pm:
+ /bin/sh: mix: not found
+Fetching dependency observer_cli:
+ /bin/sh: git: not found
+...
+```
+
+the solution is to install `git` in the container image:
+
+```bash
+docker exec --user root ejabberd apk add git
+
+fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
+fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
+(1/3) Installing pcre2 (10.43-r0)
+(2/3) Installing git (2.47.2-r0)
+(3/3) Installing git-init-template (2.47.2-r0)
+Executing busybox-1.37.0-r12.trigger
+OK: 27 MiB in 42 packages
+```
+
+and now you can upgrade the module:
+
+```bash
+docker exec ejabberd ejabberdctl module_upgrade ejabberd_observer_cli
+
+I'll download "recon" using git because I can't use Mix to fetch from hex.pm:
+/bin/sh: mix: not found
+Fetching dependency observer_cli: Cloning into 'observer_cli'...
+Fetching dependency os_stats: Cloning into 'os_stats'...
+Fetching dependency recon: Cloning into 'recon'...
+Inlining: inline_size=24 inline_effort=150
+Old inliner: threshold=0 functions=[{insert,2},{merge,2}]
+Module ejabberd_observer_cli has been installed.
+Now you can configure it in your ejabberd.yml
+I'll download "recon" using git because I can't use Mix to fetch from hex.pm:
+/bin/sh: mix: not found
+```
+
+#### Install your module
+
+If you [developed an ejabberd module](https://docs.ejabberd.im/developer/extending-ejabberd/modules/),
+you can install it in your container image:
+
+1. Create a local directory for `ejabberd-modules`:
+
+ ``` sh
+ mkdir docker-modules
+ ```
+
+2. Then create the directory structure for your custom module:
+
+ ``` sh
+ cd docker-modules
+
+ mkdir -p sources/mod_hello_world/
+ touch sources/mod_hello_world/mod_hello_world.spec
+
+ mkdir sources/mod_hello_world/src/
+ mv mod_hello_world.erl sources/mod_hello_world/src/
+
+ mkdir sources/mod_hello_world/conf/
+ echo -e "modules:\n mod_hello_world: {}" > sources/mod_hello_world/conf/mod_hello_world.yml
+
+ cd ..
+ ```
+
+3. Grant ownership of that directory to the UID that ejabberd will use inside the Docker image:
+
+ ``` sh
+ sudo chown 9000 -R docker-modules/
+ ```
+
+4. Start ejabberd in the container:
+
+ ``` sh
+ sudo docker run \
+ --name hellotest \
+ -d \
+ --volume "$(pwd)/docker-modules:/home/ejabberd/.ejabberd-modules/" \
+ -p 5222:5222 \
+ -p 5280:5280 \
+ ejabberd/ecs
+ ```
+
+5. Check the module is available for installing, and then install it:
+
+ ``` sh
+ sudo docker exec -it hellotest ejabberdctl modules_available
+ mod_hello_world []
+
+ sudo docker exec -it hellotest ejabberdctl module_install mod_hello_world
+ ```
+
+6. If the module works correctly, you will see `Hello` in the ejabberd logs when it starts:
+
+ ``` sh
+ sudo docker exec -it hellotest grep Hello logs/ejabberd.log
+ 2020-10-06 13:40:13.154335+00:00 [info]
+ <0.492.0>@mod_hello_world:start/2:15 Hello, ejabberd world!
+ ```
+
+
+### ejabberdapi
+
+When the container is running (and thus ejabberd), you can exec commands inside the container
+using `ejabberdctl` or any other of the available interfaces, see
+[Understanding ejabberd "commands"](https://docs.ejabberd.im/developer/ejabberd-api/#understanding-ejabberd-commands)
+
+Additionally, the container image includes the `ejabberdapi` executable.
+Please check the [ejabberd-api homepage](https://github.com/processone/ejabberd-api)
+for configuration and usage details.
+
+For example, if you configure ejabberd like this:
+```yaml
+listen:
+ -
+ port: 5282
+ module: ejabberd_http
+ request_handlers:
+ "/api": mod_http_api
+
+acl:
+ loopback:
+ ip:
+ - 127.0.0.0/8
+ - ::1/128
+ - ::FFFF:127.0.0.1/128
+
+api_permissions:
+ "admin access":
+ who:
+ access:
+ allow:
+ acl: loopback
+ what:
+ - "register"
+```
+
+Then you could register new accounts with this query:
+
+```bash
+docker exec -it ejabberd ejabberdapi register --endpoint=http://127.0.0.1:5282/ --jid=admin@localhost --password=passw0rd
+```
+
+
+### Clustering
When setting several containers to form a
[cluster of ejabberd nodes](https://docs.ejabberd.im/admin/guide/clustering/),
@@ -241,23 +509,27 @@ and the same
[Erlang Cookie](https://docs.ejabberd.im/admin/guide/security/#erlang-cookie).
For this you can either:
+
- edit `conf/ejabberdctl.cfg` and set variables `ERLANG_NODE` and `ERLANG_COOKIE`
- set the environment variables `ERLANG_NODE_ARG` and `ERLANG_COOKIE`
+---
+
Example to connect a local `ejabberdctl` to a containerized ejabberd:
+
1. When creating the container, export port 5210, and set `ERLANG_COOKIE`:
-```
-docker run --name ejabberd -it \
- -e ERLANG_COOKIE=`cat $HOME/.erlang.cookie` \
- -p 5210:5210 -p 5222:5222 \
- ghcr.io/processone/ejabberd
-```
-2. Set `ERL_DIST_PORT=5210` in ejabberdctl.cfg of container and local ejabberd
+ ```sh
+ docker run --name ejabberd -it \
+ -e ERLANG_COOKIE=`cat $HOME/.erlang.cookie` \
+ -p 5210:5210 -p 5222:5222 \
+ ghcr.io/processone/ejabberd
+ ```
+2. Set `ERL_DIST_PORT=5210` in `ejabberdctl.cfg` of container and local ejabberd
3. Restart the container
4. Now use `ejabberdctl` in your local ejabberd deployment
To connect using a local `ejabberd` script:
-```
+```sh
ERL_DIST_PORT=5210 _build/dev/rel/ejabberd/bin/ejabberd ping
```
@@ -268,19 +540,175 @@ Example using environment variables (see full example [docker-compose.yml](https
- ERLANG_COOKIE=dummycookie123
```
+---
-Build a Container Image
-=======================
+Once you have the ejabberd nodes properly set and running,
+you can tell the secondary nodes to join the master node using the
+[`join_cluster`](https://docs.ejabberd.im/developer/ejabberd-api/admin-api/#join-cluster)
+API call.
-This container image includes ejabberd as a standalone OTP release built using Elixir.
-That OTP release is configured with:
+Example using environment variables (see the full
+[`docker-compose.yml` clustering example](#clustering-example)):
+```yaml
+environment:
+ - ERLANG_NODE_ARG=ejabberd@replica
+ - ERLANG_COOKIE=dummycookie123
+ - CTL_ON_CREATE=join_cluster ejabberd@main
+```
+
+### Change Mnesia Node Name
+
+To use the same Mnesia database in a container with a different hostname,
+it is necessary to change the old hostname stored in Mnesia.
+
+This section is equivalent to the ejabberd Documentation
+[Change Computer Hostname](https://docs.ejabberd.im/admin/guide/managing/#change-computer-hostname),
+but particularized to containers that use this
+`ecs` container image from ejabberd 23.01 or older.
+
+#### Setup Old Container
+
+Let's assume a container running ejabberd 23.01 (or older) from
+this `ecs` container image, with the database directory binded
+and one registered account.
+This can be produced with:
+```bash
+OLDCONTAINER=ejaold
+NEWCONTAINER=ejanew
+
+mkdir database
+sudo chown 9000:9000 database
+docker run -d --name $OLDCONTAINER -p 5222:5222 \
+ -v $(pwd)/database:/opt/ejabberd/database \
+ ghcr.io/processone/ejabberd:23.01
+docker exec -it $OLDCONTAINER ejabberdctl started
+docker exec -it $OLDCONTAINER ejabberdctl register user1 localhost somepass
+docker exec -it $OLDCONTAINER ejabberdctl registered_users localhost
+```
+
+Methods to know the Erlang node name:
+```bash
+ls database/ | grep ejabberd@
+docker exec -it $OLDCONTAINER ejabberdctl status
+docker exec -it $OLDCONTAINER grep "started in the node" logs/ejabberd.log
+```
+
+#### Change Mnesia Node
+
+First of all let's store the Erlang node names and paths in variables.
+In this example they would be:
+```bash
+OLDCONTAINER=ejaold
+NEWCONTAINER=ejanew
+OLDNODE=ejabberd@95145ddee27c
+NEWNODE=ejabberd@localhost
+OLDFILE=/opt/ejabberd/database/old.backup
+NEWFILE=/opt/ejabberd/database/new.backup
+```
+
+1. Start your old container that can still read the Mnesia database correctly.
+If you have the Mnesia spool files,
+but don't have access to the old container anymore, go to
+[Create Temporary Container](#create-temporary-container)
+and later come back here.
+
+2. Generate a backup file and check it was created:
+```bash
+docker exec -it $OLDCONTAINER ejabberdctl backup $OLDFILE
+ls -l database/*.backup
+```
+
+3. Stop ejabberd:
+```bash
+docker stop $OLDCONTAINER
+```
+
+4. Create the new container. For example:
+```bash
+docker run \
+ --name $NEWCONTAINER \
+ -d \
+ -p 5222:5222 \
+ -v $(pwd)/database:/opt/ejabberd/database \
+ ghcr.io/processone/ejabberd:latest
+```
+
+5. Convert the backup file to new node name:
+```bash
+docker exec -it $NEWCONTAINER ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE
+```
+
+6. Install the backup file as a fallback:
+```bash
+docker exec -it $NEWCONTAINER ejabberdctl install_fallback $NEWFILE
+```
+
+7. Restart the container:
+```bash
+docker restart $NEWCONTAINER
+```
+
+8. Check that the information of the old database is available.
+In this example, it should show that the account `user1` is registered:
+```bash
+docker exec -it $NEWCONTAINER ejabberdctl registered_users localhost
+```
+
+9. When the new container is working perfectly with the converted Mnesia database,
+you may want to remove the unneeded files:
+the old container, the old Mnesia spool files, and the backup files.
+
+#### Create Temporary Container
+
+In case the old container that used the Mnesia database is not available anymore,
+a temporary container can be created just to read the Mnesia database
+and make a backup of it, as explained in the previous section.
+
+This method uses `--hostname` command line argument for docker,
+and `ERLANG_NODE_ARG` environment variable for ejabberd.
+Their values must be the hostname of your old container
+and the Erlang node name of your old ejabberd node.
+To know the Erlang node name please check
+[Setup Old Container](#setup-old-container).
+
+Command line example:
+```bash
+OLDHOST=${OLDNODE#*@}
+docker run \
+ -d \
+ --name $OLDCONTAINER \
+ --hostname $OLDHOST \
+ -p 5222:5222 \
+ -v $(pwd)/database:/opt/ejabberd/database \
+ -e ERLANG_NODE_ARG=$OLDNODE \
+ ghcr.io/processone/ejabberd:latest
+```
+
+Check the old database content is available:
+```bash
+docker exec -it $OLDCONTAINER ejabberdctl registered_users localhost
+```
+
+Now that you have ejabberd running with access to the Mnesia database,
+you can continue with step 2 of previous section
+[Change Mnesia Node](#change-mnesia-node).
+
+
+Build Container Image
+----------------
+
+The container image includes ejabberd as a standalone OTP release built using Elixir.
+
+### Build `ejabberd` [](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
+
+The ejabberd Erlang/OTP release is configured with:
- `mix.exs`: Customize ejabberd release
- `vars.config`: ejabberd compilation configuration options
- `config/runtime.exs`: Customize ejabberd paths
- `ejabberd.yml.template`: ejabberd default config file
-## Direct build
+#### Direct build
Build ejabberd Community Server container image from ejabberd master git repository:
@@ -291,12 +719,14 @@ docker buildx build \
.
```
-## Podman build
+#### Podman build
+
+To build the image using Podman, please notice:
-It's also possible to use podman instead of docker, just notice:
- `EXPOSE 4369-4399` port range is not supported, remove that in Dockerfile
- It mentions that `healthcheck` is not supported by the Open Container Initiative image format
-- If you want to start with command `live`, add environment variable `EJABBERD_BYPASS_WARNINGS=true`
+- to start with command `live`, you may want to add environment variable `EJABBERD_BYPASS_WARNINGS=true`
+
```bash
podman build \
-t ejabberd \
@@ -310,40 +740,41 @@ podman exec eja1 ejabberdctl status
podman exec -it eja1 sh
podman stop eja1
+
+podman run --name eja1 -it -e EJABBERD_BYPASS_WARNINGS=true -p 5222:5222 localhost/ejabberd live
```
-## Package build for `arm64`
+### Build `ecs` [](https://hub.docker.com/r/ejabberd/ecs/)
-By default, `.github/container/Dockerfile` builds this container by directly compiling ejabberd,
-it is a fast and direct method.
-However, a problem with QEMU prevents building the container in QEMU using Erlang/OTP 25
-for the `arm64` architecture.
+The ejabberd Erlang/OTP release is configured with:
-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.
+- `rel/config.exs`: Customize ejabberd release
+- `rel/dev.exs`: ejabberd environment configuration for development release
+- `rel/prod.exs`: ejabberd environment configuration for production release
+- `vars.config`: ejabberd compilation configuration options
+- `conf/ejabberd.yml`: ejabberd default config file
-In this case, to build the ejabberd container image for arm64 architecture:
+Build ejabberd Community Server base image from ejabberd master on Github:
```bash
-docker buildx build \
- --build-arg METHOD=package \
- --platform linux/arm64 \
- -t personal/ejabberd:$VERSION \
- -f .github/container/Dockerfile \
- .
+docker build -t personal/ejabberd .
```
+Build ejabberd Community Server base image for a given ejabberd version:
+
+```bash
+./build.sh 18.03
+```
Composer Examples
-=================
+-----------------
-## Minimal Example
+### Minimal Example
This is the barely minimal file to get a usable ejabberd.
-Store it as `docker-compose.yml`:
+
+If using Docker, write this `docker-compose.yml` file
+and start it with `docker-compose up`:
```yaml
services:
@@ -357,32 +788,62 @@ services:
- "5443:5443"
```
-Create and start the container with the command:
-```bash
-docker-compose up
+If using Podman, write this `minimal.yml` file
+and start it with `podman kube play minimal.yml`:
+
+```yaml
+apiVersion: v1
+
+kind: Pod
+
+metadata:
+ name: ejabberd
+
+spec:
+ containers:
+
+ - name: ejabberd
+ image: ghcr.io/processone/ejabberd
+ ports:
+ - containerPort: 5222
+ hostPort: 5222
+ - containerPort: 5269
+ hostPort: 5269
+ - containerPort: 5280
+ hostPort: 5280
+ - containerPort: 5443
+ hostPort: 5443
```
-## Customized Example
+
+### Customized Example
This example shows the usage of several customizations:
it uses a local configuration file,
+defines a configuration macro using an environment variable,
stores the mnesia database in a local path,
registers an account when it's created,
and checks the number of registered accounts every time it's started.
-Download or copy the ejabberd configuration file:
+Prepare an ejabberd configuration file:
```bash
-wget https://raw.githubusercontent.com/processone/ejabberd/master/ejabberd.yml.example
-mv ejabberd.yml.example ejabberd.yml
+mkdir conf && cp ejabberd.yml.example conf/ejabberd.yml
```
Create the database directory and allow the container access to it:
-```bash
-mkdir database
-sudo chown 9000:9000 database
-```
-Now write this `docker-compose.yml` file:
+- Docker:
+ ```bash
+ mkdir database && sudo chown 9000:9000 database
+ ```
+- Podman:
+ ```bash
+ mkdir database && podman unshare chown 9000:9000 database
+ ```
+
+If using Docker, write this `docker-compose.yml` file
+and start it with `docker-compose up`:
+
```yaml
version: '3.7'
@@ -392,8 +853,10 @@ services:
image: ghcr.io/processone/ejabberd
container_name: ejabberd
environment:
- - CTL_ON_CREATE=register admin localhost asd
- - CTL_ON_START=registered_users localhost ;
+ - EJABBERD_MACRO_HOST=example.com
+ - EJABBERD_MACRO_ADMIN=admin@example.com
+ - REGISTER_ADMIN_PASSWORD=somePassw0rd
+ - CTL_ON_START=registered_users example.com ;
status
ports:
- "5222:5222"
@@ -401,22 +864,81 @@ services:
- "5280:5280"
- "5443:5443"
volumes:
- - ./ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml:ro
+ - ./conf/ejabberd.yml:/opt/ejabberd/conf/ejabberd.yml:ro
- ./database:/opt/ejabberd/database
```
-## Clustering Example
+If using Podman, write this `custom.yml` file
+and start it with `podman kube play custom.yml`:
+
+```yaml
+apiVersion: v1
+
+kind: Pod
+
+metadata:
+ name: ejabberd
+
+spec:
+ containers:
+
+ - name: ejabberd
+ image: ghcr.io/processone/ejabberd
+ env:
+ - name: EJABBERD_MACRO_HOST
+ value: example.com
+ - name: EJABBERD_MACRO_ADMIN
+ value: admin@example.com
+ - name: REGISTER_ADMIN_PASSWORD
+ value: somePassw0rd
+ - name: CTL_ON_START
+ value: registered_users example.com ;
+ status
+ ports:
+ - containerPort: 5222
+ hostPort: 5222
+ - containerPort: 5269
+ hostPort: 5269
+ - containerPort: 5280
+ hostPort: 5280
+ - containerPort: 5443
+ hostPort: 5443
+ volumeMounts:
+ - mountPath: /opt/ejabberd/conf/ejabberd.yml
+ name: config
+ readOnly: true
+ - mountPath: /opt/ejabberd/database
+ name: db
+
+ volumes:
+ - name: config
+ hostPath:
+ path: ./conf/ejabberd.yml
+ type: File
+ - name: db
+ hostPath:
+ path: ./database
+ type: DirectoryOrCreate
+```
+
+
+### Clustering Example
In this example, the main container is created first.
Once it is fully started and healthy, a second container is created,
and once ejabberd is started in it, it joins the first one.
-An account is registered in the first node when created,
+An account is registered in the first node when created (and
+we ignore errors that can happen when doing that - for example
+when account already exists),
and it should exist in the second node after join.
Notice that in this example the main container does not have access
to the exterior; the replica exports the ports and can be accessed.
+If using Docker, write this `docker-compose.yml` file
+and start it with `docker-compose up`:
+
```yaml
version: '3.7'
@@ -424,11 +946,17 @@ services:
main:
image: ghcr.io/processone/ejabberd
- container_name: ejabberd
+ container_name: main
environment:
- ERLANG_NODE_ARG=ejabberd@main
- ERLANG_COOKIE=dummycookie123
- - CTL_ON_CREATE=register admin localhost asd
+ - CTL_ON_CREATE=! register admin localhost asd
+ healthcheck:
+ test: netstat -nl | grep -q 5222
+ start_period: 5s
+ interval: 5s
+ timeout: 5s
+ retries: 120
replica:
image: ghcr.io/processone/ejabberd
@@ -436,15 +964,132 @@ services:
depends_on:
main:
condition: service_healthy
- ports:
- - "5222:5222"
- - "5269:5269"
- - "5280:5280"
- - "5443:5443"
environment:
- ERLANG_NODE_ARG=ejabberd@replica
- ERLANG_COOKIE=dummycookie123
- CTL_ON_CREATE=join_cluster ejabberd@main
- CTL_ON_START=registered_users localhost ;
status
+ ports:
+ - "5222:5222"
+ - "5269:5269"
+ - "5280:5280"
+ - "5443:5443"
```
+
+If using Podman, write this `cluster.yml` file
+and start it with `podman kube play cluster.yml`:
+
+```yaml
+apiVersion: v1
+
+kind: Pod
+
+metadata:
+ name: cluster
+
+spec:
+ containers:
+
+ - name: first
+ image: ghcr.io/processone/ejabberd
+ env:
+ - name: ERLANG_NODE_ARG
+ value: main@cluster
+ - name: ERLANG_COOKIE
+ value: dummycookie123
+ - name: CTL_ON_CREATE
+ value: register admin localhost asd
+ - name: CTL_ON_START
+ value: stats registeredusers ;
+ status
+ - name: EJABBERD_MACRO_PORT_C2S
+ value: 6222
+ - name: EJABBERD_MACRO_PORT_C2S_TLS
+ value: 6223
+ - name: EJABBERD_MACRO_PORT_S2S
+ value: 6269
+ - name: EJABBERD_MACRO_PORT_HTTP_TLS
+ value: 6443
+ - name: EJABBERD_MACRO_PORT_HTTP
+ value: 6280
+ - name: EJABBERD_MACRO_PORT_MQTT
+ value: 6883
+ - name: EJABBERD_MACRO_PORT_PROXY65
+ value: 6777
+ volumeMounts:
+ - mountPath: /opt/ejabberd/conf/ejabberd.yml
+ name: config
+ readOnly: true
+
+ - name: second
+ image: ghcr.io/processone/ejabberd
+ env:
+ - name: ERLANG_NODE_ARG
+ value: replica@cluster
+ - name: ERLANG_COOKIE
+ value: dummycookie123
+ - name: CTL_ON_CREATE
+ value: join_cluster main@cluster ;
+ started ;
+ list_cluster
+ - name: CTL_ON_START
+ value: stats registeredusers ;
+ check_password admin localhost asd ;
+ status
+ ports:
+ - containerPort: 5222
+ hostPort: 5222
+ - containerPort: 5280
+ hostPort: 5280
+ volumeMounts:
+ - mountPath: /opt/ejabberd/conf/ejabberd.yml
+ name: config
+ readOnly: true
+
+ volumes:
+ - name: config
+ hostPath:
+ path: ./conf/ejabberd.yml
+ type: File
+
+```
+
+
+Images Comparison
+-----------------
+
+Let's summarize the differences between both container images. Legend:
+
+- :sparkle: is the recommended alternative
+- :orange_circle: added in the latest release (ejabberd 25.03)
+- :high_brightness: added in the previous release (ejabberd 24.12)
+- :low_brightness: added in the pre-previous release (ejabberd 24.10)
+
+| | [](https://github.com/processone/ejabberd/pkgs/container/ejabberd) | [](https://hub.docker.com/r/ejabberd/ecs/) |
+|:----------------------|:------------------|:-----------------------|
+| Source code | [ejabberd/.github/container](https://github.com/processone/ejabberd/tree/master/.github/container) | [docker-ejabberd/ecs](https://github.com/processone/docker-ejabberd/tree/master/ecs) |
+| Generated by | [container.yml](https://github.com/processone/ejabberd/blob/master/.github/workflows/container.yml) | [tests.yml](https://github.com/processone/docker-ejabberd/blob/master/.github/workflows/tests.yml) |
+| Built for | stable releases
`master` branch | stable releases
[`master` branch zip](https://github.com/processone/docker-ejabberd/actions/workflows/tests.yml) |
+| Architectures | `linux/amd64`
`linux/arm64` | `linux/amd64` |
+| Software | Erlang/OTP 27.3.4.3-alpine
Elixir 1.18.4 | Alpine 3.22
Erlang/OTP 26.2
Elixir 1.18.3 |
+| Published in | [ghcr.io/processone/ejabberd](https://github.com/processone/ejabberd/pkgs/container/ejabberd) | [docker.io/ejabberd/ecs](https://hub.docker.com/r/ejabberd/ecs/)
[ghcr.io/processone/ecs](https://github.com/processone/docker-ejabberd/pkgs/container/ecs) |
+| :black_square_button: **Additional content** |
+| [ejabberd-contrib](#ejabberd-contrib) | included | not included |
+| [ejabberdapi](#ejabberdapi) | included :orange_circle: | included |
+| :black_square_button: **Ports** |
+| [1880](#ports) for WebAdmin | yes :orange_circle: | yes :orange_circle: |
+| [5210](#ports) for `ERL_DIST_PORT` | supported | supported :orange_circle: |
+| :black_square_button: **Paths** |
+| `$HOME` | `/opt/ejabberd/` | `/home/ejabberd/` |
+| User data | `$HOME` :sparkle:
`/home/ejabberd/` :orange_circle: | `$HOME`
`/opt/ejabberd/` :sparkle: :low_brightness: |
+| `ejabberdctl` | `ejabberdctl` :sparkle:
`bin/ejabberdctl` :orange_circle: | `bin/ejabberdctl`
`ejabberdctl` :sparkle: :low_brightness: |
+| [`captcha.sh`](#captcha) | `$HOME/bin/captcha.sh` :orange_circle: | `$HOME/bin/captcha.sh` :orange_circle: |
+| `*.sql` files | `$HOME/sql/*.sql` :sparkle: :orange_circle:
`$HOME/database/*.sql` :orange_circle: | `$HOME/database/*.sql`
`$HOME/sql/*.sql` :sparkle: :orange_circle: |
+| Mnesia spool files | `$HOME/database/` :sparkle:
`$HOME/database/NODENAME/` :orange_circle: | `$HOME/database/NODENAME/`
`$HOME/database/` :sparkle: :orange_circle: |
+| :black_square_button: **Variables** |
+| [`EJABBERD_MACRO_*`](#macros-in-environment) | supported :high_brightness: | supported :high_brightness: |
+| Macros used in `ejabberd.yml` | yes :orange_circle: | yes :orange_circle: |
+| [`EJABBERD_MACRO_ADMIN`](#register-admin-account) | Grant admin rights :orange_circle:
(default `admin@localhost`)
| Hardcoded `admin@localhost` |
+| [`REGISTER_ADMIN_PASSWORD`](#register-admin-account) | Register admin account :orange_circle: | unsupported |
+| `CTL_OVER_HTTP` | enabled :orange_circle: | unsupported |
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a0048c4b6..819921ee5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,21 +3,21 @@
We'd love for you to contribute to our source code and to make ejabberd even better than it is
today! Here are the guidelines we'd like you to follow:
-* [Code of Conduct](#coc)
-* [Questions and Problems](#question)
-* [Issues and Bugs](#issue)
-* [Feature Requests](#feature)
-* [Issue Submission Guidelines](#submit)
-* [Pull Request Submission Guidelines](#submit-pr)
-* [Signing the CLA](#cla)
+* [Code of Conduct](#code-of-conduct)
+* [Questions and Problems](#questions-bugs-features)
+* [Issues and Bugs](#found-an-issue-or-bug)
+* [Feature Requests](#missing-a-feature)
+* [Issue Submission Guidelines](#issue-submission-guidelines)
+* [Pull Request Submission Guidelines](#pull-request-submission-guidelines)
+* [Signing the CLA](#signing-the-contributor-license-agreement-cla)
-## Code of Conduct
+## Code of Conduct
Help us keep ejabberd community open-minded and inclusive. Please read and follow our [Code of Conduct][coc].
-## Questions, Bugs, Features
+## Questions, Bugs, Features
-### Got a Question or Problem?
+### Got a Question or Problem?
Do not open issues for general support questions as we want to keep GitHub issues for bug reports
and feature requests. You've got much better chances of getting your question answered on dedicated
@@ -25,25 +25,25 @@ support platforms, the best being [Stack Overflow][stackoverflow].
Stack Overflow is a much better place to ask questions since:
-- there are thousands of people willing to help on Stack Overflow
-- questions and answers stay available for public viewing so your question / answer might help
+* there are thousands of people willing to help on Stack Overflow
+* questions and answers stay available for public viewing so your question / answer might help
someone else
-- Stack Overflow's voting system assures that the best answers are prominently visible.
+* Stack Overflow's voting system assures that the best answers are prominently visible.
To save your and our time, we will systematically close all issues that are requests for general
support and redirect people to the section you are reading right now.
Other channels for support are:
-- ejabberd XMPP room: [ejabberd@conference.process-one.net][muc]
-- [ejabberd XMPP room logs][logs]
-- [ejabberd Mailing List][list]
-### Found an Issue or Bug?
+* ejabberd XMPP room: [ejabberd@conference.process-one.net][muc]
+* [ejabberd Mailing List][list]
+
+### Found an Issue or Bug?
If you find a bug in the source code, you can help us by submitting an issue to our
[GitHub Repository][github]. Even better, you can submit a Pull Request with a fix.
-### Missing a Feature?
+### Missing a Feature?
You can request a new feature by submitting an issue to our [GitHub Repository][github-issues].
@@ -52,9 +52,9 @@ If you would like to implement a new feature then consider what kind of change i
* **Major Changes** that you wish to contribute to the project should be discussed first in an
[GitHub issue][github-issues] that clearly outlines the changes and benefits of the feature.
* **Small Changes** can directly be crafted and submitted to the [GitHub Repository][github]
- as a Pull Request. See the section about [Pull Request Submission Guidelines](#submit-pr).
+ as a Pull Request. See the section about [Pull Request Submission Guidelines](#pull-request-submission-guidelines).
-## Issue Submission Guidelines
+## Issue Submission Guidelines
Before you submit your issue search the archive, maybe your question was already answered.
@@ -64,7 +64,7 @@ the effort we can spend fixing issues and adding new features, by not reporting
The "[new issue][github-new-issue]" form contains a number of prompts that you should fill out to
make it easier to understand and categorize the issue.
-## Pull Request Submission Guidelines
+## Pull Request Submission Guidelines
By submitting a pull request for a code or doc contribution, you need to have the right
to grant your contribution's copyright license to ProcessOne. Please check [ProcessOne CLA][cla]
@@ -80,6 +80,7 @@ Before you submit your pull request consider the following guidelines:
```shell
git checkout -b my-fix-branch master
```
+
* Test your changes and, if relevant, expand the automated test suite.
* Create your patch commit, including appropriate test cases.
* If the changes affect public APIs, change or add relevant [documentation][doc-repo].
@@ -88,6 +89,7 @@ Before you submit your pull request consider the following guidelines:
```shell
git commit -a
```
+
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
* Push your branch to GitHub:
@@ -123,27 +125,25 @@ restarted.
That's it! Thank you for your contribution!
-## Signing the Contributor License Agreement (CLA)
+## Signing the Contributor License Agreement (CLA)
Upon submitting a Pull Request, we will ask you to sign our CLA if you haven't done
so before. It's a quick process, we promise, and you will be able to do it all online
-You can read [ProcessOne Contribution License Agreement][cla] in PDF.
+Here's a link to the [ProcessOne Contribution License Agreement][cla].
This is part of the legal framework of the open-source ecosystem that adds some red tape,
but protects both the contributor and the company / foundation behind the project. It also
gives us the option to relicense the code with a more permissive license in the future.
-
[coc]: https://github.com/processone/ejabberd/blob/master/CODE_OF_CONDUCT.md
[stackoverflow]: https://stackoverflow.com/questions/tagged/ejabberd?sort=newest
-[list]: https://lists.jabber.ru/mailman/listinfo/ejabberd
+[list]: https://web.archive.org/web/20230319174915/http://lists.jabber.ru/mailman/listinfo/ejabberd
[muc]: xmpp:ejabberd@conference.process-one.net
-[logs]: https://process-one.net/logs/ejabberd@conference.process-one.net/
[github]: https://github.com/processone/ejabberd
[github-issues]: https://github.com/processone/ejabberd/issues
[github-new-issue]: https://github.com/processone/ejabberd/issues/new
[github-pr]: https://github.com/processone/ejabberd/pulls
[doc-repo]: https://github.com/processone/docs.ejabberd.im
[developer-setup]: https://docs.ejabberd.im/developer/
-[cla]: https://www.process-one.net/resources/ejabberd-cla.pdf
+[cla]: https://cla.process-one.net/
diff --git a/Makefile.in b/Makefile.in
index c56070eec..cf7480702 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,8 +1,23 @@
-REBAR = @ESCRIPT@ @rebar@
+#.
+#' definitions
+#
+
+ESCRIPT = @ESCRIPT@
+REBAR = @rebar@ # rebar|rebar3|mix binary (or path to binary)
+REBAR3 = @REBAR3@ # path to rebar3 binary
MIX = @rebar@
+AWK = @AWK@
INSTALL = @INSTALL@
+MKDIR_P = @MKDIR_P@
SED = @SED@
ERL = @ERL@
+EPMD = @EPMD@
+IEX = @IEX@
+
+INSTALLUSER=@INSTALLUSER@
+INSTALLGROUP=@INSTALLGROUP@
+
+REBAR_ENABLE_ELIXIR = @elixir@
prefix = @prefix@
exec_prefix = @exec_prefix@
@@ -71,7 +86,10 @@ SPOOLDIR = @localstatedir@/lib/ejabberd
# /var/log/ejabberd/
LOGDIR = @localstatedir@/log/ejabberd
-INSTALLUSER=@INSTALLUSER@
+#.
+#' install user
+#
+
# if no user was enabled, don't set privileges or ownership
ifeq ($(INSTALLUSER),)
O_USER=
@@ -86,18 +104,22 @@ else
CHOWN_OUTPUT=&1
INIT_USER=$(INSTALLUSER)
endif
+
# if no group was enabled, don't set privileges or ownership
-INSTALLGROUP=@INSTALLGROUP@
ifneq ($(INSTALLGROUP),)
G_USER=-g $(INSTALLGROUP)
endif
-ifeq "$(MIX)" "mix"
+#.
+#' rebar / rebar3 / mix
+#
+
+ifeq "$(notdir $(MIX))" "mix"
REBAR_VER:=6
REBAR_VER_318:=0
else
-REBAR_VER:=$(shell $(REBAR) --version | awk -F '[ .]' '/rebar / {print $$2}')
-REBAR_VER_318:=$(shell $(REBAR) --version | awk -F '[ .]' '/rebar / {print ($$2 == 3 && $$3 >= 18 ? 1 : 0)}')
+REBAR_VER:=$(shell $(REBAR) --version | $(AWK) -F '[ .]' '/rebar / {print $$2}')
+REBAR_VER_318:=$(shell $(REBAR) --version | $(AWK) -F '[ .]' '/rebar / {print ($$2 == 3 && $$3 >= 18 ? 1 : 0)}')
endif
ifeq "$(REBAR_VER)" "6"
@@ -112,11 +134,26 @@ ifeq "$(REBAR_VER)" "6"
CONFIGURE_DEPS=(cd deps/eimp; ./configure)
EBINDIR=$(DEPSDIR)/ejabberd/ebin
XREFOPTIONS=graph
+ EDOCPRE=MIX_ENV=edoc
+ EDOCTASK=docs --proglang erlang
CLEANARG=--deps
+ ELIXIR_LIBDIR_RAW=$(shell elixir -e "IO.puts(:filename.dirname(:code.lib_dir(:elixir)))" -e ":erlang.halt")
+ ELIXIR_LIBDIR=":$(ELIXIR_LIBDIR_RAW)"
REBARREL=MIX_ENV=prod $(REBAR) release --overwrite
REBARDEV=MIX_ENV=dev $(REBAR) release --overwrite
- RELIVECMD=escript rel/relive.escript && MIX_ENV=dev RELIVE=true iex --name ejabberd@localhost -S mix run
+ RELIVECMD=$(ESCRIPT) rel/relive.escript && MIX_ENV=dev RELIVE=true $(IEX) --name ejabberd@localhost -S mix run
+ REL_LIB_DIR = _build/dev/rel/ejabberd/lib
+ COPY_REL_TARGET = dev
+ GET_DEPS_TRANSLATIONS=MIX_ENV=translations $(REBAR) $(GET_DEPS)
+ DEPSDIR_TRANSLATIONS=deps
else
+ifeq ($(REBAR_ENABLE_ELIXIR),true)
+ ELIXIR_LIBDIR_RAW=$(shell elixir -e "IO.puts(:filename.dirname(:code.lib_dir(:elixir)))" -e ":erlang.halt")
+ ELIXIR_LIBDIR=":$(ELIXIR_LIBDIR_RAW)"
+ EXPLICIT_ELIXIR_COMPILE=MIX_ENV=default mix compile.elixir
+ EXPLICIT_ELIXIR_COMPILE_DEV=MIX_ENV=dev mix compile.elixir
+ PREPARE_ELIXIR_SCRIPTS=$(MKDIR_P) rel/overlays; cp $(ELIXIR_LIBDIR_RAW)/../bin/iex rel/overlays/; cp $(ELIXIR_LIBDIR_RAW)/../bin/elixir rel/overlays/; sed -i 's|ERTS_BIN=$$|ERTS_BIN=$$SCRIPT_PATH/../../erts-{{erts_vsn}}/bin/|' rel/overlays/elixir
+endif
ifeq "$(REBAR_VER)" "3"
SKIPDEPS=
LISTDEPS=tree
@@ -134,8 +171,12 @@ endif
XREFOPTIONS=
CLEANARG=--all
REBARREL=$(REBAR) as prod tar
- REBARDEV=REBAR_PROFILE=dev $(REBAR) release
- RELIVECMD=$(REBAR) relive
+ REBARDEV=$(REBAR) as dev release
+ RELIVECMD=$(REBAR) as dev relive
+ REL_LIB_DIR = _build/dev/rel/ejabberd/lib
+ COPY_REL_TARGET = dev
+ GET_DEPS_TRANSLATIONS=$(REBAR) as translations $(GET_DEPS)
+ DEPSDIR_TRANSLATIONS=_build/translations/lib
else
SKIPDEPS=skip_deps=true
LISTDEPS=-q list-deps
@@ -151,10 +192,16 @@ else
REBARREL=$(REBAR) generate
REBARDEV=
RELIVECMD=@echo "Rebar2 detected... relive not supported.\
- \nTry: ./configure --with-rebar=./rebar3 ; make relive"
+ \nTry: ./configure --with-rebar=rebar3 ; make relive"
+ REL_LIB_DIR = rel/ejabberd/lib
+ COPY_REL_TARGET = rel
endif
endif
+#.
+#' main targets
+#
+
all: scripts deps src
deps: $(DEPSDIR)/.got
@@ -162,7 +209,7 @@ deps: $(DEPSDIR)/.got
$(DEPSDIR)/.got:
rm -rf $(DEPSDIR)/.got
rm -rf $(DEPSDIR)/.built
- mkdir -p $(DEPSDIR)
+ $(MKDIR_P) $(DEPSDIR)
$(REBAR) $(GET_DEPS) && :> $(DEPSDIR)/.got
$(CONFIGURE_DEPS)
@@ -171,6 +218,7 @@ $(DEPSDIR)/.built: $(DEPSDIR)/.got
src: $(DEPSDIR)/.built
$(REBAR) $(SKIPDEPS) compile
+ $(EXPLICIT_ELIXIR_COMPILE)
update:
rm -rf $(DEPSDIR)/.got
@@ -188,14 +236,45 @@ options: all
tools/opt_types.sh ejabberd_option $(EBINDIR)
translations:
- tools/prepare-tr.sh $(DEPSDIR)
+ $(GET_DEPS_TRANSLATIONS)
+ tools/prepare-tr.sh $(DEPSDIR_TRANSLATIONS)
doap:
tools/generate-doap.sh
-edoc:
- $(ERL) -noinput +B -eval \
- 'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.'
+#.
+#' edoc
+#
+
+edoc: edoc_files edoc_compile
+ $(EDOCPRE) $(REBAR) $(EDOCTASK)
+
+edoc_compile: deps
+ $(EDOCPRE) $(REBAR) compile
+
+edoc_files: _build/edoc/docs.md _build/edoc/logo.png
+
+_build/edoc/docs.md: edoc_compile
+ echo "For much more detailed and complete ejabberd documentation, " \
+ "go to the [ejabberd Docs](https://docs.ejabberd.im/) site." \
+ > _build/edoc/docs.md
+
+_build/edoc/logo.png: edoc_compile
+ wget https://docs.ejabberd.im/assets/img/footer_logo_e.png -O _build/edoc/logo.png
+
+#.
+#' format / indent
+#
+
+format:
+ tools/rebar3-format.sh $(REBAR3)
+
+indent:
+ tools/emacs-indent.sh
+
+#.
+#' copy-files
+#
JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1))
@@ -282,26 +361,58 @@ copy-files:
copy-files-sub: copy-files-sub2
+#.
+#' copy-files-rel
+#
+
+copy-files-rel: $(COPY_REL_TARGET)
+ #
+ # Libraries
+ (cd $(REL_LIB_DIR) && find . -follow -type f ! -executable -exec $(INSTALL) -vDm 640 $(G_USER) {} $(DESTDIR)$(LIBDIR)/{} \;)
+ #
+ # *.so:
+ (cd $(REL_LIB_DIR) && find . -follow -type f -executable -name *.so -exec $(INSTALL) -vDm 640 $(G_USER) {} $(DESTDIR)$(LIBDIR)/{} \;)
+ #
+ # Executable files
+ (cd $(REL_LIB_DIR) && find . -follow -type f -executable ! -name *.so -exec $(INSTALL) -vDm 550 $(G_USER) {} $(DESTDIR)$(LIBDIR)/{} \;)
+
+#.
+#' uninstall-librel
+#
+
+uninstall-librel:
+ (cd $(REL_LIB_DIR) && find . -follow -type f -exec rm -fv -v $(DESTDIR)$(LIBDIR)/{} \;)
+ (cd $(REL_LIB_DIR) && find . -follow -depth -type d -exec rm -dv -v $(DESTDIR)$(LIBDIR)/{} \;)
+
+#.
+#' relive
+#
+
relive:
+ $(EXPLICIT_ELIXIR_COMPILE_DEV)
$(RELIVECMD)
relivelibdir=$(shell pwd)/$(DEPSDIR)
relivedir=$(shell pwd)/_build/relive
-iexpath=$(shell which iex)
CONFIG_DIR = ${relivedir}/conf
SPOOL_DIR = ${relivedir}/database
LOGS_DIR = ${relivedir}/logs
+#.
+#' scripts
+#
+
ejabberdctl.relive:
- $(SED) -e "s*{{installuser}}*@INSTALLUSER@*g" \
+ $(SED) -e "s*{{installuser}}*${INSTALLUSER}*g" \
-e "s*{{config_dir}}*${CONFIG_DIR}*g" \
-e "s*{{logs_dir}}*${LOGS_DIR}*g" \
-e "s*{{spool_dir}}*${SPOOL_DIR}*g" \
- -e "s*{{bindir}}/iex*$(iexpath)*g" \
- -e "s*{{bindir}}*@bindir@*g" \
- -e "s*{{libdir}}*${relivelibdir}*g" \
- -e "s*{{erl}}*@ERL@*g" \
- -e "s*{{epmd}}*@EPMD@*g" ejabberdctl.template \
+ -e "s*{{bindir}}*${BINDIR}*g" \
+ -e "s*{{libdir}}*${relivelibdir}${ELIXIR_LIBDIR}*g" \
+ -e "s*ERTS_VSN*# ERTS_VSN*g" \
+ -e "s*{{iexpath}}*${IEX}*g" \
+ -e "s*{{erl}}*${ERL}*g" \
+ -e "s*{{epmd}}*${EPMD}*g" ejabberdctl.template \
> ejabberdctl.relive
ejabberd.init:
@@ -317,19 +428,29 @@ ejabberd.service:
chmod 644 ejabberd.service
ejabberdctl.example: vars.config
- $(SED) -e "s*{{installuser}}*@INSTALLUSER@*g" \
+ $(SED) -e "s*{{installuser}}*${INSTALLUSER}*g" \
-e "s*{{config_dir}}*${ETCDIR}*g" \
-e "s*{{logs_dir}}*${LOGDIR}*g" \
-e "s*{{spool_dir}}*${SPOOLDIR}*g" \
- -e "s*{{bindir}}*@bindir@*g" \
- -e "s*{{libdir}}*@libdir@*g" \
- -e "s*{{erl}}*@ERL@*g" \
- -e "s*{{epmd}}*@EPMD@*g" ejabberdctl.template \
+ -e "s*{{bindir}}*${BINDIR}*g" \
+ -e "s*{{libdir}}*${LIBDIR}${ELIXIR_LIBDIR}*g" \
+ -e "s*ERTS_VSN*# ERTS_VSN*g" \
+ -e "s*{{iexpath}}*${IEX}*g" \
+ -e "s*{{erl}}*${ERL}*g" \
+ -e "s*{{epmd}}*${EPMD}*g" ejabberdctl.template \
> ejabberdctl.example
scripts: ejabberd.init ejabberd.service ejabberdctl.example
-install: copy-files
+#.
+#' install
+#
+
+install: copy-files install-main
+
+install-rel: copy-files-rel install-main
+
+install-main:
#
# Configuration files
$(INSTALL) -d -m 750 $(G_USER) $(DESTDIR)$(ETCDIR)
@@ -352,12 +473,12 @@ install: copy-files
#
# Spool directory
$(INSTALL) -d -m 750 $(O_USER) $(DESTDIR)$(SPOOLDIR)
- $(CHOWN_COMMAND) -R @INSTALLUSER@ $(DESTDIR)$(SPOOLDIR) >$(CHOWN_OUTPUT)
+ $(CHOWN_COMMAND) -R $(INSTALLUSER) $(DESTDIR)$(SPOOLDIR) >$(CHOWN_OUTPUT)
chmod -R 750 $(DESTDIR)$(SPOOLDIR)
#
# Log directory
$(INSTALL) -d -m 750 $(O_USER) $(DESTDIR)$(LOGDIR)
- $(CHOWN_COMMAND) -R @INSTALLUSER@ $(DESTDIR)$(LOGDIR) >$(CHOWN_OUTPUT)
+ $(CHOWN_COMMAND) -R $(INSTALLUSER) $(DESTDIR)$(LOGDIR) >$(CHOWN_OUTPUT)
chmod -R 750 $(DESTDIR)$(LOGDIR)
#
# Documentation
@@ -368,8 +489,14 @@ install: copy-files
|| echo "Man page not included in sources"
$(INSTALL) -m 644 COPYING $(DESTDIR)$(DOCDIR)
+#.
+#' uninstall
+#
+
uninstall: uninstall-binary
+uninstall-rel: uninstall-binary uninstall-librel
+
uninstall-binary:
rm -f $(DESTDIR)$(SBINDIR)/ejabberdctl
rm -f $(DESTDIR)$(BINDIR)/iex
@@ -398,6 +525,7 @@ uninstall-binary:
rm -fr $(DESTDIR)$(LUADIR)
rm -fr $(DESTDIR)$(PRIVDIR)
rm -fr $(DESTDIR)$(EJABBERDDIR)
+ rm -f $(DESTDIR)$(MANDIR)/ejabberd.yml.5
uninstall-all: uninstall-binary
rm -rf $(DESTDIR)$(ETCDIR)
@@ -405,6 +533,10 @@ uninstall-all: uninstall-binary
rm -rf $(DESTDIR)$(SPOOLDIR)
rm -rf $(DESTDIR)$(LOGDIR)
+#.
+#' clean
+#
+
clean:
rm -rf $(DEPSDIR)/.got
rm -rf $(DEPSDIR)/.built
@@ -427,29 +559,53 @@ distclean: clean clean-rel
rm -f Makefile
rm -f vars.config
-rel:
+#.
+#' releases
+#
+
+rel: prod
+
+prod:
+ $(PREPARE_ELIXIR_SCRIPTS)
$(REBARREL)
DEV_CONFIG = _build/dev/rel/ejabberd/conf/ejabberd.yml
dev $(DEV_CONFIG):
+ $(PREPARE_ELIXIR_SCRIPTS)
$(REBARDEV)
+#.
+#' tags
+#
+
TAGS:
- etags *.erl
+ etags src/*.erl
+
+#.
+#' makefile
+#
Makefile: Makefile.in
-ifeq "$(REBAR_VER)" "3"
+#.
+#' dialyzer
+#
+
+ifeq "$(REBAR_VER)" "6" # Mix
dialyzer:
- find src/*_opt.erl -type f \! -regex ".*git.*" -exec sed -i 's/re:mp/ tuple/g' {} \;
- $(REBAR) dialyzer
- find src/*_opt.erl -type f \! -regex ".*git.*" -exec sed -i 's/ tuple/re:mp/g' {} \;
+ MIX_ENV=test $(REBAR) dialyzer
+
else
+ifeq "$(REBAR_VER)" "3" # Rebar3
+dialyzer:
+ $(REBAR) dialyzer
+
+else # Rebar2
deps := $(wildcard $(DEPSDIR)/*/ebin)
dialyzer/erlang.plt:
- @mkdir -p dialyzer
+ @$(MKDIR_P) dialyzer
@dialyzer --build_plt --output_plt dialyzer/erlang.plt \
-o dialyzer/erlang.log --apps kernel stdlib sasl crypto \
public_key ssl mnesia inets odbc compiler erts \
@@ -457,13 +613,13 @@ dialyzer/erlang.plt:
status=$$? ; if [ $$status -ne 2 ]; then exit $$status; else exit 0; fi
dialyzer/deps.plt:
- @mkdir -p dialyzer
+ @$(MKDIR_P) dialyzer
@dialyzer --build_plt --output_plt dialyzer/deps.plt \
-o dialyzer/deps.log $(deps); \
status=$$? ; if [ $$status -ne 2 ]; then exit $$status; else exit 0; fi
dialyzer/ejabberd.plt:
- @mkdir -p dialyzer
+ @$(MKDIR_P) dialyzer
@dialyzer --build_plt --output_plt dialyzer/ejabberd.plt \
-o dialyzer/ejabberd.log ebin; \
status=$$? ; if [ $$status -ne 2 ]; then exit $$status; else exit 0; fi
@@ -485,6 +641,18 @@ dialyzer: erlang_plt deps_plt ejabberd_plt
--get_warnings -o dialyzer/error.log ebin; \
status=$$? ; if [ $$status -ne 2 ]; then exit $$status; else exit 0; fi
endif
+endif
+
+#.
+#' elvis
+#
+
+elvis:
+ $(REBAR) lint
+
+#.
+#' test
+#
test:
@echo "************************** NOTICE ***************************************"
@@ -493,9 +661,32 @@ test:
@cd priv && ln -sf ../sql
$(REBAR) $(SKIPDEPS) ct
-.PHONY: src edoc dialyzer Makefile TAGS clean clean-rel distclean rel \
- install uninstall uninstall-binary uninstall-all translations deps test \
- quicktest erlang_plt deps_plt ejabberd_plt xref hooks options
+.PHONY: test-%
+define test-group-target
+test-$1:
+ $(REBAR) $(SKIPDEPS) ct --suite=test/ejabberd_SUITE --group=$1
+endef
+
+ifneq ($(filter test-%,$(MAKECMDGOALS)),)
+group_to_test := $(patsubst test-%,%,$(filter test-%,$(MAKECMDGOALS)))
+$(eval $(call test-group-target,$(group_to_test)))
+endif
+
+test-eunit:
+ $(REBAR) $(SKIPDEPS) eunit --verbose
+
+#.
+#' phony
+#
+
+.PHONY: src edoc dialyzer Makefile TAGS clean clean-rel distclean prod rel \
+ install uninstall uninstall-binary uninstall-all translations deps test test-eunit \
+ all dev doap help install-rel relive scripts uninstall-rel update \
+ erlang_plt deps_plt ejabberd_plt xref hooks options format indent
+
+#.
+#' help
+#
help:
@echo ""
@@ -503,25 +694,37 @@ help:
@echo " scripts Prepare ejabberd start scripts"
@echo " deps Get and configure dependencies"
@echo " src Compile dependencies and ejabberd"
- @echo " update Update dependencies' source code"
+ @echo " update Update dependencies source code"
@echo " clean Clean binary files"
@echo " distclean Clean completely the development files"
@echo ""
@echo " install Install ejabberd to /usr/local"
+ @echo " install-rel Install ejabberd to /usr/local (using release)"
@echo " uninstall Uninstall ejabberd (buggy)"
+ @echo " uninstall-rel Uninstall ejabberd (using release)"
@echo " uninstall-all Uninstall also configuration, logs, mnesia... (buggy)"
@echo ""
- @echo " rel Build a production release"
+ @echo " prod Build a production release"
@echo " dev Build a development release"
@echo " relive Start a live ejabberd in _build/relive/"
@echo ""
@echo " doap Generate DOAP file"
- @echo " edoc Generate edoc documentation (unused)"
+ @echo " edoc Generate EDoc documentation [mix]"
@echo " options Generate ejabberd_option.erl"
- @echo " translations Extract translation files (requires --enable-tools)"
- @echo " tags Generate tags file for text editors"
+ @echo " translations Extract translation files"
+ @echo " TAGS Generate tags file for text editors"
+ @echo ""
+ @echo " format Format source code using rebar3_format"
+ @echo " indent Indent source code using erlang-mode [emacs]"
@echo ""
@echo " dialyzer Run Dialyzer static analyzer"
+ @echo " elvis Run Elvis source code style reviewer [rebar3]"
@echo " hooks Run hooks validator"
- @echo " test Run Common Tests suite"
- @echo " xref Run cross reference analysis"
+ @echo " test Run Common Tests suite [rebar3]"
+ @echo " test-eunit Run EUnit suite [rebar3]"
+ @echo " test- Run Common Test suite for specific group only [rebar3]"
+ @echo " xref Run cross reference analysis [rebar3]"
+
+#.
+#'
+# vim: foldmarker=#',#. foldmethod=marker:
diff --git a/README.md b/README.md
index 0b3fa7809..646cc4a17 100644
--- a/README.md
+++ b/README.md
@@ -17,12 +17,13 @@
-
+
-
+
+
+
-
[ejabberd][im] is an open-source,
robust, scalable and extensible realtime platform built using [Erlang/OTP][erlang],
that includes [XMPP][xmpp] Server, [MQTT][mqtt] Broker and [SIP][sip] Service.
@@ -37,12 +38,16 @@ Installation
There are several ways to install ejabberd:
- Source code: compile yourself, see [COMPILE](COMPILE.md)
-- Installers from [ProcessOne Download][p1download] or [ejabberd GitHub Releases][releases] (run/deb/rpm for x64 and arm64)
-- `ecs` container image available in [Docker Hub][hubecs] and [Github Packages][packagesecs], see [ecs README][docker-ecs-readme] (for x64)
-- `ejabberd` container image available in [Github Packages][packages], see [CONTAINER](CONTAINER.md) (for x64 and arm64)
+- Installers:
+ - [ProcessOne Download Page][p1download] or [GitHub Releases][releases] for releases.
+ - [GitHub Actions](https://github.com/processone/ejabberd/actions/workflows/installers.yml) for master branch (`run`/`deb`/`rpm` for `x64` and `arm64`)
+- Docker Containers:
+ - `ecs` container image: [Docker Hub][hubecs] and [Github Packages][packagesecs], see [ecs README][docker-ecs-readme] (for `x64`)
+ - `ejabberd` container image: [Github Packages][packages] for releases and master branch, see [CONTAINER](CONTAINER.md) (for `x64` and `arm64`)
- Using your [Operating System package][osp]
- Using the [Homebrew][homebrew] package manager
+More info can be found in the `Installation` part of [ejabberd Docs](https://docs.ejabberd.im/admin/install/).
Documentation
-------------
@@ -59,7 +64,6 @@ Once ejabberd is installed, try:
ejabberdctl help
man ejabberd.yml
-
Development
-----------
@@ -71,6 +75,11 @@ or in your local machine as explained in [Localization][localization].
Documentation for developers is available in [ejabberd docs: Developers][docs-dev].
+There are nightly builds of ejabberd, both for `master` branch and for Pull Requests:
+
+- Installers: go to [GitHub Actions: Installers](https://github.com/processone/ejabberd/actions/workflows/installers.yml), open the most recent commit, on the bottom of that commit page, download the `ejabberd-packages.zip` artifact.
+- `ejabberd` container image: go to [ejabberd Github Packages][packages]
+
Security reports or concerns should preferably be reported privately,
please send an email to the address: contact at process-one dot net
or some other method from [ProcessOne Contact][p1contact].
@@ -78,6 +87,10 @@ or some other method from [ProcessOne Contact][p1contact].
For commercial offering and support, including [ejabberd Business Edition][p1home]
and [Fluux (ejabberd in the Cloud)][fluux], please check [ProcessOne ejabberd page][p1home].
+Security
+--------
+
+For information on how to report security vulnerabilities, please refer to the [SECURITY.md](SECURITY.md) file. It contains guidelines on how to report vulnerabilities privately and securely, ensuring that any issues are addressed in a timely and confidential manner.
Community
---------
@@ -88,13 +101,11 @@ There are several places to get in touch with other ejabberd developers and admi
- [GitHub Discussions][discussions]
- [Stack Overflow][stackoverflow]
-
License
-------
-ejabberd is released under the GNU General Public License v2 (see [COPYING](COPYING.md)),
-and [ejabberd translations](https://github.com/processone/ejabberd-po/) under MIT License.
-
+- ejabberd is released under the __GNU General Public License v2__ (see [COPYING](COPYING))
+- [ejabberd translations](https://github.com/processone/ejabberd-po/) under __MIT License__.
[discussions]: https://github.com/processone/ejabberd/discussions
[docker-ecs-readme]: https://github.com/processone/docker-ejabberd/tree/master/ecs#readme
@@ -103,23 +114,23 @@ 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/
-[homebrew]: https://docs.ejabberd.im/admin/installation/#homebrew
+[homebrew]: https://docs.ejabberd.im/admin/install/homebrew/
[hubecs]: https://hub.docker.com/r/ejabberd/ecs/
-[im]: https://ejabberd.im/
+[im]: https://www.ejabberd.im/
[issues]: https://github.com/processone/ejabberd/issues
[localization]: https://docs.ejabberd.im/developer/extending-ejabberd/localization/
[mqtt]: https://mqtt.org/
[muc]: xmpp:ejabberd@conference.process-one.net
-[osp]: https://docs.ejabberd.im/admin/installation/#operating-system-packages
-[p1contact]: https://www.process-one.net/en/company/contact/
-[p1download]: https://www.process-one.net/en/ejabberd/downloads/
-[p1home]: https://www.process-one.net/en/ejabberd/
+[osp]: https://docs.ejabberd.im/admin/install/os-package/
+[p1contact]: https://www.process-one.net/contact/
+[p1download]: https://www.process-one.net/download/ejabberd/
+[p1home]: https://www.process-one.net/ejabberd/
[packages]: https://github.com/processone/ejabberd/pkgs/container/ejabberd
[packagesecs]: https://github.com/processone/docker-ejabberd/pkgs/container/ecs
[releases]: https://github.com/processone/ejabberd/releases
[sip]: https://en.wikipedia.org/wiki/Session_Initiation_Protocol
[stackoverflow]: https://stackoverflow.com/questions/tagged/ejabberd?sort=newest
[weblate]: https://hosted.weblate.org/projects/ejabberd/ejabberd-po/
-[xeps]: https://www.process-one.net/en/ejabberd/protocols/
+[xeps]: https://www.process-one.net/ejabberd-features/
[xmpp]: https://xmpp.org/
[xmppej]: https://xmpp.org/software/servers/ejabberd/
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..bb2292826
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,45 @@
+# Security Policy
+
+## Supported Versions
+
+We recommend that all users always use the latest version of ejabberd.
+
+To ensure the best experience and security, upgrade to the latest version available on [this repo](https://github.com/processone/ejabberd).
+
+## Reporting a Vulnerability
+
+### Private Reporting
+
+**Preferred Method**: Use GitHub's private vulnerability reporting system by clicking the "Report a Vulnerability" button in the [Security tab of this repository](https://github.com/processone/ejabberd/security). This ensures your report is securely transmitted and tracked.
+
+**Alternative**: If you cannot use the GitHub system, send an email to **`contact@process-one.net`** with the following details:
+
+- A clear description of the vulnerability.
+- Steps to reproduce the issue.
+- Any potential impact or exploitation scenarios.
+
+### Response Time
+
+We aim to acknowledge receipt of your report within 72 hours. You can expect regular updates on the status of your report.
+
+### Resolution
+
+If the vulnerability is confirmed, we will work on a patch or mitigation strategy.
+We will notify you once the issue is resolved and coordinate a public disclosure if needed.
+
+### Acknowledgements
+
+We value and appreciate the contributions of security researchers and community members.
+If you wish, we are happy to acknowledge your efforts publicly by listing your name (or alias) below in this document.
+Please let us know if you would like to be recognized when reporting the vulnerability.
+
+## Public Discussion
+
+For general inquiries or discussions about the project’s security, feel free to chat with us here:
+
+- XMPP room: `ejabberd@conference.process-one.net`
+- [GitHub Discussions](https://github.com/processone/ejabberd/discussions)
+
+However, please note that if the issue is **critical** or potentially exploitable, **do not share it publicly**. Instead, we strongly recommend you contact the maintainers directly via the private reporting methods outlined above to ensure a secure and timely response.
+
+Thank you for helping us improve the security of ejabberd!
diff --git a/config/runtime.exs b/config/runtime.exs
index b4e6dc5f1..adfc18c06 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -8,6 +8,8 @@ end
rootpath = System.get_env("RELEASE_ROOT", rootdefault)
config :ejabberd,
file: Path.join(rootpath, "conf/ejabberd.yml"),
- log_path: Path.join(rootpath, 'logs/ejabberd.log')
+ log_path: Path.join(rootpath, "logs/ejabberd.log")
config :mnesia,
- dir: Path.join(rootpath, 'database/')
+ dir: Path.join(rootpath, "database/")
+config :exsync,
+ reload_callback: {:ejabberd_admin, :update, []}
diff --git a/configure.ac b/configure.ac
index ff2772ccb..b91595dc5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,15 +2,26 @@
# 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.10` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
-REQUIRE_ERLANG_MIN="9.0.5 (Erlang/OTP 20.0)"
+AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 25.08` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
+
+AC_ARG_WITH(min-erlang,
+ AS_HELP_STRING([--with-min-erlang=version],[set minimal required erlang version, default to OTP25]),
+[if test "X$withval" = "X"; then
+ REQUIRE_ERLANG_MIN="13.0 (Erlang/OTP 25.0)"
+else
+ REQUIRE_ERLANG_MIN="$withval"
+fi
+], [REQUIRE_ERLANG_MIN="13.0 (Erlang/OTP 25.0)"])
+
REQUIRE_ERLANG_MAX="100.0.0 (No Max)"
AC_CONFIG_MACRO_DIR([m4])
# Checks for programs.
AC_PROG_MAKE_SET
+AC_PROG_AWK
AC_PROG_INSTALL
+AC_PROG_MKDIR_P
AC_PROG_SED
if test "x$GCC" = "xyes"; then
@@ -28,18 +39,42 @@ fi
])
AC_ARG_WITH(rebar,
- AS_HELP_STRING([--with-rebar=bin],[use the rebar/rebar3/mix binary specified]),
+ AS_HELP_STRING([--with-rebar=bin],[use as build tool the rebar/rebar3/mix binary specified]),
[if test "$withval" = "yes" -o "$withval" = "no" -o "X$with_rebar" = "X"; then
- rebar="rebar"
+ rebar="rebar3"
else
rebar="$with_rebar"
fi
-], [rebar="rebar"])
+], [rebar="unconfigured"])
AC_PATH_TOOL(ERL, erl, , [${extra_erl_path}$PATH])
AC_PATH_TOOL(ERLC, erlc, , [${extra_erl_path}$PATH])
AC_PATH_TOOL(EPMD, epmd, , [${extra_erl_path}$PATH])
+AC_PATH_TOOL(REBAR, rebar, , [${extra_erl_path}$PATH])
+AC_PATH_TOOL(REBAR3, rebar3, , [${extra_erl_path}$PATH])
+AC_PATH_TOOL(ELIXIR, elixir, , [${extra_erl_path}$PATH])
+AC_PATH_TOOL(IEX, iex, , [${extra_erl_path}$PATH])
+AC_PATH_TOOL(MIX, mix, , [${extra_erl_path}$PATH])
+
+if test "$rebar" = unconfigured; then
+ if test "x$ELIXIR" = "x" -o "x$IEX" = "x" -o "x$MIX" = "x"; then
+ if test "x$REBAR3" = "x"; then
+ rebar="rebar3"
+ else
+ rebar=$REBAR3
+ fi
+ else
+ rebar=$MIX
+ fi
+fi
+if test "x$rebar" = "xrebar" -a "x$REBAR" = "x" ; then
+ rebar="./rebar"
+fi
+if test "x$rebar" = "xrebar3" -a "x$REBAR3" = "x" ; then
+ rebar="./rebar3"
+fi
+
AC_ERLANG_NEED_ERL
AC_ERLANG_NEED_ERLC
@@ -84,7 +119,7 @@ AC_ARG_ENABLE(debug,
esac],[if test "x$debug" = "x"; then debug=true; fi])
AC_ARG_ENABLE(elixir,
-[AS_HELP_STRING([--enable-elixir],[enable Elixir support (default: no)])],
+[AS_HELP_STRING([--enable-elixir],[enable Elixir support in Rebar3 (default: no)])],
[case "${enableval}" in
yes) elixir=true ;;
no) elixir=false ;;
@@ -112,7 +147,7 @@ esac],[full_xml=false])
ENABLEGROUP=""
AC_ARG_ENABLE(group,
- [AS_HELP_STRING([--enable-group[[[[=GROUP]]]]], [allow this system group to start ejabberd (default: no)])],
+ [AS_HELP_STRING([--enable-group[[=GROUP]]], [specify the group of the account defined in --enable-user (default: no)])],
[case "${enableval}" in
yes) ENABLEGROUP=`groups |head -n 1` ;;
no) ENABLEGROUP="" ;;
@@ -237,7 +272,7 @@ AC_ARG_ENABLE(system_deps,
esac],[if test "x$system_deps" = "x"; then system_deps=false; fi])
AC_ARG_ENABLE(tools,
-[AS_HELP_STRING([--enable-tools],[build development tools (default: no)])],
+[AS_HELP_STRING([--enable-tools],[include debugging/development tools (default: no)])],
[case "${enableval}" in
yes) tools=true ;;
no) tools=false ;;
@@ -246,7 +281,7 @@ esac],[if test "x$tools" = "x"; then tools=false; fi])
ENABLEUSER=""
AC_ARG_ENABLE(user,
- [AS_HELP_STRING([--enable-user[[[[=USER]]]]], [allow this system user to start ejabberd (default: no)])],
+ [AS_HELP_STRING([--enable-user[[=USER]]], [allow this system user to start ejabberd (default: no)])],
[case "${enableval}" in
yes) ENABLEUSER=`whoami` ;;
no) ENABLEUSER="" ;;
@@ -280,6 +315,8 @@ case "`uname`" in
;;
esac
+AC_MSG_RESULT([build tool to use (change using --with-rebar): $rebar])
+
AC_SUBST(roster_gateway_workaround)
AC_SUBST(new_sql_schema)
AC_SUBST(full_xml)
@@ -305,3 +342,28 @@ AC_SUBST(CPPFLAGS)
AC_SUBST(LDFLAGS)
AC_OUTPUT
+
+AS_CASE([$rebar],
+ [*rebar3], [
+ deps=""
+ AS_IF([test "x$stun" = "xfalse"], [deps="stun,$deps"])
+ AS_IF([test "x$sqlite" = "xfalse"], [deps="sqlite3,$deps"])
+ AS_IF([test "x$pgsql" = "xfalse"], [deps="p1_pgsql,$deps"])
+ AS_IF([test "x$mysql" = "xfalse"], [deps="p1_mysql,$deps"])
+ AS_IF([test "x$zlib" = "xfalse"], [deps="ezlib,$deps"])
+ AS_IF([test "x$sip" = "xfalse"], [deps="esip,$deps"])
+ AS_IF([test "x$redis" = "xfalse"], [deps="eredis,$deps"])
+ AS_IF([test "x$pam" = "xfalse"], [deps="epam,$deps"])
+ AS_IF([test "x$deps" = "x"], [],
+ [AC_MSG_NOTICE([unlocking disabled rebar3 dependencies: $deps])
+ $rebar unlock "$deps"])
+ deps=""
+ ERLANG_VERSION=m4_esyscmd([erl -noinput -noshell -eval 'erlang:display(list_to_integer(erlang:system_info(otp_release))), halt().'])
+ AS_IF([test "$ERLANG_VERSION" -lt "21"], [deps="luerl,$deps"])
+ AS_IF([test "$ERLANG_VERSION" -lt "22"], [deps="lager,$deps"])
+ AS_IF([test "$ERLANG_VERSION" -le "23"], [deps="jose,$deps"])
+ AS_IF([test "$ERLANG_VERSION" -ge "27"], [deps="jiffy,$deps"])
+ AS_IF([test "x$deps" = "x"], [],
+ [AC_MSG_NOTICE([unlocking rebar3 dependencies for old Erlang/OTP: $deps])
+ $rebar unlock "$deps"])
+ ])
diff --git a/ejabberd.doap b/ejabberd.doap
index bbdb311c1..bfd3f5636 100644
--- a/ejabberd.doap
+++ b/ejabberd.doap
@@ -19,10 +19,10 @@
-
+
-
+
@@ -48,8 +48,8 @@
2.9
-
-
+ 0.5.0
+ complete
@@ -57,8 +57,8 @@
2.0
-
-
+ 0.5.0
+ complete
mod_last
@@ -67,7 +67,7 @@
1.2
16.02
-
+ complete
mod_offline
@@ -75,8 +75,8 @@
1.6
-
-
+ 0.5.0
+ complete
mod_privacy
@@ -84,8 +84,8 @@
1.4
-
-
+ 0.1.0
+ complete
mod_offline
@@ -93,8 +93,8 @@
1.3
-
-
+ 0.7.5
+ complete
mod_offline
@@ -102,8 +102,8 @@
2.4
-
-
+ 0.1.0
+ complete
mod_disco
@@ -112,7 +112,7 @@
1.1
15.04
-
+ complete
mod_multicast
@@ -120,8 +120,8 @@
0.6.0
-
-
+ 0.1.0
+ complete
mod_stats
@@ -129,17 +129,26 @@
1.25
-
-
+ 0.5.0
+ complete
mod_muc
+
+
+
+ 1.2
+ 0.5.0
+ complete
+ mod_pubsub
+
+
1.2
-
-
+ 0.1.0
+ complete
mod_private
@@ -147,8 +156,8 @@
1.2
-
-
+ 1.1.0
+ complete
mod_adhoc
@@ -156,8 +165,8 @@
1.2
-
-
+ 0.1.0
+ complete
mod_vcard
@@ -165,17 +174,26 @@
1.3
-
-
+ 0.1.0
+ complete
mod_vcard
+
+
+
+ 1.0
+ 2.1.0
+ complete
+
+
+
1.14
-
-
+ 0.5.0
+ partial
mod_pubsub
@@ -183,8 +201,8 @@
1.8
-
-
+ 2.0.0
+ complete
mod_proxy65
@@ -192,8 +210,8 @@
2.4
-
-
+ 0.1.0
+ complete
mod_register
@@ -201,17 +219,26 @@
2.5
-
-
+ 17.03
+ complete
mod_legacy_auth
+
+
+
+ 1.1.1
+ 2.1.0
+ complete
+
+
+
2.1
-
-
+ 2.1.0
+ complete
mod_client_state
@@ -219,8 +246,8 @@
1.0
-
-
+ 0.5.0
+ complete
@@ -228,8 +255,8 @@
1.1
-
-
+ 0.1.0
+ complete
mod_version
@@ -237,8 +264,8 @@
1.1
-
-
+ 0.5.0
+ complete
@@ -246,8 +273,8 @@
1.6
-
-
+ 0.1.0
+ complete
ejabberd_service
@@ -255,8 +282,8 @@
1.5
-
-
+ 2.1.4
+ complete
mod_caps
@@ -264,26 +291,35 @@
1.11
-
-
+ 16.12
+ complete
ejabberd_bosh
- 1.1
-
-
+ 1.3.0
+ 13.10
+ partial
mod_configure
+
+
+
+ 2.1
+ 1.1.0
+ complete
+ ejabberd_c2s
+
+
1.1
-
-
+ 17.09
+ complete
mod_vcard
@@ -292,7 +328,7 @@
1.4.0
22.05
-
+ complete
mod_host_meta
@@ -300,8 +336,8 @@
1.0
-
-
+ 2.1.0
+ complete
mod_disco
@@ -309,8 +345,8 @@
1.0
-
-
+ 2.1.0
+ complete
ejabberd_captcha
@@ -318,8 +354,8 @@
1.0
-
-
+ 16.01
+ complete
mod_offline
@@ -327,8 +363,8 @@
1.2
-
-
+ 2.0.0
+ complete
mod_pubsub
@@ -336,26 +372,35 @@
1.0
-
-
+ 17.12
+ complete
-
- 1.0
-
-
- ejabberd_stun
+
+ 1.2
+ 1.1.0
+ complete
+ ejabberd_auth_anonymous
+
+
+
+
+
+ 1.1
+ 17.03
+ complete
+
1.0
-
-
+ 17.03
+ complete
mod_s2s_dialback
@@ -363,8 +408,8 @@
1.2
-
-
+ 2.1.7
+ complete
mod_blocking
@@ -373,7 +418,7 @@
1.5.2
14.05
-
+ complete
mod_stream_mgmt
@@ -381,8 +426,8 @@
2.0
-
-
+ 2.1.0
+ complete
mod_ping
@@ -390,17 +435,26 @@
2.0
-
-
+ 2.1.0
+ complete
mod_time
+
+
+
+ 2.0
+ 2.1.0
+ complete
+ mod_offline
+
+
1.0
-
-
+ 1.1.2
+ complete
@@ -408,80 +462,71 @@
1.4
-
-
+ 16.12
+ complete
ejabberd_bosh
-
-
-
- 1.0
-
-
-
-
-
0.7
20.04
-
+ complete
mod_stun_disco
-
- 1.0
-
-
-
+
+ 1.1.1
+ 17.03
+ complete
+ mod_s2s_dialback
-
- 1.1
-
-
- ejabberd_s2s, mod_s2s_dialback
+
+ 1.1.1
+ 2.0.0
+ complete
+ mod_pubsub
1.1
-
-
+ 2.1.0
+ partial
ejabberd_piefxis
+
+
+
+ 1.0
+ 2.1.0
+ complete
+ ejabberd_captcha
+
+
1.3
-
-
+ 2.1.0
+ complete
mod_roster
-
-
-
- 1.0
-
-
-
-
-
0.2
-
-
+ 2.1.0
+ complete
mod_pubsub
@@ -489,54 +534,54 @@
1.2
-
-
+ 0.5.0
+ complete
mod_muc
-
-
-
- 1.0
-
-
-
-
-
0.2
-
-
+ 2.1.3
+ complete
mod_sic
- 0.13.2
-
-
+ 1.0.1
+ 13.06
+ complete
mod_carboncopy
+
+
+
+ 1.0.1
+ 24.10
+ complete
+ mod_s2s_bidi
+
+
0.6.1
15.06
-
+ complete
mod_mam
- 0.1
+ 0.3.1
21.12
-
- mod_muc_room, conversejs/prosody compatible
+ complete
+ mod_muc_room, 0.3.1 since 25.xx
@@ -544,7 +589,7 @@
0.1
19.09
-
+ complete
mod_jidprep
@@ -552,8 +597,8 @@
0.2
-
-
+ 16.01
+ complete
mod_mam, mod_muc_log, mod_offline
@@ -562,7 +607,7 @@
0.1
14.12
-
+ complete
mod_client_state
@@ -571,16 +616,16 @@
0.4.1
16.09
-
+ complete
mod_delegation
- 0.2.1
- 16.09
-
+ 0.4.1
+ 24.10
+ complete
mod_privilege
@@ -589,7 +634,7 @@
0.2
17.08
-
+ complete
mod_push
@@ -597,17 +642,17 @@
0.5.0
-
-
+ 15.09
+ complete
mod_mam
- 0.2
+ 0.3.0
15.10
-
+ complete
mod_http_upload
@@ -615,8 +660,8 @@
1.1.0
-
-
+ 17.09
+ complete
@@ -625,17 +670,44 @@
0.14.1
16.03
-
+ complete
mod_mix
+
+
+
+ 0.8.3
+ 21.12
+ complete
+ node_pep
+
+
+
+
+
+ 0.3.0
+ 24.02
+ complete
+
+
+
+
+
+
+ 0.4.0
+ 24.02
+ complete
+
+
+
- 0.2.00.2.0
- 17.09
-
- mod_avatar, mod_vcard_xupdate
+ 0.2.0
+ 18.03
+ complete
+ mod_avatar
@@ -643,7 +715,7 @@
1.1.3
23.10
-
+ complete
mod_private
@@ -651,8 +723,8 @@
0.3.0
-
-
+ 19.02
+ complete
mod_mix_pam
@@ -661,7 +733,7 @@
1.1.0
18.12
-
+ complete
mod_muc_room
@@ -670,7 +742,7 @@
0.2.0
18.12
-
+ complete
mod_private
@@ -679,27 +751,99 @@
0.1.0
23.10
-
+ complete
mod_muc_occupantid
+
+
+
+ 0.4.2
+ 24.02
+ partial
+ mod_mam, Tombstones not implemented
+
+
- 0.2.1
- 23.04
-
+ 0.3.0
+ 24.06
+ complete
mod_mam
+
+
+
+ 0.2.0
+ 24.12
+ complete
+ mod_mam
+
+
+
+
+
+ 0.4.0
+ 24.02
+ complete
+
+
+
0.2.0
-
-
+ 15.06
+ complete
mod_mam
+
+
+
+ 0.4.0
+ 24.02
+ complete
+ , 0.4.0 since 25.03
+
+
+
+
+
+ 0.2.0
+ 24.10
+ complete
+ mod_scram_upgrade
+
+
+
+
+
+ 0.2.0
+ 24.12
+ complete
+ mod_auth_fast
+
+
+
+
+
+ 0.1.1
+ 25.07
+ complete
+ mod_pubsub_serverinfo
+
+
+
+
+
+ 0.1.0
+ 24.07
+ complete
+ mod_muc
+
+
diff --git a/ejabberd.service.template b/ejabberd.service.template
index 685a104d0..902a81cb2 100644
--- a/ejabberd.service.template
+++ b/ejabberd.service.template
@@ -9,7 +9,6 @@ Group=@installuser@
LimitNOFILE=65536
Restart=on-failure
RestartSec=5
-WatchdogSec=30
ExecStart=@ctlscriptpath@/ejabberdctl foreground
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
diff --git a/ejabberd.yml.example b/ejabberd.yml.example
index df52c85be..b9df7799b 100644
--- a/ejabberd.yml.example
+++ b/ejabberd.yml.example
@@ -67,7 +67,7 @@ listen:
/admin: ejabberd_web_admin
/.well-known/acme-challenge: ejabberd_acme
-
- port: 3478
+ port: 5478
ip: "::"
transport: udp
module: ejabberd_stun
@@ -111,11 +111,19 @@ access_rules:
api_permissions:
"console commands":
- from:
- - ejabberd_ctl
+ from: ejabberd_ctl
who: all
what: "*"
- "admin access":
+ "webadmin commands":
+ from: ejabberd_web_admin
+ who: admin
+ what: "*"
+ "adhoc commands":
+ from: mod_adhoc_api
+ who: admin
+ what: "*"
+ "http access":
+ from: mod_http_api
who:
access:
allow:
@@ -156,6 +164,7 @@ shaper_rules:
modules:
mod_adhoc: {}
+ mod_adhoc_api: {}
mod_admin_extra: {}
mod_announce:
access: announce
@@ -170,7 +179,7 @@ modules:
mod_fail2ban: {}
mod_http_api: {}
mod_http_upload:
- put_url: https://@HOST@:5443/upload
+ put_url: https://@HOST_URL_ENCODE@:5443/upload
custom_headers:
"Access-Control-Allow-Origin": "https://@HOST@"
"Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
@@ -196,6 +205,7 @@ modules:
default_room_options:
mam: true
mod_muc_admin: {}
+ mod_muc_occupantid: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
@@ -224,6 +234,7 @@ modules:
ip_access: trusted_network
mod_roster:
versioning: true
+ mod_s2s_bidi: {}
mod_s2s_dialback: {}
mod_shared_roster: {}
mod_stream_mgmt:
diff --git a/ejabberdctl.cfg.example b/ejabberdctl.cfg.example
index da9e1bd32..88f99cd78 100644
--- a/ejabberdctl.cfg.example
+++ b/ejabberdctl.cfg.example
@@ -109,7 +109,10 @@
#' ERL_OPTIONS: Additional Erlang options
#
# The next variable allows to specify additional options passed to
-# erlang. See erl(1) for more info.
+# all commands using erlang interpreter. This applies to starting
+# ejabberd server itself but also auxiliary commands like for example
+# starting debug shell. See erl(1) for list of commands that can be
+# used here.
#
# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you
# want to add local modules in this path.
@@ -126,10 +129,11 @@
# ejabberd is started from an init.d script options -noshell and -detached are
# added implicitly. See erl(1) for more info.
#
+# For example you can use value "-heart -env HEART_BEAT_TIMEOUT 120 -env ERL_CRASH_DUMP_SECONDS 60"
+#
# Default: ""
#
#EJABBERD_OPTS=""
-EJABBERD_OPTS="-heart -env HEART_BEAT_TIMEOUT 120 -env ERL_CRASH_DUMP_SECONDS 60"
#.
#' ERLANG_NODE: Erlang node name
@@ -194,6 +198,17 @@ EJABBERD_OPTS="-heart -env HEART_BEAT_TIMEOUT 120 -env ERL_CRASH_DUMP_SECONDS 60
#
#CONTRIB_MODULES_CONF_DIR=/etc/ejabberd/modules
+#.
+#' CTL_OVER_HTTP: Path to ejabberdctl HTTP listener socket
+#
+# To speedup ejabberdctl execution time for ejabberd commands,
+# you can setup an ejabberd_http listener with ejabberd_ctl handling requests,
+# listening in a unix domain socket.
+#
+# Default: disabled
+#
+#CTL_OVER_HTTP=sockets/ctl_over_http.sock
+
#.
#'
# vim: foldmarker=#',#. foldmethod=marker:
diff --git a/ejabberdctl.template b/ejabberdctl.template
index 1a7403e71..0d124bead 100755
--- a/ejabberdctl.template
+++ b/ejabberdctl.template
@@ -15,8 +15,8 @@ SCRIPT_DIR="$(cd "$(dirname "$SCRIPT")" && pwd -P)"
# shellcheck disable=SC2034
ERTS_VSN="{{erts_vsn}}"
ERL="{{erl}}"
-IEX="{{bindir}}/iex"
EPMD="{{epmd}}"
+IEX="{{iexpath}}"
INSTALLUSER="{{installuser}}"
# check the proper system user is used
@@ -66,10 +66,15 @@ done
# shellcheck source=ejabberdctl.cfg.example
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
[ -n "$ERLANG_NODE_ARG" ] && ERLANG_NODE="$ERLANG_NODE_ARG"
+[ "$ERLANG_NODE" = "${ERLANG_NODE%@*}" ] && ERLANG_NODE="$ERLANG_NODE@$(hostname -s)"
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
: "${SPOOL_DIR:="{{spool_dir}}"}"
: "${EJABBERD_LOG_PATH:="$LOGS_DIR/ejabberd.log"}"
+# backward support for old mnesia spool dir path
+: "${SPOOL_DIR_OLD:="$SPOOL_DIR/$ERLANG_NODE"}"
+[ -r "$SPOOL_DIR_OLD/schema.DAT" ] && [ ! -r "$SPOOL_DIR/schema.DAT" ] && SPOOL_DIR="$SPOOL_DIR_OLD"
+
# define erl parameters
ERLANG_OPTS="+K $POLL +P $ERL_PROCESSES $ERL_OPTIONS"
if [ -n "$FIREWALL_WINDOW" ] ; then
@@ -78,6 +83,9 @@ fi
if [ -n "$INET_DIST_INTERFACE" ] ; then
INET_DIST_INTERFACE2=$("$ERL" $ERLANG_OPTS -noshell -eval 'case inet:parse_address("'$INET_DIST_INTERFACE'") of {ok,IP} -> io:format("~p",[IP]); _ -> ok end.' -s erlang halt)
if [ -n "$INET_DIST_INTERFACE2" ] ; then
+ if [ "$(echo "$INET_DIST_INTERFACE2" | grep -o "," | wc -l)" -eq 7 ] ; then
+ INET_DIST_INTERFACE2="$INET_DIST_INTERFACE2 -proto_dist inet6_tcp"
+ fi
ERLANG_OPTS="$ERLANG_OPTS -kernel inet_dist_use_interface $INET_DIST_INTERFACE2"
fi
fi
@@ -89,11 +97,12 @@ ERL_CRASH_DUMP="$LOGS_DIR"/erl_crash_$(date "+%Y%m%d-%H%M%S").dump
ERL_INETRC="$CONFIG_DIR"/inetrc
# define ejabberd parameters
-EJABBERD_OPTS="$EJABBERD_OPTS\
-$(sed '/^log_rotate_size/!d;s/:[ \t]*\([0-9]\{1,\}\).*/ \1/;s/:[ \t]*\(infinity\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
-$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
-$(sed '/^log_burst_limit_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
-$(sed '/^log_burst_limit_window_time/!d;s/:[ \t]*\([0-9]*[a-z]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")"
+EJABBERD_OPTS="\
+$(sed '/^log_rotate_size/!d;s/:[ \t]*\([0-9]\{1,\}\).*/ \1/;s/:[ \t]*\(infinity\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$(sed '/^log_burst_limit_count/!d;s/:[ \t]*\([0-9]*\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$(sed '/^log_burst_limit_window_time/!d;s/:[ \t]*\([0-9]*[a-z]*\).*/ \1 /;s/^/ /' "$EJABBERD_CONFIG_PATH")\
+$EJABBERD_OPTS"
[ -n "$EJABBERD_OPTS" ] && EJABBERD_OPTS="-ejabberd $EJABBERD_OPTS"
EJABBERD_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS $EJABBERD_OPTS -s ejabberd"
@@ -174,8 +183,10 @@ livewarning()
echo "Please be extremely cautious with your actions,"
echo "and exit immediately if you are not completely sure."
echo ""
- echo "To exit this LIVE mode and stop ejabberd, press:"
- echo " q(). and press the Enter key"
+ echo "To stop ejabberd gracefully:"
+ echo " ejabberd:stop()."
+ echo "To quit erlang immediately, press:"
+ echo " control+g and then q"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
@@ -186,6 +197,39 @@ livewarning()
fi
}
+check_etop_result()
+{
+ result=$?
+ if [ $result -eq 1 ] ; then
+ echo ""
+ echo "It seems there was some problem running 'ejabberdctl etop'."
+ echo "Is the error message something like this?"
+ echo " Failed to load module 'etop' because it cannot be found..."
+ echo "Then probably ejabberd was compiled with development tools disabled."
+ echo "To use 'etop', recompile ejabberd with: ./configure --enable-tools"
+ echo ""
+ exit $result
+ fi
+}
+
+check_iex_result()
+{
+ result=$?
+ if [ $result -eq 127 ] ; then
+ echo ""
+ echo "It seems there was some problem finding 'iex' binary from Elixir."
+ echo "Probably ejabberd was compiled with Rebar3 and Elixir disabled, like:"
+ echo " ./configure"
+ echo "which is equivalent to:"
+ echo " ./configure --with-rebar=rebar3 --disable-elixir"
+ echo "To use 'iex', recompile ejabberd enabling Elixir or using Mix:"
+ echo " ./configure --enable-elixir"
+ echo " ./configure --with-rebar=mix"
+ echo ""
+ exit $result
+ fi
+}
+
help()
{
echo ""
@@ -214,16 +258,34 @@ help()
}
# dynamic node name helper
-uid()
-{
- uuid=$(uuidgen 2>/dev/null)
- random=$(awk 'BEGIN { srand(); print int(rand()*32768) }' /dev/null)
- [ -z "$uuid" ] && [ -f /proc/sys/kernel/random/uuid ] && uuid=$(cat /proc/sys/kernel/random/uuid)
- [ -z "$uuid" ] && uuid=$(printf "%X" "${random:-$$}$(date +%M%S)")
- uuid=$(printf '%s' $uuid | sed 's/^\(...\).*$/\1/')
- [ $# -eq 0 ] && echo "${uuid}-${ERLANG_NODE}"
- [ $# -eq 1 ] && echo "${uuid}-${1}-${ERLANG_NODE}"
- [ $# -eq 2 ] && echo "${uuid}-${1}@${2}"
+uid() {
+ ERTSVERSION="$("$ERL" -version 2>&1 | sed 's|.* \([0-9]*[0-9]\).*|\1|g')"
+ if [ $ERTSVERSION -lt 11 ] ; then # otp 23.0 includes erts 11.0
+ # Erlang/OTP lower than 23, which doesn's support dynamic node code
+ N=1
+ PF=$(( $$ % 97 ))
+ while
+ case $# in
+ 0) NN="${PF}-${N}-${ERLANG_NODE}"
+ ;;
+ 1) NN="${PF}-${N}-${1}-${ERLANG_NODE}"
+ ;;
+ 2) NN="${PF}-${N}-${1}@${2}"
+ ;;
+ esac
+ N=$(( N + 1 + ( $$ % 5 ) ))
+ "$EPMD" -names 2>/dev/null | grep -q " ${NN%@*} "
+ do :; done
+ echo $NN
+ else
+ # Erlang/OTP 23 or higher: use native dynamic node code
+ # https://www.erlang.org/patches/otp-23.0#OTP-13812
+ if [ "$ERLANG_NODE" != "${ERLANG_NODE%.*}" ]; then
+ echo "undefined@${ERLANG_NODE#*@}"
+ else
+ echo "undefined"
+ fi
+ fi
}
# stop epmd if there is no other running node
@@ -256,6 +318,13 @@ check_start()
# allow sync calls
wait_status()
{
+ wait_status_node "$ERLANG_NODE" $1 $2 $3
+}
+
+wait_status_node()
+{
+ CONNECT_NODE=$1
+ shift
# args: status try delay
# return: 0 OK, 1 KO
timeout="$2"
@@ -266,14 +335,71 @@ wait_status()
if [ $timeout -eq 0 ] ; then
status="$1"
else
- exec_erl "$(uid ctl)" -hidden -noinput -s ejabberd_ctl \
- -extra "$ERLANG_NODE" $NO_TIMEOUT status > /dev/null
+ exec_erl "$(uid ctl)" -hidden -noinput \
+ -eval 'net_kernel:connect_node('"'$CONNECT_NODE'"')' \
+ -s ejabberd_ctl \
+ -extra "$CONNECT_NODE" $NO_TIMEOUT status > /dev/null
status="$?"
fi
done
[ $timeout -gt 0 ]
}
+exec_other_command()
+{
+ exec_other_command_node $ERLANG_NODE "$@"
+}
+
+exec_other_command_node()
+{
+ CONNECT_NODE=$1
+ shift
+ if [ -z "$CTL_OVER_HTTP" ] || [ ! -S "$CTL_OVER_HTTP" ] \
+ || [ ! -x "$(command -v curl)" ] || [ -z "$1" ] || [ "$1" = "help" ] \
+ || [ "$1" = "mnesia_info_ctl" ]|| [ "$1" = "print_sql_schema" ] ; then
+ exec_erl "$(uid ctl)" -hidden -noinput \
+ -eval 'net_kernel:connect_node('"'$CONNECT_NODE'"')' \
+ -s ejabberd_ctl \
+ -extra "$CONNECT_NODE" $NO_TIMEOUT "$@"
+ result=$?
+ case $result in
+ 3) help;;
+ *) :;;
+ esac
+ return $result
+ else
+ exec_ctl_over_http_socket "$@"
+ fi
+}
+
+exec_ctl_over_http_socket()
+{
+ COMMAND=${1}
+ CARGS=""
+ while [ $# -gt 0 ]; do
+ [ -z "$CARGS" ] && CARGS="[" || CARGS="${CARGS}, "
+ CARGS="${CARGS}\"$1\""
+ shift
+ done
+ CARGS="${CARGS}]"
+ TEMPHEADERS=temp-headers.log
+ curl \
+ --unix-socket ${CTL_OVER_HTTP} \
+ --header "Content-Type: application/json" \
+ --header "Accept: application/json" \
+ --data "${CARGS}" \
+ --dump-header ${TEMPHEADERS} \
+ --no-progress-meter \
+ "http://localhost/ctl/${COMMAND}"
+ result=$(sed -n 's/.*status-code: \([0-9]*\).*/\1/p' < $TEMPHEADERS)
+ rm ${TEMPHEADERS}
+ case $result in
+ 2|3) exec_other_command help ${COMMAND};;
+ *) :;;
+ esac
+ exit $result
+}
+
# ensure we can change current directory to SPOOL_DIR
[ -d "$SPOOL_DIR" ] || exec_cmd mkdir -p "$SPOOL_DIR"
cd "$SPOOL_DIR" || {
@@ -281,6 +407,103 @@ cd "$SPOOL_DIR" || {
exit 6
}
+printe()
+{
+ printf "\n"
+ printf "\e[1;40;32m==> %s\e[0m\n" "$1"
+}
+
+## Function copied from tools/make-installers
+user_agrees()
+{
+ question="$*"
+
+ if [ -t 0 ]
+ then
+ printe "$question (y/n) [n]"
+ read -r response
+ case "$response" in
+ [Yy]|[Yy][Ee][Ss])
+ return 0
+ ;;
+ [Nn]|[Nn][Oo]|'')
+ return 1
+ ;;
+ *)
+ echo 'Please respond with "yes" or "no".'
+ user_agrees "$question"
+ ;;
+ esac
+ else # Assume 'yes' if not running interactively.
+ return 0
+ fi
+}
+
+mnesia_change()
+{
+ ERLANG_NODE_OLD="$1"
+ [ "$ERLANG_NODE_OLD" = "" ] \
+ && echo "Error: Please provide the old erlang node name, for example:" \
+ && echo " ejabberdctl mnesia_change ejabberd@oldmachine" \
+ && exit 1
+
+ SPOOL_DIR_BACKUP=$SPOOL_DIR/$ERLANG_NODE_OLD-backup/
+ OLDFILE=$SPOOL_DIR_BACKUP/$ERLANG_NODE_OLD.backup
+ NEWFILE=$SPOOL_DIR_BACKUP/$ERLANG_NODE.backup
+
+ printe "This changes your mnesia database from node name '$ERLANG_NODE_OLD' to '$ERLANG_NODE'"
+
+ [ -d "$SPOOL_DIR_BACKUP" ] && printe "WARNING! A backup of old node already exists in $SPOOL_DIR_BACKUP"
+
+ if ! user_agrees "Do you want to proceed?"
+ then
+ echo 'Operation aborted.'
+ exit 1
+ fi
+
+ printe "Starting ejabberd with old node name $ERLANG_NODE_OLD ..."
+ exec_erl "$ERLANG_NODE_OLD" $EJABBERD_OPTS -detached
+ wait_status_node $ERLANG_NODE_OLD 0 30 2
+ result=$?
+ case $result in
+ 1) echo "There was a problem starting ejabberd with the old erlang node name. " \
+ && echo "Check for log errors in $EJABBERD_LOG_PATH" \
+ && exit $result;;
+ *) :;;
+ esac
+ exec_other_command_node $ERLANG_NODE_OLD "status"
+
+ printe "Making backup of old database to file $OLDFILE ..."
+ mkdir $SPOOL_DIR_BACKUP
+ exec_other_command_node $ERLANG_NODE_OLD backup "$OLDFILE"
+
+ printe "Changing node name in new backup file $NEWFILE ..."
+ exec_other_command_node $ERLANG_NODE_OLD mnesia_change_nodename "$ERLANG_NODE_OLD" "$ERLANG_NODE" "$OLDFILE" "$NEWFILE"
+
+ printe "Stopping old ejabberd..."
+ exec_other_command_node $ERLANG_NODE_OLD "stop"
+ wait_status_node $ERLANG_NODE_OLD 3 30 2 && stop_epmd
+
+ printe "Moving old mnesia spool files to backup subdirectory $SPOOL_DIR_BACKUP ..."
+ mv $SPOOL_DIR/*.DAT $SPOOL_DIR_BACKUP
+ mv $SPOOL_DIR/*.DCD $SPOOL_DIR_BACKUP
+ mv $SPOOL_DIR/*.LOG $SPOOL_DIR_BACKUP
+
+ printe "Starting ejabberd with new node name $ERLANG_NODE ..."
+ exec_erl "$ERLANG_NODE" $EJABBERD_OPTS -detached
+ wait_status 0 30 2
+ exec_other_command "status"
+
+ printe "Installing fallback of new mnesia..."
+ exec_other_command install_fallback "$NEWFILE"
+
+ printe "Stopping new ejabberd..."
+ exec_other_command "stop"
+ wait_status 3 30 2 && stop_epmd
+
+ printe "Finished, now you can start ejabberd normally"
+}
+
# main
case $1 in
start)
@@ -309,23 +532,29 @@ case $1 in
set_dist_client
exec_erl "$(uid top)" -hidden -remsh "$ERLANG_NODE" -s etop \
-output text
+ check_etop_result
;;
iexdebug)
debugwarning
set_dist_client
exec_iex "$(uid debug)" --remsh "$ERLANG_NODE"
+ check_iex_result
;;
iexlive)
livewarning
exec_iex "$ERLANG_NODE" --erl "$EJABBERD_OPTS"
+ check_iex_result
;;
ping)
PEER=${2:-$ERLANG_NODE}
[ "$PEER" = "${PEER%.*}" ] && PS="-s"
set_dist_client
exec_cmd "$ERL" ${PS:--}name "$(uid ping "$(hostname $PS)")" $ERLANG_OPTS \
- -noinput -hidden -eval 'io:format("~p~n",[net_adm:ping('"'$PEER'"')])' \
- -s erlang halt -output text
+ -noinput -hidden \
+ -eval 'net_kernel:connect_node('"'$PEER'"')' \
+ -eval 'io:format("~p~n",[net_adm:ping('"'$PEER'"')])' \
+ -eval 'halt(case net_adm:ping('"'$PEER'"') of pong -> 0; pang -> 1 end).' \
+ -output text
;;
started)
set_dist_client
@@ -335,15 +564,11 @@ case $1 in
set_dist_client
wait_status 3 30 2 && stop_epmd # wait 30x2s before timeout
;;
+ mnesia_change)
+ mnesia_change $2
+ ;;
*)
set_dist_client
- exec_erl "$(uid ctl)" -hidden -noinput -s ejabberd_ctl \
- -extra "$ERLANG_NODE" $NO_TIMEOUT "$@"
- result=$?
- case $result in
- 2|3) help;;
- *) :;;
- esac
- exit $result
+ exec_other_command "$@"
;;
esac
diff --git a/elvis.config b/elvis.config
index c679b7e2f..4ac4df9e1 100644
--- a/elvis.config
+++ b/elvis.config
@@ -5,38 +5,55 @@
{config,
[#{dirs => ["src"],
filter => "*.erl",
+ ignore => ['ELDAPv3', eldap_filter_yecc],
ruleset => erl_files,
- rules => [{elvis_style, line_length, #{limit => 100,
- skip_comments => false}},
+ rules => [{elvis_text_style, line_length, #{limit => 1000, skip_comments => false}},
{elvis_text_style, no_tabs, disable},
- {elvis_style, no_debug_call, disable},
- {elvis_style, operator_spaces, disable},
+ {elvis_style, atom_naming_convention, disable},
+ {elvis_style, consistent_variable_casing, disable},
+ {elvis_style, dont_repeat_yourself, #{min_complexity => 70}},
+ {elvis_style, export_used_types, disable},
+ {elvis_style, function_naming_convention, disable},
+ {elvis_style, god_modules, #{limit => 300}},
{elvis_style, invalid_dynamic_call, disable},
- {elvis_style, variable_naming_convention, #{ regex => ".*" }},
- {elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
- ]
+ {elvis_style, macro_names, disable},
+ {elvis_style, max_function_arity, disable}, % #{max_arity => 15}},
+ {elvis_style, nesting_level, disable},
+ {elvis_style, no_author, disable},
+ {elvis_style, no_boolean_in_comparison, disable},
+ {elvis_style, no_catch_expressions, disable},
+ {elvis_style, no_debug_call, disable},
+ {elvis_style, no_if_expression, disable},
+ {elvis_style, no_import, disable},
+ {elvis_style, no_nested_try_catch, disable},
+ {elvis_style, no_operation_on_same_value, disable},
+ {elvis_style, no_receive_without_timeout, disable},
+ {elvis_style, no_single_clause_case, disable},
+ {elvis_style, no_spec_with_records, disable},
+ {elvis_style, no_throw, disable},
+ {elvis_style, operator_spaces, disable},
+ {elvis_style, param_pattern_matching, disable},
+ {elvis_style, private_data_types, disable},
+ {elvis_style, variable_naming_convention, disable}
+ ]
},
+
+ %#{dirs => ["include"],
+ % filter => "*.hrl",
+ % ruleset => hrl_files},
+
#{dirs => ["."],
filter => "Makefile.in",
ruleset => makefiles,
- rules => [{elvis_style, line_length, #{limit => 100,
+ rules => [{elvis_text_style, line_length, #{limit => 400,
skip_comments => false}},
- {elvis_style, no_tabs, disable},
- {elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
- ]
- },
- #{dirs => ["."],
- filter => "rebar.config",
- ruleset => rebar_config,
- rules => [{elvis_style, line_length, #{limit => 100,
- skip_comments => false}},
- {elvis_style, no_tabs, disable},
- {elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
- ]
+ {elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
+ ]
}
- }
]
}
]
}
].
+
+%% vim: set filetype=erlang tabstop=8:
diff --git a/erlang_ls.config b/erlang_ls.config
index 74c892a8d..83e3e52a5 100644
--- a/erlang_ls.config
+++ b/erlang_ls.config
@@ -1,5 +1,5 @@
-otp_path: "/usr/lib/erlang"
-plt_path: "_build/default/rebar3_24.3.3_plt"
+#otp_path: "/usr/lib/erlang"
+#plt_path: "_build/default/rebar3_24.3.3_plt"
#code_reload:
# node: ejabberd@localhost
apps_dirs:
@@ -14,12 +14,12 @@ macros:
- name: DEPRECATED_GET_STACKTRACE
- name: HAVE_ERL_ERROR
- name: HAVE_URI_STRING
- - name: OTP_BELOW_25
+ - name: OTP_BELOW_27
- name: SIP
- name: STUN
diagnostics:
-# enabled:
-# - crossref
+ enabled:
+ - crossref
disabled:
# - dialyzer
- unused_includes # Otherwise it complains about unused logger.hrl
diff --git a/include/bosh.hrl b/include/bosh.hrl
index baf39e187..dd9f1b6a1 100644
--- a/include/bosh.hrl
+++ b/include/bosh.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_auth.hrl b/include/ejabberd_auth.hrl
index c8f2ea95a..bf7660d3f 100644
--- a/include/ejabberd_auth.hrl
+++ b/include/ejabberd_auth.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -18,5 +18,5 @@
%%%
%%%----------------------------------------------------------------------
--record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1',
+-record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | {binary(), binary(), atom()} | '$1',
password = <<"">> :: binary() | scram() | '_'}).
diff --git a/include/ejabberd_commands.hrl b/include/ejabberd_commands.hrl
index 812aa4d38..14d19d2e1 100644
--- a/include/ejabberd_commands.hrl
+++ b/include/ejabberd_commands.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -19,13 +19,30 @@
%%%----------------------------------------------------------------------
-type aterm() :: {atom(), atype()}.
--type atype() :: integer | string | binary |
+-type atype() :: integer | string | binary | any | atom |
{tuple, [aterm()]} | {list, aterm()}.
-type rterm() :: {atom(), rtype()}.
--type rtype() :: integer | string | atom |
+-type rtype() :: integer | string | atom | any |
{tuple, [rterm()]} | {list, rterm()} |
rescode | restuple.
+%% The 'any' and 'atom' argument types and 'any' result type
+%% should only be used %% by commands with tag 'internal',
+%% which are meant to be used only internally in ejabberd,
+%% and not called using external frontends.
+
+%% The purpose of a command can either be:
+%% - informative: its purpose is to obtain information
+%% - modifier: its purpose is to produce some change in the server
+%%
+%% A modifier command should be designed just to produce its desired side-effect,
+%% and its result term should just be success or failure: rescode or restuple.
+%%
+%% ejabberd_web_admin:make_command/2 considers that commands
+%% with result type different than rescode or restuple
+%% are commands that can be safely executed automatically
+%% to get information and build the web page.
+
-type oauth_scope() :: atom().
%% ejabberd_commands OAuth ReST ACL definition:
@@ -67,42 +84,24 @@
args_example = none :: none | [any()] | '_',
result_example = none :: any()}).
-%% TODO Fix me: Type is not up to date
--type ejabberd_commands() :: #ejabberd_commands{name :: atom(),
- tags :: [atom()],
- desc :: string(),
- longdesc :: string(),
- version :: integer(),
- module :: atom(),
- function :: atom(),
- args :: [aterm()],
- policy :: open | restricted | admin | user,
- access :: [{atom(),atom(),atom()}|atom()],
- result :: rterm()}.
+-type ejabberd_commands() :: #ejabberd_commands{name :: atom(),
+ tags :: [atom()],
+ desc :: string(),
+ longdesc :: string(),
+ version :: integer(),
+ note :: string(),
+ weight :: integer(),
+ module :: atom(),
+ function :: atom(),
+ args :: [aterm()],
+ policy :: open | restricted | admin | user,
+ access :: [{atom(),atom(),atom()}|atom()],
+ definer :: atom(),
+ result :: rterm(),
+ args_rename :: [{atom(),atom()}],
+ args_desc :: none | [string()] | '_',
+ result_desc :: none | string() | '_',
+ args_example :: none | [any()] | '_',
+ result_example :: any()
+ }.
-%% @type ejabberd_commands() = #ejabberd_commands{
-%% name = atom(),
-%% tags = [atom()],
-%% desc = string(),
-%% longdesc = string(),
-%% module = atom(),
-%% function = atom(),
-%% args = [aterm()],
-%% result = rterm()
-%% }.
-%% desc: Description of the command
-%% args: Describe the accepted arguments.
-%% This way the function that calls the command can format the
-%% arguments before calling.
-
-%% @type atype() = integer | string | {tuple, [aterm()]} | {list, aterm()}.
-%% Allowed types for arguments are integer, string, tuple and list.
-
-%% @type rtype() = integer | string | atom | {tuple, [rterm()]} | {list, rterm()} | rescode | restuple.
-%% A rtype is either an atom or a tuple with two elements.
-
-%% @type aterm() = {Name::atom(), Type::atype()}.
-%% An argument term is a tuple with the term name and the term type.
-
-%% @type rterm() = {Name::atom(), Type::rtype()}.
-%% A result term is a tuple with the term name and the term type.
diff --git a/include/ejabberd_ctl.hrl b/include/ejabberd_ctl.hrl
index 73bd1ae7c..cad82da89 100644
--- a/include/ejabberd_ctl.hrl
+++ b/include/ejabberd_ctl.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_http.hrl b/include/ejabberd_http.hrl
index 76444731c..9e1373ce6 100644
--- a/include/ejabberd_http.hrl
+++ b/include/ejabberd_http.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_oauth.hrl b/include/ejabberd_oauth.hrl
index 8ab0e8eb8..4798d9070 100644
--- a/include/ejabberd_oauth.hrl
+++ b/include/ejabberd_oauth.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_sm.hrl b/include/ejabberd_sm.hrl
index cfb3480ff..54a828e1a 100644
--- a/include/ejabberd_sm.hrl
+++ b/include/ejabberd_sm.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_sql.hrl b/include/ejabberd_sql.hrl
index 6fe86f759..d0ab55cba 100644
--- a/include/ejabberd_sql.hrl
+++ b/include/ejabberd_sql.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -53,7 +53,8 @@
-record(sql_index, {columns,
- unique = false :: boolean()}).
+ unique = false :: boolean(),
+ meta = #{}}).
-record(sql_column, {name :: binary(),
type,
default = false,
@@ -67,3 +68,8 @@
update = []}).
-record(sql_references, {table :: binary(),
column :: binary()}).
+
+-record(sql_schema_info,
+ {db_type :: pgsql | mysql | sqlite,
+ db_version :: any(),
+ new_schema = true :: boolean()}).
diff --git a/include/ejabberd_sql_pt.hrl b/include/ejabberd_sql_pt.hrl
index 584e0d5d5..f89f5c969 100644
--- a/include/ejabberd_sql_pt.hrl
+++ b/include/ejabberd_sql_pt.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_web_admin.hrl b/include/ejabberd_web_admin.hrl
index 8acfb2947..45e4beada 100644
--- a/include/ejabberd_web_admin.hrl
+++ b/include/ejabberd_web_admin.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -62,6 +62,11 @@
[{<<"type">>, Type}, {<<"name">>, Name},
{<<"value">>, Value}])).
+-define(INPUTPH(Type, Name, Value, PlaceHolder),
+ ?XA(<<"input">>,
+ [{<<"type">>, Type}, {<<"name">>, Name},
+ {<<"value">>, Value}, {<<"placeholder">>, PlaceHolder}])).
+
-define(INPUTT(Type, Name, Value),
?INPUT(Type, Name, (translate:translate(Lang, Value)))).
@@ -95,16 +100,27 @@
-define(XRES(Text),
?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)).
+-define(DIVRES(Elements),
+ ?XAE(<<"div">>, [{<<"class">>, <<"result">>}], Elements)).
+
%% Guide Link
-define(XREST(Text), ?XRES((translate:translate(Lang, Text)))).
-define(GL(Ref, Title),
?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}],
[?XAE(<<"a">>,
- [{<<"href">>, <<"https://docs.ejabberd.im/admin/configuration/", Ref/binary>>},
+ [{<<"href">>, <<"https://docs.ejabberd.im/", Ref/binary>>},
{<<"target">>, <<"_blank">>}],
[?C(<<"docs: ", Title/binary>>)])])).
%% h1 with a Guide Link
--define(H1GL(Name, Ref, Title),
- [?XC(<<"h1">>, Name), ?GL(Ref, Title)]).
+-define(H1GLraw(Name, Ref, Title),
+ [?XC(<<"h1">>, Name), ?GL(Ref, Title), ?BR, ?BR]).
+-define(H1GL(Name, RefConf, Title),
+ ?H1GLraw(Name, <<"admin/configuration/", RefConf/binary>>, Title)).
+
+-define(ANCHORL(Ref),
+ ?XAE(<<"div">>, [{<<"class">>, <<"anchorlink">>}],
+ [?XAE(<<"a">>,
+ [{<<"href">>, <<"#", Ref/binary>>}],
+ [?C(unicode:characters_to_binary("¶"))])])).
diff --git a/include/eldap.hrl b/include/eldap.hrl
index 45db1d314..0b6dc97e5 100644
--- a/include/eldap.hrl
+++ b/include/eldap.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/http_bind.hrl b/include/http_bind.hrl
index 4b379b2db..ab1294e7d 100644
--- a/include/http_bind.hrl
+++ b/include/http_bind.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/logger.hrl b/include/logger.hrl
index b6e7067fe..e41ab73dd 100644
--- a/include/logger.hrl
+++ b/include/logger.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -39,20 +39,46 @@
-else.
-include_lib("kernel/include/logger.hrl").
+-define(CLEAD, "\e[1"). % bold
+-define(CMID, "\e[0"). % normal
+-define(CCLEAN, "\e[0m"). % clean
+
+-define(CDEFAULT, ";49;95m"). % light magenta
+-define(CDEBUG, ";49;90m"). % dark gray
+-define(CINFO, ";49;92m"). % green
+-define(CWARNING, ";49;93m"). % light yellow
+-define(CERROR, ";49;91m"). % light magenta
+-define(CCRITICAL,";49;31m"). % light red
+
-define(DEBUG(Format, Args),
- begin ?LOG_DEBUG(Format, Args), ok end).
+ begin ?LOG_DEBUG(Format, Args,
+ #{clevel => ?CLEAD ++ ?CDEBUG,
+ ctext => ?CMID ++ ?CDEBUG}),
+ ok end).
-define(INFO_MSG(Format, Args),
- begin ?LOG_INFO(Format, Args), ok end).
+ begin ?LOG_INFO(Format, Args,
+ #{clevel => ?CLEAD ++ ?CINFO,
+ ctext => ?CCLEAN}),
+ ok end).
-define(WARNING_MSG(Format, Args),
- begin ?LOG_WARNING(Format, Args), ok end).
+ begin ?LOG_WARNING(Format, Args,
+ #{clevel => ?CLEAD ++ ?CWARNING,
+ ctext => ?CMID ++ ?CWARNING}),
+ ok end).
-define(ERROR_MSG(Format, Args),
- begin ?LOG_ERROR(Format, Args), ok end).
+ begin ?LOG_ERROR(Format, Args,
+ #{clevel => ?CLEAD ++ ?CERROR,
+ ctext => ?CMID ++ ?CERROR}),
+ ok end).
-define(CRITICAL_MSG(Format, Args),
- begin ?LOG_CRITICAL(Format, Args), ok end).
+ begin ?LOG_CRITICAL(Format, Args,
+ #{clevel => ?CLEAD++ ?CCRITICAL,
+ ctext => ?CMID ++ ?CCRITICAL}),
+ ok end).
-endif.
%% Use only when trying to troubleshoot test problem with ExUnit
@@ -62,7 +88,5 @@
_ -> 'Elixir.Logger':bare_log(error, io_lib:format(Format, Args), [?MODULE])
end).
--type re_mp() :: {re_pattern, _, _, _, _}. % Copied from re.erl
-
%% Uncomment if you want to debug p1_fsm/gen_fsm
%%-define(DBGFSM, true).
diff --git a/include/mod_announce.hrl b/include/mod_announce.hrl
index 975d77070..77badf90e 100644
--- a/include/mod_announce.hrl
+++ b/include/mod_announce.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/ejabberd_stacktrace.hrl b/include/mod_antispam.hrl
similarity index 59%
rename from include/ejabberd_stacktrace.hrl
rename to include/mod_antispam.hrl
index d51426fad..c30f24620 100644
--- a/include/ejabberd_stacktrace.hrl
+++ b/include/mod_antispam.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -18,10 +18,19 @@
%%%
%%%----------------------------------------------------------------------
--ifdef(DEPRECATED_GET_STACKTRACE).
--define(EX_RULE(Class, Reason, Stack), Class:Reason:Stack).
--define(EX_STACK(Stack), Stack).
--else.
--define(EX_RULE(Class, Reason, _), Class:Reason).
--define(EX_STACK(_), erlang:get_stacktrace()).
--endif.
+-define(MODULE_ANTISPAM, mod_antispam).
+
+-type url() :: binary().
+-type filename() :: binary() | none | false.
+-type jid_set() :: sets:set(ljid()).
+-type url_set() :: sets:set(url()).
+
+-define(DEFAULT_RTBL_DOMAINS_NODE, <<"spam_source_domains">>).
+
+-record(rtbl_service,
+ {host = none :: binary() | none,
+ node = ?DEFAULT_RTBL_DOMAINS_NODE :: binary(),
+ subscribed = false :: boolean(),
+ retry_timer = undefined :: reference() | undefined}).
+
+-type rtbl_service() :: #rtbl_service{}.
diff --git a/include/mod_caps.hrl b/include/mod_caps.hrl
index 6180868f5..ee1bbe44e 100644
--- a/include/mod_caps.hrl
+++ b/include/mod_caps.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_last.hrl b/include/mod_last.hrl
index 923ed20ce..b1c13621a 100644
--- a/include/mod_last.hrl
+++ b/include/mod_last.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_mam.hrl b/include/mod_mam.hrl
index 184afb4fb..77ea54a5e 100644
--- a/include/mod_mam.hrl
+++ b/include/mod_mam.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -26,7 +26,8 @@
bare_peer = {<<"">>, <<"">>, <<"">>} :: ljid(),
packet = #xmlel{} :: xmlel() | message(),
nick = <<"">> :: binary(),
- type = chat :: chat | groupchat}).
+ type = chat :: chat | groupchat,
+ origin_id = <<"">> :: binary()}).
-record(archive_prefs,
{us = {<<"">>, <<"">>} :: {binary(), binary()},
diff --git a/include/mod_matrix_gw.hrl b/include/mod_matrix_gw.hrl
new file mode 100644
index 000000000..cdb272e8e
--- /dev/null
+++ b/include/mod_matrix_gw.hrl
@@ -0,0 +1,36 @@
+%%%----------------------------------------------------------------------
+%%%
+%%% ejabberd, Copyright (C) 2002-2025 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.
+%%%
+%%%----------------------------------------------------------------------
+
+-record(room_version,
+ {id :: binary(),
+ %% use the same field names as in Synapse
+ enforce_key_validity :: boolean(),
+ special_case_aliases_auth :: boolean(),
+ strict_canonicaljson :: boolean(),
+ limit_notifications_power_levels :: boolean(),
+ knock_join_rule :: boolean(),
+ restricted_join_rule :: boolean(),
+ restricted_join_rule_fix :: boolean(),
+ knock_restricted_join_rule :: boolean(),
+ enforce_int_power_levels :: boolean(),
+ implicit_room_creator :: boolean(),
+ updated_redaction_rules :: boolean(),
+ hydra :: boolean()
+ }).
diff --git a/include/mod_muc.hrl b/include/mod_muc.hrl
index 173d32afe..f801b29e1 100644
--- a/include/mod_muc.hrl
+++ b/include/mod_muc.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_muc_room.hrl b/include/mod_muc_room.hrl
index 54773415c..5f81fe026 100644
--- a/include/mod_muc_room.hrl
+++ b/include/mod_muc_room.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -44,7 +44,7 @@
allow_visitor_nickchange = true :: boolean(),
public = true :: boolean(),
public_list = true :: boolean(),
- persistent = false :: boolean(),
+ persistent = false :: boolean() | {destroying, boolean()},
moderated = true :: boolean(),
captcha_protected = false :: boolean(),
members_by_default = true :: boolean(),
@@ -126,7 +126,8 @@
history = #lqueue{} :: lqueue(),
subject = [] :: [text()],
subject_author = {<<"">>, #jid{}} :: {binary(), jid()},
- hats_users = #{} :: map(), % FIXME on OTP 21+: #{ljid() => #{binary() => binary()}},
+ hats_defs = #{} :: #{binary() => {binary(), binary()}},
+ hats_users = #{} :: #{ljid() => [binary()]},
just_created = erlang:system_time(microsecond) :: true | integer(),
activity = treap:empty() :: treap:treap(),
room_shaper = none :: ejabberd_shaper:shaper(),
diff --git a/include/mod_offline.hrl b/include/mod_offline.hrl
index 73b2c2386..e1bb236f6 100644
--- a/include/mod_offline.hrl
+++ b/include/mod_offline.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_privacy.hrl b/include/mod_privacy.hrl
index 4e2345c17..8118a6de6 100644
--- a/include/mod_privacy.hrl
+++ b/include/mod_privacy.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_private.hrl b/include/mod_private.hrl
index 46fdc5c1d..05adc7d8b 100644
--- a/include/mod_private.hrl
+++ b/include/mod_private.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_proxy65.hrl b/include/mod_proxy65.hrl
index dfd3bf923..4f017124a 100644
--- a/include/mod_proxy65.hrl
+++ b/include/mod_proxy65.hrl
@@ -2,7 +2,7 @@
%%% RFC 1928 constants.
%%%
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_push.hrl b/include/mod_push.hrl
index 1408c74a3..8a9de102b 100644
--- a/include/mod_push.hrl
+++ b/include/mod_push.hrl
@@ -1,5 +1,5 @@
%%%----------------------------------------------------------------------
-%%% ejabberd, Copyright (C) 2017-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2017-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_roster.hrl b/include/mod_roster.hrl
index 68ad0bd88..a056dd22c 100644
--- a/include/mod_roster.hrl
+++ b/include/mod_roster.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_shared_roster.hrl b/include/mod_shared_roster.hrl
index 1605831ed..4c35878e8 100644
--- a/include/mod_shared_roster.hrl
+++ b/include/mod_shared_roster.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mod_vcard.hrl b/include/mod_vcard.hrl
index 6c5cf716f..d97e5c900 100644
--- a/include/mod_vcard.hrl
+++ b/include/mod_vcard.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/include/mqtt.hrl b/include/mqtt.hrl
index 097e22d4c..bf910368f 100644
--- a/include/mqtt.hrl
+++ b/include/mqtt.hrl
@@ -1,6 +1,6 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov
-%%% @copyright (C) 2002-2023 ProcessOne, SARL. All Rights Reserved.
+%%% @copyright (C) 2002-2025 ProcessOne, SARL. All Rights Reserved.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
diff --git a/include/pubsub.hrl b/include/pubsub.hrl
index 8e2c2bd81..316be342a 100644
--- a/include/pubsub.hrl
+++ b/include/pubsub.hrl
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
-%%% ejabberd, Copyright (C) 2002-2023 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2025 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
diff --git a/install-sh b/install-sh
old mode 100644
new mode 100755
diff --git a/lib/ejabberd/config/attr.ex b/lib/ejabberd/config/attr.ex
index 9d17b157d..85d19191b 100644
--- a/lib/ejabberd/config/attr.ex
+++ b/lib/ejabberd/config/attr.ex
@@ -41,7 +41,7 @@ defmodule Ejabberd.Config.Attr do
"""
@spec validate([attr]) :: [{:ok, attr}] | [{:error, attr, atom()}]
def validate(attrs) when is_list(attrs), do: Enum.map(attrs, &valid_attr?/1)
- def validate(attr), do: validate([attr]) |> List.first
+ def validate(attr), do: validate([attr])
@doc """
Returns the type of an attribute, given its name.
diff --git a/lib/ejabberd/config/config.ex b/lib/ejabberd/config/config.ex
index df508fb4d..a8805e612 100644
--- a/lib/ejabberd/config/config.ex
+++ b/lib/ejabberd/config/config.ex
@@ -105,11 +105,8 @@ defmodule Ejabberd.Config do
Code.eval_file(file_path) |> extract_and_store_module_name()
# Getting start/0 config
- Ejabberd.Config.Store.get(:module_name)
- |> case do
- nil -> IO.puts "[ ERR ] Configuration module not found."
- [module] -> call_start_func_and_store_data(module)
- end
+ [module] = Ejabberd.Config.Store.get(:module_name)
+ call_start_func_and_store_data(module)
# Fetching git modules and install them
get_modules_parsed_in_order()
diff --git a/lib/ejabberd/config/ejabberd_hook.ex b/lib/ejabberd/config/ejabberd_hook.ex
index 8b7858d23..5f9de4aa0 100644
--- a/lib/ejabberd/config/ejabberd_hook.ex
+++ b/lib/ejabberd/config/ejabberd_hook.ex
@@ -13,7 +13,6 @@ defmodule Ejabberd.Config.EjabberdHook do
@doc """
Register a hook to ejabberd.
"""
- @spec start(EjabberdHook.t) :: none
def start(%EjabberdHook{hook: hook, opts: opts, fun: fun}) do
host = Keyword.get(opts, :host, :global)
priority = Keyword.get(opts, :priority, 50)
diff --git a/lib/ejabberd/config/ejabberd_module.ex b/lib/ejabberd/config/ejabberd_module.ex
index 6a74fe460..6d5b1e467 100644
--- a/lib/ejabberd/config/ejabberd_module.ex
+++ b/lib/ejabberd/config/ejabberd_module.ex
@@ -7,12 +7,13 @@ defmodule Ejabberd.Config.EjabberdModule do
the already existing Elixir.Module.
"""
- @type t :: %{module: atom, attrs: [Attr.t]}
-
- defstruct [:module, :attrs]
-
alias Ejabberd.Config.EjabberdModule
alias Ejabberd.Config.Validation
+ alias Ejabberd.Config.Attr
+
+ @type t :: %{module: atom, attrs: [Attr.attr]}
+
+ defstruct [:module, :attrs]
@doc """
Given a list of modules / single module
@@ -29,7 +30,6 @@ defmodule Ejabberd.Config.EjabberdModule do
a git attribute and tries to fetch the repo,
then, it install them through :ext_mod.install/1
"""
- @spec fetch_git_repos([EjabberdModule.t]) :: none()
def fetch_git_repos(modules) do
modules
|> Enum.filter(&is_git_module?/1)
@@ -60,7 +60,7 @@ defmodule Ejabberd.Config.EjabberdModule do
defp fetch_and_store_repo_source_if_not_exists(path, repo) do
unless File.exists?(path) do
IO.puts "[info] Fetching: #{repo}"
- :os.cmd('git clone #{repo} #{path}')
+ :os.cmd(~c"git clone #{repo} #{path}")
end
end
diff --git a/lib/ejabberd/config/opts_formatter.ex b/lib/ejabberd/config/opts_formatter.ex
index 67887fa4f..3d3db926f 100644
--- a/lib/ejabberd/config/opts_formatter.ex
+++ b/lib/ejabberd/config/opts_formatter.ex
@@ -14,15 +14,12 @@ defmodule Ejabberd.Config.OptsFormatter do
Look at how Config.get_ejabberd_opts/0 is constructed for
more informations.
"""
- @spec format_opts_for_ejabberd([{atom(), any()}]) :: list()
+ @spec format_opts_for_ejabberd(map) :: list()
def format_opts_for_ejabberd(opts) do
opts
|> format_attrs_for_ejabberd
end
- defp format_attrs_for_ejabberd(opts) when is_list(opts),
- do: (Enum.map opts, &format_attrs_for_ejabberd/1)
-
defp format_attrs_for_ejabberd({:listeners, mods}),
do: {:listen, format_listeners_for_ejabberd(mods)}
@@ -32,6 +29,9 @@ defmodule Ejabberd.Config.OptsFormatter do
defp format_attrs_for_ejabberd({key, opts}) when is_atom(key),
do: {key, opts}
+ defp format_attrs_for_ejabberd(opts),
+ do: (Enum.map opts, &format_attrs_for_ejabberd/1)
+
defp format_mods_for_ejabberd(mods) do
Enum.map mods, fn %EjabberdModule{module: mod, attrs: attrs} ->
{mod, attrs[:opts]}
diff --git a/lib/ejabberd/config/validator/validation.ex b/lib/ejabberd/config/validator/validation.ex
index af582676e..227a3545f 100644
--- a/lib/ejabberd/config/validator/validation.ex
+++ b/lib/ejabberd/config/validator/validation.ex
@@ -3,12 +3,12 @@ defmodule Ejabberd.Config.Validation do
Module used to validate a list of modules.
"""
- @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
- @type mod_validation_result :: {:ok, EjabberdModule.t} | {:error, EjabberdModule.t, map}
-
alias Ejabberd.Config.EjabberdModule
alias Ejabberd.Config.Validator
+ @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
+ @type mod_validation_result :: {:ok, EjabberdModule.t} | {:error, EjabberdModule.t, map}
+
@doc """
Given a module or a list of modules it runs validators on them
and returns {:ok, mod} or {:error, mod, errors}, for each
diff --git a/lib/ejabberd/config/validator/validator_attrs.ex b/lib/ejabberd/config/validator/validator_attrs.ex
index 6a85c068d..e0e133b61 100644
--- a/lib/ejabberd/config/validator/validator_attrs.ex
+++ b/lib/ejabberd/config/validator/validator_attrs.ex
@@ -3,11 +3,12 @@ defmodule Ejabberd.Config.Validator.Attrs do
Validator module used to validate attributes.
"""
- # TODO: Duplicated from validator.ex !!!
- @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
-
import Ejabberd.Config.ValidatorUtility
alias Ejabberd.Config.Attr
+ alias Ejabberd.Config.EjabberdModule
+
+ # TODO: Duplicated from validator.ex !!!
+ @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
@doc """
Given a module (with the form used for validation)
@@ -17,9 +18,9 @@ defmodule Ejabberd.Config.Validator.Attrs do
@spec validate(mod_validation) :: mod_validation
def validate({modules, mod, errors}) do
errors = Enum.reduce mod.attrs, errors, fn(attr, err) ->
- case Attr.validate(attr) do
- {:ok, _attr} -> err
- {:error, attr, cause} -> put_error(err, :attribute, {attr, cause})
+ case Attr.validate([attr]) do
+ [{:ok, _attr}] -> err
+ [{:error, attr, cause}] -> put_error(err, :attribute, {attr, cause})
end
end
diff --git a/lib/ejabberd/config/validator/validator_dependencies.ex b/lib/ejabberd/config/validator/validator_dependencies.ex
index d44c8a136..4eb466663 100644
--- a/lib/ejabberd/config/validator/validator_dependencies.ex
+++ b/lib/ejabberd/config/validator/validator_dependencies.ex
@@ -4,6 +4,8 @@ defmodule Ejabberd.Config.Validator.Dependencies do
with the @dependency annotation.
"""
+ alias Ejabberd.Config.EjabberdModule
+
# TODO: Duplicated from validator.ex !!!
@type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
import Ejabberd.Config.ValidatorUtility
diff --git a/lib/ejabberd/config/validator/validator_utility.ex b/lib/ejabberd/config/validator/validator_utility.ex
index 17805f748..6047618b6 100644
--- a/lib/ejabberd/config/validator/validator_utility.ex
+++ b/lib/ejabberd/config/validator/validator_utility.ex
@@ -4,8 +4,6 @@ defmodule Ejabberd.Config.ValidatorUtility do
Imports utility functions for working with validation structures.
"""
- alias Ejabberd.Config.EjabberdModule
-
@doc """
Inserts an error inside the errors collection, for the given key.
If the key doesn't exists then it creates an empty collection
@@ -22,7 +20,6 @@ defmodule Ejabberd.Config.ValidatorUtility do
Given a list of modules it extracts and returns a list
of the module names (which are Elixir.Module).
"""
- @spec extract_module_names(EjabberdModule.t) :: [atom]
def extract_module_names(modules) when is_list(modules) do
modules
|> Enum.map(&Map.get(&1, :module))
diff --git a/lib/ejabberd/config_util.ex b/lib/ejabberd/config_util.ex
index 6592104a2..71d854f15 100644
--- a/lib/ejabberd/config_util.ex
+++ b/lib/ejabberd/config_util.ex
@@ -7,7 +7,7 @@ defmodule Ejabberd.ConfigUtil do
@doc """
Returns true when the config file is based on elixir.
"""
- @spec is_elixir_config(list) :: boolean
+ @spec is_elixir_config(binary) :: boolean
def is_elixir_config(filename) when is_list(filename) do
is_elixir_config(to_string(filename))
end
diff --git a/lib/ejabberd/module.ex b/lib/ejabberd/module.ex
deleted file mode 100644
index 9fb3f040c..000000000
--- a/lib/ejabberd/module.ex
+++ /dev/null
@@ -1,19 +0,0 @@
-defmodule Ejabberd.Module do
-
- defmacro __using__(opts) do
- logger_enabled = Keyword.get(opts, :logger, true)
-
- quote do
- @behaviour :gen_mod
- import Ejabberd.Module
-
- unquote(if logger_enabled do
- quote do: import Ejabberd.Logger
- end)
- end
- end
-
- # gen_mod callbacks
- def depends(_host, _opts), do: []
- def mod_opt_type(_), do: []
-end
diff --git a/lib/ejabberd_auth_example.ex b/lib/ejabberd_auth_example.ex
new file mode 100644
index 000000000..5bc37e093
--- /dev/null
+++ b/lib/ejabberd_auth_example.ex
@@ -0,0 +1,44 @@
+defmodule Ejabberd.Auth.Example do
+
+ @moduledoc """
+ Example ejabberd auth method written in Elixir.
+
+ This is an example to demonstrate the usage of Elixir to
+ create ejabberd auth methods.
+
+ Example configuration:
+ auth_method: 'Ejabberd.Auth.Example'
+ """
+
+ @behaviour :ejabberd_auth
+ import Ejabberd.Logger
+
+ @impl true
+ def start(host) do
+ info("Starting Ejabberd.Auth.Example to authenticate '#{host}' users")
+ nil
+ end
+
+ @impl true
+ def stop(host) do
+ info("Stopping Ejabberd.Auth.Example to authenticate '#{host}' users")
+ nil
+ end
+
+ @impl true
+ def check_password("alice", _authz_id, _host, "secret"), do: {:nocache, true}
+ def check_password(_username, _authz_id, _host, _secret), do: {:nocache, false}
+
+ @impl true
+ def user_exists("alice", _host), do: {:nocache, true}
+ def user_exists(_username, _host), do: {:nocache, false}
+
+ @impl true
+ def plain_password_required(_binary), do: true
+
+ @impl true
+ def store_type(_host), do: :external
+
+ @impl true
+ def use_cache(_host), do: false
+end
diff --git a/lib/mod_example.ex b/lib/mod_example.ex
new file mode 100644
index 000000000..12166810a
--- /dev/null
+++ b/lib/mod_example.ex
@@ -0,0 +1,46 @@
+defmodule Ejabberd.Module.Example do
+
+ @moduledoc """
+ Example ejabberd module written in Elixir.
+
+ This is an example to demonstrate the usage of Elixir to
+ create ejabberd modules.
+
+ Example configuration:
+ modules:
+ 'Ejabberd.Module.Example': {}
+ """
+
+ @behaviour :gen_mod
+ import Ejabberd.Logger
+
+ def start(host, _opts) do
+ info("Starting Ejabberd.Module.Example for host '#{host}'")
+ Ejabberd.Hooks.add(:set_presence_hook, host, __MODULE__, :on_presence, 50)
+ :ok
+ end
+
+ def stop(host) do
+ info("Stopping Ejabberd.Module.Example for host '#{host}'")
+ Ejabberd.Hooks.delete(:set_presence_hook, host, __MODULE__, :on_presence, 50)
+ :ok
+ end
+
+ def on_presence(user, _server, _resource, _packet) do
+ info("Receive presence for #{user}")
+ :none
+ end
+
+ def depends(_host, _opts) do
+ []
+ end
+
+ def mod_options(_host) do
+ []
+ end
+
+ def mod_doc() do
+ %{:desc => "This is just a demonstration."}
+ end
+
+end
diff --git a/lib/mod_presence_demo.ex b/lib/mod_presence_demo.ex
deleted file mode 100644
index f41a53a31..000000000
--- a/lib/mod_presence_demo.ex
+++ /dev/null
@@ -1,33 +0,0 @@
-defmodule ModPresenceDemo do
- use Ejabberd.Module
-
- def start(host, _opts) do
- info('Starting ejabberd module Presence Demo')
- Ejabberd.Hooks.add(:set_presence_hook, host, __MODULE__, :on_presence, 50)
- :ok
- end
-
- def stop(host) do
- info('Stopping ejabberd module Presence Demo')
- Ejabberd.Hooks.delete(:set_presence_hook, host, __MODULE__, :on_presence, 50)
- :ok
- end
-
- def on_presence(user, _server, _resource, _packet) do
- info('Receive presence for #{user}')
- :none
- end
-
- def depends(_host, _opts) do
- []
- end
-
- def mod_options(_host) do
- []
- end
-
- def mod_doc() do
- %{:desc => 'This is just a demonstration.'}
- end
-
-end
diff --git a/man/ejabberd.yml.5 b/man/ejabberd.yml.5
index 64d22c8d5..aa42e20b2 100644
--- a/man/ejabberd.yml.5
+++ b/man/ejabberd.yml.5
@@ -2,12 +2,12 @@
.\" Title: ejabberd.yml
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot
-.\" Date: 10/16/2023
+.\" Date: 08/22/2025
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
-.TH "EJABBERD\&.YML" "5" "10/16/2023" "\ \&" "\ \&"
+.TH "EJABBERD\&.YML" "5" "08/22/2025" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -82,17 +82,17 @@ 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\&.10/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
+It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/25\&.08/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
.sp
Note that this document is intended to provide comprehensive description of all configuration options that can be consulted to understand the meaning of a particular option, its format and possible values\&. It will be quite hard to understand how to configure ejabberd by reading this document only \- for this purpose the reader is recommended to read online Configuration Guide available at https://docs\&.ejabberd\&.im/admin/configuration\&.
.SH "TOP LEVEL OPTIONS"
.sp
-This section describes top level options of ejabberd\&.
+This section describes top level options of ejabberd 25\&.08\&. The options that changed in this version are marked with 🟤\&.
.PP
-\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLRules|ACLName}}\fR
+\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLName|ACLDefinition}}\fR
.RS 4
This option defines
-Access Rules\&. Each access rule is assigned a name that can be referenced from other parts of the configuration file (mostly from
+\fIbasic\&.md#access\-rules|Access Rules\fR\&. Each access rule is assigned a name that can be referenced from other parts of the configuration file (mostly from
\fIaccess\fR
options of ejabberd modules)\&. Each rule definition may contain arbitrary number of
\fIallow\fR
@@ -138,7 +138,8 @@ access_rules:
.PP
\fBacl\fR: \fI{ACLName: {ACLType: ACLValue}}\fR
.RS 4
-The option defines access control lists: named sets of rules which are used to match against different targets (such as a JID or an IP address)\&. Every set of rules has name
+This option defines
+\fI\&.\&./configuration/basic\&.md#acl|access control lists\fR: named sets of rules which are used to match against different targets (such as a JID or an IP address)\&. Every set of rules has name
\fIACLName\fR: it can be any string except
\fIall\fR
or
@@ -247,7 +248,7 @@ is in the form of "regexp", the rule matches any JID with node part matching reg
.PP
\fBacme\fR: \fIOptions\fR
.RS 4
-ACME
+\fIbasic\&.md#acme|ACME\fR
configuration, to automatically obtain SSL certificates for the domains served by ejabberd, which means that certificate requests and renewals are performed to some CA server (aka "ACME server") in a fully automated mode\&. The
\fIOptions\fR
are:
@@ -304,7 +305,7 @@ acme:
\fBallow_contrib_modules\fR: \fItrue | false\fR
.RS 4
Whether to allow installation of third\-party modules or not\&. See
-ejabberd\-contrib
+\fI\&.\&./\&.\&./admin/guide/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR
documentation section\&. The default value is
\fItrue\fR\&.
.RE
@@ -319,7 +320,9 @@ means that the same username can be taken multiple times in anonymous login mode
.PP
\fBanonymous_protocol\fR: \fIlogin_anon | sasl_anon | both\fR
.RS 4
-Define what anonymous protocol will be used:
+Define what
+\fIauthentication\&.md#anonymous\-login\-and\-sasl\-anonymous|anonymous\fR
+protocol will be used:
.sp
.RS 4
.ie n \{\
@@ -363,16 +366,13 @@ The default value is \fIsasl_anon\fR\&.
\fBapi_permissions\fR: \fI[Permission, \&.\&.\&.]\fR
.RS 4
Define the permissions for API access\&. Please consult the ejabberd Docs web → For Developers → ejabberd ReST API →
-API Permissions\&.
+\fI\&.\&./\&.\&./developer/ejabberd\-api/permissions\&.md|API Permissions\fR\&.
.RE
.PP
\fBappend_host_config\fR: \fI{Host: Options}\fR
.RS 4
-To define specific ejabberd modules in a virtual host, you can define the global
-\fImodules\fR
-option with the common modules, and later add specific modules to certain virtual hosts\&. To accomplish that,
-\fIappend_host_config\fR
-option can be used\&.
+Add a few specific options to a certain
+\fI\&.\&./configuration/basic\&.md#virtual\-hosting|virtual host\fR\&.
.RE
.PP
\fBauth_cache_life_time\fR: \fItimeout()\fR
@@ -398,14 +398,13 @@ Same as
\fIcache_size\fR
will be used\&.
.RE
-.sp
-\fINote\fR about the next option: added in 23\&.10:
.PP
\fBauth_external_user_exists_check\fR: \fItrue | false\fR
.RS 4
-Supplement check for user existence based on
+\fINote\fR
+about this option: added in 23\&.10\&. Supplement check for user existence based on
\fImod_last\fR
-data, for authentication methods that don\(cqt have a way to reliable tell if user exists (like is the case for
+data, for authentication methods that don\(cqt have a way to reliably tell if a user exists (like is the case for
\fIjwt\fR
and certificate based authentication)\&. This helps with processing offline message for those users\&. The default value is
\fItrue\fR\&.
@@ -413,7 +412,9 @@ and certificate based authentication)\&. This helps with processing offline mess
.PP
\fBauth_method\fR: \fI[mnesia | sql | anonymous | external | jwt | ldap | pam, \&.\&.\&.]\fR
.RS 4
-A list of authentication methods to use\&. If several methods are defined, authentication is considered successful as long as authentication of at least one of the methods succeeds\&. The default value is
+A list of
+\fIauthentication\&.md|authentication\fR
+methods to use\&. If several methods are defined, authentication is considered successful as long as authentication of at least one of the methods succeeds\&. The default value is
\fI[mnesia]\fR\&.
.RE
.PP
@@ -422,15 +423,16 @@ A list of authentication methods to use\&. If several methods are defined, authe
This is used by the contributed module
\fIejabberd_auth_http\fR
that can be installed from the
-ejabberd\-contrib
+\fI\&.\&./\&.\&./admin/guide/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR
Git repository\&. Please refer to that module\(cqs README file for details\&.
.RE
-.sp
-\fINote\fR about the next option: improved in 20\&.01:
.PP
\fBauth_password_format\fR: \fIplain | scram\fR
.RS 4
-The option defines in what format the users passwords are stored:
+\fINote\fR
+about this option: improved in 20\&.01\&. The option defines in what format the users passwords are stored, plain text or in
+\fIauthentication\&.md#scram|SCRAM\fR
+format:
.sp
.RS 4
.ie n \{\
@@ -440,7 +442,7 @@ The option defines in what format the users passwords are stored:
.sp -1
.IP \(bu 2.3
.\}
-\fIplain\fR: The password is stored as plain text in the database\&. This is risky because the passwords can be read if your database gets compromised\&. This is the default value\&. This format allows clients to authenticate using: the old Jabber Non\-SASL (XEP\-0078), SASL PLAIN, SASL DIGEST\-MD5, and SASL SCRAM\-SHA\-1\&.
+\fIplain\fR: The password is stored as plain text in the database\&. This is risky because the passwords can be read if your database gets compromised\&. This is the default value\&. This format allows clients to authenticate using: the old Jabber Non\-SASL (XEP\-0078), SASL PLAIN, SASL DIGEST\-MD5, and SASL SCRAM\-SHA\-1/256/512(\-PLUS)\&.
.RE
.sp
.RS 4
@@ -451,17 +453,39 @@ The option defines in what format the users passwords are stored:
.sp -1
.IP \(bu 2.3
.\}
-\fIscram\fR: The password is not stored, only some information that allows to verify the hash provided by the client\&. It is impossible to obtain the original plain password from the stored information; for this reason, when this value is configured it cannot be changed to plain anymore\&. This format allows clients to authenticate using: SASL PLAIN and SASL SCRAM\-SHA\-1\&. The default value is
-\fIplain\fR\&.
+\fIscram\fR: The password is not stored, only some information required to verify the hash provided by the client\&. It is impossible to obtain the original plain password from the stored information; for this reason, when this value is configured it cannot be changed to plain anymore\&. This format allows clients to authenticate using: SASL PLAIN and SASL SCRAM\-SHA\-1/256/512(\-PLUS)\&. The SCRAM variant depends on the
+\fIauth_scram_hash\fR
+option\&.
.RE
.RE
+.sp
+The default value is \fIplain\fR\&.
+.PP
+\fBauth_password_types_hidden_in_sasl1\fR: \fI[plain | scram_sha1 | scram_sha256 | scram_sha512]\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.07\&. List of password types that should not be offered in SASL1 authenticatication\&. Because SASL1, unlike SASL2, can\(cqt have list of available mechanisms tailored to individual user, it\(cqs possible that offered mechanisms will not be compatible with stored password, especially if new password type was added recently\&. This option allows disabling offering some mechanisms in SASL1, to a time until new password type will be available for all users\&.
+.RE
.PP
\fBauth_scram_hash\fR: \fIsha | sha256 | sha512\fR
.RS 4
-Hash algorithm that should be used to store password in SCRAM format\&. You shouldn\(cqt change this if you already have passwords generated with a different algorithm \- users that have such passwords will not be able to authenticate\&. The default value is
+Hash algorithm that should be used to store password in
+\fIauthentication\&.md#scram|SCRAM\fR
+format\&. You shouldn\(cqt change this if you already have passwords generated with a different algorithm \- users that have such passwords will not be able to authenticate\&. The default value is
\fIsha\fR\&.
.RE
.PP
+\fBauth_stored_password_types\fR: \fI[plain | scram_sha1 | scram_sha256 | scram_sha512]\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.03\&. List of password types that should be stored simultaneously for each user in database\&. When the user sets the account password, database will be updated to store the password in formats compatible with each type listed here\&. This can be used to migrate user passwords to a more secure format\&. If this option if set, it will override values set in
+\fIauth_scram_hash\fR
+and
+\fIauth_password_format\fR
+options\&. The default value is
+[]\&.
+.RE
+.PP
\fBauth_use_cache\fR: \fItrue | false\fR
.RS 4
Same as
@@ -477,9 +501,9 @@ Full path to a file containing one or more CA certificates in PEM format\&. All
field\&. There is no default value\&.
.RE
.sp
-You can use host_config to specify this option per\-vhost\&.
+You can use \fIhost_config\fR to specify this option per\-vhost\&.
.sp
-To set a specific file per listener, use the listener\(cqs cafile option\&. Please notice that \fIc2s_cafile\fR overrides the listener\(cqs \fIcafile\fR option\&.
+To set a specific file per listener, use the listener\(cqs \fIlisten\-options\&.md#cafile|cafile\fR option\&. Please notice that \fIc2s_cafile\fR overrides the listener\(cqs \fIcafile\fR option\&.
.PP
\fBc2s_ciphers\fR: \fI[Cipher, \&.\&.\&.]\fR
.RS 4
@@ -505,7 +529,8 @@ c2s_ciphers:
.PP
\fBc2s_dhfile\fR: \fIPath\fR
.RS 4
-Full path to a file containing custom DH parameters to use for c2s connections\&. Such a file could be created with the command "openssl dhparam \-out dh\&.pem 2048"\&. If this option is not specified, 2048\-bit MODP Group with 256\-bit Prime Order Subgroup will be used as defined in RFC5114 Section 2\&.3\&.
+Full path to a file containing custom DH parameters to use for c2s connections\&. Such a file could be created with the command
+\fI"openssl dhparam \-out dh\&.pem 2048"\fR\&. If this option is not specified, 2048\-bit MODP Group with 256\-bit Prime Order Subgroup will be used as defined in RFC5114 Section 2\&.3\&.
.RE
.PP
\fBc2s_protocol_options\fR: \fI[Option, \&.\&.\&.]\fR
@@ -540,7 +565,7 @@ Whether to enable or disable TLS compression for c2s connections\&. The default
Path to a file of CA root certificates\&. The default is to use system defined file if possible\&.
.RE
.sp
-For server connections, this \fIca_file\fR option is overridden by the s2s_cafile option\&.
+For server connections, this \fIca_file\fR option is overridden by the \fIs2s_cafile\fR option\&.
.PP
\fBcache_life_time\fR: \fItimeout()\fR
.RS 4
@@ -573,21 +598,22 @@ A maximum number of items (not memory!) in cache\&. The rule of thumb, for all t
\fIrouter_cache_size\fR, and
\fIsm_cache_size\fR\&.
.RE
-.sp
-\fINote\fR about the next option: improved in 23\&.01:
.PP
\fBcaptcha_cmd\fR: \fIPath | ModuleName\fR
.RS 4
-Full path to a script that generates
-CAPTCHA
-images\&.
+\fINote\fR
+about this option: improved in 23\&.01\&. Full path to a script that generates
+\fIbasic\&.md#captcha|CAPTCHA\fR
+images\&. The keyword
\fI@VERSION@\fR
is replaced with ejabberd version number in
\fIXX\&.YY\fR
-format\&.
+format\&. The keyword
\fI@SEMVER@\fR
is replaced with ejabberd version number in semver format when compiled with Elixir\(cqs mix, or XX\&.YY format otherwise\&. Alternatively, it can be the name of a module that implements ejabberd CAPTCHA support\&. There is no default value: when this option is not set, CAPTCHA functionality is completely disabled\&.
.sp
+\fBExamples\fR:
+.sp
When using the ejabberd installers or container image, the example captcha scripts can be used like this:
.sp
.if n \{\
@@ -611,17 +637,16 @@ instead\&.
\fBcaptcha_limit\fR: \fIpos_integer() | infinity\fR
.RS 4
Maximum number of
-CAPTCHA
+\fIbasic\&.md#captcha|CAPTCHA\fR
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 | auto | undefined\fR
.RS 4
-An URL where
-CAPTCHA
+\fINote\fR
+about this option: improved in 23\&.04\&. An URL where
+\fIbasic\&.md#captcha|CAPTCHA\fR
requests should be sent\&. NOTE: you need to configure
\fIrequest_handlers\fR
for
@@ -632,7 +657,7 @@ listener as well\&. If set to
already enabled, with encryption if available\&. If set to
\fIundefined\fR, it builds the URL using the deprecated
\fIcaptcha_host\fR
-+ /captcha\&. The default value is
+\fI+ /captcha\fR\&. The default value is
\fIauto\fR\&.
.RE
.PP
@@ -645,6 +670,8 @@ and so on\&. NOTE: if you modify the certificate files or change the value of th
\fIejabberdctl reload\-config\fR
in order to rebuild and reload the certificate chains\&.
.sp
+\fBExamples\fR:
+.sp
If you use
Let\(cqs Encrypt
certificates for your domain "domain\&.tld", the configuration will look like this:
@@ -675,23 +702,55 @@ A list of Erlang nodes to connect on ejabberd startup\&. This option is mostly i
.PP
\fBdefault_db\fR: \fImnesia | sql\fR
.RS 4
-Default persistent storage for ejabberd\&. Modules and other components (e\&.g\&. authentication) may have its own value\&. The default value is
+\fIdatabase\&.md#default\-database|Default database\fR
+to store persistent data in ejabberd\&. Some components can be configured with specific toplevel options like
+\fIoauth_db_type\fR\&. Many modules can be configured with specific module options, usually named
+db_type\&. The default value is
\fImnesia\fR\&.
.RE
.PP
\fBdefault_ram_db\fR: \fImnesia | redis | sql\fR
.RS 4
-Default volatile (in\-memory) storage for ejabberd\&. Modules and other components (e\&.g\&. session management) may have its own value\&. The default value is
+Default volatile (in\-memory) storage for ejabberd\&. Some components can be configured with specific toplevel options like
+\fIrouter_db_type\fR
+and
+\fIsm_db_type\fR\&. Some modules can be configured with specific module options, usually named
+ram_db_type\&. The default value is
\fImnesia\fR\&.
.RE
.PP
-\fBdefine_macro\fR: \fI{MacroName: MacroValue}\fR
+\fBdefine_keyword\fR: \fI{NAME: Value}\fR
.RS 4
-Defines a macro\&. The value can be any valid arbitrary YAML value\&. For convenience, it\(cqs recommended to define a
-\fIMacroName\fR
-in capital letters\&. Duplicated macros are not allowed\&. Macros are processed after additional configuration files have been included, so it is possible to use macros that are defined in configuration files included before the usage\&. It is possible to use a
-\fIMacroValue\fR
-in the definition of another macro\&.
+\fINote\fR
+about this option: added in 25\&.03\&. Allows to define configuration
+\fI\&.\&./configuration/file\-format\&.md#macros\-and\-keywords|keywords\fR\&.
+.sp
+\fBExample\fR:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+define_keyword:
+ SQL_USERNAME: "eja\&.global"
+
+host_config:
+ localhost:
+ define_keyword:
+ SQL_USERNAME: "eja\&.localhost"
+
+sql_username: "prefix\&.@SQL_USERNAME@"
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.PP
+\fBdefine_macro\fR: \fI{NAME: Value}\fR
+.RS 4
+\fINote\fR
+about this option: improved in 25\&.03\&. Allows to define configuration
+\fI\&.\&./configuration/file\-format\&.md#macros\-and\-keywords|macros\fR\&.
.sp
\fBExample\fR:
.sp
@@ -725,9 +784,19 @@ or
is case\-insensitive\&. The default value is an empty list, i\&.e\&. no mechanisms are disabled by default\&.
.RE
.PP
+\fBdisable_sasl_scram_downgrade_protection\fR: \fItrue | false\fR
+.RS 4
+Allows to disable sending data required by
+\fIXEP\-0474: SASL SCRAM Downgrade Protection\fR\&. There are known buggy clients (like those that use strophejs 1\&.6\&.2) which will not be able to authenticatate when servers sends data from that specification\&. This options allows server to disable it to allow even buggy clients connects, but in exchange decrease MITM protection\&. The default value of this option is
+\fIfalse\fR
+which enables this extension\&.
+.RE
+.PP
\fBdomain_balancing\fR: \fI{Domain: Options}\fR
.RS 4
-An algorithm to load balance the components that are plugged on an ejabberd cluster\&. It means that you can plug one or several instances of the same component on each ejabberd node and that the traffic will be automatically distributed\&. The algorithm to deliver messages to the component(s) can be specified by this option\&. For any component connected as
+An algorithm to
+\fI\&.\&./guide/clustering\&.md#service\-load\-balancing|load\-balance\fR
+the components that are plugged on an ejabberd cluster\&. It means that you can plug one or several instances of the same component on each ejabberd node and that the traffic will be automatically distributed\&. The algorithm to deliver messages to the component(s) can be specified by this option\&. For any component connected as
\fIDomain\fR, available
\fIOptions\fR
are:
@@ -737,28 +806,43 @@ are:
The number of components to balance\&.
.RE
.PP
-\fBtype\fR: \fIrandom | source | destination | bare_source | bare_destination\fR
+\fBtype\fR: \fIValue\fR
.RS 4
-How to deliver stanzas to connected components:
-\fIrandom\fR
-\- an instance is chosen at random;
-\fIdestination\fR
-\- an instance is chosen by the full JID of the packet\(cqs
+How to deliver stanzas to connected components\&. The default value is
+\fIrandom\fR\&. Possible values:
+.RE
+.PP
+\fB\- bare_destination\fR
+.RS 4
+by the bare JID (without resource) of the packet\(cqs
\fIto\fR
-attribute;
-\fIsource\fR
-\- by the full JID of the packet\(cqs
+attribute
+.RE
+.PP
+\fB\- bare_source\fR
+.RS 4
+by the bare JID (without resource) of the packet\(cqs
\fIfrom\fR
-attribute;
-\fIbare_destination\fR
-\- by the the bare JID (without resource) of the packet\(cqs
+attribute is used
+.RE
+.PP
+\fB\- destination\fR
+.RS 4
+an instance is chosen by the full JID of the packet\(cqs
\fIto\fR
-attribute;
-\fIbare_source\fR
-\- by the bare JID (without resource) of the packet\(cqs
+attribute
+.RE
+.PP
+\fB\- random\fR
+.RS 4
+an instance is chosen at random
+.RE
+.PP
+\fB\- source\fR
+.RS 4
+by the full JID of the packet\(cqs
\fIfrom\fR
-attribute is used\&. The default value is
-\fIrandom\fR\&.
+attribute
.RE
.sp
\fBExample\fR:
@@ -806,18 +890,22 @@ Define the base URI when performing ReST requests\&. The default value is:
.PP
\fBextauth_pool_name\fR: \fIName\fR
.RS 4
-Define the pool name appendix, so the full pool name will be
+Define the pool name appendix in
+\fIauthentication\&.md#external\-script|external auth\fR, so the full pool name will be
\fIextauth_pool_Name\fR\&. The default value is the hostname\&.
.RE
.PP
\fBextauth_pool_size\fR: \fISize\fR
.RS 4
-The option defines the number of instances of the same external program to start for better load balancing\&. The default is the number of available CPU cores\&.
+The option defines the number of instances of the same
+\fIauthentication\&.md#external\-script|external auth\fR
+program to start for better load balancing\&. The default is the number of available CPU cores\&.
.RE
.PP
\fBextauth_program\fR: \fIPath\fR
.RS 4
-Indicate in this option the full path to the external authentication script\&. The script must be executable by ejabberd\&.
+Indicate in this option the full path to the
+\fIauthentication\&.md#external\-script|external authentication script\fR\&. The script must be executable by ejabberd\&.
.RE
.PP
\fBfqdn\fR: \fIDomain\fR
@@ -836,7 +924,8 @@ for backward compatibility\&.
.RS 4
The option is used to redefine
\fIOptions\fR
-for virtual host
+for
+\fI\&.\&./configuration/basic\&.md#virtual\-hosting|virtual host\fR
\fIHost\fR\&. In the example below LDAP authentication method will be used on virtual host
\fIdomain\&.tld\fR
and SQL method will be used on virtual host
@@ -867,16 +956,46 @@ host_config:
.PP
\fBhosts\fR: \fI[Domain1, Domain2, \&.\&.\&.]\fR
.RS 4
-The option defines a list containing one or more domains that
-\fIejabberd\fR
-will serve\&. This is a
+List of one or more
+\fI\&.\&./configuration/basic\&.md#host\-names|host names\fR
+(or domains) that ejabberd will serve\&. This is a
\fBmandatory\fR
option\&.
.RE
.PP
+\fBhosts_alias\fR: \fI{Alias: Host}\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.07\&. Define aliases for existing vhosts managed by ejabberd\&. An alias may be a regexp expression\&. This option is only consulted by the
+\fIejabberd_http\fR
+listener\&.
+.sp
+\fBExample\fR:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+hosts:
+ \- domain\&.tld
+ \- example\&.org
+
+hosts_alias:
+ xmpp\&.domain\&.tld: domain\&.tld
+ jabber\&.domain\&.tld: domain\&.tld
+ mytest\&.net: example\&.org
+ "exa*": example\&.org
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.PP
\fBinclude_config_file\fR: \fI[Filename, \&.\&.\&.] | {Filename: Options}\fR
.RS 4
-Read additional configuration from
+Read and
+\fI\&.\&./configuration/file\-format\&.md#include\-additional\-files|include additional file\fR
+from
\fIFilename\fR\&. If the value is provided in
\fI{Filename: Options}\fR
format, the
@@ -895,20 +1014,21 @@ Disallows the usage of those options in the included file
\fIFilename\fR\&. The options that match this criteria are not accepted\&. The default value is an empty list\&.
.RE
.RE
-.sp
-\fINote\fR about the next option: added in 23\&.10:
.PP
\fBinstall_contrib_modules\fR: \fI[Module, \&.\&.\&.]\fR
.RS 4
-Modules to install from
-ejabberd\-contrib
+\fINote\fR
+about this option: added in 23\&.10\&. Modules to install from
+\fI\&.\&./\&.\&./admin/guide/modules\&.md#ejabberd\-contrib|ejabberd\-contrib\fR
at start time\&. The default value is an empty list of modules:
\fI[]\fR\&.
.RE
.PP
\fBjwt_auth_only_rule\fR: \fIAccessName\fR
.RS 4
-This ACL rule defines accounts that can use only this auth method, even if others are also defined in the ejabberd configuration file\&. In other words: if there are several auth methods enabled for this host (JWT, SQL, \&...), users that match this rule can only use JWT\&. The default value is
+This ACL rule defines accounts that can use only the
+\fIauthentication\&.md#jwt\-authentication|JWT\fR
+auth method, even if others are also defined in the ejabberd configuration file\&. In other words: if there are several auth methods enabled for this host (JWT, SQL, \&...), users that match this rule can only use JWT\&. The default value is
\fInone\fR\&.
.RE
.PP
@@ -916,18 +1036,24 @@ This ACL rule defines accounts that can use only this auth method, even if other
.RS 4
By default, the JID is defined in the
\fI"jid"\fR
-JWT field\&. This option allows to specify other JWT field name where the JID is defined\&.
+JWT field\&. In this option you can specify other
+\fIauthentication\&.md#jwt\-authentication|JWT\fR
+field name where the JID is defined\&.
.RE
.PP
\fBjwt_key\fR: \fIFilePath\fR
.RS 4
-Path to the file that contains the JWK Key\&. The default value is
+Path to the file that contains the
+\fIauthentication\&.md#jwt\-authentication|JWT\fR
+key\&. The default value is
\fIundefined\fR\&.
.RE
.PP
\fBlanguage\fR: \fILanguage\fR
.RS 4
-The option defines the default language of server strings that can be seen by XMPP clients\&. If an XMPP client does not possess
+Define the
+\fI\&.\&./configuration/basic\&.md#default\-language|default language\fR
+of server strings that can be seen by XMPP clients\&. If an XMPP client does not possess
\fIxml:lang\fR
attribute, the specified language is used\&. The default value is
\fI"en"\fR\&.
@@ -935,9 +1061,10 @@ attribute, the specified language is used\&. The default value is
.PP
\fBldap_backups\fR: \fI[Host, \&.\&.\&.]\fR
.RS 4
-A list of IP addresses or DNS names of LDAP backup servers\&. When no servers listed in
+A list of IP addresses or DNS names of LDAP backup servers (see
+\fI\&.\&./configuration/ldap\&.md#ldap\-connection|LDAP connection\fR)\&. When no servers listed in
\fIldap_servers\fR
-option are reachable, ejabberd will try to connect to these backup servers\&. The default is an empty list, i\&.e\&. no backup servers specified\&. WARNING: ejabberd doesn\(cqt try to reconnect back to the main servers when they become operational again, so the only way to restore these connections is to restart ejabberd\&. This limitation might be fixed in future releases\&.
+option are reachable, ejabberd connects to these backup servers\&. The default is an empty list, i\&.e\&. no backup servers specified\&. Please notice that ejabberd only connects to the next server when the existing connection is lost; it doesn\(cqt detect when a previously\-attempted server becomes available again\&.
.RE
.PP
\fBldap_base\fR: \fIBase\fR
@@ -954,10 +1081,23 @@ Whether to dereference aliases or not\&. The default value is
\fBldap_dn_filter\fR: \fI{Filter: FilterAttrs}\fR
.RS 4
This filter is applied on the results returned by the main filter\&. The filter performs an additional LDAP lookup to make the complete result\&. This is useful when you are unable to define all filter rules in
-\fIldap_filter\fR\&. You can define "%u", "%d", "%s" and "%D" pattern variables in
-\fIFilter\fR: "%u" is replaced by a user\(cqs part of the JID, "%d" is replaced by the corresponding domain (virtual host), all "%s" variables are consecutively replaced by values from the attributes in
+\fIldap_filter\fR\&. You can define
+\fI"%u"\fR,
+\fI"%d"\fR,
+\fI"%s"\fR
+and
+\fI"%D"\fR
+pattern variables in
+\fIFilter: "%u"\fR
+is replaced by a user\(cqs part of the JID,
+\fI"%d"\fR
+is replaced by the corresponding domain (virtual host), all
+\fI"%s"\fR
+variables are consecutively replaced by values from the attributes in
\fIFilterAttrs\fR
-and "%D" is replaced by Distinguished Name from the result set\&. There is no default value, which means the result is not filtered\&. WARNING: Since this filter makes additional LDAP lookups, use it only as the last resort: try to define all filter rules in
+and
+\fI"%D"\fR
+is replaced by Distinguished Name from the result set\&. There is no default value, which means the result is not filtered\&. WARNING: Since this filter makes additional LDAP lookups, use it only as the last resort: try to define all filter rules in
\fIldap_filter\fR
option if possible\&.
.sp
@@ -984,7 +1124,10 @@ Whether to encrypt LDAP connection using TLS or not\&. The default value is
\fBldap_filter\fR: \fIFilter\fR
.RS 4
An LDAP filter as defined in
-RFC4515\&. There is no default value\&. Example: "(&(objectClass=shadowAccount)(memberOf=XMPP Users))"\&. NOTE: don\(cqt forget to close brackets and don\(cqt use superfluous whitespaces\&. Also you must not use "uid" attribute in the filter because this attribute will be appended to the filter automatically\&.
+RFC4515\&. There is no default value\&. Example:
+\fI"(&(objectClass=shadowAccount)(memberOf=XMPP Users))"\fR\&. NOTE: don\(cqt forget to close brackets and don\(cqt use superfluous whitespaces\&. Also you must not use
+\fI"uid"\fR
+attribute in the filter because this attribute will be appended to the filter automatically\&.
.RE
.PP
\fBldap_password\fR: \fIPassword\fR
@@ -1008,7 +1151,8 @@ Bind Distinguished Name\&. The default value is an empty string, which means "an
.PP
\fBldap_servers\fR: \fI[Host, \&.\&.\&.]\fR
.RS 4
-A list of IP addresses or DNS names of your LDAP servers\&. The default value is
+A list of IP addresses or DNS names of your LDAP servers (see
+\fI\&.\&./configuration/ldap\&.md#ldap\-connection|LDAP connection\fR)\&. ejabberd connects immediately to all of them, and reconnects infinitely if connection is lost\&. The default value is
\fI[localhost]\fR\&.
.RE
.PP
@@ -1046,41 +1190,45 @@ LDAP attributes which hold a list of attributes to use as alternatives for getti
\fIAttr\fR
is an LDAP attribute which holds the user\(cqs part of the JID and
\fIAttrFormat\fR
-must contain one and only one pattern variable "%u" which will be replaced by the user\(cqs part of the JID\&. For example, "%u@example\&.org"\&. If the value is in the form of
+must contain one and only one pattern variable
+\fI"%u"\fR
+which will be replaced by the user\(cqs part of the JID\&. For example,
+\fI"%\fR\fIu@example\fR\fI\&.org"\fR\&. If the value is in the form of
\fI[Attr]\fR
then
\fIAttrFormat\fR
-is assumed to be "%u"\&.
+is assumed to be
+\fI"%u"\fR\&.
.RE
.PP
\fBlisten\fR: \fI[Options, \&.\&.\&.]\fR
.RS 4
The option for listeners configuration\&. See the
-Listen Modules
+\fIlisten\&.md|Listen Modules\fR
section for details\&.
.RE
-.sp
-\fINote\fR about the next option: added in 22\&.10:
.PP
\fBlog_burst_limit_count\fR: \fINumber\fR
.RS 4
-The number of messages to accept in
+\fINote\fR
+about this option: added in 22\&.10\&. The number of messages to accept in
log_burst_limit_window_time
-period before starting to drop them\&. Default 500
+period before starting to drop them\&. Default
+500
.RE
-.sp
-\fINote\fR about the next option: added in 22\&.10:
.PP
\fBlog_burst_limit_window_time\fR: \fINumber\fR
.RS 4
-The time period to rate\-limit log messages by\&. Defaults to 1 second\&.
+\fINote\fR
+about this option: added in 22\&.10\&. The time period to rate\-limit log messages by\&. Defaults to
+1
+second\&.
.RE
-.sp
-\fINote\fR about the next option: added in 23\&.01:
.PP
\fBlog_modules_fully\fR: \fI[Module, \&.\&.\&.]\fR
.RS 4
-List of modules that will log everything independently from the general loglevel option\&.
+\fINote\fR
+about this option: added in 23\&.01\&. List of modules that will log everything independently from the general loglevel option\&.
.RE
.PP
\fBlog_rotate_count\fR: \fINumber\fR
@@ -1096,14 +1244,14 @@ crash\&.log\&.0\&.
\fBlog_rotate_size\fR: \fIpos_integer() | infinity\fR
.RS 4
The size (in bytes) of a log file to trigger rotation\&. If set to
-\fIinfinity\fR, log rotation is disabled\&. The default value is
-\fI10485760\fR
-(that is, 10 Mb)\&.
+\fIinfinity\fR, log rotation is disabled\&. The default value is 10 Mb expressed in bytes:
+\fI10485760\fR\&.
.RE
.PP
\fBloglevel\fR: \fInone | emergency | alert | critical | error | warning | notice | info | debug\fR
.RS 4
-Verbosity of log files generated by ejabberd\&. The default value is
+Verbosity of ejabberd
+\fI\&.\&./configuration/basic\&.md#logging|logging\fR\&. The default value is
\fIinfo\fR\&. NOTE: previous versions of ejabberd had log levels defined in numeric format (\fI0\&.\&.5\fR)\&. The numeric values are still accepted for backward compatibility, but are not recommended\&.
.RE
.PP
@@ -1115,15 +1263,15 @@ This option specifies the maximum number of elements in the queue of the FSM (Fi
.PP
\fBmodules\fR: \fI{Module: Options}\fR
.RS 4
-The option for modules configuration\&. See
-Modules
-section for details\&.
+Set all the
+\fImodules\&.md|modules\fR
+configuration options\&.
.RE
.PP
\fBnegotiation_timeout\fR: \fItimeout()\fR
.RS 4
Time to wait for an XMPP stream negotiation to complete\&. When timeout occurs, the corresponding XMPP stream is closed\&. The default value is
-\fI30\fR
+\fI120\fR
seconds\&.
.RE
.PP
@@ -1136,12 +1284,11 @@ This option can be used to tune tick time parameter of
.PP
\fBnew_sql_schema\fR: \fItrue | false\fR
.RS 4
-Whether to use
+Whether to use the
+\fIdatabase\&.md#default\-and\-new\-schemas|new SQL schema\fR\&. All schemas are located at
+https://github\&.com/processone/ejabberd/tree/25\&.08/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The
\fInew\fR
-SQL schema\&. All schemas are located at
-https://github\&.com/processone/ejabberd/tree/23\&.10/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
+schema can handle several XMPP domains in a single ejabberd database\&. Using this
\fInew\fR
schema is best when serving several XMPP domains and/or changing domains from time to time\&. This avoid need to manage several databases and handle complex configuration changes\&. The default depends on configuration flag
\fI\-\-enable\-new\-sql\-schema\fR
@@ -1172,12 +1319,11 @@ Same as
\fIcache_missed\fR
will be used\&.
.RE
-.sp
-\fINote\fR about the next option: added in 21\&.01:
.PP
\fBoauth_cache_rest_failure_life_time\fR: \fItimeout()\fR
.RS 4
-The time that a failure in OAuth ReST is cached\&. The default value is
+\fINote\fR
+about this option: added in 21\&.01\&. The time that a failure in OAuth ReST is cached\&. The default value is
\fIinfinity\fR\&.
.RE
.PP
@@ -1248,29 +1394,28 @@ option)\&. Later, when memory drops below this
\fI80\fR
percents\&.
.RE
-.sp
-\fINote\fR about the next option: changed in 23\&.01:
.PP
\fBoutgoing_s2s_families\fR: \fI[ipv6 | ipv4, \&.\&.\&.]\fR
.RS 4
-Specify which address families to try, in what order\&. The default is
+\fINote\fR
+about this option: changed in 23\&.01\&. 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\&.
.RE
-.sp
-\fINote\fR about the next option: added in 20\&.12:
.PP
\fBoutgoing_s2s_ipv4_address\fR: \fIAddress\fR
.RS 4
-Specify the IPv4 address that will be used when establishing an outgoing S2S IPv4 connection, for example "127\&.0\&.0\&.1"\&. The default value is
+\fINote\fR
+about this option: added in 20\&.12\&. Specify the IPv4 address that will be used when establishing an outgoing S2S IPv4 connection, for example
+\fI"127\&.0\&.0\&.1"\fR\&. The default value is
\fIundefined\fR\&.
.RE
-.sp
-\fINote\fR about the next option: added in 20\&.12:
.PP
\fBoutgoing_s2s_ipv6_address\fR: \fIAddress\fR
.RS 4
-Specify the IPv6 address that will be used when establishing an outgoing S2S IPv6 connection, for example "::FFFF:127\&.0\&.0\&.1"\&. The default value is
+\fINote\fR
+about this option: added in 20\&.12\&. Specify the IPv6 address that will be used when establishing an outgoing S2S IPv6 connection, for example
+\fI"::FFFF:127\&.0\&.0\&.1"\fR\&. The default value is
\fIundefined\fR\&.
.RE
.PP
@@ -1289,13 +1434,17 @@ seconds\&.
.PP
\fBpam_service\fR: \fIName\fR
.RS 4
-This option defines the PAM service name\&. Refer to the PAM documentation of your operation system for more information\&. The default value is
+This option defines the
+\fIauthentication\&.md#pam\-authentication|PAM\fR
+service name\&. Refer to the PAM documentation of your operation system for more information\&. The default value is
\fIejabberd\fR\&.
.RE
.PP
\fBpam_userinfotype\fR: \fIusername | jid\fR
.RS 4
-This option defines what type of information about the user ejabberd provides to the PAM service: only the username, or the user\(cqs JID\&. Default is
+This option defines what type of information about the user ejabberd provides to the
+\fIauthentication\&.md#pam\-authentication|PAM\fR
+service: only the username, or the user\(cqs JID\&. Default is
\fIusername\fR\&.
.RE
.PP
@@ -1329,36 +1478,47 @@ option where file queues will be placed\&. The default value is
.PP
\fBredis_connect_timeout\fR: \fItimeout()\fR
.RS 4
-A timeout to wait for the connection to be re\-established to the Redis server\&. The default is
+A timeout to wait for the connection to be re\-established to the
+\fIdatabase\&.md#redis|Redis\fR
+server\&. The default is
\fI1 second\fR\&.
.RE
.PP
\fBredis_db\fR: \fINumber\fR
.RS 4
-Redis database number\&. The default is
+\fIdatabase\&.md#redis|Redis\fR
+database number\&. The default is
\fI0\fR\&.
.RE
.PP
\fBredis_password\fR: \fIPassword\fR
.RS 4
-The password to the Redis server\&. The default is an empty string, i\&.e\&. no password\&.
+The password to the
+\fIdatabase\&.md#redis|Redis\fR
+server\&. The default is an empty string, i\&.e\&. no password\&.
.RE
.PP
\fBredis_pool_size\fR: \fINumber\fR
.RS 4
-The number of simultaneous connections to the Redis server\&. The default value is
+The number of simultaneous connections to the
+\fIdatabase\&.md#redis|Redis\fR
+server\&. The default value is
\fI10\fR\&.
.RE
.PP
\fBredis_port\fR: \fI1\&.\&.65535\fR
.RS 4
-The port where the Redis server is accepting connections\&. The default is
+The port where the
+\fIdatabase\&.md#redis|Redis\fR
+server is accepting connections\&. The default is
\fI6379\fR\&.
.RE
.PP
\fBredis_queue_type\fR: \fIram | file\fR
.RS 4
-The type of request queue for the Redis server\&. See description of
+The type of request queue for the
+\fIdatabase\&.md#redis|Redis\fR
+server\&. See description of
\fIqueue_type\fR
option for the explanation\&. The default value is the value defined in
\fIqueue_type\fR
@@ -1367,9 +1527,13 @@ or
if the latter is not set\&.
.RE
.PP
-\fBredis_server\fR: \fIHostname\fR
+\fBredis_server\fR: \fIHost | IP Address | Unix Socket Path\fR
.RS 4
-A hostname or an IP address of the Redis server\&. The default is
+\fINote\fR
+about this option: improved in 24\&.12\&. A hostname, IP address or unix domain socket file of the
+\fIdatabase\&.md#redis|Redis\fR
+server\&. Setup the path to unix domain socket like:
+\fI"unix:/path/to/socket"\fR\&. The default value is
\fIlocalhost\fR\&.
.RE
.PP
@@ -1389,6 +1553,30 @@ XMPP Core: section 7\&.7\&.2\&.2\&. The default value is
\fIcloseold\fR\&.
.RE
.PP
+\fBrest_proxy\fR: \fIHost\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.07\&. Address of a HTTP Connect proxy used by modules issuing rest calls (like ejabberd_oauth_rest)
+.RE
+.PP
+\fBrest_proxy_password\fR: \fIstring()\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.07\&. Password used to authenticate to HTTP Connect proxy used by modules issuing rest calls (like ejabberd_oauth_rest)
+.RE
+.PP
+\fBrest_proxy_port\fR: \fI1\&.\&.65535\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.07\&. Port of a HTTP Connect proxy used by modules issuing rest calls (like ejabberd_oauth_rest)
+.RE
+.PP
+\fBrest_proxy_username\fR: \fIstring()\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.07\&. Username used to authenticate to HTTP Connect proxy used by modules issuing rest calls (like ejabberd_oauth_rest)
+.RE
+.PP
\fBrouter_cache_life_time\fR: \fItimeout()\fR
.RS 4
Same as
@@ -1440,7 +1628,7 @@ seconds\&.
\fBs2s_access\fR: \fIAccess\fR
.RS 4
This
-Access Rule
+\fIbasic\&.md#access\-rules|Access Rule\fR
defines to what remote servers can s2s connections be established\&. The default value is
\fIall\fR; no restrictions are applied, it is allowed to connect s2s to/from all remote servers\&.
.RE
@@ -1448,11 +1636,11 @@ defines to what remote servers can s2s connections be established\&. The default
\fBs2s_cafile\fR: \fIPath\fR
.RS 4
A path to a file with CA root certificates that will be used to authenticate s2s connections\&. If not set, the value of
-ca_file
+\fIca_file\fR
will be used\&.
.RE
.sp
-You can use host_config to specify this option per\-vhost\&.
+You can use \fIhost_config\fR to specify this option per\-vhost\&.
.PP
\fBs2s_ciphers\fR: \fI[Cipher, \&.\&.\&.]\fR
.RS 4
@@ -1478,7 +1666,8 @@ s2s_ciphers:
.PP
\fBs2s_dhfile\fR: \fIPath\fR
.RS 4
-Full path to a file containing custom DH parameters to use for s2s connections\&. Such a file could be created with the command "openssl dhparam \-out dh\&.pem 2048"\&. If this option is not specified, 2048\-bit MODP Group with 256\-bit Prime Order Subgroup will be used as defined in RFC5114 Section 2\&.3\&.
+Full path to a file containing custom DH parameters to use for s2s connections\&. Such a file could be created with the command
+\fI"openssl dhparam \-out dh\&.pem 2048"\fR\&. If this option is not specified, 2048\-bit MODP Group with 256\-bit Prime Order Subgroup will be used as defined in RFC5114 Section 2\&.3\&.
.RE
.PP
\fBs2s_dns_retries\fR: \fINumber\fR
@@ -1572,7 +1761,8 @@ XEP\-0138) or not\&. The default value is
.PP
\fBshaper\fR: \fI{ShaperName: Rate}\fR
.RS 4
-The option defines a set of shapers\&. Every shaper is assigned a name
+The option defines a set of
+\fI\&.\&./configuration/basic\&.md#shapers|shapers\fR\&. Every shaper is assigned a name
\fIShaperName\fR
that can be used in other parts of the configuration file, such as
\fIshaper_rules\fR
@@ -1602,9 +1792,11 @@ shaper:
.\}
.RE
.PP
-\fBshaper_rules\fR: \fI{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}\fR
+\fBshaper_rules\fR: \fI{ShaperRuleName: {Number|ShaperName: ACLName|ACLDefinition}}\fR
.RS 4
-An entry allowing to declaring shaper to use for matching user/hosts\&. Semantics is similar to
+This option defines
+\fI\&.\&./configuration/basic\&.md#shaper\-rules|shaper rules\fR
+to use for matching user/hosts\&. Semantics is similar to
\fIaccess_rules\fR
option, the only difference is that instead using
\fIallow\fR
@@ -1690,16 +1882,23 @@ An SQL database name\&. For SQLite this must be a full path to a database file\&
\fIejabberd\fR\&.
.RE
.PP
+\fBsql_flags\fR: \fI[mysql_alternative_upsert]\fR
+.RS 4
+\fINote\fR
+about this option: added in 24\&.02\&. This option accepts a list of SQL flags, and is empty by default\&.
+\fImysql_alternative_upsert\fR
+forces the alternative upsert implementation in MySQL\&.
+.RE
+.PP
\fBsql_keepalive_interval\fR: \fItimeout()\fR
.RS 4
An interval to make a dummy SQL request to keep alive the connections to the database\&. There is no default value, so no keepalive requests are made\&.
.RE
-.sp
-\fINote\fR about the next option: added in 20\&.12:
.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 only applies if the
+\fINote\fR
+about this option: added in 20\&.12\&. 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
@@ -1716,7 +1915,8 @@ The password for SQL authentication\&. The default is empty string\&.
.PP
\fBsql_pool_size\fR: \fISize\fR
.RS 4
-Number of connections to the SQL server that ejabberd will open for each virtual host\&. The default value is 10\&. WARNING: for SQLite this value is
+Number of connections to the SQL server that ejabberd will open for each virtual host\&. The default value is
+\fI10\fR\&. WARNING: for SQLite this value is
\fI1\fR
by default and it\(cqs not recommended to change it due to potential race conditions\&.
.RE
@@ -1731,14 +1931,13 @@ for PostgreSQL and
\fI1433\fR
for MS SQL\&. The option has no effect for SQLite\&.
.RE
-.sp
-\fINote\fR about the next option: added in 20\&.01:
.PP
\fBsql_prepared_statements\fR: \fItrue | false\fR
.RS 4
-This option is
+\fINote\fR
+about this option: added in 20\&.01\&. This option is
\fItrue\fR
-by default, and is useful to disable prepared statements\&. The option is valid for PostgreSQL\&.
+by default, and is useful to disable prepared statements\&. The option is valid for PostgreSQL and MySQL\&.
.RE
.PP
\fBsql_query_timeout\fR: \fItimeout()\fR
@@ -1759,22 +1958,28 @@ or
if the latter is not set\&.
.RE
.PP
-\fBsql_server\fR: \fIHost\fR
+\fBsql_server\fR: \fIHost | IP Address | ODBC Connection String | Unix Socket Path\fR
.RS 4
-The hostname or IP address of the SQL server\&. For
+\fINote\fR
+about this option: improved in 24\&.06\&. 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
+this can also be an ODBC connection string\&. When
+\fIsql_type\fR
+is
+\fImysql\fR
+or
+\fIpgsql\fR, this can be the path to a unix domain socket expressed like:
+\fI"unix:/path/to/socket"\fR\&.The default value is
\fIlocalhost\fR\&.
.RE
-.sp
-\fINote\fR about the next option: improved in 20\&.03:
.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, MS SQL and PostgreSQL\&. The default value is
+\fINote\fR
+about this option: improved in 20\&.03\&. 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
@@ -1831,12 +2036,25 @@ A user name for SQL authentication\&. The default value is
Specify what proxies are trusted when an HTTP request contains the header
\fIX\-Forwarded\-For\fR\&. You can specify
\fIall\fR
-to allow all proxies, or specify a list of IPs, possibly with masks\&. The default value is an empty list\&. This allows, if enabled, to be able to know the real IP of the request, for admin purpose, or security configuration (for example using
+to allow all proxies, or specify a list of IPs, possibly with masks\&. The default value is an empty list\&. Using this option you can know the real IP of the request, for admin purpose, or security configuration (for example using
\fImod_fail2ban\fR)\&. IMPORTANT: The proxy MUST be configured to set the
\fIX\-Forwarded\-For\fR
header if you enable this option as, otherwise, the client can set it itself and as a result the IP value cannot be trusted for security rules in ejabberd\&.
.RE
.PP
+\fBupdate_sql_schema\fR: \fItrue | false\fR
+.RS 4
+\fINote\fR
+about this option: updated in 24\&.06\&. Allow ejabberd to update SQL schema in MySQL, PostgreSQL and SQLite databases\&. This option was added in ejabberd 23\&.10, and enabled by default since 24\&.06\&. The default value is
+\fItrue\fR\&.
+.RE
+.PP
+\fBupdate_sql_schema_timeout\fR: \fItimeout()\fR
+.RS 4
+\fINote\fR
+about this option: added in 24\&.07\&. Time allocated to SQL schema update queries\&. The default value is set to 5 minutes\&.
+.RE
+.PP
\fBuse_cache\fR: \fItrue | false\fR
.RS 4
Enable or disable cache\&. The default is
@@ -1868,7 +2086,8 @@ This option enables validation for
header to protect against connections from other domains than given in the configuration file\&. In this way, the lower layer load balancer can be chosen for a specific ejabberd implementation while still providing a secure WebSocket connection\&. The default value is
\fIignore\fR\&. An example value of the
\fIURL\fR
-is "https://test\&.example\&.org:8081"\&.
+is
+\fI"https://test\&.example\&.org:8081"\fR\&.
.RE
.PP
\fBwebsocket_ping_interval\fR: \fItimeout()\fR
@@ -1888,9 +2107,13 @@ seconds\&.
.RE
.SH "MODULES"
.sp
-This section describes options of all ejabberd modules\&.
+This section describes modules options of ejabberd 25\&.08\&. The modules that changed in this version are marked with 🟤\&.
.SS "mod_adhoc"
.sp
+def:ad\-hoc command
+.sp
+: Command that can be executed by an XMPP client using XEP\-0050\&.
+.sp
This module implements XEP\-0050: Ad\-Hoc Commands\&. It\(cqs an auxiliary module and is only needed by some of the other modules\&.
.sp
.it 1 an-trap
@@ -1907,45 +2130,74 @@ Provide the Commands item in the Service Discovery\&. Default value:
\fIfalse\fR\&.
.RE
.RE
+.SS "mod_adhoc_api"
+.sp
+\fINote\fR about this option: added in 25\&.03\&.
+.sp
+Execute (def:API commands) in a XMPP client using XEP\-0050: Ad\-Hoc Commands\&. This module requires \fImod_adhoc\fR (to execute the commands), and recommends \fImod_disco\fR (to discover the commands)\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBAvailable options:\fR
+.RS 4
+.PP
+\fBdefault_version\fR: \fIinteger() | string()\fR
+.RS 4
+What API version to use\&. If setting an ejabberd version, it will use the latest API version that was available in that (def:c2s) ejabberd version\&. For example, setting
+\fI"24\&.06"\fR
+in this option implies
+\fI2\fR\&. The default value is the latest version\&.
+.RE
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBExample:\fR
+.RS 4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+acl:
+ admin:
+ user: jan@localhost
+
+api_permissions:
+ "adhoc commands":
+ from: mod_adhoc_api
+ who: admin
+ what:
+ \- "[tag:roster]"
+ \- "[tag:session]"
+ \- stats
+ \- status
+
+modules:
+ mod_adhoc_api:
+ default_version: 2
+.fi
+.if n \{\
+.RE
+.\}
+.RE
.SS "mod_admin_extra"
.sp
This module provides additional administrative commands\&.
.sp
Details for some commands:
.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-\fIban\-acount\fR: This command kicks all the connected sessions of the account from the server\&. It also changes their password to a randomly generated one, so they can\(cqt login anymore unless a server administrator changes their password again\&. It is possible to define the reason of the ban\&. The new password also includes the reason and the date and time of the ban\&. See an example below\&.
-.RE
+\fIban_account\fR API: This command kicks all the connected sessions of the account from the server\&. It also changes their password to a randomly generated one, so they can\(cqt login anymore unless a server administrator changes their password again\&. It is possible to define the reason of the ban\&. The new password also includes the reason and the date and time of the ban\&. See an example below\&.
.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-\fIpushroster\fR: (and
-\fIpushroster\-all\fR) The roster file must be placed, if using Windows, on the directory where you installed ejabberd: C:/Program Files/ejabberd or similar\&. If you use other Operating System, place the file on the same directory where the \&.beam files are installed\&. See below an example roster file\&.
-.RE
+\fIpush_roster\fR API (and \fIpush_roster_all\fR API): The roster file must be placed, if using Windows, on the directory where you installed ejabberd: C:/Program Files/ejabberd or similar\&. If you use other Operating System, place the file on the same directory where the \&.beam files are installed\&. See below an example roster file\&.
.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-\fIsrg\-create\fR: If you want to put a group Name with blankspaces, use the characters "\*(Aq and \*(Aq" to define when the Name starts and ends\&. See an example below\&.
-.RE
+\fIsrg_create\fR API: If you want to put a group Name with blank spaces, use the characters \fI"\fR\*(Aq and \fI\*(Aq"\fR to define when the Name starts and ends\&. See an example below\&.
.sp
The module has no options\&.
.sp
@@ -1978,7 +2230,7 @@ modules:
.RE
.\}
.sp
-Content of roster file for \fIpushroster\fR command:
+Content of roster file for \fIpush_roster\fR API:
.sp
.if n \{\
.RS 4
@@ -1992,44 +2244,60 @@ Content of roster file for \fIpushroster\fR command:
.RE
.\}
.sp
-With this call, the sessions of the local account which JID is boby@example\&.org will be kicked, and its password will be set to something like \fIBANNED_ACCOUNT\(em20080425T21:45:07\(em2176635\(emSpammed_rooms\fR
+With this call, the sessions of the local account which JID is \fIboby@example\&.org\fR will be kicked, and its password will be set to something like \fIBANNED_ACCOUNT\(em20080425T21:45:07\(em2176635\(emSpammed_rooms\fR
.sp
.if n \{\
.RS 4
.\}
.nf
-ejabberdctl vhost example\&.org ban\-account boby "Spammed rooms"
+ejabberdctl vhost example\&.org ban_account boby "Spammed rooms"
.fi
.if n \{\
.RE
.\}
.sp
-Call to srg\-create using double\-quotes and single\-quotes:
+Call to \fIsrg_create\fR API using double\-quotes and single\-quotes:
.sp
.if n \{\
.RS 4
.\}
.nf
-ejabberdctl srg\-create g1 example\&.org "\*(AqGroup number 1\*(Aq" this_is_g1 g1
+ejabberdctl srg_create g1 example\&.org "\*(AqGroup number 1\*(Aq" this_is_g1 g1
.fi
.if n \{\
.RE
.\}
+.sp
+\fBAPI Tags:\fR \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#accounts|accounts\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#erlang|erlang\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#last|last\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#private|private\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#purge|purge\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#roster|roster\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#session|session\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#shared_roster_group|shared_roster_group\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#stanza|stanza\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#statistics|statistics\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#vcard|vcard\fR
.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 MS SQL, MySQL, and PostgreSQL are 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 \fIdatabase\&.md#default\-and\-new\-schemas|Default and New Schemas\fR 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"
.sp
-This module enables configured users to broadcast announcements and to set the message of the day (MOTD)\&. Configured users can perform these actions with an XMPP client either using Ad\-hoc Commands or sending messages to specific JIDs\&.
+This module enables configured users to broadcast announcements and to set the message of the day (MOTD)\&. Configured users can perform these actions with an XMPP client either using Ad\-Hoc Commands or sending messages to specific JIDs\&.
+.if n \{\
.sp
-Note that this module can be resource intensive on large deployments as it may broadcast a lot of messages\&. This module should be disabled for instances of ejabberd with hundreds of thousands users\&.
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBNote\fR
+.ps -1
+.br
.sp
-The Ad\-hoc Commands are listed in the Server Discovery\&. For this feature to work, \fImod_adhoc\fR must be enabled\&.
+This module can be resource intensive on large deployments as it may broadcast a lot of messages\&. This module should be disabled for instances of ejabberd with hundreds of thousands users\&.
+.sp .5v
+.RE
.sp
-The specific JIDs where messages can be sent are listed below\&. The first JID in each entry will apply only to the specified virtual host example\&.org, while the JID between brackets will apply to all virtual hosts in ejabberd:
+To send announcements using XEP\-0050: Ad\-Hoc Commands, this module requires \fImod_adhoc\fR (to execute the commands), and recommends \fImod_disco\fR (to discover the commands)\&.
+.sp
+To send announcements by sending messages to specific JIDs, these are the destination JIDs:
.sp
.RS 4
.ie n \{\
@@ -2039,7 +2307,7 @@ The specific JIDs where messages can be sent are listed below\&. The first JID i
.sp -1
.IP \(bu 2.3
.\}
-example\&.org/announce/all (example\&.org/announce/all\-hosts/all):: The message is sent to all registered users\&. If the user is online and connected to several resources, only the resource with the highest priority will receive the message\&. If the registered user is not connected, the message will be stored offline in assumption that offline storage (see
+\fIexample\&.org/announce/all\fR: Send the message to all registered users in that vhost\&. If the user is online and connected to several resources, only the resource with the highest priority will receive the message\&. If the registered user is not connected, the message is stored offline in assumption that offline storage (see
\fImod_offline\fR) is enabled\&.
.RE
.sp
@@ -2051,7 +2319,7 @@ example\&.org/announce/all (example\&.org/announce/all\-hosts/all):: The message
.sp -1
.IP \(bu 2.3
.\}
-example\&.org/announce/online (example\&.org/announce/all\-hosts/online):: The message is sent to all connected users\&. If the user is online and connected to several resources, all resources will receive the message\&.
+\fIexample\&.org/announce/online\fR: Send the message to all connected users\&. If the user is online and connected to several resources, all resources will receive the message\&.
.RE
.sp
.RS 4
@@ -2062,7 +2330,8 @@ example\&.org/announce/online (example\&.org/announce/all\-hosts/online):: The m
.sp -1
.IP \(bu 2.3
.\}
-example\&.org/announce/motd (example\&.org/announce/all\-hosts/motd):: The message is set as the message of the day (MOTD) and is sent to users when they login\&. In addition the message is sent to all connected users (similar to announce/online)\&.
+\fIexample\&.org/announce/motd\fR: Set the message of the day (MOTD) that is sent to users when they login\&. Also sends the message to all connected users (similar to
+\fIannounce/online\fR)\&.
.RE
.sp
.RS 4
@@ -2073,7 +2342,7 @@ example\&.org/announce/motd (example\&.org/announce/all\-hosts/motd):: The messa
.sp -1
.IP \(bu 2.3
.\}
-example\&.org/announce/motd/update (example\&.org/announce/all\-hosts/motd/update):: The message is set as message of the day (MOTD) and is sent to users when they login\&. The message is not sent to any currently connected user\&.
+\fIexample\&.org/announce/motd/update\fR: Set the message of the day (MOTD) that is sent to users when they login\&. This does not send the message to any currently connected user\&.
.RE
.sp
.RS 4
@@ -2084,7 +2353,64 @@ example\&.org/announce/motd/update (example\&.org/announce/all\-hosts/motd/updat
.sp -1
.IP \(bu 2.3
.\}
-example\&.org/announce/motd/delete (example\&.org/announce/all\-hosts/motd/delete):: Any message sent to this JID removes the existing message of the day (MOTD)\&.
+\fIexample\&.org/announce/motd/delete\fR: Remove the existing message of the day (MOTD) by sending a message to this JID\&.
+.RE
+.sp
+There are similar destination JIDs to apply to all virtual hosts in ejabberd:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIexample\&.org/announce/all\-hosts/all\fR: send to all registered accounts
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIexample\&.org/announce/all\-hosts/online\fR: send to online sessions
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIexample\&.org/announce/all\-hosts/motd\fR: set MOTD and send to online
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIexample\&.org/announce/all\-hosts/motd/update\fR: update MOTD
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+\fIexample\&.org/announce/all\-hosts/motd/delete\fR: delete MOTD
.RE
.sp
.it 1 an-trap
@@ -2137,6 +2463,186 @@ Same as top\-level
option, but applied to this module only\&.
.RE
.RE
+.SS "mod_antispam"
+.sp
+\fINote\fR about this option: added in 25\&.07\&.
+.sp
+Filter spam messages and subscription requests received from remote servers based on Real\-Time Block Lists (RTBL), lists of known spammer JIDs and/or URLs mentioned in spam messages\&. Traffic classified as spam is rejected with an error (and an \fI[info]\fR message is logged) unless the sender is subscribed to the recipient\(cqs presence\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBAvailable options:\fR
+.RS 4
+.PP
+\fBaccess_spam\fR: \fIAccess\fR
+.RS 4
+Access rule that controls what accounts may receive spam messages\&. If the rule returns
+\fIallow\fR
+for a given recipient, spam messages aren\(cqt rejected for that recipient\&. The default value is
+\fInone\fR, which means that all recipients are subject to spam filtering verification\&.
+.RE
+.PP
+\fBcache_size\fR: \fIpos_integer()\fR
+.RS 4
+Maximum number of JIDs that will be cached due to sending spam URLs\&. If that limit is exceeded, the least recently used entries are removed from the cache\&. Setting this option to
+\fI0\fR
+disables the caching feature\&. Note that separate caches are used for each virtual host, and that the caches aren\(cqt distributed across cluster nodes\&. The default value is
+\fI10000\fR\&.
+.RE
+.PP
+\fBrtbl_services\fR: \fI[Service]\fR
+.RS 4
+Query a RTBL service to get domains to block, as provided by
+xmppbl\&.org\&. Please note right now this option only supports one service in that list\&. For blocking spam and abuse on MUC channels, please use
+\fImod_muc_rtbl\fR
+for now\&. If only the host is provided, the default node names will be assumed\&. If the node name is different than
+\fIspam_source_domains\fR, you can setup the custom node name with the option
+\fIspam_source_domains_node\fR\&. The default value is an empty list of services\&.
+.sp
+\fBExample\fR:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+rtbl_services:
+ \- pubsub\&.server1\&.localhost:
+ spam_source_domains_node: actual_custom_pubsub_node
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.PP
+\fBspam_domains_file\fR: \fInone | Path\fR
+.RS 4
+Path to a plain text file containing a list of known spam domains, one domain per line\&. Messages and subscription requests sent from one of the listed domains are classified as spam if sender is not in recipient\(cqs roster\&. This list of domains gets merged with the one retrieved by an RTBL host if any given\&. Use an absolute path, or the
+\fI@CONFIG_PATH@\fR
+predefined keyword
+if the file is available in the configuration directory\&. The default value is
+\fInone\fR\&.
+.RE
+.PP
+\fBspam_dump_file\fR: \fIfalse | true | Path\fR
+.RS 4
+Path to the file to store blocked messages\&. Use an absolute path, or the
+\fI@LOG_PATH@\fR
+predefined keyword
+to store logs in the same place that the other ejabberd log files\&. If set to
+\fIfalse\fR, it doesn\(cqt dump stanzas, which is the default\&. If set to
+\fItrue\fR, it stores in
+\fI"@LOG_PATH@/spam_dump_@HOST@\&.log"\fR\&.
+.RE
+.PP
+\fBspam_jids_file\fR: \fInone | Path\fR
+.RS 4
+Path to a plain text file containing a list of known spammer JIDs, one JID per line\&. Messages and subscription requests sent from one of the listed JIDs are classified as spam\&. Messages containing at least one of the listed JIDsare classified as spam as well\&. Furthermore, the sender\(cqs JID will be cached, so that future traffic originating from that JID will also be classified as spam\&. Use an absolute path, or the
+\fI@CONFIG_PATH@\fR
+predefined keyword
+if the file is available in the configuration directory\&. The default value is
+\fInone\fR\&.
+.RE
+.PP
+\fBspam_urls_file\fR: \fInone | Path\fR
+.RS 4
+Path to a plain text file containing a list of URLs known to be mentioned in spam message bodies\&. Messages containing at least one of the listed URLs are classified as spam\&. Furthermore, the sender\(cqs JID will be cached, so that future traffic originating from that JID will be classified as spam as well\&. Use an absolute path, or the
+\fI@CONFIG_PATH@\fR
+predefined keyword
+if the file is available in the configuration directory\&. The default value is
+\fInone\fR\&.
+.RE
+.PP
+\fBwhitelist_domains_file\fR: \fInone | Path\fR
+.RS 4
+Path to a file containing a list of domains to whitelist from being blocked, one per line\&. If either it is in
+\fIspam_domains_file\fR
+or more realistically in a domain sent by a RTBL host (see option
+\fIrtbl_services\fR) then this domain will be ignored and stanzas from there won\(cqt be blocked\&. Use an absolute path, or the
+\fI@CONFIG_PATH@\fR
+predefined keyword
+if the file is available in the configuration directory\&. The default value is
+\fInone\fR\&.
+.RE
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBExample:\fR
+.RS 4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+modules:
+ mod_antispam:
+ rtbl_services:
+ \- xmppbl\&.org
+ spam_jids_file: "@CONFIG_PATH@/spam_jids\&.txt"
+ spam_dump_file: "@LOG_PATH@/spam/host\-@HOST@\&.log"
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SS "mod_auth_fast"
+.sp
+\fINote\fR about this option: added in 24\&.12\&.
+.sp
+The module adds support for XEP\-0484: Fast Authentication Streamlining Tokens that allows users to authenticate using self\-managed tokens\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBAvailable options:\fR
+.RS 4
+.PP
+\fBdb_type\fR: \fImnesia\fR
+.RS 4
+Same as top\-level
+\fIdefault_db\fR
+option, but applied to this module only\&.
+.RE
+.PP
+\fBtoken_lifetime\fR: \fItimeout()\fR
+.RS 4
+Time that tokens will be kept, measured from it\(cqs creation time\&. Default value set to 30 days
+.RE
+.PP
+\fBtoken_refresh_age\fR: \fItimeout()\fR
+.RS 4
+This time determines age of token, that qualifies for automatic refresh\&. Default value set to 1 day
+.RE
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBExample:\fR
+.RS 4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+modules:
+ mod_auth_fast:
+ token_lifetime: 14days
+.fi
+.if n \{\
+.RE
+.\}
+.RE
.SS "mod_avatar"
.sp
The purpose of the module is to cope with legacy and modern XMPP clients posting avatars\&. The process is described in XEP\-0398: User Avatar to vCard\-Based Avatars Conversion\&.
@@ -2186,7 +2692,7 @@ Limit any given JID by the number of avatars it is able to convert per minute\&.
.RE
.SS "mod_block_strangers"
.sp
-This module allows to block/log messages coming from an unknown entity\&. If a writing entity is not in your roster, you can let this module drop and/or log the message\&. By default you\(cqll just not receive message from that entity\&. Enable this module if you want to drop SPAM messages\&.
+This module blocks and logs any messages coming from an unknown entity\&. If a writing entity is not in your roster, you can let this module drop and/or log the message\&. By default you\(cqll just not receive message from that entity\&. Enable this module if you want to drop SPAM messages\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -2227,7 +2733,7 @@ and some server\(cqs JID is in user\(cqs roster, then messages from any user of
\fBcaptcha\fR: \fItrue | false\fR
.RS 4
Whether to generate CAPTCHA or not in response to messages from strangers\&. See also section
-CAPTCHA
+\fIbasic\&.md#captcha|CAPTCHA\fR
of the Configuration Guide\&. The default value is
\fIfalse\fR\&.
.RE
@@ -2452,21 +2958,104 @@ While a client is inactive, queue presence stanzas that indicate (un)availabilit
.RE
.SS "mod_configure"
.sp
-The module provides server configuration functionality via XEP\-0050: Ad\-Hoc Commands\&. This module requires \fImod_adhoc\fR to be loaded\&.
+The module provides server configuration functionalities using XEP\-0030: Service Discovery and XEP\-0050: Ad\-Hoc Commands:
.sp
-The module has no options\&.
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+List and discover outgoing s2s, online client sessions and all registered accounts
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Most of the ad\-hoc commands defined in
+XEP\-0133: Service Administration
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Additional custom ad\-hoc commands specific to ejabberd
+.RE
+.sp
+This module requires \fImod_adhoc\fR (to execute the commands), and recommends \fImod_disco\fR (to discover the commands)\&.
+.sp
+Please notice that all the ad\-hoc commands implemented by this module have an equivalent API Command that you can execute using \fImod_adhoc_api\fR or any other API frontend\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBAvailable options:\fR
+.RS 4
+.PP
+\fBaccess\fR: \fIAccessName\fR
+.RS 4
+\fINote\fR
+about this option: added in 25\&.03\&. This option defines which access rule will be used to control who is allowed to access the features provided by this module\&. The default value is
+\fIconfigure\fR\&.
+.RE
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBExample:\fR
+.RS 4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+acl:
+ admin:
+ user: sun@localhost
+
+access_rules:
+ configure:
+ allow: admin
+
+modules:
+ mod_configure:
+ access: configure
+.fi
+.if n \{\
+.RE
+.\}
+.RE
.SS "mod_conversejs"
.sp
+\fINote\fR about this option: improved in 25\&.07\&.
+.sp
This module serves a simple page for the Converse XMPP web browser client\&.
.sp
-This module is available since ejabberd 21\&.12\&. Several options were improved in ejabberd 22\&.05\&.
+To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
-To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → request_handlers\&.
-.sp
-Make sure either \fImod_bosh\fR or \fIejabberd_http_ws\fR request_handlers are enabled\&.
+Make sure either \fImod_bosh\fR or \fIlisten\&.md#ejabberd_http_ws|ejabberd_http_ws\fR are enabled in at least one \fIrequest_handlers\fR\&.
.sp
When \fIconversejs_css\fR and \fIconversejs_script\fR are \fIauto\fR, by default they point to the public Converse client\&.
.sp
+This module is available since ejabberd 21\&.12\&.
+.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
@@ -2491,20 +3080,29 @@ Converse CSS URL\&. The keyword
is replaced with the hostname\&. The default value is
\fIauto\fR\&.
.RE
-.sp
-\fINote\fR about the next option: added in 22\&.05:
.PP
\fBconversejs_options\fR: \fI{Name: Value}\fR
.RS 4
-Specify additional options to be passed to Converse\&. See
+\fINote\fR
+about this option: added in 22\&.05\&. Specify additional options to be passed to Converse\&. See
Converse configuration\&. Only boolean, integer and string values are supported; lists are not supported\&.
.RE
-.sp
-\fINote\fR about the next option: added in 22\&.05:
+.PP
+\fBconversejs_plugins\fR: \fI[Filename]\fR
+.RS 4
+List of additional local files to include as scripts in the homepage\&. Please make sure those files are available in the path specified in
+\fIconversejs_resources\fR
+option, in subdirectory
+\fIplugins/\fR\&. If using the public Converse client, then
+\fI"libsignal"\fR
+gets replaced with the URL of the public library\&. The default value is
+\fI[]\fR\&.
+.RE
.PP
\fBconversejs_resources\fR: \fIPath\fR
.RS 4
-Local path to the Converse files\&. If not set, the public Converse client will be used instead\&.
+\fINote\fR
+about this option: added in 22\&.05\&. Local path to the Converse files\&. If not set, the public Converse client will be used instead\&.
.RE
.PP
\fBconversejs_script\fR: \fIauto | URL\fR
@@ -2525,9 +3123,9 @@ is replaced with the hostname\&. The default value is
.PP
\fBwebsocket_url\fR: \fIauto | WebSocketURL\fR
.RS 4
-A WebSocket URL to which Converse can connect to\&. The keyword
+A WebSocket URL to which Converse can connect to\&. The
\fI@HOST@\fR
-is replaced with the real virtual host name\&. If set to
+keyword is replaced with the real virtual host name\&. If set to
\fIauto\fR, it will build the URL of the first configured WebSocket request handler\&. The default value is
\fIauto\fR\&.
.RE
@@ -2559,6 +3157,7 @@ listen:
modules:
mod_bosh: {}
mod_conversejs:
+ conversejs_plugins: ["libsignal"]
websocket_url: "ws://@HOST@:5280/websocket"
.fi
.if n \{\
@@ -2582,7 +3181,9 @@ listen:
modules:
mod_conversejs:
- conversejs_resources: "/home/ejabberd/conversejs\-9\&.0\&.0/package/dist"
+ conversejs_resources: "/home/ejabberd/conversejs\-x\&.y\&.z/package/dist"
+ conversejs_plugins: ["libsignal\-protocol\&.min\&.js"]
+ # File path is: /home/ejabberd/conversejs\-x\&.y\&.z/package/dist/plugins/libsignal\-protocol\&.min\&.js
.fi
.if n \{\
.RE
@@ -2697,7 +3298,6 @@ acl:
server: sat\-pubsub\&.example\&.org
modules:
- \&.\&.\&.
mod_delegation:
namespaces:
urn:xmpp:mam:1:
@@ -2846,16 +3446,18 @@ hour\&.
The number of C2S authentication failures to trigger the IP ban\&. The default value is
\fI20\fR\&.
.RE
+.sp
+\fBAPI Tags:\fR \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#accounts|accounts\fR
.RE
.SS "mod_host_meta"
.sp
+\fINote\fR about this option: added in 22\&.05\&.
+.sp
This module serves small \fIhost\-meta\fR files as described in XEP\-0156: Discovering Alternative XMPP Connection Methods\&.
.sp
-This module is available since ejabberd 22\&.05\&.
+To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
-To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → request_handlers\&.
-.sp
-Notice it only works if ejabberd_http has tls enabled\&.
+Notice it only works if \fIlisten\&.md#ejabberd_http|ejabberd_http\fR has \fIlisten\-options\&.md#tls|tls\fR enabled\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -2919,15 +3521,31 @@ modules:
.RE
.SS "mod_http_api"
.sp
-This module provides a ReST interface to call ejabberd API commands using JSON data\&.
+This module provides a ReST interface to call \fI\&.\&./\&.\&./developer/ejabberd\-api/index\&.md|ejabberd API\fR commands using JSON data\&.
.sp
-To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → request_handlers\&.
+To use this module, in addition to adding it to the \fImodules\fR section, you must also enable it in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
-To use a specific API version N, when defining the URL path in the request_handlers, add a \fIvN\fR\&. For example: \fI/api/v2: mod_http_api\fR
+To use a specific API version N, when defining the URL path in the request_handlers, add a vN\&. For example: \fI/api/v2: mod_http_api\fR\&.
.sp
-To run a command, send a POST request to the corresponding URL: \fIhttp://localhost:5280/api/\fR
+To run a command, send a POST request to the corresponding URL: \fIhttp://localhost:5280/api/COMMAND\-NAME\fR
.sp
-The module has no options\&.
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBAvailable options:\fR
+.RS 4
+.PP
+\fBdefault_version\fR: \fIinteger() | string()\fR
+.RS 4
+\fINote\fR
+about this option: added in 24\&.12\&. What API version to use when none is specified in the URL path\&. If setting an ejabberd version, it will use the latest API version that was available in that ejabberd version\&. For example, setting
+\fI"24\&.06"\fR
+in this option implies
+\fI2\fR\&. The default value is the latest version\&.
+.RE
+.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -2949,7 +3567,8 @@ listen:
/api: mod_http_api
modules:
- mod_http_api: {}
+ mod_http_api:
+ default_version: 2
.fi
.if n \{\
.RE
@@ -3040,25 +3659,20 @@ List of accounts that are allowed to use this service\&. Default value:
\fBExamples:\fR
.RS 4
.sp
-This example configuration will serve the files from the local directory \fI/var/www\fR in the address \fIhttp://example\&.org:5280/pub/archive/\fR\&. In this example a new content type \fIogg\fR is defined, \fIpng\fR is redefined, and \fIjpg\fR definition is deleted:
+This example configuration will serve the files from the local directory \fI/var/www\fR in the address \fIhttp://example\&.org:5280/pub/content/\fR\&. In this example a new content type \fIogg\fR is defined, \fIpng\fR is redefined, and \fIjpg\fR definition is deleted:
.sp
.if n \{\
.RS 4
.\}
.nf
listen:
- \&.\&.\&.
\-
port: 5280
module: ejabberd_http
request_handlers:
- \&.\&.\&.
- /pub/archive: mod_http_fileserver
- \&.\&.\&.
- \&.\&.\&.
+ /pub/content: mod_http_fileserver
modules:
- \&.\&.\&.
mod_http_fileserver:
docroot: /var/www
accesslog: /var/log/ejabberd/access\&.log
@@ -3072,7 +3686,6 @@ modules:
\&.ogg: audio/ogg
\&.png: image/png
default_content_type: text/html
- \&.\&.\&.
.fi
.if n \{\
.RE
@@ -3082,7 +3695,7 @@ modules:
.sp
This module allows for requesting permissions to upload a file via HTTP as described in XEP\-0363: HTTP File Upload\&. If the request is accepted, the client receives a URL for uploading the file and another URL from which that file can later be downloaded\&.
.sp
-In order to use this module, it must be enabled in \fIlisten\fR → \fIejabberd_http\fR → request_handlers\&.
+In order to use this module, it must be enabled in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -3107,26 +3720,34 @@ This option specifies additional header fields to be included in all HTTP respon
.RS 4
This option defines the permission bits of the
\fIdocroot\fR
-directory and any directories created during file uploads\&. The bits are specified as an octal number (see the chmod(1) manual page) within double quotes\&. For example: "0755"\&. The default is undefined, which means no explicit permissions will be set\&.
+directory and any directories created during file uploads\&. The bits are specified as an octal number (see the
+\fIchmod(1)\fR
+manual page) within double quotes\&. For example:
+\fI"0755"\fR\&. The default is undefined, which means no explicit permissions will be set\&.
.RE
.PP
\fBdocroot\fR: \fIPath\fR
.RS 4
-Uploaded files are stored below the directory specified (as an absolute path) with this option\&. The keyword @HOME@ is replaced with the home directory of the user running ejabberd, and the keyword @HOST@ with the virtual host name\&. The default value is "@HOME@/upload"\&.
+Uploaded files are stored below the directory specified (as an absolute path) with this option\&. The keyword
+\fI@HOME@\fR
+is replaced with the home directory of the user running ejabberd, and the keyword
+\fI@HOST@\fR
+with the virtual host name\&. The default value is
+\fI"@HOME@/upload"\fR\&.
.RE
.PP
\fBexternal_secret\fR: \fIText\fR
.RS 4
This option makes it possible to offload all HTTP Upload processing to a separate HTTP server\&. Both ejabberd and the HTTP server should share this secret and behave exactly as described at
-Prosody\(cqs mod_http_upload_external
-in the
-\fIImplementation\fR
-section\&. There is no default value\&.
+Prosody\(cqs mod_http_upload_external: Implementation\&. There is no default value\&.
.RE
.PP
\fBfile_mode\fR: \fIPermission\fR
.RS 4
-This option defines the permission bits of uploaded files\&. The bits are specified as an octal number (see the chmod(1) manual page) within double quotes\&. For example: "0644"\&. The default is undefined, which means no explicit permissions will be set\&.
+This option defines the permission bits of uploaded files\&. The bits are specified as an octal number (see the
+\fIchmod(1)\fR
+manual page) within double quotes\&. For example:
+\fI"0644"\fR\&. The default is undefined, which means no explicit permissions will be set\&.
.RE
.PP
\fBget_url\fR: \fIURL\fR
@@ -3134,8 +3755,9 @@ This option defines the permission bits of uploaded files\&. The bits are specif
This option specifies the initial part of the GET URLs used for downloading the files\&. The default value is
\fIundefined\fR\&. When this option is
\fIundefined\fR, this option is set to the same value as
-\fIput_url\fR\&. The keyword @HOST@ is replaced with the virtual host name\&. NOTE: if GET requests are handled by
-\fImod_http_upload\fR, the
+\fIput_url\fR\&. The keyword
+\fI@HOST@\fR
+is replaced with the virtual host name\&. NOTE: if GET requests are handled by this module, the
\fIget_url\fR
must match the
\fIput_url\fR\&. Setting it to a different value only makes sense if an external web server or
@@ -3154,7 +3776,8 @@ instead\&.
.RS 4
This option defines the Jabber IDs of the service\&. If the
\fIhosts\fR
-option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix "upload\&."\&. The keyword
+option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix
+\fI"upload\&."\fR\&. The keyword
\fI@HOST@\fR
is replaced with the real virtual host name\&.
.RE
@@ -3177,12 +3800,18 @@ must be specified\&. The default value is
.PP
\fBname\fR: \fIName\fR
.RS 4
-A name of the service in the Service Discovery\&. This will only be displayed by special XMPP clients\&. The default value is "HTTP File Upload"\&.
+A name of the service in the Service Discovery\&. The default value is
+\fI"HTTP File Upload"\fR\&. Please note this will only be displayed by some XMPP clients\&.
.RE
.PP
\fBput_url\fR: \fIURL\fR
.RS 4
-This option specifies the initial part of the PUT URLs used for file uploads\&. The keyword @HOST@ is replaced with the virtual host name\&. NOTE: different virtual hosts cannot use the same PUT URL\&. The default value is "https://@HOST@:5443/upload"\&.
+This option specifies the initial part of the PUT URLs used for file uploads\&. The keyword
+\fI@HOST@\fR
+is replaced with the virtual host name\&. And
+\fI@HOST_URL_ENCODE@\fR
+is replaced with the host name encoded for URL, useful when your virtual hosts contain non\-latin characters\&. NOTE: different virtual hosts cannot use the same PUT URL\&. The default value is
+\fI"https://@HOST@:5443/upload"\fR\&.
.RE
.PP
\fBrm_on_unregister\fR: \fItrue | false\fR
@@ -3194,7 +3823,9 @@ This option specifies whether files uploaded by a user should be removed when th
\fBsecret_length\fR: \fILength\fR
.RS 4
This option defines the length of the random string included in the GET and PUT URLs generated by
-\fImod_http_upload\fR\&. The minimum length is 8 characters, but it is recommended to choose a larger value\&. The default value is
+\fImod_http_upload\fR\&. The minimum length is
+\fI8\fR
+characters, but it is recommended to choose a larger value\&. The default value is
\fI40\fR\&.
.RE
.PP
@@ -3215,30 +3846,22 @@ A custom vCard of the service that will be displayed by some XMPP clients in Ser
\fIvCard\fR
is a YAML map constructed from an XML representation of vCard\&. Since the representation has no attributes, the mapping is straightforward\&.
.sp
-For example, the following XML representation of vCard:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-
- Conferences
-
-
- Elm Street
-
-
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-will be translated to:
+\fBExample\fR:
.sp
.if n \{\
.RS 4
.\}
.nf
+# This XML representation of vCard:
+#
+# Conferences
+#
+#
+# Elm Street
+#
+#
+#
+# is translated to:
vcard:
fn: Conferences
adr:
@@ -3265,23 +3888,17 @@ vcard:
.\}
.nf
listen:
- \&.\&.\&.
\-
port: 5443
module: ejabberd_http
tls: true
request_handlers:
- \&.\&.\&.
/upload: mod_http_upload
- \&.\&.\&.
- \&.\&.\&.
modules:
- \&.\&.\&.
mod_http_upload:
docroot: /ejabberd/upload
put_url: "https://@HOST@:5443/upload"
- \&.\&.\&.
.fi
.if n \{\
.RE
@@ -3303,7 +3920,7 @@ This module depends on \fImod_http_upload\fR\&.
.PP
\fBaccess_hard_quota\fR: \fIAccessName\fR
.RS 4
-This option defines which access rule is used to specify the "hard quota" for the matching JIDs\&. That rule must yield a positive number for any JID that is supposed to have a quota limit\&. This is the number of megabytes a corresponding user may upload\&. When this threshold is exceeded, ejabberd deletes the oldest files uploaded by that user until their disk usage equals or falls below the specified soft quota (see
+This option defines which access rule is used to specify the "hard quota" for the matching JIDs\&. That rule must yield a positive number for any JID that is supposed to have a quota limit\&. This is the number of megabytes a corresponding user may upload\&. When this threshold is exceeded, ejabberd deletes the oldest files uploaded by that user until their disk usage equals or falls below the specified soft quota (see also option
\fIaccess_soft_quota\fR)\&. The default value is
\fIhard_upload_quota\fR\&.
.RE
@@ -3333,26 +3950,22 @@ directory, once per day\&. The default value is
\fBExamples:\fR
.RS 4
.sp
-Please note that it\(cqs not necessary to specify the \fIaccess_hard_quota\fR and \fIaccess_soft_quota\fR options in order to use the quota feature\&. You can stick to the default names and just specify access rules such as those in this example:
+Notice it\(cqs not necessary to specify the \fIaccess_hard_quota\fR and \fIaccess_soft_quota\fR options in order to use the quota feature\&. You can stick to the default names and just specify access rules such as those in this example:
.sp
.if n \{\
.RS 4
.\}
.nf
shaper_rules:
- \&.\&.\&.
soft_upload_quota:
1000: all # MiB
hard_upload_quota:
1100: all # MiB
- \&.\&.\&.
modules:
- \&.\&.\&.
mod_http_upload: {}
mod_http_upload_quota:
max_days: 100
- \&.\&.\&.
.fi
.if n \{\
.RE
@@ -3446,7 +4059,23 @@ This type of authentication was obsoleted in 2008 and you unlikely need this mod
The module has no options\&.
.SS "mod_mam"
.sp
-This module implements XEP\-0313: Message Archive Management\&. Compatible XMPP clients can use it to store their chat history on the server\&.
+This module implements XEP\-0313: Message Archive Management and XEP\-0441: Message Archive Management Preferences\&. Compatible XMPP clients can use it to store their chat history on the server\&.
+.if n \{\
+.sp
+.\}
+.RS 4
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBNote\fR
+.ps -1
+.br
+.sp
+Mnesia backend for mod_mam is not recommended: it\(cqs limited to 2GB and often gets corrupted when reaching this limit\&. SQL backend is recommended\&. Namely, for small servers SQLite is a preferred choice because it\(cqs very easy to configure\&.
+.sp .5v
+.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -3541,9 +4170,113 @@ option, but applied to this module only\&.
.PP
\fBuser_mucsub_from_muc_archive\fR: \fItrue | false\fR
.RS 4
-When this option is disabled, for each individual subscriber a separa mucsub message is stored\&. With this option enabled, when a user fetches archive virtual mucsub, messages are generated from muc archives\&. The default value is
+When this option is disabled, for each individual subscriber a separate mucsub message is stored\&. With this option enabled, when a user fetches archive virtual mucsub, messages are generated from muc archives\&. The default value is
\fIfalse\fR\&.
.RE
+.sp
+\fBAPI Tags:\fR \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#mam|mam\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#purge|purge\fR
+.RE
+.SS "mod_matrix_gw 🟤"
+.sp
+\fINote\fR about this option: improved in 25\&.08\&.
+.sp
+Matrix gateway\&. Supports room versions 9, 10 and 11 since ejabberd 25\&.03; room versions 4 and higher since ejabberd 25\&.07; room version 12 (hydra rooms) since ejabberd 25\&.08\&. Erlang/OTP 25 or higher is required to use this module\&. This module is available since ejabberd 24\&.02\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBAvailable options:\fR
+.RS 4
+.PP
+\fBhost\fR: \fIHost\fR
+.RS 4
+This option defines the Jabber IDs of the service\&. If the
+\fIhost\fR
+option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix
+\fI"matrix\&."\fR\&. The keyword
+\fI@HOST@\fR
+is replaced with the real virtual host name\&.
+.RE
+.PP
+\fBkey\fR: \fIstring()\fR
+.RS 4
+Value of the matrix signing key, in base64\&.
+.RE
+.PP
+\fBkey_name\fR: \fIstring()\fR
+.RS 4
+Name of the matrix signing key\&.
+.RE
+.PP
+\fBleave_timeout\fR: \fIinteger()\fR
+.RS 4
+Delay in seconds between a user leaving a MUC room and sending
+\fIleave\fR
+Matrix event\&.
+.RE
+.PP
+\fBmatrix_domain\fR: \fIDomain\fR
+.RS 4
+Specify a domain in the Matrix federation\&. The keyword
+\fI@HOST@\fR
+is replaced with the hostname\&. The default value is
+\fI@HOST@\fR\&.
+.RE
+.PP
+\fBmatrix_id_as_jid\fR: \fItrue | false\fR
+.RS 4
+If set to
+\fItrue\fR, all packets failing to be delivered via an XMPP server\-to\-server connection will then be routed to the Matrix gateway by translating a Jabber ID
+\fIuser@matrixdomain\&.tld\fR
+to a Matrix user identifier
+\fI@user:matrixdomain\&.tld\fR\&. When set to
+\fIfalse\fR, messages must be explicitly sent to the matrix gateway service Jabber ID to be routed to a remote Matrix server\&. In this case, to send a message to Matrix user
+\fI@user:matrixdomain\&.tld\fR, the client must send a message to the JID
+\fIuser%\fR\fImatrixdomain\&.tld@matrix\&.myxmppdomain\fR\fI\&.tld\fR, where
+\fImatrix\&.myxmppdomain\&.tld\fR
+is the JID of the gateway service as set by the
+\fIhost\fR
+option\&. The default is
+\fIfalse\fR\&.
+.RE
+.PP
+\fBnotary_servers\fR: \fI[Server, \&.\&.\&.]\fR
+.RS 4
+A list of notary servers\&.
+.RE
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBExample:\fR
+.RS 4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+listen:
+ \-
+ port: 8448
+ module: ejabberd_http
+ tls: true
+ request_handlers:
+ "/_matrix": mod_matrix_gw
+
+modules:
+ mod_matrix_gw:
+ key_name: "key1"
+ key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+ matrix_id_as_jid: true
+.fi
+.if n \{\
+.RE
+.\}
.RE
.SS "mod_metrics"
.sp
@@ -3672,9 +4405,11 @@ An internet port number at which the backend is listening for incoming connectio
.RE
.SS "mod_mix"
.sp
-This module is an experimental implementation of XEP\-0369: Mediated Information eXchange (MIX)\&. MIX support was added in ejabberd 16\&.03 as an experimental feature, updated in 19\&.02, and is not yet ready to use in production\&. It\(cqs asserted that the MIX protocol is going to replace the MUC protocol in the future (see \fImod_muc\fR)\&.
+\fINote\fR about this option: added in 16\&.03 and improved in 19\&.02\&.
.sp
-To learn more about how to use that feature, you can refer to our tutorial: Getting started with XEP\-0369: Mediated Information eXchange (MIX) v0\&.1\&.
+This module is an experimental implementation of XEP\-0369: Mediated Information eXchange (MIX)\&. It\(cqs asserted that the MIX protocol is going to replace the MUC protocol in the future (see \fImod_muc\fR)\&.
+.sp
+To learn more about how to use that feature, you can refer to our tutorial: \fI\&.\&./\&.\&./tutorials/mix\-010\&.md|Getting started with MIX\fR
.sp
The module depends on \fImod_mam\fR\&.
.sp
@@ -3710,7 +4445,8 @@ instead\&.
.RS 4
This option defines the Jabber IDs of the service\&. If the
\fIhosts\fR
-option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix "mix\&."\&. The keyword
+option is not specified, the only Jabber ID will be the hostname of the virtual host with the prefix
+\fI"mix\&."\fR\&. The keyword
\fI@HOST@\fR
is replaced with the real virtual host name\&.
.RE
@@ -3786,7 +4522,7 @@ option, but applied to this module only\&.
.RE
.SS "mod_mqtt"
.sp
-This module adds support for the MQTT protocol version \fI3\&.1\&.1\fR and \fI5\&.0\fR\&. Remember to configure \fImod_mqtt\fR in \fImodules\fR and \fIlisten\fR sections\&.
+This module adds \fI\&.\&./guide/mqtt/index\&.md|support for the MQTT\fR protocol version \fI3\&.1\&.1\fR and \fI5\&.0\fR\&. Remember to configure \fImod_mqtt\fR in \fImodules\fR and \fIlisten\fR sections\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -3905,15 +4641,40 @@ This module adds ability to synchronize local MQTT topics with data on remote se
Identifier of a user that will be assigned as owner of local changes\&.
.RE
.PP
-\fBservers\fR: \fI{ServerUrl: {publish: [TopicPairs, subscribe: [TopicPairs], authentication: [AuthInfo]}}]\fR
+\fBservers\fR: \fI{ServerUrl: {Key: Value}}\fR
.RS 4
-Declaration of data to share, must contain
-\fIpublish\fR
-or
-\fIsubscribe\fR
-or both, and
-\fIauthentication\fR
-section with username/password field or certfile pointing to client certificate\&. Accepted urls can use schema mqtt, mqtts (mqtt with tls), mqtt5, mqtt5s (both to trigger v5 protocol), ws, wss, ws5, wss5\&. Certifcate authentication can be only used with mqtts, mqtt5s, wss, wss5\&.
+Declaration of data to share for each ServerUrl\&. Server URLs can use schemas:
+\fImqtt\fR,
+\fImqtts\fR
+(mqtt with tls),
+\fImqtt5\fR,
+\fImqtt5s\fR
+(both to trigger v5 protocol),
+\fIws\fR,
+\fIwss\fR,
+\fIws5\fR,
+\fIwss5\fR\&. Keys must be:
+.PP
+\fBauthentication\fR: \fI{AuthKey: AuthValue}\fR
+.RS 4
+List of authentication information, where AuthKey can be:
+\fIusername\fR
+and
+\fIpassword\fR
+fields, or
+\fIcertfile\fR
+pointing to client certificate\&. Certificate authentication can be used only with mqtts, mqtt5s, wss, wss5\&.
+.RE
+.PP
+\fBpublish\fR: \fI{LocalTopic: RemoteTopic}\fR
+.RS 4
+Either publish or subscribe must be set, or both\&.
+.RE
+.PP
+\fBsubscribe\fR: \fI{RemoteTopic: LocalTopic}\fR
+.RS 4
+Either publish or subscribe must be set, or both\&.
+.RE
.RE
.RE
.sp
@@ -3930,19 +4691,17 @@ section with username/password field or certfile pointing to client certificate\
.\}
.nf
modules:
- \&.\&.\&.
mod_mqtt_bridge:
+ replication_user: "mqtt@xmpp\&.server\&.com"
servers:
"mqtt://server\&.com":
+ authentication:
+ certfile: "/etc/ejabberd/mqtt_server\&.pem"
publish:
"localA": "remoteA" # local changes to \*(AqlocalA\*(Aq will be replicated on remote server as \*(AqremoteA\*(Aq
"topicB": "topicB"
subscribe:
"remoteB": "localB" # changes to \*(AqremoteB\*(Aq on remote server will be stored as \*(AqlocalB\*(Aq on local server
- authentication:
- certfile: "/etc/ejabberd/mqtt_server\&.pem"
- replication_user: "mqtt@xmpp\&.server\&.com"
- \&.\&.\&.
.fi
.if n \{\
.RE
@@ -3998,21 +4757,19 @@ To configure who is allowed to modify the
room option\&. The default value is
\fIall\fR, which means everyone is allowed to modify that option\&.
.RE
-.sp
-\fINote\fR about the next option: improved in 23\&.10:
.PP
\fBaccess_register\fR: \fIAccessName\fR
.RS 4
-This option specifies who is allowed to register nickname within the Multi\-User Chat service and rooms\&. The default is
+\fINote\fR
+about this option: improved in 23\&.10\&. This option specifies who is allowed to register nickname within the Multi\-User Chat service and rooms\&. The default is
\fIall\fR
for backward compatibility, which means that any user is allowed to register any free nick in the MUC service and in the rooms\&.
.RE
-.sp
-\fINote\fR about the next option: added in 22\&.05:
.PP
\fBcleanup_affiliations_on_start\fR: \fItrue | false\fR
.RS 4
-Remove affiliations for non\-existing local users on startup\&. The default value is
+\fINote\fR
+about this option: added in 22\&.05\&. Remove affiliations for non\-existing local users on startup\&. The default value is
\fIfalse\fR\&.
.RE
.PP
@@ -4022,12 +4779,10 @@ Same as top\-level
\fIdefault_db\fR
option, but applied to this module only\&.
.RE
-.sp
-\fINote\fR about the next option: improved in 22\&.05:
.PP
\fBdefault_room_options\fR: \fIOptions\fR
.RS 4
-This option allows to define the desired default room options\&. Note that the creator of a room can modify the options of his room at any time using an XMPP client with MUC capability\&. The
+Define the default room options\&. Note that the creator of a room can modify the options of his room at any time using an XMPP client with MUC capability\&. The
\fIOptions\fR
are:
.PP
@@ -4053,7 +4808,7 @@ Occupants can send IQ queries to other occupants\&. The default value is
\fBallow_subscription\fR: \fItrue | false\fR
.RS 4
Allow users to subscribe to room events as described in
-Multi\-User Chat Subscriptions\&. The default value is
+\fI\&.\&./\&.\&./developer/xmpp\-clients\-bots/extensions/muc\-sub\&.md|Multi\-User Chat Subscriptions\fR\&. The default value is
\fIfalse\fR\&.
.RE
.PP
@@ -4096,7 +4851,7 @@ The room is anonymous: occupants don\(cqt see the real JIDs of other occupants\&
\fBcaptcha_protected\fR: \fItrue | false\fR
.RS 4
When a user tries to join a room where they have no affiliation (not owner, admin or member), the room requires them to fill a CAPTCHA challenge (see section
-CAPTCHA
+\fIbasic\&.md#captcha|CAPTCHA\fR
in order to accept their join in the room\&. The default value is
\fIfalse\fR\&.
.RE
@@ -4108,7 +4863,10 @@ Short description of the room\&. The default value is an empty string\&.
.PP
\fBenable_hats\fR: \fItrue | false\fR
.RS 4
-Allow extended roles as defined in XEP\-0317 Hats\&. The default value is
+\fINote\fR
+about this option: improved in 25\&.03\&. Allow extended roles as defined in XEP\-0317 Hats\&. Check the
+\fI\&.\&./\&.\&./tutorials/muc\-hats\&.md|MUC Hats\fR
+tutorial\&. The default value is
\fIfalse\fR\&.
.RE
.PP
@@ -4174,7 +4932,7 @@ The room persists even if the last participant leaves\&. The default value is
\fIfalse\fR\&.
.RE
.PP
-\fBpresence_broadcast\fR: \fI[moderator | participant | visitor, \&.\&.\&.]\fR
+\fBpresence_broadcast\fR: \fI[Role]\fR
.RS 4
List of roles for which presence is broadcasted\&. The list can contain one or several of:
\fImoderator\fR,
@@ -4224,6 +4982,12 @@ A human\-readable title of the room\&. There is no default value
A custom vCard for the room\&. See the equivalent mod_muc option\&.The default value is an empty string\&.
.RE
.PP
+\fBvcard_xupdate\fR: \fIundefined | external | AvatarHash\fR
+.RS 4
+Set the hash of the avatar image\&. The default value is
+\fIundefined\fR\&.
+.RE
+.PP
\fBvoice_request_min_interval\fR: \fINumber\fR
.RS 4
Minimum interval between voice requests, in seconds\&. The default value is
@@ -4239,7 +5003,10 @@ Timeout before hibernating the room process, expressed in seconds\&. The default
.PP
\fBhistory_size\fR: \fISize\fR
.RS 4
-A small history of the current discussion is sent to users when they enter the room\&. With this option you can define the number of history messages to keep and send to users joining the room\&. The value is a non\-negative integer\&. Setting the value to 0 disables the history feature and, as a result, nothing is kept in memory\&. The default value is 20\&. This value affects all rooms on the service\&. NOTE: modern XMPP clients rely on Message Archives (XEP\-0313), so feel free to disable the history feature if you\(cqre only using modern clients and have
+A small history of the current discussion is sent to users when they enter the room\&. With this option you can define the number of history messages to keep and send to users joining the room\&. The value is a non\-negative integer\&. Setting the value to
+\fI0\fR
+disables the history feature and, as a result, nothing is kept in memory\&. The default value is
+\fI20\fR\&. This value affects all rooms on the service\&. NOTE: modern XMPP clients rely on Message Archives (XEP\-0313), so feel free to disable the history feature if you\(cqre only using modern clients and have
\fImod_mam\fR
module loaded\&.
.RE
@@ -4259,20 +5026,18 @@ option is not specified, the only Jabber ID will be the hostname of the virtual
\fI@HOST@\fR
is replaced with the real virtual host name\&.
.RE
-.sp
-\fINote\fR about the next option: added in 21\&.01:
.PP
\fBmax_captcha_whitelist\fR: \fINumber\fR
.RS 4
-This option defines the maximum number of characters that Captcha Whitelist can have when configuring the room\&. The default value is
+\fINote\fR
+about this option: added in 21\&.01\&. This option defines the maximum number of characters that Captcha Whitelist can have when configuring the room\&. The default value is
\fIinfinity\fR\&.
.RE
-.sp
-\fINote\fR about the next option: added in 21\&.01:
.PP
\fBmax_password\fR: \fINumber\fR
.RS 4
-This option defines the maximum number of characters that Password can have when configuring the room\&. The default value is
+\fINote\fR
+about this option: added in 21\&.01\&. This option defines the maximum number of characters that Password can have when configuring the room\&. The default value is
\fIinfinity\fR\&.
.RE
.PP
@@ -4321,18 +5086,22 @@ This option defines the number of service admins or room owners allowed to enter
.PP
\fBmax_users_presence\fR: \fINumber\fR
.RS 4
-This option defines after how many users in the room, it is considered overcrowded\&. When a MUC room is considered overcrowed, presence broadcasts are limited to reduce load, traffic and excessive presence "storm" received by participants\&. The default value is
+This option defines after how many users in the room, it is considered overcrowded\&. When a MUC room is considered overcrowded, presence broadcasts are limited to reduce load, traffic and excessive presence "storm" received by participants\&. The default value is
\fI1000\fR\&.
.RE
.PP
\fBmin_message_interval\fR: \fINumber\fR
.RS 4
-This option defines the minimum interval between two messages send by an occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, message rate is not limited\&. This feature can be used to protect a MUC service from occupant abuses and limit number of messages that will be broadcasted by the service\&. A good value for this minimum message interval is 0\&.4 second\&. If an occupant tries to send messages faster, an error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable\&.
+This option defines the minimum interval between two messages send by an occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, message rate is not limited\&. This feature can be used to protect a MUC service from occupant abuses and limit number of messages that will be broadcasted by the service\&. A good value for this minimum message interval is
+\fI0\&.4\fR
+second\&. If an occupant tries to send messages faster, an error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable\&.
.RE
.PP
\fBmin_presence_interval\fR: \fINumber\fR
.RS 4
-This option defines the minimum of time between presence changes coming from a given occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, no restriction is applied\&. This option can be used to protect a MUC service for occupants abuses\&. If an occupant tries to change its presence more often than the specified interval, the presence is cached by ejabberd and only the last presence is broadcasted to all occupants in the room after expiration of the interval delay\&. Intermediate presence packets are silently discarded\&. A good value for this option is 4 seconds\&.
+This option defines the minimum of time between presence changes coming from a given occupant in seconds\&. This option is global and valid for all rooms\&. A decimal value can be used\&. When this option is not defined, no restriction is applied\&. This option can be used to protect a MUC service for occupants abuses\&. If an occupant tries to change its presence more often than the specified interval, the presence is cached by ejabberd and only the last presence is broadcasted to all occupants in the room after expiration of the interval delay\&. Intermediate presence packets are silently discarded\&. A good value for this option is
+\fI4\fR
+seconds\&.
.RE
.PP
\fBname\fR: \fIstring()\fR
@@ -4391,30 +5160,22 @@ A custom vCard of the service that will be displayed by some XMPP clients in Ser
\fIvCard\fR
is a YAML map constructed from an XML representation of vCard\&. Since the representation has no attributes, the mapping is straightforward\&.
.sp
-For example, the following XML representation of vCard:
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-
- Conferences
-
-
- Elm Street
-
-
-.fi
-.if n \{\
-.RE
-.\}
-.sp
-will be translated to:
+\fBExample\fR:
.sp
.if n \{\
.RS 4
.\}
.nf
+# This XML representation of vCard:
+#
+# Conferences
+#
+#
+# Elm Street
+#
+#
+#
+# is translated to:
vcard:
fn: Conferences
adr:
@@ -4440,16 +5201,17 @@ This module depends on \fImod_muc\fR\&.
.ps +1
\fBAvailable options:\fR
.RS 4
-.sp
-\fINote\fR about the next option: added in 22\&.05:
.PP
\fBsubscribe_room_many_max_users\fR: \fINumber\fR
.RS 4
-How many users can be subscribed to a room at once using the
+\fINote\fR
+about this option: added in 22\&.05\&. How many users can be subscribed to a room at once using the
\fIsubscribe_room_many\fR
-command\&. The default value is
+API\&. The default value is
\fI50\fR\&.
.RE
+.sp
+\fBAPI Tags:\fR \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#muc|muc\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#muc_room|muc_room\fR, \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#muc_sub|muc_sub\fR
.RE
.SS "mod_muc_log"
.sp
@@ -4609,7 +5371,7 @@ to a remote file\&. By default a predefined CSS will be embedded into the HTML p
.PP
\fBdirname\fR: \fIroom_jid | room_name\fR
.RS 4
-Allows to configure the name of the room directory\&. If set to
+Configure the name of the room directory\&. If set to
\fIroom_jid\fR, the room directory name will be the full room JID\&. Otherwise, the room directory name will be only the room name, not including the MUC service name\&. The default value is
\fIroom_jid\fR\&.
.RE
@@ -4705,21 +5467,21 @@ otherwise\&. There is no default value\&.
.RE
.SS "mod_muc_occupantid"
.sp
+\fINote\fR about this option: added in 23\&.10\&.
+.sp
This module implements XEP\-0421: Anonymous unique occupant identifiers for MUCs\&.
.sp
When the module is enabled, the feature is enabled in all semi\-anonymous rooms\&.
.sp
-This module is available since ejabberd 23\&.10\&.
-.sp
The module has no options\&.
.SS "mod_muc_rtbl"
.sp
+\fINote\fR about this option: added in 23\&.04\&.
+.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
@@ -4905,22 +5667,8 @@ modules:
.SS "mod_offline"
.sp
This module implements XEP\-0160: Best Practices for Handling Offline Messages and XEP\-0013: Flexible Offline Message Retrieval\&. This means that all messages sent to an offline user will be stored on the server until that user comes online again\&. Thus it is very similar to how email works\&. A user is considered offline if no session presence priority > 0 are currently open\&.
-.if n \{\
.sp
-.\}
-.RS 4
-.it 1 an-trap
-.nr an-no-space-flag 1
-.nr an-break-flag 1
-.br
-.ps +1
-\fBNote\fR
-.ps -1
-.br
-.sp
-\fIejabberdctl\fR has a command to delete expired messages (see chapter Managing an ejabberd server in online documentation\&.
-.sp .5v
-.RE
+The \fIdelete_expired_messages\fR API allows to delete expired messages, and \fIdelete_old_messages\fR API deletes older ones\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
@@ -4932,15 +5680,17 @@ This module implements XEP\-0160: Best Practices for Handling Offline Messages a
.PP
\fBaccess_max_user_messages\fR: \fIAccessName\fR
.RS 4
-This option defines which access rule will be enforced to limit the maximum number of offline messages that a user can have (quota)\&. When a user has too many offline messages, any new messages that they receive are discarded, and a error is returned to the sender\&. The default value is
+This option defines which access rule will be enforced to limit the maximum number of offline messages that a user can have (quota)\&. When a user has too many offline messages, any new messages that they receive are discarded, and a
+\fI\fR
+error is returned to the sender\&. The default value is
\fImax_user_offline_messages\fR\&.
.RE
.PP
\fBbounce_groupchat\fR: \fItrue | false\fR
.RS 4
-This option is use the disable an optimisation that avoids bouncing error messages when groupchat messages could not be stored as offline\&. It will reduce chat room load, without any drawback in standard use cases\&. You may change default value only if you have a custom module which uses offline hook after
+This option is use the disable an optimization that avoids bouncing error messages when groupchat messages could not be stored as offline\&. It will reduce chat room load, without any drawback in standard use cases\&. You may change default value only if you have a custom module which uses offline hook after
\fImod_offline\fR\&. This option can be useful for both standard MUC and MucSub, but the bounce is much more likely to happen in the context of MucSub, so it is even more important to have it on large MucSub services\&. The default value is
-\fIfalse\fR, meaning the optimisation is enabled\&.
+\fIfalse\fR, meaning the optimization is enabled\&.
.RE
.PP
\fBcache_life_time\fR: \fItimeout()\fR
@@ -4966,8 +5716,12 @@ option, but applied to this module only\&.
.PP
\fBstore_empty_body\fR: \fItrue | false | unless_chat_state\fR
.RS 4
-Whether or not to store messages that lack a element\&. The default value is
-\fIunless_chat_state\fR, which tells ejabberd to store messages even if they lack the element, unless they only contain a chat state notification (as defined in
+Whether or not to store messages that lack a
+\fI\fR
+element\&. The default value is
+\fIunless_chat_state\fR, which tells ejabberd to store messages even if they lack the
+\fI