Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8138b48cad | |||
| 7de0afb613 | |||
| c407e87da3 | |||
| 2681f3b5d8 | |||
| f9a187c3aa | |||
| 40fffe6cf4 | |||
| 903943362e | |||
| e6120641f9 | |||
| 43f0b811f5 | |||
| bd61571ce5 | |||
| e06bdd6b30 | |||
| 75c66cba9c | |||
| 531d17ddb9 | |||
| 1aa2e75a21 | |||
| 416bee969f | |||
| fa75800ee1 | |||
| 5426358959 | |||
| 8e01c04e96 | |||
| 809d9d2d0f | |||
| 7c2db2aebb | |||
| 4f930cb94d | |||
| 9a48088d84 | |||
| 2e9b538c27 | |||
| 1a6d22615d | |||
| 97fc89bc7f | |||
| fbc3349e04 | |||
| 42122b7aa7 | |||
| ee05a863f7 | |||
| 44fa357534 | |||
| 354e4920b3 | |||
| 9bfdb2b8d4 | |||
| e31fced208 | |||
| f65903a181 | |||
| f21bd9b96e | |||
| 0647a23ea7 | |||
| 9b5ea84ee5 | |||
| 7732984133 | |||
| 6f59b7e63d | |||
| 40d6ef6156 | |||
| b5f8bc7c15 | |||
| 97e0530be1 | |||
| 3ab3c71cf6 | |||
| 7bc96ee464 | |||
| ca07b182c6 | |||
| 3a5f7e6cfe | |||
| c8ba793851 | |||
| d0646e8009 | |||
| d89da2d3eb | |||
| 99b54916f4 | |||
| d0437ab19a | |||
| 12910ed023 | |||
| ae5356b2a6 | |||
| f417b9f7c3 | |||
| bd3c805e67 |
@@ -24,6 +24,9 @@ inputs:
|
||||
rel_name_vsn:
|
||||
default: ""
|
||||
description: 'Base name of installer files'
|
||||
configure:
|
||||
default: ""
|
||||
description: 'Options to append to ./configure'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
@@ -68,6 +71,20 @@ runs:
|
||||
;;
|
||||
esac
|
||||
|
||||
############################################################# Compile #####
|
||||
|
||||
- if: contains(inputs.do, 'compile')
|
||||
shell: sh
|
||||
run: |
|
||||
TOOL=${{ inputs.tool }}
|
||||
[ "${TOOL%3}" = "rebar" ] && TOOL="./$TOOL"
|
||||
./autogen.sh
|
||||
./configure --with-rebar=$TOOL \
|
||||
--prefix=/tmp/ejabberd \
|
||||
--enable-all ${{ inputs.configure }}
|
||||
sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
|
||||
make
|
||||
|
||||
############################################################## Deploy #####
|
||||
|
||||
- if: contains(inputs.do, 'deploy') &&
|
||||
|
||||
@@ -243,7 +243,6 @@ modules:
|
||||
default_room_options:
|
||||
mam: true
|
||||
mod_muc_admin: {}
|
||||
mod_muc_occupantid: {}
|
||||
mod_offline:
|
||||
access_max_user_messages: max_user_offline_messages
|
||||
mod_ping: {}
|
||||
|
||||
@@ -54,14 +54,15 @@ jobs:
|
||||
key: ci-${{ matrix.otp }}-${{hashFiles('rebar.config')}}
|
||||
|
||||
- name: Compile
|
||||
uses: ./.github/actions/manage-ejabberd
|
||||
with:
|
||||
for: prod
|
||||
do: compile
|
||||
tool: rebar3
|
||||
configure: --disable-elixir
|
||||
|
||||
- name: Compress compiled.tar
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --with-rebar=./rebar3 \
|
||||
--prefix=/tmp/ejabberd \
|
||||
--enable-all \
|
||||
--disable-elixir
|
||||
sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
|
||||
make
|
||||
tar -cvf /tmp/compiled.tar .
|
||||
|
||||
- uses: actions/upload-artifact@v6
|
||||
|
||||
@@ -72,14 +72,12 @@ jobs:
|
||||
key: runtime-${{ matrix.otp }}-${{matrix.rebar}}-${{hashFiles('rebar.config')}}
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --with-rebar=./${{ matrix.rebar }} \
|
||||
--prefix=/tmp/ejabberd \
|
||||
--with-min-erlang=9.0.5 \
|
||||
--enable-all \
|
||||
--disable-elixir
|
||||
make
|
||||
uses: ./.github/actions/manage-ejabberd
|
||||
with:
|
||||
for: prod
|
||||
do: compile
|
||||
tool: ${{ matrix.rebar }}
|
||||
configure: --disable-elixir
|
||||
|
||||
- run: make hooks
|
||||
- run: make options
|
||||
@@ -154,11 +152,14 @@ jobs:
|
||||
mix local.rebar --force
|
||||
|
||||
- name: Compile
|
||||
uses: ./.github/actions/manage-ejabberd
|
||||
with:
|
||||
for: prod
|
||||
do: compile
|
||||
tool: ./rebar3
|
||||
|
||||
- name: Test scripts, deps, eunit
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --with-rebar=./rebar3 \
|
||||
--prefix=/tmp/ejabberd \
|
||||
--enable-all
|
||||
make scripts deps
|
||||
./rebar3 eunit --verbose
|
||||
|
||||
@@ -240,12 +241,11 @@ jobs:
|
||||
mix local.rebar --force
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --with-rebar=mix \
|
||||
--prefix=/tmp/ejabberd \
|
||||
--enable-all
|
||||
make
|
||||
uses: ./.github/actions/manage-ejabberd
|
||||
with:
|
||||
for: prod
|
||||
do: compile
|
||||
tool: mix
|
||||
|
||||
- run: make hooks
|
||||
- run: make options
|
||||
|
||||
@@ -14,6 +14,7 @@ jobs:
|
||||
matrix:
|
||||
otp: ['25', '26', '27', '28']
|
||||
|
||||
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
@@ -31,16 +32,12 @@ jobs:
|
||||
libsqlite3-dev libwebp-dev libyaml-dev
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure --with-rebar=./rebar3 \
|
||||
--prefix=/tmp/ejabberd \
|
||||
--enable-all \
|
||||
--disable-elixir \
|
||||
--disable-mssql \
|
||||
--disable-odbc
|
||||
sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
|
||||
make
|
||||
uses: ./.github/actions/manage-ejabberd
|
||||
with:
|
||||
for: prod
|
||||
do: compile
|
||||
tool: rebar3
|
||||
configure: --disable-elixir --disable-mssql
|
||||
|
||||
########################################################## Static Tests #####
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
## Version 26.02
|
||||
|
||||
- Fixes issue with adding hats data in presences send by group chats ([#4516](https://github.com/processone/ejabberd/issues/4516))
|
||||
- Removes `mod_muc_occupantid` modules, and integrates its functionality directly into `mod_muc` ([#4521](https://github.com/processone/ejabberd/issues/4521))
|
||||
- Fixes issue with reset occupant-id values after restart of ejabberd ([#4521](https://github.com/processone/ejabberd/issues/4521))
|
||||
- Improves handling of mediated group chat invitations in `mod_block_stranger` ([#4523](https://github.com/processone/ejabberd/issues/4523))
|
||||
- Properly install `mod_invites` templates in `make install` call ([#4514](https://github.com/processone/ejabberd/issues/4514))
|
||||
- Better errors in `mod_invites` ([#4515](https://github.com/processone/ejabberd/issues/4515))
|
||||
- Accessibility improvements in `mod_invites` ([#4524](https://github.com/processone/ejabberd/issues/4524))
|
||||
- Improves handling of request with invalid url encoded values in request handled by `ejabberd_http`
|
||||
- Improves handling of invalid responses to disco queries in `mod_pubsub_serverinfo`
|
||||
- Fixes conversion of MUC room configs from ejabberd older than 21.12
|
||||
- Fixes to autologin in WebAdmin
|
||||
|
||||
## Version 26.01
|
||||
|
||||
#### Compile and Start
|
||||
|
||||
+2
-2
@@ -311,8 +311,8 @@ BINARIES=$(DEPSDIR)/epam/priv/bin/epam $(DEPSDIR)/eimp/priv/bin/eimp $(DEPSDIR)/
|
||||
DEPS_FILES_FILTERED=$(filter-out $(BINARIES) $(DEPSDIR)/elixir/ebin/elixir.app,$(DEPS_FILES))
|
||||
DEPS_DIRS=$(sort $(DEPSDIR)/ $(foreach DEP,$(DEPS),$(DEPSDIR)/$(DEP)/) $(dir $(DEPS_FILES)))
|
||||
|
||||
MAIN_FILES=$(filter-out %/configure.beam,$(call FILES_WILDCARD,$(EBINDIR)/*.beam $(EBINDIR)/*.app priv/msgs/*.msg priv/css/*.css priv/img/*.png priv/js/*.js priv/lib/* include/*.hrl COPYING))
|
||||
MAIN_DIRS=$(sort $(dir $(MAIN_FILES)) priv/bin priv/sql priv/lua)
|
||||
MAIN_FILES=$(filter-out %/configure.beam,$(call FILES_WILDCARD,$(EBINDIR)/*.beam $(EBINDIR)/*.app priv/msgs/*.msg priv/css/*.css priv/img/*.png priv/js/*.js priv/lib/* priv/mod_invites/* priv/mod_invites/static/* priv/mod_invites/static/logos/* include/*.hrl COPYING))
|
||||
MAIN_DIRS=$(sort $(dir $(MAIN_FILES)) priv/bin priv/sql priv/lua priv/mod_invites)
|
||||
|
||||
define DEP_VERSION_template
|
||||
DEP_$(1)_VERSION:=$(shell $(SED) -e '/vsn/!d;s/.*, *"/$(1)-/;s/".*//' $(2) 2>/dev/null)
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 26.01` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
|
||||
AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 26.02` | 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]),
|
||||
|
||||
+1
-1
@@ -770,7 +770,7 @@
|
||||
<xmpp:version>1.0.1</xmpp:version>
|
||||
<xmpp:since>23.10</xmpp:since>
|
||||
<xmpp:status>complete</xmpp:status>
|
||||
<xmpp:note>mod_muc_occupantid</xmpp:note>
|
||||
<xmpp:note>mod_muc</xmpp:note>
|
||||
</xmpp:SupportedXep>
|
||||
</implements>
|
||||
<implements>
|
||||
|
||||
@@ -205,7 +205,6 @@ modules:
|
||||
default_room_options:
|
||||
mam: true
|
||||
mod_muc_admin: {}
|
||||
mod_muc_occupantid: {}
|
||||
mod_offline:
|
||||
access_max_user_messages: max_user_offline_messages
|
||||
mod_ping: {}
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
role :: role(),
|
||||
%%is_subscriber = false :: boolean(),
|
||||
%%subscriptions = [] :: [binary()],
|
||||
last_presence :: presence() | undefined
|
||||
last_presence :: presence() | undefined,
|
||||
occupant_id :: binary()
|
||||
}).
|
||||
|
||||
-record(subscriber, {jid :: jid(),
|
||||
@@ -132,7 +133,8 @@
|
||||
activity = treap:empty() :: treap:treap(),
|
||||
room_shaper = none :: ejabberd_shaper:shaper(),
|
||||
room_queue :: p1_queue:queue({message | presence, jid()}) | undefined,
|
||||
hibernate_timer = none :: reference() | none | hibernating
|
||||
hibernate_timer = none :: reference() | none | hibernating,
|
||||
salt = <<>> :: binary()
|
||||
}).
|
||||
|
||||
-type users() :: #{ljid() => #user{}}.
|
||||
|
||||
+84
-33
@@ -2,12 +2,12 @@
|
||||
.\" Title: ejabberd.yml
|
||||
.\" Author: [see the "AUTHOR" section]
|
||||
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
|
||||
.\" Date: 01/21/2026
|
||||
.\" Date: 02/11/2026
|
||||
.\" Manual: \ \&
|
||||
.\" Source: \ \&
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "EJABBERD\&.YML" "5" "01/21/2026" "\ \&" "\ \&"
|
||||
.TH "EJABBERD\&.YML" "5" "02/11/2026" "\ \&" "\ \&"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@@ -82,12 +82,12 @@ All options can be changed in runtime by running \fIejabberdctl reload\-config\f
|
||||
.sp
|
||||
Some options can be specified for particular virtual host(s) only using \fIhost_config\fR or \fIappend_host_config\fR options\&. Such options are called \fIlocal\fR\&. Examples are \fImodules\fR, \fIauth_method\fR and \fIdefault_db\fR\&. The options that cannot be defined per virtual host are called \fIglobal\fR\&. Examples are \fIloglevel\fR, \fIcertfiles\fR and \fIlisten\fR\&. It is a configuration mistake to put \fIglobal\fR options under \fIhost_config\fR or \fIappend_host_config\fR section \- ejabberd will refuse to load such configuration\&.
|
||||
.sp
|
||||
It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/26\&.01/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
|
||||
It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/26\&.02/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 26\&.01\&. The options that changed in this version are marked with 🟤\&.
|
||||
This section describes top level options of ejabberd 26\&.02\&. The options that changed in this version are marked with 🟠\&.
|
||||
.PP
|
||||
\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLName|ACLDefinition}}\fR
|
||||
.RS 4
|
||||
@@ -1556,7 +1556,7 @@ This is a global option for module
|
||||
\fI600 seconds\fR\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBreplaced_connection_timeout 🟤\fR: \fItimeout()\fR
|
||||
\fBreplaced_connection_timeout\fR: \fItimeout()\fR
|
||||
.RS 4
|
||||
\fINote\fR
|
||||
about this option: added in 26\&.01\&. Maximum time that new session will wait for termination of session that it\(cqs replacing\&. This allows old session to properly sends its unavailable presences, and helps with potetnial race conditions between old and new sessions presences\&.
|
||||
@@ -1980,7 +1980,7 @@ if the latter is not set\&.
|
||||
\fINote\fR
|
||||
about this option: renamed in 25\&.10\&. Whether to use the
|
||||
\fIdatabase\&.md#singlehost\-or\-multihost|multihost SQL schema\fR\&. All schemas are located at
|
||||
https://github\&.com/processone/ejabberd/tree/26\&.01/sql\&. There are two schemas available\&. The legacy
|
||||
https://github\&.com/processone/ejabberd/tree/26\&.02/sql\&. There are two schemas available\&. The legacy
|
||||
\fIsinglehost\fR
|
||||
schema stores one XMPP domain into one ejabberd database\&. The
|
||||
\fImultihost\fR
|
||||
@@ -2142,7 +2142,7 @@ seconds\&.
|
||||
.RE
|
||||
.SH "MODULES"
|
||||
.sp
|
||||
This section describes modules options of ejabberd 26\&.01\&. The modules that changed in this version are marked with 🟤\&.
|
||||
This section describes modules options of ejabberd 26\&.02\&. The modules that changed in this version are marked with 🟠\&.
|
||||
.SS "mod_adhoc"
|
||||
.sp
|
||||
def:ad\-hoc command
|
||||
@@ -2310,8 +2310,6 @@ ejabberdctl srg_create g1 example\&.org "\*(AqGroup number 1\*(Aq" this_is_g1 g1
|
||||
This module can be used to convert your existing SQL database from the singlehost to the multihost schema\&. Check the section \fIdatabase\&.md#singlehost\-or\-multihost|Singlehost or Multihost\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\&.
|
||||
.sp
|
||||
\fBAPI Tags:\fR \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#sql|sql\fR
|
||||
.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\&. Equivalent API commands are also available\&.
|
||||
@@ -2629,8 +2627,6 @@ modules:
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.sp
|
||||
\fBAPI Tags:\fR \fI\&.\&./\&.\&./developer/ejabberd\-api/admin\-tags\&.md#spam|spam\fR
|
||||
.RE
|
||||
.SS "mod_auth_fast"
|
||||
.sp
|
||||
@@ -3193,6 +3189,8 @@ Make sure either \fImod_bosh\fR or \fIlisten\&.md#ejabberd_http_ws|ejabberd_http
|
||||
.sp
|
||||
When \fIconversejs_css\fR and \fIconversejs_script\fR are \fIauto\fR, by default they point to the public Converse client\&.
|
||||
.sp
|
||||
When this module is enabled in \fImodules\fR, it adds automatically a requesthandler and link in WebAdmin\&. \&.
|
||||
.sp
|
||||
This module is available since ejabberd 21\&.12\&.
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
@@ -3713,7 +3711,7 @@ modules:
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_http_fileserver 🟤"
|
||||
.SS "mod_http_fileserver"
|
||||
.sp
|
||||
\fINote\fR about this option: improved \fIdocroot\fR in 26\&.01\&.
|
||||
.sp
|
||||
@@ -3803,7 +3801,7 @@ Indicate one or more directory index files, similarly to Apache\(cqs
|
||||
variable\&. When an HTTP request hits a directory instead of a regular file, those directory indices are looked in order, and the first one found is returned\&. The default value is an empty list\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBdocroot 🟤\fR: \fIPathDir | {PathURL, PathDir}\fR
|
||||
\fBdocroot\fR: \fIPathDir | {PathURL, PathDir}\fR
|
||||
.RS 4
|
||||
\fINote\fR
|
||||
about this option: improved in 26\&.01\&. Directory to serve the files from, or a map with several URL path (as specified in
|
||||
@@ -3882,7 +3880,7 @@ modules:
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_http_upload 🟤"
|
||||
.SS "mod_http_upload"
|
||||
.sp
|
||||
\fINote\fR about this option: added \fIcontent_types\fR in 26\&.01\&.
|
||||
.sp
|
||||
@@ -3904,7 +3902,7 @@ This option defines the access rule to limit who is permitted to use the HTTP up
|
||||
\fIlocal\fR\&. If no access rule of that name exists, no user will be allowed to use the service\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBcontent_types 🟤\fR: \fI{Extension: Type}\fR
|
||||
\fBcontent_types\fR: \fI{Extension: Type}\fR
|
||||
.RS 4
|
||||
\fINote\fR
|
||||
about this option: added in 26\&.01\&. Specify mappings of extension to content type, similarly to the option
|
||||
@@ -4173,7 +4171,7 @@ modules:
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_invites 🟤"
|
||||
.SS "mod_invites"
|
||||
.sp
|
||||
\fINote\fR about this option: added in 26\&.01\&.
|
||||
.sp
|
||||
@@ -4202,7 +4200,8 @@ libjs\-jquery
|
||||
and
|
||||
libjs\-bootstrap4
|
||||
which will put them under
|
||||
/usr/share/javascript/{jquery,bootstrap4}
|
||||
/usr/share/javascript/{jquery,bootstrap4}\&. Alternatively you can use
|
||||
tools/dl_invites_page_deps\&.sh <outdir>\&.
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
@@ -4335,7 +4334,7 @@ A human readable name for your site\&. E\&.g\&.
|
||||
"My Beautiful Laundrette"\&. Used in landing page templates\&.
|
||||
.RE
|
||||
.PP
|
||||
\fBtemplates_dir\fR: \fIbinary()\fR
|
||||
\fBtemplates_dir\fR: \fIPath\fR
|
||||
.RS 4
|
||||
The directory containing templates and static files used for landing page and web registration form\&. Only needs to be set if you want to ship your own set of templates or list of recommended apps\&.
|
||||
.RE
|
||||
@@ -5174,9 +5173,68 @@ modules:
|
||||
.RE
|
||||
.\}
|
||||
.RE
|
||||
.SS "mod_muc"
|
||||
.SS "mod_muc 🟠"
|
||||
.sp
|
||||
This module provides support for XEP\-0045: Multi\-User Chat\&. Users can discover existing rooms, join or create them\&. Occupants of a room can chat in public or have private chats\&.
|
||||
\fINote\fR about this option: incorporated \fImod_muc_occupantid\fR in 26\&.02\&.
|
||||
.sp
|
||||
This module provides support for Multi\-User Chat (MUC)\&. Users can discover existing rooms, join or create them\&. Occupants of a room can chat in public or have private chats\&.
|
||||
.sp
|
||||
Protocols implemented in this module:
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
XEP\-0045: Multi\-User Chat
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
XEP\-0249: Direct MUC Invitations
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
XEP\-0421: Occupant identifiers for semi\-anonymous MUCs
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
XEP\-0486: MUC Avatars
|
||||
.RE
|
||||
.sp
|
||||
.RS 4
|
||||
.ie n \{\
|
||||
\h'-04'\(bu\h'+03'\c
|
||||
.\}
|
||||
.el \{\
|
||||
.sp -1
|
||||
.IP \(bu 2.3
|
||||
.\}
|
||||
Muc/Sub: Multi\-User Chat Subscriptions
|
||||
.RE
|
||||
.sp
|
||||
The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service\&. To register a nickname, open the Service Discovery in your XMPP client and register in the MUC service\&.
|
||||
.sp
|
||||
@@ -5933,15 +5991,6 @@ or a conference JID is appended to the
|
||||
otherwise\&. There is no default value\&.
|
||||
.RE
|
||||
.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
|
||||
The module has no options\&.
|
||||
.SS "mod_muc_rtbl"
|
||||
.sp
|
||||
\fINote\fR about this option: added in 23\&.04\&.
|
||||
@@ -7674,7 +7723,9 @@ This module supports \fIbasic\&.md#captcha|CAPTCHA\fR to register a new account\
|
||||
.sp
|
||||
As an example usage, the users of the host \fIlocalhost\fR can visit the page: \fIhttps://localhost:5280/register/\fR It is important to include the last / character in the URL, otherwise the subpages URL will be incorrect\&.
|
||||
.sp
|
||||
This module is enabled in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR, no need to enable in \fImodules\fR\&. The module depends on \fImod_register\fR where all the configuration is performed\&.
|
||||
This module is enabled in \fIlisten\fR → \fIejabberd_http\fR → \fIlisten\-options\&.md#request_handlers|request_handlers\fR\&.
|
||||
.sp
|
||||
There is no need to enable this module in \fImodules\fR, but it adds a link to the register page in WebAdmin menu\&. The module depends on \fImod_register\fR where all the configuration is performed\&.
|
||||
.sp
|
||||
The module has no options\&.
|
||||
.sp
|
||||
@@ -9330,7 +9381,7 @@ Should the operating system be revealed or not\&. The default value is
|
||||
.RE
|
||||
.SH "LISTENERS"
|
||||
.sp
|
||||
This section describes listeners options of ejabberd 26\&.01\&.
|
||||
This section describes listeners options of ejabberd 26\&.02\&.
|
||||
.sp
|
||||
TODO
|
||||
.SH "AUTHOR"
|
||||
@@ -9338,13 +9389,13 @@ TODO
|
||||
ProcessOne\&.
|
||||
.SH "VERSION"
|
||||
.sp
|
||||
This document describes the configuration file of ejabberd 26\&.01\&. Configuration options of other ejabberd versions may differ significantly\&.
|
||||
This document describes the configuration file of ejabberd 26\&.02\&. Configuration options of other ejabberd versions may differ significantly\&.
|
||||
.SH "REPORTING BUGS"
|
||||
.sp
|
||||
Report bugs to https://github\&.com/processone/ejabberd/issues
|
||||
.SH "SEE ALSO"
|
||||
.sp
|
||||
Default configuration file: https://github\&.com/processone/ejabberd/blob/26\&.01/ejabberd\&.yml\&.example
|
||||
Default configuration file: https://github\&.com/processone/ejabberd/blob/26\&.02/ejabberd\&.yml\&.example
|
||||
.sp
|
||||
Main site: https://ejabberd\&.im
|
||||
.sp
|
||||
|
||||
@@ -84,6 +84,7 @@ defmodule Ejabberd.MixProject do
|
||||
includes = ["include", deps_include()]
|
||||
result = [{:d, :ELIXIR_ENABLED}] ++
|
||||
cond_options() ++
|
||||
if Mix.env == :test do [{:d, :TEST}] else [] end ++
|
||||
Enum.map(includes, fn (path) -> {:i, path} end) ++
|
||||
if_version_below(~c"26", [{:d, :OTP_BELOW_26}]) ++
|
||||
if_version_below(~c"27", [{:d, :OTP_BELOW_27}]) ++
|
||||
@@ -108,7 +109,7 @@ defmodule Ejabberd.MixProject do
|
||||
[{:cache_tab, "~> 1.0"},
|
||||
{:dialyxir, "~> 1.2", only: [:test], runtime: false},
|
||||
{:eimp, "~> 1.0"},
|
||||
{:erlydtl, git: "https://github.com/erlydtl/erlydtl", tag: "0.15.0", override: true},
|
||||
{:erlydtl, "~> 0.14.0"},
|
||||
{:ex_doc, "~> 0.31", only: [:edoc], runtime: false},
|
||||
{:fast_tls, "~> 1.1.24"},
|
||||
{:fast_xml, "~> 1.1.56"},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"},
|
||||
"eredis": {:hex, :eredis, "1.7.1", "39e31aa02adcd651c657f39aafd4d31a9b2f63c6c700dc9cece98d4bc3c897ab", [:mix, :rebar3], [], "hexpm", "7c2b54c566fed55feef3341ca79b0100a6348fd3f162184b7ed5118d258c3cc1"},
|
||||
"erlex": {:hex, :erlex, "0.2.8", "cd8116f20f3c0afe376d1e8d1f0ae2452337729f68be016ea544a72f767d9c12", [:mix], [], "hexpm", "9d66ff9fedf69e49dc3fd12831e12a8a37b76f8651dd21cd45fcf5561a8a7590"},
|
||||
"erlydtl": {:git, "https://github.com/erlydtl/erlydtl", "aae414692b6052e96d890e03bbeeeca0f4dc01c2", [tag: "0.15.0"]},
|
||||
"erlydtl": {:hex, :erlydtl, "0.14.0", "964b2dc84f8c17acfaa69c59ba129ef26ac45d2ba898c3c6ad9b5bdc8ba13ced", [:rebar3], [], "hexpm", "d80ec044cd8f58809c19d29ac5605be09e955040911b644505e31e9dd8143431"},
|
||||
"esip": {:hex, :esip, "1.0.59", "eb202f8c62928193588091dfedbc545fe3274c34ecd209961f86dcb6c9ebce88", [:rebar3], [{:fast_tls, "1.1.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.28", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.21", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "0bdf2e3c349dc0b144f173150329e675c6a51ac473d7a0b2e362245faad3fbe6"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.39.3", "519c6bc7e84a2918b737aec7ef48b96aa4698342927d080437f61395d361dcee", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "0590955cf7ad3b625780ee1c1ea627c28a78948c6c0a9b0322bd976a079996e1"},
|
||||
"exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"},
|
||||
|
||||
+26
-26
@@ -1,26 +1,26 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{% for item in apps %}
|
||||
<div class="card m-3 client-card {% for platform in item.platforms %}app-platform-{{ platform|lower }} {% endfor %} flex-wrap col-sm-12 col-md-8 col-lg-5">
|
||||
<div class="row no-gutters h-100">
|
||||
<div class="col-md-4">
|
||||
<img src="{{ static }}/{{ item.image }}" class="p-2 img-fluid" alt="{{ item.imagetext }}">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h5 class="card-title text-nowrap mb-1">{{ item.name }}</h5>
|
||||
<div>
|
||||
{% for platform in item.platforms %}<span class="badge badge-info client-platform-badge client-platform-badge-{{ platform|lower }} mr-1 mb-3">{{ platform }}</span>{% endfor %}
|
||||
</div>
|
||||
<p class="card-text">{{ item.text }}</p>
|
||||
<a href="{{ item.proceed_url }}" class="btn btn-primary mt-md-auto">{% if item.select_text %}{{ item.select_text }}{% else %}{% trans "Select" %}{% endif %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="show-all-clients-button-container" class="d-none alert alert-info">
|
||||
{% trans "Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>" %}
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{% for item in apps %}
|
||||
<div class="card m-3 client-card {% for platform in item.platforms %}app-platform-{{ platform|lower }} {% endfor %} flex-wrap col-sm-12 col-md-8 col-lg-5">
|
||||
<div class="row no-gutters h-100">
|
||||
<div class="col-md-4">
|
||||
<img src="{{ static }}/{{ item.image }}" class="p-2 img-fluid" alt="{{ item.alttext }}">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h3 class="card-title text-nowrap mb-1 h5">{{ item.name }}</h3>
|
||||
<div>
|
||||
{% for platform in item.platforms %}<span class="badge badge-info client-platform-badge client-platform-badge-{{ platform|lower }} mr-1 mb-3">{{ platform }}</span>{% endfor %}
|
||||
</div>
|
||||
<p class="card-text">{{ item.text }}</p>
|
||||
<a href="{{ item.proceed_url }}" class="btn btn-primary mt-md-auto">{% if item.select_text %}{{ item.select_text }}{% else %}{% trans "Select" %}{% endif %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="show-all-clients-button-container" class="d-none alert alert-info">
|
||||
{% trans "Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>" %}
|
||||
</div>
|
||||
|
||||
+27
-14
@@ -4,17 +4,20 @@
|
||||
"buttons": [
|
||||
{
|
||||
"image": "{{ static }}/logos/google_ps.png",
|
||||
"alttext": "{% trans 'Google Play Store Logo' %}",
|
||||
"url": "https://play.google.com/store/apps/details?id=eu.siacs.conversations",
|
||||
"magic_link_format": "https://play.google.com/store/apps/details?id=eu.siacs.conversations&referrer={{ uri }}"
|
||||
},
|
||||
{
|
||||
"image": "{{ static }}/logos/fdroid.png",
|
||||
"alttext": "{% trans 'F-Droid Store Logo' %}",
|
||||
"url": "https://f-droid.org/en/packages/eu.siacs.conversations/",
|
||||
"magic_link_format": "https://f-droid.org/packages/eu.siacs.conversations/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/conversations.svg",
|
||||
"alttext": "{% trans 'Conversations Logo' %}",
|
||||
"link": "https://play.google.com/store/apps/details?id=eu.siacs.conversations",
|
||||
"magic_link_format": "https://play.google.com/store/apps/details?id=eu.siacs.conversations&referrer={{ uri }}",
|
||||
"name": "Conversations",
|
||||
@@ -22,116 +25,125 @@
|
||||
"Android"
|
||||
],
|
||||
"supports_preauth_uri": true,
|
||||
"text": "{% trans "Conversations is a Jabber/XMPP client for Android 6.0+ smartphones that has been optimized to provide a unique mobile experience." %}"
|
||||
"text": "{% trans 'Conversations is a Jabber/XMPP client for Android 6.0+ smartphones that has been optimized to provide a unique mobile experience.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"image": "{{ static }}/logos/apple_as.svg",
|
||||
"alttext": "{% trans 'Apple Store Logo' %}",
|
||||
"target": "_blank",
|
||||
"url": "https://apps.apple.com/app/id317711500"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/monal-tmp.svg",
|
||||
"alttext": "{% trans 'Monal Logo' %}",
|
||||
"link": "https://monal-im.org/",
|
||||
"name": "Monal",
|
||||
"platforms": [
|
||||
"iOS", "iPadOS"
|
||||
],
|
||||
"supports_preauth_uri": true,
|
||||
"text": "{% trans "A modern open-source chat client for iPhone and iPad. It is easy to use and has a clean user interface." %}"
|
||||
"text": "{% trans 'A modern open-source chat client for iPhone and iPad. It is easy to use and has a clean user interface.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"image": "{{ static }}/logos/apple_as.svg",
|
||||
"alttext": "{% trans 'Apple Store Logo' %}",
|
||||
"target": "_blank",
|
||||
"url": "https://apps.apple.com/app/id1637078500"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/monal-tmp.svg",
|
||||
"alttext": "{% trans 'Monal Logo' %}",
|
||||
"link": "https://monal-im.org/",
|
||||
"name": "Monal (macOS)",
|
||||
"platforms": [
|
||||
"macOS"
|
||||
],
|
||||
"supports_preauth_uri": true,
|
||||
"text": "{% trans "A modern open-source chat client for Mac. It is easy to use and has a clean user interface." %}"
|
||||
"text": "{% trans 'A modern open-source chat client for Mac. It is easy to use and has a clean user interface.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"image": "{{ static }}/logos/apple_as.svg",
|
||||
"alttext": "{% trans 'Apple Store Logo' %}",
|
||||
"target": "_blank",
|
||||
"url": "https://apps.apple.com/us/app/siskin-im/id1153516838"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/siskin-im.svg",
|
||||
"alttext": "{% trans 'Siskin IM Logo' %}",
|
||||
"link": "https://apps.apple.com/us/app/siskin-im/id1153516838",
|
||||
"name": "Siskin IM",
|
||||
"platforms": [
|
||||
"iOS", "iPadOS"
|
||||
],
|
||||
"supports_preauth_uri": true,
|
||||
"text": "{% trans "A lightweight and powerful XMPP client for iPhone and iPad. It provides an easy way to talk and share moments with your friends." %}"
|
||||
"text": "{% trans 'A lightweight and powerful XMPP client for iPhone and iPad. It provides an easy way to talk and share moments with your friends.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"target": "_blank",
|
||||
"text": "{% trans "Download from Mac App Store" %}",
|
||||
"text": "{% trans 'Download from Mac App Store' %}",
|
||||
"url": "https://apps.apple.com/us/app/beagle-im/id1445349494"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/beagle-im.svg",
|
||||
"alttext": "{% trans 'Beagle IM Logo' %}",
|
||||
"link": "https://apps.apple.com/us/app/beagle-im/id1445349494",
|
||||
"name": "Beagle IM",
|
||||
"platforms": [
|
||||
"macOS"
|
||||
],
|
||||
"setup": {
|
||||
"text": "{% trans "Launch Beagle IM, and select 'Yes' to add a new account. Click the '+' button under the empty account list and then enter your credentials." %}"
|
||||
"text": "{% trans 'Launch Beagle IM, and select \'Yes\' to add a new account. Click the \'+\' button under the empty account list and then enter your credentials.' %}"
|
||||
},
|
||||
"text": "{% trans "Beagle IM by Tigase, Inc. is a lightweight and powerful XMPP client for macOS." %}"
|
||||
"text": "{% trans 'Beagle IM by Tigase, Inc. is a lightweight and powerful XMPP client for macOS.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"target": "_blank",
|
||||
"text": "{% trans "Download Dino for Linux" %}",
|
||||
"text": "{% trans 'Download Dino for Linux' %}",
|
||||
"url": "https://dino.im/#download"
|
||||
}
|
||||
],
|
||||
"text": "{% trans "Click the button to open the Dino website where you can download and install it on your PC." %}"
|
||||
"text": "{% trans 'Click the button to open the Dino website where you can download and install it on your PC.' %}"
|
||||
},
|
||||
"image": "logos/dino.svg",
|
||||
"alttext": "{% trans 'Dino Logo' %}",
|
||||
"link": "https://dino.im/",
|
||||
"name": "Dino",
|
||||
"platforms": [
|
||||
"Linux"
|
||||
],
|
||||
"text": "{% trans "A modern open-source chat client for the desktop. It focuses on providing a clean and reliable Jabber/XMPP experience while having your privacy in mind." %}"
|
||||
"text": "{% trans 'A modern open-source chat client for the desktop. It focuses on providing a clean and reliable Jabber/XMPP experience while having your privacy in mind.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"target": "_blank",
|
||||
"text": "{% trans "Download Gajim" %}",
|
||||
"text": "{% trans 'Download Gajim' %}",
|
||||
"url": "https://gajim.org/download/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/gajim.svg",
|
||||
"alttext": "{% trans 'Gajim Logo' %}",
|
||||
"link": "https://gajim.org/",
|
||||
"name": "Gajim",
|
||||
"platforms": [
|
||||
@@ -139,24 +151,25 @@
|
||||
"Linux",
|
||||
"macOS"
|
||||
],
|
||||
"text": "{% trans "A fully-featured desktop chat client for Windows and Linux." %}"
|
||||
"text": "{% trans 'A fully-featured desktop chat client for Windows and Linux.' %}"
|
||||
},
|
||||
{
|
||||
"download": {
|
||||
"buttons": [
|
||||
{
|
||||
"target": "_blank",
|
||||
"text": "{% trans "Download Renga for Haiku" %}",
|
||||
"text": "{% trans 'Download Renga for Haiku' %}",
|
||||
"url": "https://depot.haiku-os.org/#!/pkg/renga?bcguid=bc233-PQIA"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image": "logos/renga.svg",
|
||||
"alttext": "{% trans 'Renga Logo' %}",
|
||||
"link": "https://pulkomandy.tk/projects/renga",
|
||||
"name": "Renga",
|
||||
"platforms": [
|
||||
"Haiku"
|
||||
],
|
||||
"text": "{% trans "XMPP client for Haiku" %}"
|
||||
"text": "{% trans 'XMPP client for Haiku' %}"
|
||||
}
|
||||
]
|
||||
|
||||
+33
-36
@@ -1,47 +1,44 @@
|
||||
{% extends "base_min.html" %}
|
||||
|
||||
{% block rel_alternate %}
|
||||
<link rel="alternate" href="{{ uri }}">
|
||||
{% endblock %}
|
||||
{% block rel_alternate %}<link rel="alternate" href="{{ uri }}">{% endblock %}
|
||||
|
||||
{% block qr_button %}
|
||||
<div id="qr-button-container" class="float-right w-25 border border-info p-3 d-none">
|
||||
{% trans "<strong>Tip:</strong> You can open this invite on your mobile device by scanning a barcode with your camera." %}
|
||||
<button id="qr-modal-show" class="mt-2 d-block btn btn-info" title="{% trans "Send this invite to your device" %}"
|
||||
data-toggle="modal" data-target="#qr-modal">
|
||||
<img src="{{ static }}/qr-logo.png" alt="{% trans "QR code icon" %}" class="align-middle h-50 mt-1" style="display:inline" >
|
||||
{% trans "Scan with mobile device" %}
|
||||
</button>
|
||||
</div>
|
||||
<div id="qr-button-container" class="float-right w-25 border border-info p-3 d-none">
|
||||
{% trans "<strong>Tip:</strong> You can open this invite on your mobile device by scanning a barcode with your camera." %}
|
||||
<button id="qr-modal-show" class="mt-2 d-block btn btn-info" title="{% trans "Send this invite to your device" %}"
|
||||
data-toggle="modal" data-target="#qr-modal">
|
||||
{% trans "Scan with mobile device" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block qr_code %}
|
||||
<div class="modal" tabindex="-1" role="dialog" id="qr-modal">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans "Scan invite code" %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{% trans "You can transfer this invite to your mobile device by scanning a code with your camera." %}</p>
|
||||
<div id="qr-info-url" class="tab-pane show active">
|
||||
<p>{% trans "Use a <em>QR code</em> scanner on your mobile device to scan the code below:" %}</p>
|
||||
<div id="qr-invite-page" style="width: 256px;" class="bg-light mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" role="dialog" id="qr-modal">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title h5">{% trans "Scan invite code" %}</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{% trans "You can transfer this invite to your mobile device by scanning a code with your camera." %}</p>
|
||||
<div id="qr-info-url" class="tab-pane show active">
|
||||
<p>{% trans "Use a <em>QR code</em> scanner on your mobile device to scan the code below:" %}</p>
|
||||
<div id="qr-invite-page" style="width: 256px;" class="bg-light mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script src="{{ static }}/qrcode.min.js"></script>
|
||||
<script src="{{ static }}/platform.min.js"></script>
|
||||
<script src="{{ static }}/invite.js"></script>
|
||||
<script src="{{ static }}/qrcode.min.js"></script>
|
||||
<script src="{{ static }}/platform.min.js"></script>
|
||||
<script src="{{ static }}/invite.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,35 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{% blocktrans %}Invite to {{ site_name }}{% endblocktrans %}{% endblock %}</title>
|
||||
{% block rel_alternate %}{% endblock %}
|
||||
<link rel="stylesheet" href="/share/bootstrap4/css/bootstrap.min.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#fbd308">
|
||||
<meta name="theme-color" content="#fbd308">
|
||||
</head>
|
||||
<body>
|
||||
<div id="background" class="fixed-top overflow-hidden"></div>
|
||||
<div id="form" class="{% block form_class %}container col-md-10 col-md-offset-1 col-sm-8 col-sm-offset-2 col-lg-10 col-lg-offset-1 mt-2 mt-md-5{% endblock %}">
|
||||
<div class="card rounded-lg shadow">
|
||||
<h1 class="card-header rounded-lg rounded-lg">
|
||||
{%block h1 %}{% blocktrans %}Invite to {{ site_name }}{% endblocktrans %}{% endblock %}<br/>
|
||||
</h1>
|
||||
<div class="card-body">
|
||||
{% block qr_button %}{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block qr_code %}{% endblock %}
|
||||
{% block extra_scripts %}{% endblock %}
|
||||
<script src="/share/jquery/jquery.min.js"></script>
|
||||
<script src="/share/bootstrap4/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
<html lang="{{ lang }}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{% blocktrans %}Invite to {{ site_name }}{% endblocktrans %}{% endblock %}</title>
|
||||
{% block rel_alternate %}{% endblock %}
|
||||
<link rel="stylesheet" href="/share/bootstrap4/css/bootstrap.min.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#fbd308">
|
||||
<meta name="theme-color" content="#fbd308">
|
||||
<style>
|
||||
#other-software a {
|
||||
text-decoration: underline;
|
||||
color: #0072ed;
|
||||
}
|
||||
a#show-all-clients-button {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: #0072ed;
|
||||
}
|
||||
.badge-success {
|
||||
background-color: #0a8927;
|
||||
}
|
||||
.alert-info, .alert-info a, .btn-info {
|
||||
background-color: #008297;
|
||||
color: white;
|
||||
}
|
||||
.border-info {
|
||||
border-color: #008297 !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="background" class="fixed-top overflow-hidden"></div>
|
||||
<div id="form" class="{% block form_class %}container col-md-10 col-md-offset-1 col-sm-8 col-sm-offset-2 col-lg-10 col-lg-offset-1 mt-2 mt-md-5{% endblock %}">
|
||||
<div class="card rounded-lg shadow">
|
||||
<h1 class="card-header rounded-lg rounded-lg">{%block h1 %}{% blocktrans %}Invite to {{ site_name }}{% endblocktrans %}{% endblock %}</h1>
|
||||
<div class="card-body">
|
||||
{% block qr_button %}{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block qr_code %}{% endblock %}
|
||||
{% block extra_scripts %}{% endblock %}
|
||||
<script src="/share/jquery/jquery.min.js"></script>
|
||||
<script src="/share/bootstrap4/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,70 +1,76 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block h1 %}
|
||||
{% blocktrans with app_name=app.name %}Join {{ site_name }} with {{ app_name }}{% endblocktrans %}
|
||||
{% endblock %}
|
||||
{% block h1 %}{% blocktrans with app_name=app.name %}Join {{ site_name }} with {{ app_name }}{% endblocktrans %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>{% if invite.inviter|user %}
|
||||
<p>{% if invite.inviter|user %}
|
||||
{% blocktrans with inviter=invite.inviter|user %}You have been invited to chat with <strong>{{ inviter }}</strong> on {{ site_name }}, part of the XMPP secure and decentralized messaging network.{% endblocktrans %}
|
||||
{% else %}
|
||||
{% else %}
|
||||
{% blocktrans %}You have been invited to chat on {{ site_name }}, part of the XMPP secure and decentralized messaging network.{% endblocktrans %}
|
||||
{% endif %}</p>
|
||||
|
||||
<h2 class="h5">{% blocktrans with app_name=app.name %}You can start chatting right away with {{ app_name }}. Let's get started!{% endblocktrans %}</h2>
|
||||
|
||||
<div class="card m-3 client-card {% for item in app.platforms %}app-platform-{{ item|lower }} {% endfor %} flex-wrap col-sm-12 col-md-8 col-lg-5">
|
||||
<div class="row no-gutters h-100">
|
||||
<div class="col-md-4">
|
||||
<img src="{{ static }}/{{ app.image }}" class="p-2 img-fluid" alt="{{ app.alttext }}">
|
||||
</div>
|
||||
<div class="col-md-8 h-100">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h3 class="card-title text-nowrap mb-1 h5">{{ app.name }}</h3>
|
||||
<div>
|
||||
{% for item in app.platforms %}<span class="badge badge-info client-platform-badge client-platform-badge-{{ item|lower }} mr-1 mb-3">{{ item }}</span> {% endfor %}
|
||||
</div>
|
||||
<p class="card-text">{{ app.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 style="clear:both" class="h3">{% blocktrans with app_name=app.name %}Step 1: Install {{ app_name }}{% endblocktrans %}</h2>
|
||||
|
||||
<p>{% if app.download.text %}{{ app.download.text }}{% else %}{% blocktrans with app_name=app.name %}Download and install {{ app_name }} below:{% endblocktrans %}{% endif %}</p>
|
||||
|
||||
<div class="ml-5">
|
||||
{% for button in app.download.buttons %}
|
||||
{% if button.image %}
|
||||
<a href="{% if button.magic_link %}{{ button.magic_link }}{% else %}{{ button.url }}{% endif %}" {% if button.target %}target="{{ button.target }}"{% endif %} rel="noopener">
|
||||
<img src="{{ button.image }}" {% if button.alttext %}alt="{{ button.alttext }}"{% endif %} style="max-width: 160px;">
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% if button.text %}
|
||||
<a href="{{ button.url }}" {% if button.target %}target="{{ button.target }}"{% endif %} class="btn btn-primary" rel="noopener">
|
||||
{{ button.text }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<p>{% blocktrans with app_name=app.name %}You can start chatting right away with {{ app_name }}. Let's get started!{% endblocktrans %}</p>
|
||||
<p class="mt-3">{% blocktrans with app_name=app.name %}After successfully installing {{ app_name }}, come back to this page and <strong>continue with Step 2</strong>.{% endblocktrans %}</p>
|
||||
|
||||
<div class="card m-3 client-card {% for item in app.platforms %}app-platform-{{ item|lower }} {% endfor %} flex-wrap col-sm-12 col-md-8 col-lg-5">
|
||||
<div class="row no-gutters h-100">
|
||||
<div class="col-md-4">
|
||||
<img src="{{ static }}/{{ app.image }}" class="p-2 img-fluid" alt="{{ app.imagetext }}">
|
||||
</div>
|
||||
<div class="col-md-8 h-100">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h5 class="card-title text-nowrap mb-1">{{ app.name }}</h5>
|
||||
<div>
|
||||
{% for item in app.platforms %}<span class="badge badge-info client-platform-badge client-platform-badge-{{ item|lower }} mr-1 mb-3">{{ item }}</span> {% endfor %}
|
||||
</div>
|
||||
<p class="card-text">{{ app.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="h3">{% trans "Step 2: Activate your account" %}</h2>
|
||||
|
||||
<h3 style="clear:both">{% blocktrans with app_name=app.name %}Step 1: Install {{ app_name }}{% endblocktrans %}</h3>
|
||||
<p>{% trans "Installed ok? Great! <strong>Click or tap the button below</strong> to accept your invite and continue with your account setup:" %}</p>
|
||||
|
||||
<p>{% if app.download.text %}{{ app.download.text }}{% else %}{% blocktrans with app_name=app.name %}Download and install {{ app_name }} below:{% endblocktrans %}{% endif %}</p>
|
||||
<div>
|
||||
<a href="{{ uri }}" id="uri-cta" class="btn btn-primary ml-5 mt-1 mb-3">{% blocktrans with app_name=app.name %}Accept invite using {{ app_name }}{% endblocktrans %}</a><br/>
|
||||
</div>
|
||||
|
||||
<div class="ml-5">
|
||||
{% for button in app.download.buttons %}
|
||||
{% if button.image %}
|
||||
<a href="{% if button.magic_link %}{{ button.magic_link }}{% else %}{{ button.url }}{% endif %}" {% if button.target %}target="{{ button.target }}"{% endif %} rel="noopener">
|
||||
<img src="{{ button.image }}" {% if button.alttext %}alt="{{ button.alttext }}"{% endif %} style="max-width: 160px;">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if button.text %}
|
||||
<a href="{{ button.url }}" {% if button.target %}target="{{ button.target }}"{% endif %} class="btn btn-primary" rel="noopener">
|
||||
{{ button.text }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p>{% blocktrans with app_name=app.name %}After clicking the button you will be taken to {{ app_name }} to finish setting up your new {{ site_name }} account.{% endblocktrans %}</p>
|
||||
<nav aria-label="{% trans 'Page navigation' %}">
|
||||
<ul class="pagination">
|
||||
<li class="page-item"><a tabindex="4" class="page-link" href="/{{ base }}/{{ token }}" aria-label="{% trans 'Previous' %}">
|
||||
<span aria-hidden="true">«</span>
|
||||
<span>{% trans "Previous" %}</span>
|
||||
</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<p class="mt-3">{% blocktrans with app_name=app.name %}After successfully installing {{ app_name }}, come back to this page and <strong>continue with Step 2</strong>.{% endblocktrans %}</p>
|
||||
|
||||
<h3>{% trans "Step 2: Activate your account" %}</h3>
|
||||
|
||||
<p>{% trans "Installed ok? Great! <strong>Click or tap the button below</strong> to accept your invite and continue with your account setup:" %}</p>
|
||||
|
||||
<div>
|
||||
<a href="{{ uri }}" id="uri-cta" class="btn btn-primary ml-5 mt-1 mb-3">{% blocktrans with app_name=app.name %}Accept invite using {{ app_name }}{% endblocktrans %}</a><br/>
|
||||
</div>
|
||||
|
||||
<p>{% blocktrans with app_name=app.name %}After clicking the button you will be taken to {{ app_name }} to finish setting up your new {{ site_name }} account.{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script src="{{ static }}/qrcode.min.js"></script>
|
||||
<script src="{{ static }}/platform.min.js"></script>
|
||||
<script src="{{ static }}/invite.js"></script>
|
||||
<script src="{{ static }}/qrcode.min.js"></script>
|
||||
<script src="{{ static }}/platform.min.js"></script>
|
||||
<script src="{{ static }}/invite.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<p>{% if invite.inviter|user %}
|
||||
<p>{% if invite.inviter|user %}
|
||||
{% blocktrans with inviter=invite.inviter|user %}You have been invited to chat with <strong>{{ inviter }}</strong> on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.{% endblocktrans %}
|
||||
{% else %}
|
||||
{% else %}
|
||||
{% blocktrans %}You have been invited to chat on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.{% endblocktrans %}
|
||||
{% endif %}</p>
|
||||
{% endif %}</p>
|
||||
<h2 class="card-title h5" style="clear:both">{% trans "Get started" %}</h2>
|
||||
<p>{% trans "To get started, you need to install an app for your platform:" %}</p>
|
||||
|
||||
<h5 class="card-title" style="clear:both">{% trans "Get started" %}</h5>
|
||||
{% include "apps.html" %}
|
||||
|
||||
<p>{% trans "To get started, you need to install an app for your platform:" %}</p>
|
||||
|
||||
{% include "apps.html" %}
|
||||
|
||||
<h5>{% trans "Other software" %}</h5>
|
||||
<p>{% blocktrans %}You can connect to {{ site_name }} using any XMPP-compatible software. If your preferred software is not listed above, you may still <a href="{{ registration_url }}">register an account manually</a>.{% endblocktrans %}</p>
|
||||
<h2 class="h5">{% trans "Other software" %}</h2>
|
||||
<p id="other-software">{% blocktrans %}You can connect to {{ site_name }} using any XMPP-compatible software. If your preferred software is not listed above, you may still <a href="{{ registration_url }}">register an account manually</a>.{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{% extends "base_min.html" %}
|
||||
{% block form_class %}container col-md-8 col-md-offset-2 col-sm-8 cold-sm-offset-2 col-lg-6 col-lg-offset-3 mt-2 mt-md-5{% endblock %}
|
||||
{% block content %}
|
||||
<h5 class="card-title">{% trans "Invite expired" %}</h5>
|
||||
<h2 class="card-title h5">{% trans "Invite expired" %}</h2>
|
||||
|
||||
<p>{% trans "Sorry, it looks like this invite code has expired!" %}</p>
|
||||
<p>{% trans "Sorry, it looks like this invite code has expired!" %}</p>
|
||||
|
||||
<img class="w-100" alt="{% trans "Sad person holding empty box" %}" src="{{ static }}/illus-empty.svg">
|
||||
<img class="w-100" alt="{% trans "Sad person holding empty box" %}" src="{{ static }}/illus-empty.svg">
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,64 +1,93 @@
|
||||
{% extends "base_min.html" %}
|
||||
|
||||
{% block title %}{% blocktrans %}Register on {{ site_name }}{% endblocktrans %}{% endblock %}
|
||||
{% block h1 %}{% blocktrans %}Register on {{ site_name }}{% endblocktrans %}{% endblock %}
|
||||
|
||||
{% block title %}{% if error %}{% trans "Registration Error" %}{% else %}{% blocktrans %}Register on {{ site_name }}{% endblocktrans %}{% endif %}{% endblock %}
|
||||
{% block h1 %}{% block title %}{% endblock %}{% endblock %}
|
||||
|
||||
{% block form_class %}container col-md-8 col-md-offset-2 col-sm-8 cold-sm-offset-2 col-lg-6 col-lg-offset-3 mt-2 mt-md-5{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>{% if app %}{% blocktrans with app_name=app.name %}<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting using <strong>{{ app_name }}</strong> you need to first register an account.{% endblocktrans %}{% else %}{% blocktrans %}<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting you need to first register an account.{% endblocktrans %}{% endif %}</p>
|
||||
<p>{% if app %}{% blocktrans with app_name=app.name %}<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting using <strong>{{ app_name }}</strong> you need to first register an account.{% endblocktrans %}{% else %}{% blocktrans %}<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting you need to first register an account.{% endblocktrans %}{% endif %}</p>
|
||||
|
||||
<p>{%if invite.inviter %}{% blocktrans with inviter=invite.inviter|user %}Creating an account will allow to communicate with <strong>{{ inviter }}</strong> and other people on <strong>{{ site_name }}</strong> and other services on the XMPP network.{% endblocktrans %}{% else %}{% blocktrans %}Creating an account will allow to communicate with other people on <strong>{{ site_name }}</strong> and other services on the XMPP network.{% endblocktrans %}{% endif %}</p>
|
||||
<p>{%if invite.inviter %}{% blocktrans with inviter=invite.inviter|user %}Creating an account will allow to communicate with <strong>{{ inviter }}</strong> and other people on <strong>{{ site_name }}</strong> and other services on the XMPP network.{% endblocktrans %}{% else %}{% blocktrans %}Creating an account will allow to communicate with other people on <strong>{{ site_name }}</strong> and other services on the XMPP network.{% endblocktrans %}{% endif %}</p>
|
||||
|
||||
{% if app %}{% if app.supports_preauth_uri %}
|
||||
<div class="alert alert-info">
|
||||
<p>{% blocktrans with app_name=app.name %}If you already have {{ app_name }} installed, we recommend that you continue the account creation process using the app by clicking on the button below:{% endblocktrans %}</p>
|
||||
|
||||
<h6 class="text-center">{% blocktrans with app_name=app.name %}{{ app_name }} already installed?{% endblocktrans %}</h6>
|
||||
|
||||
<div class="text-center">
|
||||
<a href="{{ uri }}"><button class="btn btn-secondary btn-sm">{% trans "Open the app" %}</button></a><br/>
|
||||
<small class="text-muted">{% trans "This button works only if you have the app installed already!" %}</small>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
{% endif %}{% endif %}
|
||||
|
||||
<h5 class="card-title">{% trans "Create an account" %}</h5>
|
||||
|
||||
{%if message %}<div class="alert {%if message.class %}{{ message.class }}{% else %}alert-info{% endif %}" role="alert">
|
||||
{{ message.text }}
|
||||
</div>{% endif %}
|
||||
|
||||
<form method="post">
|
||||
<div class="form-group form-row">
|
||||
<label for="user" class="col-md-4 col-lg-12 col-form-label">{% trans "Username" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text" name="user" class="form-control" aria-describedby="usernameHelp"
|
||||
required autofocus minlength="1" maxlength="30" length="30"{% if username %} value="{{ username }}"{% endif %}
|
||||
>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">@{{ domain }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<small id="usernameHelp" class="d-block form-text text-muted">{% trans "Choose a username, this will become the first part of your new chat address." %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<label for="password" class="col-md-4 col-lg-12 col-form-label">{% trans "Password" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<input type="password" name="password" class="form-control" aria-describedby="passwordHelp"
|
||||
autocomplete="new-password" required minlength="{{ password_policy.length }}"
|
||||
>
|
||||
<small id="passwordHelp" class="form-text text-muted">{% trans "Enter a secure password that you do not use anywhere else." %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<input type="hidden" name="token" value="{{ token }}">
|
||||
{% if app %}<input type="hidden" name="app_id" value="{{ app.id }}">{% endif %}
|
||||
<button type="submit" class="btn btn-primary btn-lg">{% trans "Submit" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
{% if app %}{% if app.supports_preauth_uri %}
|
||||
<div class="alert alert-info">
|
||||
<p>{% blocktrans with app_name=app.name %}If you already have {{ app_name }} installed, we recommend that you continue the account creation process using the app by clicking on the button below:{% endblocktrans %}</p>
|
||||
<p class="text-center h6">{% blocktrans with app_name=app.name %}{{ app_name }} already installed?{% endblocktrans %}</p>
|
||||
<div class="text-center">
|
||||
<a href="{{ uri }}"><button class="btn btn-secondary btn-sm">{% trans "Open the app" %}</button></a><br/>
|
||||
<small class="text-muted">{% trans "This button works only if you have the app installed already!" %}</small>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
{% endif %}{% endif %}
|
||||
<h2 class="card-title h5">{% trans "Create an account" %}</h2>
|
||||
{%if error and error.class == 'undefined' %}<div class="alert alert-danger" role="alert">{{ error.text }}</div>{% endif %}
|
||||
<form method="post" class="needs-validation" novalidate>
|
||||
<div class="form-group form-row">
|
||||
<label for="user" class="col-md-4 col-lg-12 col-form-label">{% trans "Username" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text" name="user" class="form-control {% if error.class == 'username' %}is-invalid{% endif %}" aria-describedby="usernameHelp" tabindex="1"
|
||||
required autofocus minlength="1" maxlength="30" length="30"{% if username %} value="{{ username }}"{% endif %}>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">@{{ domain }}</span>
|
||||
</div>
|
||||
<div class="invalid-feedback">
|
||||
{% if error.class == 'username' %}{{ error.text }}{% else %}
|
||||
{% blocktrans %}Please provide a valid username!{% endblocktrans %}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<small id="usernameHelp" class="d-block form-text text-muted">{% trans "Choose a username, this will become the first part of your new chat address." %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<label for="password" class="col-md-4 col-lg-12 col-form-label">{% trans "Password" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<input type="password" name="password" class="form-control {% if error.class == 'password' %}is-invalid{% endif %}" aria-describedby="passwordHelp" tabindex="2"
|
||||
autocomplete="new-password" required minlength="{{ password_min_length }}">
|
||||
<div class="invalid-feedback">
|
||||
{% if error.class == 'password' %}{{ error.text }}{% else %}
|
||||
{% blocktrans %}Please provide a password! Minimum length: {{ password_min_length }}{% endblocktrans %}{% endif %}
|
||||
</div>
|
||||
<small id="passwordHelp" class="form-text text-muted">{% trans "Enter a secure password that you do not use anywhere else." %}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-row">
|
||||
<input type="hidden" name="token" value="{{ token }}">
|
||||
{% if app %}<input type="hidden" name="app_id" value="{{ app.id }}">{% endif %}
|
||||
<button type="submit" tabindex="3" class="btn btn-primary btn-lg">{% trans "Submit" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
<nav aria-label="{% trans 'Page navigation' %}">
|
||||
<ul class="pagination">
|
||||
<li class="page-item"><a tabindex="4" class="page-link" href="/{{ base }}/{{ token }}" aria-label="{% trans 'Previous' %}">
|
||||
<span aria-hidden="true">«</span>
|
||||
<span>{% trans "Previous" %}</span>
|
||||
</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
window.addEventListener('load', function() {
|
||||
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
||||
var forms = document.getElementsByClassName('needs-validation');
|
||||
// Loop over them and prevent submission
|
||||
var validation = Array.prototype.filter.call(forms, function(form) {
|
||||
form.addEventListener('submit', function(event) {
|
||||
if (form.checkValidity() === false) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
form.classList.add('was-validated');
|
||||
}, false);
|
||||
});
|
||||
}, false);
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "base_min.html" %}
|
||||
{% block form_class %}container col-md-8 col-md-offset-2 col-sm-8 cold-sm-offset-2 col-lg-6 col-lg-offset-3 mt-2 mt-md-5{% endblock %}
|
||||
{% block content %}
|
||||
<h5 class="card-title">{% trans "Registration error" %}</h5>
|
||||
<h2 class="card-title h5">{% trans "Registration error" %}</h2>
|
||||
|
||||
<p>{% if message %}{{ message }}{% else %}{% trans "Sorry, there was a problem registering your account." %}{% endif %}</p>
|
||||
<p>{% if message %}{{ message }}{% else %}{% trans "Sorry, there was a problem registering your account." %}{% endif %}</p>
|
||||
{% endblock%}
|
||||
|
||||
@@ -3,99 +3,99 @@
|
||||
{% block title %}{{site_name}}{% endblock %}
|
||||
{% block h1 %}{{site_name}}{% endblock %}
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
function toggle_password(e) {
|
||||
var button = e.target;
|
||||
var input = button.parentNode.parentNode.querySelector("input");
|
||||
switch(input.attributes.type.value) {
|
||||
case "password":
|
||||
input.attributes.type.value = "text";
|
||||
button.innerText = "{% trans "Hide" %}";
|
||||
break;
|
||||
case "text":
|
||||
input.attributes.type.value = "password";
|
||||
button.innerText = "{% trans "Show" %}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function toggle_password(e) {
|
||||
var button = e.target;
|
||||
var input = button.parentNode.parentNode.querySelector("input");
|
||||
switch(input.attributes.type.value) {
|
||||
case "password":
|
||||
input.attributes.type.value = "text";
|
||||
button.innerText = "{% trans "Hide" %}";
|
||||
break;
|
||||
case "text":
|
||||
input.attributes.type.value = "password";
|
||||
button.innerText = "{% trans "Show" %}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h5 class="card-title">{% trans "Congratulations!" %}</h5>
|
||||
<h2 class="card-title h5">{% trans "Congratulations!" %}</h2>
|
||||
|
||||
<p>{% blocktrans %}You have created an account on <strong>{{ site_name }}</strong>.{% endblocktrans %}</p>
|
||||
<p>{% blocktrans %}You have created an account on <strong>{{ site_name }}</strong>.{% endblocktrans %}</p>
|
||||
|
||||
<p>{% trans "To start chatting, you need to enter your new account credentials into your chosen XMPP software." %}</p>
|
||||
<p>{% trans "To start chatting, you need to enter your new account credentials into your chosen XMPP software." %}</p>
|
||||
|
||||
{% if webchat_url %}
|
||||
<div class="alert alert-success">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-9">
|
||||
<p>{% trans "<strong>No suitable software installed right now?</strong> You can also log in to your account through our online web chat!" %}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a class="btn btn-primary" href="{{ webchat_url }}">{% trans "Log in via web" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if webchat_url %}
|
||||
<div class="alert alert-success">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-9">
|
||||
<p>{% trans "<strong>No suitable software installed right now?</strong> You can also log in to your account through our online web chat!" %}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a class="btn btn-primary" href="{{ webchat_url }}">{% trans "Log in via web" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if app %}
|
||||
<p>{% blocktrans with app_name=app.name %}You can now set up {{ app_name }} and connect it to your new account.{% endblocktrans %}</p>
|
||||
|
||||
<h5>{% blocktrans with app_name=app.name %}Step 1: Download and install {{ app_name }}{% endblocktrans %}</h5>
|
||||
<h2 class="h5">{% blocktrans with app_name=app.name %}Step 1: Download and install {{ app_name }}{% endblocktrans %}</h2>
|
||||
|
||||
<p>{% if app.download.text %}{{ app.download.text }}{% else %}{% blocktrans with app_name=app.name %}Download and install {{ app_name }} below:{% endblocktrans %}{% endif %}</p>
|
||||
<p>{% if app.download.text %}{{ app.download.text }}{% else %}{% blocktrans with app_name=app.name %}Download and install {{ app_name }} below:{% endblocktrans %}{% endif %}</p>
|
||||
|
||||
<div class="ml-5 mb-3">
|
||||
{% for item in app.download.buttons %}
|
||||
{% if item.image %}
|
||||
<a href="{{ item.url }}" {%if item.target %}target="{{ item.target }}"{% endif %} rel="noopener">
|
||||
<img src="{{ item.image }}" {% if item.alttext %}alt="{{ item.alttext }}"{% endif %}>
|
||||
</a>
|
||||
{% endif %}
|
||||
{%if item.text %}
|
||||
<a href="{{item.url}}" {% if item.target %}target="{{ item.target }}"{% endif %} rel="noopener">
|
||||
<button class="btn btn-primary">
|
||||
{{ item.text }}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="ml-5 mb-3">
|
||||
{% for item in app.download.buttons %}
|
||||
{% if item.image %}
|
||||
<a href="{{ item.url }}" {%if item.target %}target="{{ item.target }}"{% endif %} rel="noopener">
|
||||
<img src="{{ item.image }}" {% if item.alttext %}alt="{{ item.alttext }}"{% endif %}>
|
||||
</a>
|
||||
{% endif %}
|
||||
{%if item.text %}
|
||||
<a href="{{item.url}}" {% if item.target %}target="{{ item.target }}"{% endif %} rel="noopener">
|
||||
<button class="btn btn-primary">
|
||||
{{ item.text }}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<h5>{% blocktrans with app_name=app.name %}Step 2: Connect {{ app_name }} to your new account{% endblocktrans %}</h5>
|
||||
<h2 class="h5">{% blocktrans with app_name=app.name %}Step 2: Connect {{ app_name }} to your new account{% endblocktrans %}</h2>
|
||||
|
||||
<p>{% if app.setup.text %}{{ app.setup.text }}{% else %}{% blocktrans with app_name=app.name %}Launch {{ app_name }} and sign in using your account credentials.{% endblocktrans %}{% endif %}</p>
|
||||
<p>{% if app.setup.text %}{{ app.setup.text }}{% else %}{% blocktrans with app_name=app.name %}Launch {{ app_name }} and sign in using your account credentials.{% endblocktrans %}{% endif %}</p>
|
||||
{% endif %}
|
||||
|
||||
<p>{% trans "As a final reminder, your account details are shown below:" %}</p>
|
||||
<p>{% trans "As a final reminder, your account details are shown below:" %}</p>
|
||||
|
||||
<form class="account-details col-12 col-lg-6 mx-auto">
|
||||
<div class="form-group form-row">
|
||||
<label for="user" class="col-md-4 col-lg-12 col-form-label">{% trans "Chat address (JID)" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<input type="text" class="form-control-plaintext" readonly value="{{ username }}@{{ domain }}">
|
||||
</div>
|
||||
</div>
|
||||
{% if password %}
|
||||
<div class="form-group form-row">
|
||||
<label for="password" class="col-md-4 col-lg-12 col-form-label">{% trans "Password" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<div class="input-group">
|
||||
<input type="password" readonly class="form-control" value="{{ password }}">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="toggle_password(event)">{% trans "Show" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
<form class="account-details col-12 col-lg-6 mx-auto">
|
||||
<div class="form-group form-row">
|
||||
<label for="user" class="col-md-4 col-lg-12 col-form-label">{% trans "Chat address (JID)" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<input type="text" class="form-control-plaintext" readonly value="{{ username }}@{{ domain }}">
|
||||
</div>
|
||||
</div>
|
||||
{% if password %}
|
||||
<div class="form-group form-row">
|
||||
<label for="password" class="col-md-4 col-lg-12 col-form-label">{% trans "Password" %}:</label>
|
||||
<div class="col-md-8 col-lg-12">
|
||||
<div class="input-group">
|
||||
<input type="password" readonly class="form-control" value="{{ password }}">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="toggle_password(event)">{% trans "Show" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if password %}
|
||||
{% if password %}
|
||||
<p>{% trans "Your password is stored encrypted on the server and will not be accessible after you close this page. Keep it safe and never share it with anyone." %}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{% blocktrans with inviter=invite.inviter|jid %}{{ inviter }} has invited you to connect!{% endblocktrans %}{% endblock %}
|
||||
{% block title %}{% trans "Add Contact" %}{% endblock %}
|
||||
{% block h1 %}{% blocktrans with inviter=invite.inviter|user %}{{ inviter }} has invited you to connect!{% endblocktrans %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-8">
|
||||
{% blocktrans with inviter=invite.inviter|jid %}This is an invite from <strong>{{ inviter }}</strong> to connect and chat on the XMPP network. If you already have an XMPP client installed just press the button below!{% endblocktrans %}
|
||||
<div class="col-md-4">
|
||||
<a href="{{ invite.uri }}" class="btn btn-primary my-3 mb-3">{% blocktrans with inviter=invite.inviter|user %}Add {{ inviter }} to your contact list{% endblocktrans %}</a><br/>
|
||||
<!-- {{ invite.uri }} -->
|
||||
</div>
|
||||
</div>
|
||||
<p>{% trans "If you don't have an XMPP client installed yet, here's a list of suitable clients for your platform." %}</p>
|
||||
<div class="col-md-8">
|
||||
{% blocktrans with inviter=invite.inviter|jid %}This is an invite from <strong>{{ inviter }}</strong> to connect and chat on the XMPP network. If you already have an XMPP client installed just press the button below!{% endblocktrans %}
|
||||
<div class="col-md-4">
|
||||
<a href="{{ invite.uri }}" class="btn btn-primary my-3 mb-3">{% blocktrans with inviter=invite.inviter|user %}Add {{ inviter }} to your contact list{% endblocktrans %}</a><br/>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="h6">{% trans "If you don't have an XMPP client installed yet, here's a list of suitable clients for your platform." %}</h2>
|
||||
|
||||
{% include "apps.html" %}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(function () {
|
||||
// If QR lib loaded ok, show QR button on desktop devices
|
||||
if(window.QRCode) {
|
||||
const qrcode_opts = {
|
||||
text : document.location.href,
|
||||
addQuietZone: true
|
||||
};
|
||||
const qrcode_opts = {
|
||||
text : document.location.href,
|
||||
addQuietZone: true
|
||||
};
|
||||
new QRCode(document.getElementById("qr-invite-page"), qrcode_opts);
|
||||
document.getElementById('qr-button-container').classList.add("d-md-block");
|
||||
}
|
||||
@@ -34,16 +34,16 @@
|
||||
platform_friendly = "Windows Phone";
|
||||
platform_classname = "windows-phone";
|
||||
break;
|
||||
case "OS X":
|
||||
case "OS X":
|
||||
if (navigator.maxTouchPoints > 1) {
|
||||
// looks like iPad to me!
|
||||
platform_friendly = "iPadOS";
|
||||
// looks like iPad to me!
|
||||
platform_friendly = "iPadOS";
|
||||
platform_classname = "ipados";
|
||||
} else {
|
||||
} else {
|
||||
platform_friendly = "macOS";
|
||||
platform_classname = "macos";
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(platform.os.family.startsWith("Windows")) {
|
||||
platform_friendly = "Windows";
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 219 B |
+1
-1
File diff suppressed because one or more lines are too long
@@ -8,6 +8,7 @@
|
||||
{"# participants","# участници"}.
|
||||
{"A description of the node","Описание на нода"}.
|
||||
{"A friendly name for the node","Удобно име на нода"}.
|
||||
{"A fully-featured desktop chat client for Windows and Linux.","Пълнофункционален чат клиент за Windows и Linux."}.
|
||||
{"A password is required to enter this room","Необходима е парола за влизане в тази стая"}.
|
||||
{"A Web Page","Уеб страница"}.
|
||||
{"Accept","Приемам"}.
|
||||
@@ -19,6 +20,7 @@
|
||||
{"Administration of ","Администриране на "}.
|
||||
{"Administration","Администриране"}.
|
||||
{"Administrator privileges required","Изискватт се администраторски права"}.
|
||||
{"After successfully installing {{ app_name }}, come back to this page and <strong>continue with Step 2</strong>.","След като инсталирате успешно {{ app_name }}, върнете се на тази страница и <strong>продължете със стъпка 2</strong>."}.
|
||||
{"All activity","Цялата статистика"}.
|
||||
{"All Users","Всички потребители"}.
|
||||
{"Allow subscription","Разреши абониране"}.
|
||||
@@ -61,6 +63,7 @@
|
||||
{"Backup to File at ","Архивиране във файл на "}.
|
||||
{"Backup","Резервно копие"}.
|
||||
{"Bad format","Лош формат"}.
|
||||
{"BAD REQUEST","BAD REQUEST"}.
|
||||
{"Birthday","Рожден ден"}.
|
||||
{"Both the username and the resource are required","Изискват се потребителското име и ресурсът"}.
|
||||
{"Bytestream already activated","Bytestream вече е активиран"}.
|
||||
@@ -97,6 +100,7 @@
|
||||
{"Contacts","Контакти"}.
|
||||
{"Country","Държава"}.
|
||||
{"Create a Hat","Създай Шапка"}.
|
||||
{"Create Account","Създай профил"}.
|
||||
{"Current Discussion Topic","Текуща тема на дискусита"}.
|
||||
{"Database failure","Грешка в базата данни"}.
|
||||
{"Database Tables Configuration at ","Конфигурация на таблиците в базата данни при "}.
|
||||
@@ -112,6 +116,8 @@
|
||||
{"Disable User","Деактивирай потребителя"}.
|
||||
{"Disc only copy","Копие само на диска"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the XMPP server.","Не казвайте паролата си на никого, дори на администраторите на XMPP сървъра."}.
|
||||
{"Download and install {{ app_name }} below:","Изтеглете и инсталирайте {{ app_name }} по-долу:"}.
|
||||
{"Download Gajim","Свалете Gajim"}.
|
||||
{"Dump Backup to Text File at ","Архивиране в текстов файл при "}.
|
||||
{"Dump to Text File","Архивиране в текстов файл"}.
|
||||
{"Duplicated groups are not allowed by RFC6121","Дублирани групи не са разрешени от RFC6121"}.
|
||||
@@ -176,6 +182,7 @@
|
||||
{"Get User Roster","Списък с потребители"}.
|
||||
{"Get User Statistics","Покажи статистика за потребителя"}.
|
||||
{"Given Name","Наименование"}.
|
||||
{"Google Play Store Logo","Google Play Store лого"}.
|
||||
{"Grant voice to this person?","Предоставяне на глас за потребителя?"}.
|
||||
{"has been banned","е със забранен достъп"}.
|
||||
{"has been kicked because of a system shutdown","е отстранен поради изключване на системата"}.
|
||||
@@ -189,6 +196,7 @@
|
||||
{"Hat URI","URI адрес за шапка"}.
|
||||
{"Hats limit exceeded","Превишен е лимитът за шапка"}.
|
||||
{"Host unknown","Неизвестен хост"}.
|
||||
{"Hostname invalid","Невалидно име за хост"}.
|
||||
{"HTTP File Upload","Качване на файл по HTTP"}.
|
||||
{"Idle connection","Неактивна връзка"}.
|
||||
{"If you don't see the CAPTCHA image here, visit the web page.","Ако не виждате CAPTCHA изображението, посетете уеб страницата."}.
|
||||
@@ -216,6 +224,7 @@
|
||||
{"Invalid node name","Невалидно име на нода"}.
|
||||
{"Invalid 'previd' value","Невалидна стойност на 'previd'"}.
|
||||
{"Invitations are not allowed in this conference","Поканите не са разрешени в тази конференция"}.
|
||||
{"Invite User","Покани потребител"}.
|
||||
{"IP addresses","IP адреси"}.
|
||||
{"is now known as","е известен като"}.
|
||||
{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","Не е позволено да изпращате съобщения за грешки в стаята. Участникът (~s) е изпратил съобщение за грешка (~s) и е бил отстранен от стаята"}.
|
||||
@@ -225,6 +234,7 @@
|
||||
{"January","Януари"}.
|
||||
{"JID normalization denied by service policy","Политиката на услугата не допуска нормализирането на JID"}.
|
||||
{"JID normalization failed","Нормализирането на JID е неуспешно"}.
|
||||
{"Join {{ site_name }} with {{ app_name }}","Присъединете се към {{ site_name }} с {{ app_name }}"}.
|
||||
{"Joined MIX channels of ~ts","Свързани MIX канали на ~ts"}.
|
||||
{"Joined MIX channels:","Свързани MIX канали:"}.
|
||||
{"joins the room","се присъединява към стаята"}.
|
||||
@@ -256,9 +266,11 @@
|
||||
{"Max payload size in bytes","Максимален размер на прикачения обект в байтове"}.
|
||||
{"Maximum file size","Максимален размер на файла"}.
|
||||
{"Maximum Number of History Messages Returned by Room","Максимален брой съобщения от хронологията, върнати от стая"}.
|
||||
{"Maximum number of invites reached","Максималният брой покани е достигнат"}.
|
||||
{"Maximum number of items to persist","Максимален брой елементи за запазване"}.
|
||||
{"Maximum Number of Occupants","Максимален брой участници"}.
|
||||
{"May","Май"}.
|
||||
{"Members are allowed to invite others","Участниците могат да канят други"}.
|
||||
{"Membership is required to enter this room","Изисква се членство, за вход в тази стая"}.
|
||||
{"Memorize your password, or write it in a paper placed in a safe place. In XMPP there isn't an automated way to recover your password if you forget it.","Запомнете паролата си или я запишете на лист хартия, поставен на сигурно място. В XMPP няма автоматичен начин за възстановяване на паролата в случай, че я забравите."}.
|
||||
{"Mere Availability in XMPP (No Show Value)","Наличност в XMPP (Не показвай стойност)"}.
|
||||
@@ -326,6 +338,7 @@
|
||||
{"Node","Нод"}.
|
||||
{"None","Нито един"}.
|
||||
{"Not allowed","Не е разрешено"}.
|
||||
{"NOT FOUND","NOT FOUND"}.
|
||||
{"Not Found","Не е намерен"}.
|
||||
{"Not subscribed","Няма абонамент"}.
|
||||
{"Notify subscribers when items are removed from the node","Уведоми абонатите, когато елементите бъдат премахнати от нода"}.
|
||||
@@ -363,6 +376,7 @@
|
||||
{"Only service administrators are allowed to send service messages","Само администраторите на услуги имат право да изпращат системни съобщения"}.
|
||||
{"Only those on a whitelist may associate leaf nodes with the collection","Само тези от списъка с позволени могат да свързват листови нодове с колекцията"}.
|
||||
{"Only those on a whitelist may subscribe and retrieve items","Само тези от списъка с позволени могат да се абонират и да извличат елементи"}.
|
||||
{"Open the app","Отворете приложението"}.
|
||||
{"Organization Name","Име на организацията"}.
|
||||
{"Organization Unit","Отдел"}.
|
||||
{"Other Modules Available:","Други налични модули:"}.
|
||||
@@ -393,6 +407,7 @@
|
||||
{"Previous session PID has exited","Предишният PID на сесията е излязъл"}.
|
||||
{"Previous session PID is dead","PID от предишната сесия не съществува"}.
|
||||
{"Previous session timed out","Времето на предишната сесия изтече"}.
|
||||
{"Previous","Предишен"}.
|
||||
{"private, ","частна, "}.
|
||||
{"Public","Публичен"}.
|
||||
{"Publish model","Модел за публикуване"}.
|
||||
@@ -413,9 +428,11 @@
|
||||
{"Re-Enable User","Активиране на потребител"}.
|
||||
{"Register an XMPP account","Регистрирай XMPP акаунт"}.
|
||||
{"Register","Регистрирай"}.
|
||||
{"Registration Error","Грешка при регистрация"}.
|
||||
{"Remote copy","Отдалечено копие"}.
|
||||
{"Remove a hat from a user","Премахни шапка от потребител"}.
|
||||
{"Remove User","Премахни потребител"}.
|
||||
{"Renga Logo","Renga лого"}.
|
||||
{"Replaced by new connection","Заменен от нова връзка"}.
|
||||
{"Request has timed out","Времето за заявка изтече"}.
|
||||
{"Request is ignored","Заявката е игнорирано"}.
|
||||
@@ -441,6 +458,7 @@
|
||||
{"Roster size","Размер на списъка с контакти"}.
|
||||
{"Running Nodes","Работещи нодове"}.
|
||||
{"~s invites you to the room ~s","~s ви кани в стая ~s"}.
|
||||
{"Sad person holding empty box","Тъжен човек, държащ празна кутия"}.
|
||||
{"Saturday","Събота"}.
|
||||
{"Search from the date","Търси от дата"}.
|
||||
{"Search Results for ","Резултати от търсенето за "}.
|
||||
@@ -461,9 +479,12 @@
|
||||
{"Show Integral Table","Покажи интегрална таблица"}.
|
||||
{"Show Occupants Join/Leave","Покажи участници Влязъл/Напускнал"}.
|
||||
{"Show Ordinary Table","Покажи обикновена таблица"}.
|
||||
{"Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>","Показаните приложения са само за <span class='platform-name'>, което е текущата ви платформа</span>. Можете също да <a href='#' id='show-all-clients-button'>прегледате всички налични приложения.</a>"}.
|
||||
{"Shut Down Service","Изключи услугата"}.
|
||||
{"Siskin IM Logo","Siskin IM лого"}.
|
||||
{"SOCKS5 Bytestreams","SOCKS5 байтови потоци"}.
|
||||
{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","Някои XMPP клиенти могат да съхраняват паролата Ви в компютъра, но от съображения за сигурност трябва да го правите само на личния си компютър."}.
|
||||
{"Sorry, it looks like this invite code has expired!","Съжалявам, изглежда, че този код за покана е изтекъл!"}.
|
||||
{"Sources Specs:","Спецификации на източниците:"}.
|
||||
{"Specify the access model","Задай модела за достъп"}.
|
||||
{"Specify the event message type","Задай типа на съобщението за събитие"}.
|
||||
@@ -536,11 +557,13 @@
|
||||
{"The sender of the last received message","Подателят на последното получено съобщение"}.
|
||||
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","Строфата ТРЯБВА да съдържа само един <active/> елемент, един <default/> елемент или един <list/> елемент"}.
|
||||
{"The subscription identifier associated with the subscription request","Идентификаторът на абонамента, свързан със заявката за абонамент"}.
|
||||
{"The token provided is either invalid or expired.","Предоставеният токен код е невалиден или изтекъл."}.
|
||||
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","URL адрес на XSL трансформацията, която може да се приложи към прикачените данни, за да се генерира подходящ елемент от тялото на съобщението."}.
|
||||
{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","URL адрес на XSL трансформацията, която може да се приложи към формата на прикачените данни, за да се генерира валиден резултат от Data Forms, който клиентът може да покаже с помощта на общ механизъм за визуализация на Data Forms"}.
|
||||
{"There was an error changing the password: ","Възникна грешка при промяна на паролата: "}.
|
||||
{"There was an error creating the account: ","Възникна грешка при създаването на профила: "}.
|
||||
{"There was an error deleting the account: ","Възникна грешка при изтриването на профила: "}.
|
||||
{"This is an invite from <strong>{{ inviter }}</strong> to connect and chat on the XMPP network. If you already have an XMPP client installed just press the button below!","Това е покана от <strong>{{ inviter }}</strong> за свързване и чат в XMPP мрежата. Ако вече имате инсталиран XMPP клиент, просто натиснете бутона по-долу!"}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Не е чувствително към регистъра (главни и малки букви): \"macbeth\"е същото като \"MacBeth\"и \"Macbeth\"."}.
|
||||
{"This page allows to register an XMPP account in this XMPP server. Your JID (Jabber ID) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Тази страница позволява регистриране на XMPP профил на този сървър. Вашият JID (Jabber ID) ще бъде във формата: username@server. Моля, прочетете внимателно инструкциите, за да попълните правилно полетата."}.
|
||||
{"This page allows to unregister an XMPP account in this XMPP server.","Тази страница позволява премахване на XMPP профил от този сървър."}.
|
||||
@@ -591,6 +614,9 @@
|
||||
{"User session not found","Потребителската сесия не е намерена"}.
|
||||
{"User session terminated","Потребителската сесия е прекратена"}.
|
||||
{"User ~ts","Потребител ~ts"}.
|
||||
{"Username invalid","Невалидно потребителско име"}.
|
||||
{"Username is reserved","Потребителското име е резервирано"}.
|
||||
{"Username","Потребителско име"}.
|
||||
{"Username:","Потребителско име:"}.
|
||||
{"Users are not allowed to register accounts so quickly","Не е разрешено потребителите да регистрират профили толкова бързо"}.
|
||||
{"Users Last Activity","Последна активност на потребителите"}.
|
||||
@@ -638,6 +664,7 @@
|
||||
{"You are not joined to the channel","Не сте присъединени към канала"}.
|
||||
{"You can later change your password using an XMPP client.","По-късно можете да промените паролата си с помощта на XMPP клиент."}.
|
||||
{"You have been banned from this room","Достъпът ви до тази стая е забранен"}.
|
||||
{"You have created an account on <strong>{{ site_name }}</strong>.","Създадохте профил в <strong>{{ site_name }}</strong>."}.
|
||||
{"You have joined too many conferences","Присъединили сте се към твърде много конференции"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Трябва да попълните полето \"Псевдоним\" във формата"}.
|
||||
{"You need a client that supports x:data and CAPTCHA to register","За да се регистрирате Ви е нужен клиент, който поддържа x:data и CAPTCHA"}.
|
||||
|
||||
+112
-9
@@ -4,21 +4,33 @@
|
||||
%% https://docs.ejabberd.im/developer/extending-ejabberd/localization/
|
||||
|
||||
{" (Add * to the end of field to match substring)"," (Afegix * al final d'un camp per a buscar subcadenes)"}.
|
||||
{"{{ app_name }} already installed?","Ja està instal·lat {{ app_name }}?"}.
|
||||
{" has set the subject to: "," ha posat el tema: "}.
|
||||
{"{{ inviter }} has invited you to connect!","{{ inviter }} t'ha invitat a connectar-te!"}.
|
||||
{"# participants","# participants"}.
|
||||
{"A description of the node","Una descripció del node"}.
|
||||
{"A friendly name for the node","Un nom per al node"}.
|
||||
{"A fully-featured desktop chat client for Windows and Linux.","Un client de xat molt complet d'escriptori per a Windows i Linux."}.
|
||||
{"A lightweight and powerful XMPP client for iPhone and iPad. It provides an easy way to talk and share moments with your friends.","Un client XMPP lleuger i potent per a iPhone e iPad. Proporciona una forma senzilla de xarrar i compartir moments amb les teues amistats."}.
|
||||
{"A modern open-source chat client for iPhone and iPad. It is easy to use and has a clean user interface.","Un client de xat modern i de software lliure per a iPhone i iPad. Es simple d'usar i te una interfície d'usuari neta."}.
|
||||
{"A modern open-source chat client for Mac. It is easy to use and has a clean user interface.","Un client de xat modern i de software lliure per a Mac. Es simple d'usar i te una interfície d'usuari neta."}.
|
||||
{"A modern open-source chat client for the desktop. It focuses on providing a clean and reliable Jabber/XMPP experience while having your privacy in mind.","Un client de xat modern i de software lliure per a l'escriptori. Està enfocat en proporcionar una experiència Jabber/XMPP neta i comfiable, mentre mantenes la teva privacitat en ment."}.
|
||||
{"A password is required to enter this room","Es necessita contrasenya per a entrar en aquesta sala"}.
|
||||
{"A Web Page","Una Pàgina Web"}.
|
||||
{"Accept invite using {{ app_name }}","Accepta la invitació usant {{ app_name }}"}.
|
||||
{"Accept","Acceptar"}.
|
||||
{"Access denied by service policy","Accés denegat per la política del servei"}.
|
||||
{"Access model","Model d'Accés"}.
|
||||
{"Account doesn't exist","El compte no existeix"}.
|
||||
{"Action on user","Acció en l'usuari"}.
|
||||
{"Add {{ inviter }} to your contact list","Afegir {{ inviter }} a la teua llista de contactes"}.
|
||||
{"Add Contact","Afegir Contacte"}.
|
||||
{"Add User","Afegir usuari"}.
|
||||
{"Administration of ","Administració de "}.
|
||||
{"Administration","Administració"}.
|
||||
{"Administrator privileges required","Es necessita tenir privilegis d'administrador"}.
|
||||
{"After clicking the button you will be taken to {{ app_name }} to finish setting up your new {{ site_name }} account.","Al polsar el boto, s'obrirà {{ app_name }} per a terminar de configurar el teu compte a {{ site_name }}."}.
|
||||
{"After successfully installing {{ app_name }}, come back to this page and <strong>continue with Step 2</strong>.","Després d'instal·lar correctament {{ app_name }}, torna ací i <strong>continua amb el Pas 2</strong>."}.
|
||||
{"All activity","Tota l'activitat"}.
|
||||
{"All Users","Tots els usuaris"}.
|
||||
{"Allow subscription","Permetre subscripció"}.
|
||||
@@ -46,8 +58,10 @@
|
||||
{"Anyone with Voice","Qualsevol amb Veu"}.
|
||||
{"Anyone","Qualsevol"}.
|
||||
{"API Commands","Comandaments API"}.
|
||||
{"Apple Store Logo","Logo de la Apple Store"}.
|
||||
{"April","Abril"}.
|
||||
{"Arguments","Arguments"}.
|
||||
{"As a final reminder, your account details are shown below:","Com a recordatori final, el detalls del teu compte es mostren ací:"}.
|
||||
{"Assign a hat to a user","Asignar un barret a un usuari"}.
|
||||
{"Attribute 'channel' is required for this request","L'atribut 'channel' és necessari per a aquesta petició"}.
|
||||
{"Attribute 'id' is mandatory for MIX messages","L'atribut 'id' es necessari per a missatges MIX"}.
|
||||
@@ -61,6 +75,9 @@
|
||||
{"Backup to File at ","Desar còpia de seguretat a fitxer en "}.
|
||||
{"Backup","Guardar còpia de seguretat"}.
|
||||
{"Bad format","Format erroni"}.
|
||||
{"BAD REQUEST","MALA PETICIÓ"}.
|
||||
{"Beagle IM by Tigase, Inc. is a lightweight and powerful XMPP client for macOS.","Beagle IM de Tigase, Inc. es un client XMPP lleuger i poderós per a macOS."}.
|
||||
{"Beagle IM Logo","Logo de Beagle IM"}.
|
||||
{"Birthday","Aniversari"}.
|
||||
{"Both the username and the resource are required","Es requereixen tant el nom d'usuari com el recurs"}.
|
||||
{"Bytestream already activated","El Bytestream ja està activat"}.
|
||||
@@ -77,6 +94,7 @@
|
||||
{"Channel JID","JID del Canal"}.
|
||||
{"Channels","Canals"}.
|
||||
{"Characters not allowed:","Caràcters no permesos:"}.
|
||||
{"Chat address (JID)","Direcció de xarrar (JID)"}.
|
||||
{"Chatroom configuration modified","Configuració de la sala de xat modificada"}.
|
||||
{"Chatroom is created","La sala s'ha creat"}.
|
||||
{"Chatroom is destroyed","La sala s'ha destruït"}.
|
||||
@@ -84,34 +102,50 @@
|
||||
{"Chatroom is stopped","La sala s'ha aturat"}.
|
||||
{"Chatrooms","Sales de xat"}.
|
||||
{"Choose a username and password to register with this server","Tria nom d'usuari i contrasenya per a registrar-te en aquest servidor"}.
|
||||
{"Choose a username, this will become the first part of your new chat address.","Elegeix un nom de compte, que serà la primera part de la direcció del teu compte."}.
|
||||
{"Choose storage type of tables","Selecciona el tipus d'almacenament de les taules"}.
|
||||
{"Choose whether to approve this entity's subscription.","Tria si aproves aquesta entitat de subscripció."}.
|
||||
{"City","Ciutat"}.
|
||||
{"Click the button to open the Dino website where you can download and install it on your PC.","Polsa el botó per a obrir la pàgina web de Dino on podràs descarregar el programa per a instalarlo al teu ordinador."}.
|
||||
{"Client acknowledged more stanzas than sent by server","El client ha reconegut més paquets dels que ha enviat el servidor"}.
|
||||
{"Close","Tancar"}.
|
||||
{"Clustering","Clustering"}.
|
||||
{"Commands","Comandaments"}.
|
||||
{"Conference room does not exist","La sala de conferències no existeix"}.
|
||||
{"Configuration of room ~s","Configuració de la sala ~s"}.
|
||||
{"Configuration","Configuració"}.
|
||||
{"Congratulations!","Enhorabona!"}.
|
||||
{"Contact Addresses (normally, room owner or owners)","Adreces de contacte (normalment, propietaris de la sala)"}.
|
||||
{"Contacts","Contactes"}.
|
||||
{"Conversations is a Jabber/XMPP client for Android 6.0+ smartphones that has been optimized to provide a unique mobile experience.","Conversations es un client Jabber/XMPP per a mòbils Android 6.0+ que ha sigut optimitzat per a proporcionar una experiència mòbil unica."}.
|
||||
{"Conversations Logo","Logo de Conversations"}.
|
||||
{"Country","Pais"}.
|
||||
{"Create a Hat","Crear un barret"}.
|
||||
{"Create Account","Crear un Compte"}.
|
||||
{"Create an account","Crear un compte"}.
|
||||
{"Creating an account will allow to communicate with other people on <strong>{{ site_name }}</strong> and other services on the XMPP network.","Crear un compte et permetrà comunicar-te amb altra gent a <strong>{{ site_name }}</strong> i a altres serveis de la xarxa XMPP."}.
|
||||
{"Creating an account will allow to communicate with <strong>{{ inviter }}</strong> and other people on <strong>{{ site_name }}</strong> and other services on the XMPP network.","Crear un compte e permetrà comunicar-te amb <strong>{{ inviter }}</strong> i altra gent a <strong>{{ site_name }}</strong> i a altres serveis de la xarxa XMPP."}.
|
||||
{"Current Discussion Topic","Assumpte de discussió actual"}.
|
||||
{"Database failure","Error a la base de dades"}.
|
||||
{"Database Tables Configuration at ","Configuració de la base de dades en "}.
|
||||
{"Database","Base de dades"}.
|
||||
{"December","Decembre"}.
|
||||
{"Default users as participants","Els usuaris són participants per defecte"}.
|
||||
{"Delete message of the day on all hosts","Elimina el missatge del dis de tots els hosts"}.
|
||||
{"Delete message of the day on all hosts","Elimina el missatge del dia de tots els dominis"}.
|
||||
{"Delete message of the day","Eliminar el missatge del dia"}.
|
||||
{"Delete User","Eliminar Usuari"}.
|
||||
{"Deliver event notifications","Entrega de notificacions d'events"}.
|
||||
{"Deliver payloads with event notifications","Enviar payloads junt a les notificacions d'events"}.
|
||||
{"Destroy a Hat","Destruir un barret"}.
|
||||
{"Dino Logo","Logo de Dino"}.
|
||||
{"Disable User","Deshabilitar un Usuari"}.
|
||||
{"Disc only copy","Còpia sols en disc"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the XMPP server.","No li donis la teva contrasenya a ningú, ni tan sols als administradors del servidor XMPP."}.
|
||||
{"Download and install {{ app_name }} below:","Descarrega e instal·la {{ app_name }} ací baix:"}.
|
||||
{"Download Dino for Linux","Descarrega Dino per a Linux"}.
|
||||
{"Download from Mac App Store","Descarrega de la Tenda d'Apps de Mac"}.
|
||||
{"Download Gajim","Descarregar Gajim"}.
|
||||
{"Download Renga for Haiku","Descarrega Renga per a Haiku"}.
|
||||
{"Dump Backup to Text File at ","Exporta còpia de seguretat a fitxer de text en "}.
|
||||
{"Dump to Text File","Exportar a fitxer de text"}.
|
||||
{"Duplicated groups are not allowed by RFC6121","No estan permesos els grups duplicats al RFC6121"}.
|
||||
@@ -133,6 +167,7 @@
|
||||
{"Enable message archiving","Activar l'emmagatzematge de missatges"}.
|
||||
{"Enabling push without 'node' attribute is not supported","No està suportat activar Push sense l'atribut 'node'"}.
|
||||
{"End User Session","Finalitzar Sesió d'Usuari"}.
|
||||
{"Enter a secure password that you do not use anywhere else.","Introdueix una contrasenya segura que no estiguis usant en cap altre lloc."}.
|
||||
{"Enter nickname you want to register","Introdueix el sobrenom que vols registrar"}.
|
||||
{"Enter path to backup file","Introdueix ruta al fitxer de còpia de seguretat"}.
|
||||
{"Enter path to jabberd14 spool dir","Introdueix la ruta al directori de jabberd14 spools"}.
|
||||
@@ -143,7 +178,7 @@
|
||||
{"Exclude Jabber IDs from CAPTCHA challenge","Excloure Jabber IDs de la comprovació CAPTCHA"}.
|
||||
{"Export all tables as SQL queries to a file:","Exporta totes les taules a un fitxer SQL:"}.
|
||||
{"Export data of all users in the server to PIEFXIS files (XEP-0227):","Exportar dades de tots els usuaris del servidor a arxius PIEFXIS (XEP-0227):"}.
|
||||
{"Export data of users in a host to PIEFXIS files (XEP-0227):","Exportar dades d'usuaris d'un host a arxius PIEFXIS (XEP-0227):"}.
|
||||
{"Export data of users in a host to PIEFXIS files (XEP-0227):","Exportar dades d'usuaris d'un domini a arxius PIEFXIS (XEP-0227):"}.
|
||||
{"External component failure","Error al component extern"}.
|
||||
{"External component timeout","Temps esgotat al component extern"}.
|
||||
{"Failed to activate bytestream","Errada al activar bytestream"}.
|
||||
@@ -153,6 +188,7 @@
|
||||
{"Failed to process option '~s'","Ha fallat el processat de la opció '~s'"}.
|
||||
{"Family Name","Cognom"}.
|
||||
{"FAQ Entry","Entrada a la FAQ"}.
|
||||
{"F-Droid Store Logo","Logo de la F-Droid Store"}.
|
||||
{"February","Febrer"}.
|
||||
{"File larger than ~w bytes","El fitxer es més gran que ~w bytes"}.
|
||||
{"Fill in the form to search for any matching XMPP User","Emplena camps per a buscar usuaris XMPP que concorden"}.
|
||||
@@ -161,6 +197,7 @@
|
||||
{"Full List of Room Admins","Llista completa de administradors de la sala"}.
|
||||
{"Full List of Room Owners","Llista completa de propietaris de la sala"}.
|
||||
{"Full Name","Nom complet"}.
|
||||
{"Gajim Logo","Logo de Gajim"}.
|
||||
{"Get List of Active Users","Obté la llista d'usuaris actius"}.
|
||||
{"Get List of Disabled Users","Obté la llista d'usuaris deshabilitats"}.
|
||||
{"Get List of Idle Users","Obté la llista d'usuaris inactius"}.
|
||||
@@ -172,10 +209,12 @@
|
||||
{"Get Number of Online Users","Obtenir Número d'Usuaris Connectats"}.
|
||||
{"Get Number of Registered Users","Obtenir Número d'Usuaris Registrats"}.
|
||||
{"Get Pending","Obtenir Pendents"}.
|
||||
{"Get started","Comencem"}.
|
||||
{"Get User Last Login Time","Obtenir la última connexió d'Usuari"}.
|
||||
{"Get User Roster","Obtenir llista de contactes de l'usuari"}.
|
||||
{"Get User Statistics","Obtenir Estadístiques d'Usuari"}.
|
||||
{"Given Name","Nom propi"}.
|
||||
{"Google Play Store Logo","Logo de la Google Play Store"}.
|
||||
{"Grant voice to this person?","Concedir veu a aquesta persona?"}.
|
||||
{"has been banned","ha sigut bloquejat"}.
|
||||
{"has been kicked because of a system shutdown","ha sigut expulsat perquè el sistema va a apagar-se"}.
|
||||
@@ -188,9 +227,13 @@
|
||||
{"Hat title","Títol del barret"}.
|
||||
{"Hat URI","URI del barret"}.
|
||||
{"Hats limit exceeded","El límit de tràfic ha sigut sobrepassat"}.
|
||||
{"Host unknown","Host desconegut"}.
|
||||
{"Hide","Amagar"}.
|
||||
{"Host unknown","Domini desconegut"}.
|
||||
{"Hostname invalid","Nom de domini no vàlid"}.
|
||||
{"HTTP File Upload","HTTP File Upload"}.
|
||||
{"Idle connection","Connexió sense us"}.
|
||||
{"If you already have {{ app_name }} installed, we recommend that you continue the account creation process using the app by clicking on the button below:","Si ja tens instal·lat {{ app_name }}, et recomanem que continues la creació del teu compte usant eixa app, polsa el boto:"}.
|
||||
{"If you don't have an XMPP client installed yet, here's a list of suitable clients for your platform.","Si encara no tens un client XMPP instal·lat, mira esta llista de clients disponibles per a la teva plataforma."}.
|
||||
{"If you don't see the CAPTCHA image here, visit the web page.","Si no veus la imatge CAPTCHA açí, visita la pàgina web."}.
|
||||
{"Import Directory","Importar directori"}.
|
||||
{"Import File","Importar fitxer"}.
|
||||
@@ -209,6 +252,7 @@
|
||||
{"Incorrect value of 'action' in data form","Valor incorrecte de 'action' al formulari de dades"}.
|
||||
{"Incorrect value of 'path' in data form","Valor incorrecte de 'path' al formulari de dades"}.
|
||||
{"Installed Modules:","Mòduls instal·lats:"}.
|
||||
{"Installed ok? Great! <strong>Click or tap the button below</strong> to accept your invite and continue with your account setup:","S'ha instal·lat correctament? Perfecte! <strong>Polsa en el següent boto</strong> per a acceptar l'invitació i continuar preparant el teu compte:"}.
|
||||
{"Install","Instal·lar"}.
|
||||
{"Insufficient privilege","Privilegi insuficient"}.
|
||||
{"Internal server error","Error intern del servidor"}.
|
||||
@@ -216,6 +260,9 @@
|
||||
{"Invalid node name","Nom de node no vàlid"}.
|
||||
{"Invalid 'previd' value","Valor no vàlid de 'previd'"}.
|
||||
{"Invitations are not allowed in this conference","Les invitacions no estan permeses en aquesta sala de conferència"}.
|
||||
{"Invite expired","La invitació ha expirat"}.
|
||||
{"Invite to {{ site_name }}","Invitació a {{ site_name }}"}.
|
||||
{"Invite User","Invitar Usuari"}.
|
||||
{"IP addresses","Adreça IP"}.
|
||||
{"is now known as","ara es conegut com"}.
|
||||
{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","No està permés enviar missatges d'error a la sala. El participant (~s) ha enviat un missatge d'error (~s) i ha sigut expulsat de la sala"}.
|
||||
@@ -225,6 +272,7 @@
|
||||
{"January","Gener"}.
|
||||
{"JID normalization denied by service policy","S'ha denegat la normalització del JID per política del servei"}.
|
||||
{"JID normalization failed","Ha fallat la normalització del JID"}.
|
||||
{"Join {{ site_name }} with {{ app_name }}","Uneix-te a {{ site_name }} amb {{ app_name }}"}.
|
||||
{"Joined MIX channels of ~ts","Canals MIX units de ~ts"}.
|
||||
{"Joined MIX channels:","Canals MIX units:"}.
|
||||
{"joins the room","entra a la sala"}.
|
||||
@@ -236,10 +284,13 @@
|
||||
{"Last message","Últim missatge"}.
|
||||
{"Last month","Últim mes"}.
|
||||
{"Last year","Últim any"}.
|
||||
{"Launch {{ app_name }} and sign in using your account credentials.","Inicia {{ app_name }} i entra al compte usant les teves credencials."}.
|
||||
{"Launch Beagle IM, and select \\'Yes\\' to add a new account. Click the \\'+\\' button under the empty account list and then enter your credentials.","Inicia Beagle IM, i selecciona \\'Sí\\' per a afegir un nou compte. Polsa el botó \\'+\\' baix la llista de comptes buida i ja podràs introduir les teues credencials."}.
|
||||
{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","Els bits menys significants del hash SHA-256 del text deurien ser iguals a l'etiqueta hexadecimal"}.
|
||||
{"leaves the room","surt de la sala"}.
|
||||
{"List of Hats","Llista de barrets"}.
|
||||
{"List users with hats","Llista d'usuaris amb barrets"}.
|
||||
{"Log in via web","Entrar usant la web"}.
|
||||
{"Logged Out","Desconectat"}.
|
||||
{"Logging","Registre"}.
|
||||
{"Make participants list public","Crear una llista de participants pública"}.
|
||||
@@ -256,9 +307,11 @@
|
||||
{"Max payload size in bytes","Màxim tamany del payload en bytes"}.
|
||||
{"Maximum file size","Mida màxima de fitxer"}.
|
||||
{"Maximum Number of History Messages Returned by Room","Numero màxim de missatges de l'historia que retorna la sala"}.
|
||||
{"Maximum number of invites reached","Ja has arribat al número màxim d'invitacions"}.
|
||||
{"Maximum number of items to persist","Número màxim d'elements que persistixen"}.
|
||||
{"Maximum Number of Occupants","Número màxim d'ocupants"}.
|
||||
{"May","Maig"}.
|
||||
{"Members are allowed to invite others","Els membres poden invitar a altres"}.
|
||||
{"Membership is required to enter this room","Necessites ser membre d'aquesta sala per a poder entrar"}.
|
||||
{"Memorize your password, or write it in a paper placed in a safe place. In XMPP there isn't an automated way to recover your password if you forget it.","Memoritza la teva contrasenya, o escriu-la en un paper guardat a un lloc segur. A XMPP no hi ha una forma automatitzada de recuperar la teva contrasenya si la oblides."}.
|
||||
{"Mere Availability in XMPP (No Show Value)","Simplement disponibilitat a XMPP (sense valor de 'show')"}.
|
||||
@@ -273,6 +326,7 @@
|
||||
{"Moderator","Moderador"}.
|
||||
{"Moderators Only","Només moderadors"}.
|
||||
{"Module failed to handle the query","El modul ha fallat al gestionar la petició"}.
|
||||
{"Monal Logo","Logo de Monal"}.
|
||||
{"Monday","Dilluns"}.
|
||||
{"Multicast","Multicast"}.
|
||||
{"Multiple <item/> elements are not allowed by RFC6121","No estan permesos múltiples elements <item/> per RFC6121"}.
|
||||
@@ -327,6 +381,7 @@
|
||||
{"None","Cap"}.
|
||||
{"Not allowed","No permès"}.
|
||||
{"Not Found","No Trobat"}.
|
||||
{"NOT FOUND","NO TROBAT"}.
|
||||
{"Not subscribed","No subscrit"}.
|
||||
{"Notify subscribers when items are removed from the node","Notificar subscriptors quan els elements són eliminats del node"}.
|
||||
{"Notify subscribers when the node configuration changes","Notificar subscriptors quan canvia la configuració del node"}.
|
||||
@@ -363,12 +418,15 @@
|
||||
{"Only service administrators are allowed to send service messages","Sols els administradors del servei tenen permís per a enviar missatges de servei"}.
|
||||
{"Only those on a whitelist may associate leaf nodes with the collection","Només qui estiga a una llista blanca pot associar nodes fulla amb la col·lecció"}.
|
||||
{"Only those on a whitelist may subscribe and retrieve items","Només qui estiga a una llista blanca pot subscriure's i recuperar elements"}.
|
||||
{"Open the app","Obrir l'app"}.
|
||||
{"Organization Name","Nom de la organizació"}.
|
||||
{"Organization Unit","Unitat de la organizació"}.
|
||||
{"Other Modules Available:","Altres mòduls disponibles:"}.
|
||||
{"Other software","Altres programes"}.
|
||||
{"Outgoing s2s Connections","Connexions s2s d'eixida"}.
|
||||
{"Owner privileges required","Es requerixen privilegis de propietari de la sala"}.
|
||||
{"Packet relay is denied by service policy","S'ha denegat el reenviament del paquet per política del servei"}.
|
||||
{"Page navigation","Navegació de pàgina"}.
|
||||
{"Participant ID","ID del Participant"}.
|
||||
{"Participant","Participant"}.
|
||||
{"Password Verification","Verificació de la Contrasenya"}.
|
||||
@@ -384,6 +442,8 @@
|
||||
{"Ping query is incorrect","La petició de Ping es incorrecta"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Recorda que aquestes opcions només fan còpia de seguretat de la base de dades Mnesia. Si estàs utilitzant el mòdul d'ODBC també deus de fer una còpia de seguretat de la base de dades de SQL a part."}.
|
||||
{"Please provide a password! Minimum length: {{ password_min_length }}","Per favor proporciona una contrasenya ! Llargària minima: {{ password_min_length }}"}.
|
||||
{"Please provide a valid username!","Per favor proporciona un nom vàlid per al teu compte!"}.
|
||||
{"Please, wait for a while before sending new voice request","Si us plau, espera una mica abans d'enviar una nova petició de veu"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Possessing 'ask' attribute is not allowed by RFC6121","Posseir l'atribut 'ask' no està permès per RFC6121"}.
|
||||
@@ -393,6 +453,7 @@
|
||||
{"Previous session PID has exited","El procés de la sessió prèvia ha sortit"}.
|
||||
{"Previous session PID is dead","El procés de la sessió prèvia està mort"}.
|
||||
{"Previous session timed out","La sessió prèvia ha caducat"}.
|
||||
{"Previous","Anterior"}.
|
||||
{"private, ","privat, "}.
|
||||
{"Public","Public"}.
|
||||
{"Publish model","Model de publicació"}.
|
||||
@@ -412,10 +473,14 @@
|
||||
{"Recipient is not in the conference room","El receptor no està en la sala de conferència"}.
|
||||
{"Re-Enable User","Rehabilitar usuari"}.
|
||||
{"Register an XMPP account","Registrar un compte XMPP"}.
|
||||
{"Register on {{ site_name }}","Registrar a {{ site_name }}"}.
|
||||
{"Register","Registrar"}.
|
||||
{"Registration error","Error al fer el registre"}.
|
||||
{"Registration Error","Error al fer el Registre"}.
|
||||
{"Remote copy","Còpia remota"}.
|
||||
{"Remove a hat from a user","Eliminar un barret d'un usuari"}.
|
||||
{"Remove User","Eliminar usuari"}.
|
||||
{"Renga Logo","Logo de Renga"}.
|
||||
{"Replaced by new connection","Reemplaçat per una nova connexió"}.
|
||||
{"Request has timed out","La petició ha caducat"}.
|
||||
{"Request is ignored","La petició ha sigut ignorada"}.
|
||||
@@ -441,29 +506,39 @@
|
||||
{"Roster size","Mida de la llista"}.
|
||||
{"Running Nodes","Nodes funcionant"}.
|
||||
{"~s invites you to the room ~s","~s et convida a la sala ~s"}.
|
||||
{"Sad person holding empty box","Persona trista agafant una caixa buida"}.
|
||||
{"Saturday","Dissabte"}.
|
||||
{"Scan invite code","Escaneja el codi d'invitació"}.
|
||||
{"Scan with mobile device","Escanejar amb el mòbil"}.
|
||||
{"Search from the date","Buscar des de la data"}.
|
||||
{"Search Results for ","Resultats de la búsqueda "}.
|
||||
{"Search the text","Buscar el text"}.
|
||||
{"Search until the date","Buscar fins la data"}.
|
||||
{"Search users in ","Cerca usuaris en "}.
|
||||
{"Send announcement to all online users on all hosts","Enviar anunci a tots els usuaris connectats a tots els hosts"}.
|
||||
{"Select","Seleccionar"}.
|
||||
{"Send announcement to all online users on all hosts","Enviar anunci a tots els usuaris connectats a tots els dominis"}.
|
||||
{"Send announcement to all online users","Enviar anunci a tots els usuaris connectats"}.
|
||||
{"Send announcement to all users on all hosts","Enviar anunci a tots els usuaris de tots els hosts"}.
|
||||
{"Send announcement to all users on all hosts","Enviar anunci a tots els usuaris de tots els dominis"}.
|
||||
{"Send announcement to all users","Enviar anunci a tots els usuaris"}.
|
||||
{"Send this invite to your device","Envia esta invitació al teu dispositiu"}.
|
||||
{"September","Setembre"}.
|
||||
{"Server:","Servidor:"}.
|
||||
{"Service list retrieval timed out","L'intent de recuperar la llista de serveis ha caducat"}.
|
||||
{"Session state copying timed out","La copia del estat de la sessió ha caducat"}.
|
||||
{"Set message of the day and send to online users","Configurar el missatge del dia i enviar a tots els usuaris"}.
|
||||
{"Set message of the day on all hosts and send to online users","Escriure missatge del dia en tots els hosts i enviar-ho als usuaris connectats"}.
|
||||
{"Set message of the day on all hosts and send to online users","Escriure missatge del dia en tots els dominis i enviar-ho als usuaris connectats"}.
|
||||
{"Shared Roster Groups","Grups de contactes compartits"}.
|
||||
{"Show Integral Table","Mostrar Taula Integral"}.
|
||||
{"Show Occupants Join/Leave","Mostrar Entrades/Eixides dels Ocupants"}.
|
||||
{"Show Ordinary Table","Mostrar Taula Ordinaria"}.
|
||||
{"Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>","Mostrant apps només per a <span class='platform-name'>la teua plataforma actual</span>. Tambè pots <a href='#' id='show-all-clients-button'>vore totes les apps.</a>"}.
|
||||
{"Show","Mostrar"}.
|
||||
{"Shut Down Service","Apager el Servei"}.
|
||||
{"Siskin IM Logo","Logo de Siskin IM"}.
|
||||
{"SOCKS5 Bytestreams","SOCKS5 Bytestreams"}.
|
||||
{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","Alguns clients XMPP poden emmagatzemar la teva contrasenya al ordinador, però només hauries de fer això al teu ordinador personal, per raons de seguretat."}.
|
||||
{"Sorry, it looks like this invite code has expired!","Perdona, però pareix que esta invitació ja ha expirat!"}.
|
||||
{"Sorry, there was a problem registering your account.","Perdona, però hi ha hagut un error creant el compte."}.
|
||||
{"Sources Specs:","Especificacions de Codi Font:"}.
|
||||
{"Specify the access model","Especificar el model d'accés"}.
|
||||
{"Specify the event message type","Especifica el tipus de missatge d'event"}.
|
||||
@@ -471,11 +546,19 @@
|
||||
{"Stanza id is not valid","L'identificador del paquet no es vàlid"}.
|
||||
{"Stanza ID","ID del paquet"}.
|
||||
{"Statically specify a replyto of the node owner(s)","Especifica estaticament una adreça on respondre al propietari del node"}.
|
||||
{"Step 1: Download and install {{ app_name }}","Pas 1: Descarrega e instal·la {{ app_name }}"}.
|
||||
{"Step 1: Install {{ app_name }}","Pas 1: Instal·la {{ app_name }}"}.
|
||||
{"Step 2: Activate your account","Pas 2: Activa el teu compte"}.
|
||||
{"Step 2: Connect {{ app_name }} to your new account","Pas 2: Connecta {{ app_name }} al teu nou compte"}.
|
||||
{"Stopped Nodes","Nodes parats"}.
|
||||
{"Store binary backup:","Guardar una còpia de seguretat binària:"}.
|
||||
{"Store plain text backup:","Guardar una còpia de seguretat en format de text pla:"}.
|
||||
{"Stream management is already enabled","L'administració de la connexió (stream management) ja està activada"}.
|
||||
{"Stream management is not enabled","L'administració de la conexió (stream management) no està activada"}.
|
||||
{"<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting using <strong>{{ app_name }}</strong> you need to first register an account.","<strong>{{ site_name }}</strong> és part de XMPP, una xarxa de missatgeria segura i descentralitzada. Per a començar a xarrar usant <strong>{{ app_name }}</strong> primer tens que registrar un compte."}.
|
||||
{"<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting you need to first register an account.","<strong>{{ site_name }}</strong> és part de la xarxa XMPP de missatgeria segura i descentralitzada. Per a començar a xarrar, primer tindries que crear-te un compte."}.
|
||||
{"<strong>No suitable software installed right now?</strong> You can also log in to your account through our online web chat!","<strong>No tens instal·lat cap programa compatible?</strong> També pots connectarte al teu compte amb el nostre xat web en linia!"}.
|
||||
{"<strong>Tip:</strong> You can open this invite on your mobile device by scanning a barcode with your camera.","<strong>Truquet:</strong> Pots obrir esta invitació al teu mòbil escanejant el codi amb la camera de fotos."}.
|
||||
{"Subject","Tema"}.
|
||||
{"Submit","Enviar"}.
|
||||
{"Submitted","Enviat"}.
|
||||
@@ -495,7 +578,7 @@
|
||||
{"The body text of the last received message","El contingut del text de l'ultim missatge rebut"}.
|
||||
{"The CAPTCHA is valid.","El CAPTCHA es vàlid."}.
|
||||
{"The CAPTCHA verification has failed","La verificació CAPTCHA ha fallat"}.
|
||||
{"The captcha you entered is wrong","El CAPTCHA que has proporcionat és incorrecte"}.
|
||||
{"The captcha you entered is wrong","El captcha que has proporcionat és incorrecte"}.
|
||||
{"The child nodes (leaf or collection) associated with a collection","El nodes fills (fulla o col·leccions) associats amb una col·lecció"}.
|
||||
{"The collections with which a node is affiliated","Les col.leccions amb les que un node està afiliat"}.
|
||||
{"The DateTime at which a leased subscription will end or has ended","La Data i Hora a la que una subscripció prestada terminarà o ha terminat"}.
|
||||
@@ -536,11 +619,14 @@
|
||||
{"The sender of the last received message","Qui ha enviat l'ultim missatge rebut"}.
|
||||
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","El paquet DEU contindre només un element <active/>, un element <default/>, o un element <list/>"}.
|
||||
{"The subscription identifier associated with the subscription request","L'identificador de subscripció associat amb la petició de subscripció"}.
|
||||
{"The token provided is either invalid or expired.","El token proporcionat no es vàlid o ja ha expirat."}.
|
||||
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","La URL de uns transformació XSL que pot ser aplicada als payloads per a generar un element apropiat de contingut de missatge."}.
|
||||
{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","La URL de una transformació XSL que pot ser aplicada al format de payload per a generar un resultat valid de Data Forms, que el client puga mostrar usant un métode generic de Data Forms"}.
|
||||
{"There was an error changing the password: ","Hi ha hagut un error canviant la contrasenya: "}.
|
||||
{"There was an error creating the account: ","Hi ha hagut un error creant el compte: "}.
|
||||
{"There was an error deleting the account: ","Hi ha hagut un error esborrant el compte: "}.
|
||||
{"This button works only if you have the app installed already!","Aquest botó funciona només si ja tens la app instal·lada!"}.
|
||||
{"This is an invite from <strong>{{ inviter }}</strong> to connect and chat on the XMPP network. If you already have an XMPP client installed just press the button below!","Esta es una invitació de <strong>{{ inviter }}</strong> per a connectar i xarrar en la xarxa XMPP. Si ja tens un client XMPP instal·lat, ja pots polsar el boto de baix!"}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Això no distingeix majúscules de minúscules: macbeth es el mateix que MacBeth i Macbeth."}.
|
||||
{"This page allows to register an XMPP account in this XMPP server. Your JID (Jabber ID) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Aquesta pàgina permet crear un compte XMPP en aquest servidor XMPP. El teu JID (Jabber ID; Identificador Jabber) tindrà aquesta forma: usuari@servidor. Si us plau, llegeix amb cura les instruccions per emplenar correctament els camps."}.
|
||||
{"This page allows to unregister an XMPP account in this XMPP server.","Aquesta pàgina permet esborrar un compte XMPP en aquest servidor XMPP."}.
|
||||
@@ -549,7 +635,9 @@
|
||||
{"Thursday","Dijous"}.
|
||||
{"Time delay","Temps de retard"}.
|
||||
{"Timed out waiting for stream resumption","Massa temps esperant que es resumisca la connexió"}.
|
||||
{"To get started, you need to install an app for your platform:","Per a començar, tens que instal·lar alguna app:"}.
|
||||
{"To register, visit ~s","Per a registrar-te, visita ~s"}.
|
||||
{"To start chatting, you need to enter your new account credentials into your chosen XMPP software.","Per a començar a xarrar, tens que proporcionar les credencials del teu no compte al programa XMPP escollit."}.
|
||||
{"To ~ts","A ~ts"}.
|
||||
{"Token TTL","Token TTL"}.
|
||||
{"Too many active bytestreams","N'hi ha massa Bytestreams actius"}.
|
||||
@@ -576,12 +664,13 @@
|
||||
{"Unsupported <index/> element","Element <index/> no soportat"}.
|
||||
{"Unsupported version","Versió no suportada"}.
|
||||
{"Update message of the day (don't send)","Actualitzar el missatge del dia (no enviar)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Actualitza el missatge del dia en tots els hosts (no enviar)"}.
|
||||
{"Update message of the day on all hosts (don't send)","Actualitza el missatge del dia en tots els dominis (no enviar)"}.
|
||||
{"Update specs to get modules source, then install desired ones.","Actualitza les especificacions per obtindre el codi font dels mòduls, després instal·la els que vulgues."}.
|
||||
{"Update Specs","Actualitzar Especificacions"}.
|
||||
{"Updating the vCard is not supported by the vCard storage backend","El sistema d'almacenament de vCard no te capacitat per a actualitzar la vCard"}.
|
||||
{"Upgrade","Actualitza"}.
|
||||
{"URL for Archived Discussion Logs","URL dels Arxius de Discussions"}.
|
||||
{"Use a <em>QR code</em> scanner on your mobile device to scan the code below:","Usa un escanejador de <em>codis QR</em> al te mòbil per a escanejar aquest codi:"}.
|
||||
{"User already exists","El usuari ja existeix"}.
|
||||
{"User JID","JID del usuari"}.
|
||||
{"User (jid)","Usuari (jid)"}.
|
||||
@@ -591,6 +680,9 @@
|
||||
{"User session not found","Sessió d'usuari no trobada"}.
|
||||
{"User session terminated","Sessió d'usuari terminada"}.
|
||||
{"User ~ts","Usuari ~ts"}.
|
||||
{"Username invalid","El nom d'usuari no es vàlid"}.
|
||||
{"Username is reserved","El nom d'usuari està reservat"}.
|
||||
{"Username","Nom d'usuari"}.
|
||||
{"Username:","Nom d'usuari:"}.
|
||||
{"Users are not allowed to register accounts so quickly","Els usuaris no tenen permís per a crear comptes tan depresa"}.
|
||||
{"Users Last Activity","Última activitat d'usuari"}.
|
||||
@@ -603,7 +695,7 @@
|
||||
{"Value 'set' of 'type' attribute is not allowed","El valor 'set' a l'atribut 'type' no és permès"}.
|
||||
{"vCard User Search","vCard recerca d'usuari"}.
|
||||
{"View joined MIX channels","Vore els canals MIX units"}.
|
||||
{"Virtual Hosts","Hosts virtuals"}.
|
||||
{"Virtual Hosts","Dominis Virtuals"}.
|
||||
{"Visitors are not allowed to change their nicknames in this room","Els visitants no tenen permés canviar el seus Nicknames en esta sala"}.
|
||||
{"Visitors are not allowed to send messages to all occupants","Els visitants no poden enviar missatges a tots els ocupants"}.
|
||||
{"Visitor","Visitant"}.
|
||||
@@ -627,6 +719,7 @@
|
||||
{"Wrong parameters in the web formulary","Paràmetres incorrectes en el formulari web"}.
|
||||
{"Wrong xmlns","El xmlns ès incorrecte"}.
|
||||
{"XMPP Account Registration","Registre de compte XMPP"}.
|
||||
{"XMPP client for Haiku","Client XMPP per a Haiku"}.
|
||||
{"XMPP Domains","Dominis XMPP"}.
|
||||
{"XMPP Show Value of Away","Valor 'show' de XMPP: Ausent"}.
|
||||
{"XMPP Show Value of Chat","Valor 'show' de XMPP: Disposat per a xarrar"}.
|
||||
@@ -636,8 +729,17 @@
|
||||
{"You are being removed from the room because of a system shutdown","Has sigut expulsat de la sala perquè el sistema va a apagar-se"}.
|
||||
{"You are not allowed to send private messages","No tens permés enviar missatges privats"}.
|
||||
{"You are not joined to the channel","No t'has unit al canal"}.
|
||||
{"You can connect to {{ site_name }} using any XMPP-compatible software. If your preferred software is not listed above, you may still <a href=\"{{ registration_url }}\">register an account manually</a>.","Pots connectar-te a {{ site_name }} usant qualsevol programa compatible amb XMPP. Si el teu programa preferit no està en esta llista, pots <a href=\"{{ registration_url }}\">registrarte el teu compte manualment</a>."}.
|
||||
{"You can later change your password using an XMPP client.","Podràs canviar la teva contrasenya més endavant utilitzant un client XMPP."}.
|
||||
{"You can now set up {{ app_name }} and connect it to your new account.","Ara pots configurar {{ app_name }} i connectar al teu nou compte."}.
|
||||
{"You can start chatting right away with {{ app_name }}. Let's get started!","Ja pots començar a xarrar usant {{ app_name }}. Comencem!"}.
|
||||
{"You can transfer this invite to your mobile device by scanning a code with your camera.","Pots transferir esta invitació al teu mòbil si escanejes el codi amb la càmera de fotos."}.
|
||||
{"You have been banned from this room","Has sigut bloquejat en aquesta sala"}.
|
||||
{"You have been invited to chat on {{ site_name }}, part of the XMPP secure and decentralized messaging network.","Has rebut una invitació per a xarrar a {{ site_name }}, que és part de la xarxa XMPP de missatgeria segura i descentralitzada."}.
|
||||
{"You have been invited to chat on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.","Has rebut una invitació per a xarrar a <strong>{{ site_name }}</strong>, que és part de la xarxa XMPP de missatgeria segura i descentralitzada."}.
|
||||
{"You have been invited to chat with <strong>{{ inviter }}</strong> on {{ site_name }}, part of the XMPP secure and decentralized messaging network.","Has rebut una invitació a xarrar amb <strong>{{ inviter }}</strong> a {{ site_name }}, que és part de la xarxa XMPP de missatgeria segura i descentralitzada."}.
|
||||
{"You have been invited to chat with <strong>{{ inviter }}</strong> on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.","T'han invitat a xarrar amb <strong>{{ inviter }}</strong> a <strong>{{ site_name }}</strong>, que és part de la xarxa XMPP de missatgeria segura i descentralitzada."}.
|
||||
{"You have created an account on <strong>{{ site_name }}</strong>.","Has creat un compte en <strong>{{ site_name }}</strong>."}.
|
||||
{"You have joined too many conferences","Has entrat en massa sales de conferència"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Deus d'omplir el camp \"Nickname\" al formulari"}.
|
||||
{"You need a client that supports x:data and CAPTCHA to register","Necessites un client amb suport x:data i de CAPTCHA para poder registrar-te"}.
|
||||
@@ -645,6 +747,7 @@
|
||||
{"You need an x:data capable client to search","Necessites un client amb suport x:data per a poder buscar"}.
|
||||
{"Your active privacy list has denied the routing of this stanza.","La teva llista de privacitat activa ha denegat l'encaminament d'aquesta stanza."}.
|
||||
{"Your contact offline message queue is full. The message has been discarded.","La teua cua de missatges offline és plena. El missatge ha sigut descartat."}.
|
||||
{"Your password is stored encrypted on the server and will not be accessible after you close this page. Keep it safe and never share it with anyone.","La teva contrasenya es guardarà xifrada al servidor, i no serà accessible una vegada que tanques esta pàgina. Mantin la contrasenya segura i no la compartis amb ningú mes."}.
|
||||
{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","La teua petició de subscripció i/o missatges a ~s han sigut bloquejats. Per a desbloquejar-los, visita ~s"}.
|
||||
{"Your XMPP account was successfully registered.","El teu compte XMPP ha sigut creat correctament."}.
|
||||
{"Your XMPP account was successfully unregistered.","El teu compte XMPP ha sigut esborrat correctament."}.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
%% https://docs.ejabberd.im/developer/extending-ejabberd/localization/
|
||||
|
||||
{" has set the subject to: "," změnil(a) téma na: "}.
|
||||
{"A description of the node","Popis uzlu"}.
|
||||
{"A friendly name for the node","Přívětivé jméno pro uzel"}.
|
||||
{"A password is required to enter this room","Pro vstup do místnosti musíte zadat heslo"}.
|
||||
{"Accept","Přijmout"}.
|
||||
@@ -25,6 +26,7 @@
|
||||
{"Allow visitors to send status text in presence updates","Povolit návštěvníkům posílat stavové zprávy ve statusu"}.
|
||||
{"Allow visitors to send voice requests","Povolit uživatelům posílat žádosti o voice práva"}.
|
||||
{"Announcements","Oznámení"}.
|
||||
{"API Commands","API příkazy"}.
|
||||
{"April",". dubna"}.
|
||||
{"August",". srpna"}.
|
||||
{"Automatic node creation is not enabled","Automatické vytváření uzlů není povoleno"}.
|
||||
|
||||
+26
-10
@@ -17,13 +17,14 @@
|
||||
{"A modern open-source chat client for the desktop. It focuses on providing a clean and reliable Jabber/XMPP experience while having your privacy in mind.","Ein moderner open-source Jabber/XMPP Chatclient für den Desktop mit Fokus auf Einfachheit und Zuverlässigkeit, aber auch Schutz deiner Privatsphäre."}.
|
||||
{"A password is required to enter this room","Ein Passwort ist erforderlich um diesen Raum zu betreten"}.
|
||||
{"A Web Page","Eine Webseite"}.
|
||||
{"Accept invite using {{ app_name }}","Einladung mittels {{ app_name }} annehmen!"}.
|
||||
{"Accept invite using {{ app_name }}","Einladung mittels {{ app_name }} annehmen"}.
|
||||
{"Accept","Akzeptieren"}.
|
||||
{"Access denied by service policy","Zugriff aufgrund der Dienstrichtlinien verweigert"}.
|
||||
{"Access model","Zugriffsmodell"}.
|
||||
{"Account doesn't exist","Konto existiert nicht"}.
|
||||
{"Action on user","Aktion auf Benutzer"}.
|
||||
{"Add {{ inviter }} to your contact list","Füge {{ inviter }} zu deiner Kontaktliste hinzu"}.
|
||||
{"Add Contact","Kontakt hinzufügen"}.
|
||||
{"Add User","Benutzer hinzufügen"}.
|
||||
{"Administration of ","Administration von "}.
|
||||
{"Administration","Verwaltung"}.
|
||||
@@ -57,6 +58,7 @@
|
||||
{"Anyone with Voice","Jeder mit Stimme"}.
|
||||
{"Anyone","Jeder"}.
|
||||
{"API Commands","API Befehle"}.
|
||||
{"Apple Store Logo","Apple Store Logo"}.
|
||||
{"April","April"}.
|
||||
{"Arguments","Argumente"}.
|
||||
{"As a final reminder, your account details are shown below:","Zur Erinnerung hier nochmal deine Kontodetails:"}.
|
||||
@@ -75,6 +77,7 @@
|
||||
{"Bad format","Ungültiges Format"}.
|
||||
{"BAD REQUEST","UNGÜLTIGE ANFRAGE"}.
|
||||
{"Beagle IM by Tigase, Inc. is a lightweight and powerful XMPP client for macOS.","Beagle IM von Tigase Inc. ist eine schlanker aber funktionsreicher XMPP-Client für macOS."}.
|
||||
{"Beagle IM Logo","Beagle IM Logo"}.
|
||||
{"Birthday","Geburtsdatum"}.
|
||||
{"Both the username and the resource are required","Sowohl der Benutzername als auch die Ressource sind erforderlich"}.
|
||||
{"Bytestream already activated","Bytestream bereits aktiviert"}.
|
||||
@@ -106,6 +109,7 @@
|
||||
{"Click the button to open the Dino website where you can download and install it on your PC.","Klicke auf den Button um Dino's Webseite zu öffnen, wo du ihn für deinen PC herunterladen und installieren kannst."}.
|
||||
{"Client acknowledged more stanzas than sent by server","Client bestätigte mehr Stanzas als vom Server gesendet"}.
|
||||
{"Close","Schließen"}.
|
||||
{"Clustering","Clustering"}.
|
||||
{"Commands","Befehle"}.
|
||||
{"Conference room does not exist","Konferenzraum existiert nicht"}.
|
||||
{"Configuration of room ~s","Konfiguration des Raumes ~s"}.
|
||||
@@ -114,6 +118,7 @@
|
||||
{"Contact Addresses (normally, room owner or owners)","Kontaktadresse (normalerweise Raumbesitzer)"}.
|
||||
{"Contacts","Kontakte"}.
|
||||
{"Conversations is a Jabber/XMPP client for Android 6.0+ smartphones that has been optimized to provide a unique mobile experience.","Conversations ist ein Jabber/XMPP-Client für Android 6.0+, der für mobile Endgeräte optimiert wurde."}.
|
||||
{"Conversations Logo","Conversations Logo"}.
|
||||
{"Country","Land"}.
|
||||
{"Create a Hat","Einen Hut erstellen"}.
|
||||
{"Create Account","Konto anlegen"}.
|
||||
@@ -132,6 +137,7 @@
|
||||
{"Deliver event notifications","Ereignisbenachrichtigungen zustellen"}.
|
||||
{"Deliver payloads with event notifications","Nutzdaten mit Ereignisbenachrichtigungen zustellen"}.
|
||||
{"Destroy a Hat","Einen Hut zerstören"}.
|
||||
{"Dino Logo","Dino Logo"}.
|
||||
{"Disable User","Benutzer deaktivieren"}.
|
||||
{"Disc only copy","Nur auf Festplatte"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the XMPP server.","Geben Sie niemandem Ihr Passwort, auch nicht den Administratoren des XMPP-Servers."}.
|
||||
@@ -182,6 +188,7 @@
|
||||
{"Failed to process option '~s'","Konnte Option '~s' nicht verarbeiten"}.
|
||||
{"Family Name","Nachname"}.
|
||||
{"FAQ Entry","FAQ-Eintrag"}.
|
||||
{"F-Droid Store Logo","F-Droid Store Logo"}.
|
||||
{"February","Februar"}.
|
||||
{"File larger than ~w bytes","Datei größer als ~w Bytes"}.
|
||||
{"Fill in the form to search for any matching XMPP User","Füllen Sie das Formular aus, um nach jeglichen passenden XMPP-Benutzern zu suchen"}.
|
||||
@@ -190,6 +197,7 @@
|
||||
{"Full List of Room Admins","Vollständige Liste der Raumadmins"}.
|
||||
{"Full List of Room Owners","Vollständige Liste der Raumbesitzer"}.
|
||||
{"Full Name","Vollständiger Name"}.
|
||||
{"Gajim Logo","Gajim Logo"}.
|
||||
{"Get List of Active Users","Liste der aktiven Benutzer abrufen"}.
|
||||
{"Get List of Disabled Users","Liste der deaktivierten Benutzer abrufen"}.
|
||||
{"Get List of Idle Users","Liste der inaktiven Benutzer abrufen"}.
|
||||
@@ -206,6 +214,7 @@
|
||||
{"Get User Roster","Kontaktliste abrufen"}.
|
||||
{"Get User Statistics","Benutzerstatistiken abrufen"}.
|
||||
{"Given Name","Vorname"}.
|
||||
{"Google Play Store Logo","Google Play Store Logo"}.
|
||||
{"Grant voice to this person?","Dieser Person Sprachrechte erteilen?"}.
|
||||
{"has been banned","wurde gebannt"}.
|
||||
{"has been kicked because of a system shutdown","wurde wegen einer Systemabschaltung hinausgeworfen"}.
|
||||
@@ -276,7 +285,7 @@
|
||||
{"Last month","Letzter Monat"}.
|
||||
{"Last year","Letztes Jahr"}.
|
||||
{"Launch {{ app_name }} and sign in using your account credentials.","Starte {{ app_name }} und logge dich mit deinen Anmeldedaten ein."}.
|
||||
{"Launch Beagle IM, and select 'Yes' to add a new account. Click the '+' button under the empty account list and then enter your credentials.","Starte Beagle IM und wähle 'Yes' um ein neues Konto hinzuzufügen. Drücke auf das '+' unter der leeren Account-Liste und gib dann deine Anmeldedaten ein!"}.
|
||||
{"Launch Beagle IM, and select \\'Yes\\' to add a new account. Click the \\'+\\' button under the empty account list and then enter your credentials.","Starte Beagle IM und wähle \\'Yes\\' um ein neues Konto hinzuzufügen. Drücke auf das \\'+\\' unter der leeren Account-Liste und gib dann deine Anmeldedaten ein."}.
|
||||
{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","Niederwertigstes Bit des SHA-256-Hashes des Textes sollte hexadezimalem Label gleichen"}.
|
||||
{"leaves the room","verlässt den Raum"}.
|
||||
{"List of Hats","Liste aller Hüte"}.
|
||||
@@ -317,6 +326,7 @@
|
||||
{"Moderator","Moderator"}.
|
||||
{"Moderators Only","nur Moderatoren"}.
|
||||
{"Module failed to handle the query","Modul konnte die Anfrage nicht verarbeiten"}.
|
||||
{"Monal Logo","Monal Logo"}.
|
||||
{"Monday","Montag"}.
|
||||
{"Multicast","Multicast"}.
|
||||
{"Multiple <item/> elements are not allowed by RFC6121","Mehrere <item/>-Elemente sind laut RFC6121 nicht erlaubt"}.
|
||||
@@ -416,6 +426,7 @@
|
||||
{"Outgoing s2s Connections","Ausgehende s2s-Verbindungen"}.
|
||||
{"Owner privileges required","Besitzerrechte erforderlich"}.
|
||||
{"Packet relay is denied by service policy","Paket-Relay aufgrund der Dienstrichtlinien verweigert"}.
|
||||
{"Page navigation","Seiten-Navigation"}.
|
||||
{"Participant ID","Teilnehmer-ID"}.
|
||||
{"Participant","Teilnehmer"}.
|
||||
{"Password Verification","Passwort bestätigen"}.
|
||||
@@ -431,6 +442,8 @@
|
||||
{"Ping query is incorrect","Ping-Anfrage ist falsch"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Beachten Sie, dass diese Optionen nur die eingebaute Mnesia-Datenbank sichern. Wenn Sie das ODBC-Modul verwenden, müssen Sie auch Ihre SQL-Datenbank separat sichern."}.
|
||||
{"Please provide a password! Minimum length: {{ password_min_length }}","Bitte gibt ein Passwort ein! Mindestens {{ password_min_length }} Zeichen."}.
|
||||
{"Please provide a valid username!","Bitte gib einen gültigen Benutzernamen ein!"}.
|
||||
{"Please, wait for a while before sending new voice request","Bitte warten Sie ein wenig, bevor Sie eine weitere Sprachrecht-Anforderung senden"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Possessing 'ask' attribute is not allowed by RFC6121","Ein 'ask'-Attribut zu besitzen ist laut RFC6121 nicht erlaubt"}.
|
||||
@@ -440,6 +453,7 @@
|
||||
{"Previous session PID has exited","Vorherige Sitzungs-PID wurde beendet"}.
|
||||
{"Previous session PID is dead","Vorherige Sitzungs-PID ist tot"}.
|
||||
{"Previous session timed out","Zeitüberschreitung bei vorheriger Sitzung"}.
|
||||
{"Previous","Zurück"}.
|
||||
{"private, ","privat, "}.
|
||||
{"Public","Öffentlich"}.
|
||||
{"Publish model","Veröffentlichungsmodell"}.
|
||||
@@ -447,7 +461,6 @@
|
||||
{"PubSub subscriber request","PubSub-Abonnenten-Anforderung"}.
|
||||
{"Purge all items when the relevant publisher goes offline","Alle Items löschen, wenn der relevante Veröffentlicher offline geht"}.
|
||||
{"Push record not found","Push-Eintrag nicht gefunden"}.
|
||||
{"QR code icon","QR-Code Icon"}.
|
||||
{"Queries to the conference members are not allowed in this room","Anfragen an die Konferenzteilnehmer sind in diesem Raum nicht erlaubt"}.
|
||||
{"Query to another users is forbidden","Anfrage an andere Benutzer ist verboten"}.
|
||||
{"RAM and disc copy","RAM und Festplatte"}.
|
||||
@@ -462,10 +475,12 @@
|
||||
{"Register an XMPP account","Ein XMPP-Konto registrieren"}.
|
||||
{"Register on {{ site_name }}","Registriere dich auf {{ site_name }}"}.
|
||||
{"Register","Anmelden"}.
|
||||
{"Registration error","Fehler beim Registrieren"}.
|
||||
{"Registration error","Fehler beim registrieren"}.
|
||||
{"Registration Error","Fehler beim Registrieren"}.
|
||||
{"Remote copy","Fernkopie"}.
|
||||
{"Remove a hat from a user","Eine Funktion bei einem Benutzer entfernen"}.
|
||||
{"Remove User","Benutzer löschen"}.
|
||||
{"Renga Logo","Renga Logo"}.
|
||||
{"Replaced by new connection","Durch neue Verbindung ersetzt"}.
|
||||
{"Request has timed out","Zeitüberschreitung bei Anforderung"}.
|
||||
{"Request is ignored","Anforderung wird ignoriert"}.
|
||||
@@ -519,6 +534,7 @@
|
||||
{"Show","Anzeigen"}.
|
||||
{"Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>","Wir zeigen dir nur Apps für <span class=\"platform-name\">deine aktuelle Platform</span> an. Du kannst dir gerne auch <a href=\"#\" id=\"show-all-clients-button\">sämtliche Apps anzeigen lassen</a>."}.
|
||||
{"Shut Down Service","Dienst herunterfahren"}.
|
||||
{"Siskin IM Logo","Siskin IM Logo"}.
|
||||
{"SOCKS5 Bytestreams","SOCKS5-Bytestreams"}.
|
||||
{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","Einige XMPP-Clients speichern Ihr Passwort auf dem Computer. Aus Sicherheitsgründen sollten Sie das nur auf Ihrem persönlichen Computer tun."}.
|
||||
{"Sorry, it looks like this invite code has expired!","Entschuldigung, es sieht so aus als wäre diese Einladung abgelaufen!"}.
|
||||
@@ -532,7 +548,7 @@
|
||||
{"Statically specify a replyto of the node owner(s)","Ein 'replyto' des/der Nodebesitzer(s) statisch angeben"}.
|
||||
{"Step 1: Download and install {{ app_name }}","Schritt 1: {{ app_name }} herunterladen und installieren"}.
|
||||
{"Step 1: Install {{ app_name }}","Schritt 1: Installiere {{ app_name }}"}.
|
||||
{"Step 2: Activate your account","Konto aktivieren"}.
|
||||
{"Step 2: Activate your account","Schritt 2: Konto aktivieren"}.
|
||||
{"Step 2: Connect {{ app_name }} to your new account","Schritt 2: Verbinde {{ app_name }} mit deinem neuen Konto"}.
|
||||
{"Stopped Nodes","Angehaltene Knoten"}.
|
||||
{"Store binary backup:","Speichere binäres Backup:"}.
|
||||
@@ -603,14 +619,14 @@
|
||||
{"The sender of the last received message","Der Absender der letzten erhaltenen Nachricht"}.
|
||||
{"The stanza MUST contain only one <active/> element, one <default/> element, or one <list/> element","Das Stanza darf nur ein <active/>-Element, ein <default/>-Element oder ein <list/>-Element enthalten"}.
|
||||
{"The subscription identifier associated with the subscription request","Die mit der Abonnement-Anforderung verknüpfte Abonnement-Bezeichnung"}.
|
||||
{"The token provided is either invalid or expired.","Der Einladungscode ist entweder ungültig oder abgelaufen"}.
|
||||
{"The token provided is either invalid or expired.","Der Einladungscode ist entweder ungültig oder abgelaufen."}.
|
||||
{"The URL of an XSL transformation which can be applied to payloads in order to generate an appropriate message body element.","Die URL einer XSL-Transformation welche auf Nutzdaten angewendet werden kann, um ein geeignetes Nachrichtenkörper-Element zu generieren."}.
|
||||
{"The URL of an XSL transformation which can be applied to the payload format in order to generate a valid Data Forms result that the client could display using a generic Data Forms rendering engine","Die URL einer XSL-Transformation welche auf das Nutzdaten-Format angewendet werden kann, um ein gültiges Data Forms-Ergebnis zu generieren das der Client mit Hilfe einer generischen Data Forms-Rendering-Engine anzeigen könnte"}.
|
||||
{"There was an error changing the password: ","Es trat ein Fehler beim Ändern des Passwortes auf: "}.
|
||||
{"There was an error creating the account: ","Es trat ein Fehler beim Erstellen des Kontos auf: "}.
|
||||
{"There was an error deleting the account: ","Es trat ein Fehler beim Löschen des Kontos auf: "}.
|
||||
{"This button works only if you have the app installed already!","Dieser Button funktioniert nur, wenn du die App bereits installiert hast!"}.
|
||||
{"This is an invite from <strong>{{ inviter }}</strong> to connect and chat on the XMPP network. If you already have an XMPP client installed just press the button below!","Die ist eine Kontakt-Einladung von <strong>{{ inviter }}</strong> um miteinander über XMPP zu chatten. Solltest du bereits einen XMPP-Client haben, so drücke einfach auf den Button hier unten!"}.
|
||||
{"This is an invite from <strong>{{ inviter }}</strong> to connect and chat on the XMPP network. If you already have an XMPP client installed just press the button below!","Dies ist eine Kontakt-Einladung von <strong>{{ inviter }}</strong> um miteinander über XMPP zu chatten. Solltest du bereits einen XMPP-Client haben, so drücke einfach auf den Button hier unten!"}.
|
||||
{"This is case insensitive: macbeth is the same that MacBeth and Macbeth.","Dies ist schreibungsunabhängig: macbeth ist gleich MacBeth und Macbeth."}.
|
||||
{"This page allows to register an XMPP account in this XMPP server. Your JID (Jabber ID) will be of the form: username@server. Please read carefully the instructions to fill correctly the fields.","Diese Seite erlaubt das Anlegen eines XMPP-Kontos auf diesem XMPP-Server. Ihre JID (Jabber-ID) wird diese Form aufweisen: benutzername@server. Bitte lesen Sie die Anweisungen genau durch, um die Felder korrekt auszufüllen."}.
|
||||
{"This page allows to unregister an XMPP account in this XMPP server.","Diese Seite erlaubt es, ein XMPP-Konto von diesem XMPP-Server zu entfernen."}.
|
||||
@@ -703,7 +719,7 @@
|
||||
{"Wrong parameters in the web formulary","Falsche Parameter im Webformular"}.
|
||||
{"Wrong xmlns","Falscher xmlns"}.
|
||||
{"XMPP Account Registration","XMPP-Konto-Registrierung"}.
|
||||
{"XMPP client for Haiku","XMPP-Client für Haiku."}.
|
||||
{"XMPP client for Haiku","XMPP-Client für Haiku"}.
|
||||
{"XMPP Domains","XMPP-Domänen"}.
|
||||
{"XMPP Show Value of Away","XMPP-Anzeigewert von Abwesend"}.
|
||||
{"XMPP Show Value of Chat","XMPP-Anzeigewert von Chat"}.
|
||||
@@ -722,7 +738,7 @@
|
||||
{"You have been invited to chat on {{ site_name }}, part of the XMPP secure and decentralized messaging network.","Du wurdest auf <strong>{{ site_name }}</strong> zum Chat eingeladen, Teil des sicheren und dezentralen XMPP-Sofortnachrichten-Netzwerkes."}.
|
||||
{"You have been invited to chat on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.","Du wurdest auf <strong>{{ site_name }}</strong> zum Chat eingeladen. <strong>{{ site_name }}</strong> ist Teil des sicheren und dezentralen XMPP-Sofortnachrichten-Netzwerkes."}.
|
||||
{"You have been invited to chat with <strong>{{ inviter }}</strong> on {{ site_name }}, part of the XMPP secure and decentralized messaging network.","Du wurdest von <strong>{{ inviter }}</strong> auf {{ site_name }} zum Chat eingeladen. {{ site_name }} ist Teil des sicheren und dezentralen XMPP-Sofortnachrichten-Netzwerkes."}.
|
||||
{"You have been invited to chat with <strong>{{ inviter }}</strong> on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.","Du wurdest von <strong>{{ inviter }}</strong> auf {{ site_name }} zum Chat eingeladen. {{ site_name }} ist Teil des sicheren und dezentralen XMPP-Sofortnachrichten-Netzwerkes."}.
|
||||
{"You have been invited to chat with <strong>{{ inviter }}</strong> on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.","Du wurdest von <strong>{{ inviter }}</strong> auf <strong>{{ site_name }}</strong> zum Chat eingeladen. <strong>{{ site_name }}</strong> ist Teil des sicheren und dezentralen XMPP-Sofortnachrichten-Netzwerkes."}.
|
||||
{"You have created an account on <strong>{{ site_name }}</strong>.","Du hast ein Konto auf <strong>{{ site_name }}</strong> angelegt."}.
|
||||
{"You have joined too many conferences","Sie sind zu vielen Konferenzen beigetreten"}.
|
||||
{"You must fill in field \"Nickname\" in the form","Sie müssen das Feld \"Spitzname\" im Formular ausfüllen"}.
|
||||
@@ -731,7 +747,7 @@
|
||||
{"You need an x:data capable client to search","Sie benötigen einen Client der x:data unterstützt, um zu suchen"}.
|
||||
{"Your active privacy list has denied the routing of this stanza.","Ihre aktive Privacy-Liste hat das Routing dieses Stanzas verweigert."}.
|
||||
{"Your contact offline message queue is full. The message has been discarded.","Die Offline-Nachrichten-Warteschlange Ihres Kontaktes ist voll. Die Nachricht wurde verworfen."}.
|
||||
{"Your password is stored encrypted on the server and will not be accessible after you close this page. Keep it safe and never share it with anyone.","Dein Passwort wird verschlüsselt auf dem Server gespeichert und wird nicht mehr im Klartext verfügbar sein nachdem du diese Seite geschlossen hast. Verwahre es an einem sicheren Ort und teile es mit niemandem!"}.
|
||||
{"Your password is stored encrypted on the server and will not be accessible after you close this page. Keep it safe and never share it with anyone.","Dein Passwort wird verschlüsselt auf dem Server gespeichert und wird nicht mehr im Klartext verfügbar sein, nachdem du diese Seite geschlossen hast. Verwahre es an einem sicheren Ort und teile es mit niemandem!"}.
|
||||
{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","Ihre Abonnement-Anforderung und/oder Nachrichten an ~s wurden blockiert. Um Ihre Abonnement-Anforderungen freizugeben, besuchen Sie ~s"}.
|
||||
{"Your XMPP account was successfully registered.","Ihr XMPP-Konto wurde erfolgreich registriert."}.
|
||||
{"Your XMPP account was successfully unregistered.","Ihr XMPP-Konto wurde erfolgreich entfernt."}.
|
||||
|
||||
+21
-6
@@ -24,6 +24,7 @@
|
||||
{"Account doesn't exist","La cuenta no existe"}.
|
||||
{"Action on user","Acción en el usuario"}.
|
||||
{"Add {{ inviter }} to your contact list","Añade {{ inviter }} a tu lista de contactos"}.
|
||||
{"Add Contact","Añadir Contacto"}.
|
||||
{"Add User","Añadir usuario"}.
|
||||
{"Administration of ","Administración de "}.
|
||||
{"Administration","Administración"}.
|
||||
@@ -57,6 +58,7 @@
|
||||
{"Anyone with Voice","Cualquiera con Voz"}.
|
||||
{"Anyone","Cualquiera"}.
|
||||
{"API Commands","Comandos API"}.
|
||||
{"Apple Store Logo","Logo de la Apple Store"}.
|
||||
{"April","Abril"}.
|
||||
{"Arguments","Argumentos"}.
|
||||
{"As a final reminder, your account details are shown below:","Como último recordatorio, los detalles de tu cuenta se muestran aquí:"}.
|
||||
@@ -75,6 +77,7 @@
|
||||
{"Bad format","Mal formato"}.
|
||||
{"BAD REQUEST","MALA PETICIÓN"}.
|
||||
{"Beagle IM by Tigase, Inc. is a lightweight and powerful XMPP client for macOS.","Beagle IM de Tigase, Inc. es un cliente XMPP ligero y potente para macOS."}.
|
||||
{"Beagle IM Logo","Logo de Beagle IM"}.
|
||||
{"Birthday","Cumpleaños"}.
|
||||
{"Both the username and the resource are required","Se requiere tanto el nombre de usuario como el recurso"}.
|
||||
{"Bytestream already activated","Bytestream ya está activado"}.
|
||||
@@ -115,6 +118,7 @@
|
||||
{"Contact Addresses (normally, room owner or owners)","Direcciones de contacto (normalmente la del dueño o dueños de la sala)"}.
|
||||
{"Contacts","Contactos"}.
|
||||
{"Conversations is a Jabber/XMPP client for Android 6.0+ smartphones that has been optimized to provide a unique mobile experience.","Conversations es un cliente Jabber/XMPP para móviles Android 6.0+ optimizado para proporcionar una experiencia móvil única."}.
|
||||
{"Conversations Logo","Logo de Conversations"}.
|
||||
{"Country","País"}.
|
||||
{"Create a Hat","Crear un sombrero"}.
|
||||
{"Create Account","Crear Cuenta"}.
|
||||
@@ -133,6 +137,7 @@
|
||||
{"Deliver event notifications","Entregar notificaciones de eventos"}.
|
||||
{"Deliver payloads with event notifications","Enviar contenidos junto con las notificaciones de eventos"}.
|
||||
{"Destroy a Hat","Destruir un sombrero"}.
|
||||
{"Dino Logo","Logo de Dino"}.
|
||||
{"Disable User","Deshabilitar un usuario"}.
|
||||
{"Disc only copy","Copia en disco solamente"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the XMPP server.","No le digas tu contraseña a nadie, ni siquiera a los administradores del servidor XMPP."}.
|
||||
@@ -183,6 +188,7 @@
|
||||
{"Failed to process option '~s'","Falló el procesado de la opción '~s'"}.
|
||||
{"Family Name","Apellido"}.
|
||||
{"FAQ Entry","Apunte en la FAQ"}.
|
||||
{"F-Droid Store Logo","Logo de la F-Droid Store"}.
|
||||
{"February","Febrero"}.
|
||||
{"File larger than ~w bytes","El fichero es más grande que ~w bytes"}.
|
||||
{"Fill in the form to search for any matching XMPP User","Rellena campos para buscar usuarios XMPP que concuerden"}.
|
||||
@@ -191,6 +197,7 @@
|
||||
{"Full List of Room Admins","Lista completa de administradores de la sala"}.
|
||||
{"Full List of Room Owners","Lista completa de dueños de la sala"}.
|
||||
{"Full Name","Nombre completo"}.
|
||||
{"Gajim Logo","Logo de Gajim"}.
|
||||
{"Get List of Active Users","Ver lista de usuarios activos"}.
|
||||
{"Get List of Disabled Users","Ver lista de usuarios deshabilitados"}.
|
||||
{"Get List of Idle Users","Ver lista de usuarios inactivos"}.
|
||||
@@ -207,6 +214,7 @@
|
||||
{"Get User Roster","Ver lista de contactos del usuario"}.
|
||||
{"Get User Statistics","Ver estadísticas de usuario"}.
|
||||
{"Given Name","Nombre de pila"}.
|
||||
{"Google Play Store Logo","Logo de la Google Play Store"}.
|
||||
{"Grant voice to this person?","¿Conceder voz a esta persona?"}.
|
||||
{"has been banned","ha sido bloqueado"}.
|
||||
{"has been kicked because of a system shutdown","ha sido expulsado porque el sistema se va a detener"}.
|
||||
@@ -277,7 +285,7 @@
|
||||
{"Last month","Último mes"}.
|
||||
{"Last year","Último año"}.
|
||||
{"Launch {{ app_name }} and sign in using your account credentials.","Lanza {{ app_name }} y entra en la cuenta usando tus credenciales."}.
|
||||
{"Launch Beagle IM, and select 'Yes' to add a new account. Click the '+' button under the empty account list and then enter your credentials.","Inicia Beagle IM, y pulsa 'Sí' para añadir una nueva cuenta. Pulsa el botón '+' debajo de la lista de cuentas vacía e introduce tus credenciales."}.
|
||||
{"Launch Beagle IM, and select \\'Yes\\' to add a new account. Click the \\'+\\' button under the empty account list and then enter your credentials.","Inicia Beagle IM, y pulsa \\'Sí\\' para añadir una nueva cuenta. Pulsa el botón \\'+\\' debajo de la lista de cuentas vacía e introduce tus credenciales."}.
|
||||
{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","Los bits menos significativos del hash SHA-256 del texto deberían ser iguales a la etiqueta hexadecimal"}.
|
||||
{"leaves the room","sale de la sala"}.
|
||||
{"List of Hats","Lista de sombreros"}.
|
||||
@@ -318,6 +326,7 @@
|
||||
{"Moderator","Moderador"}.
|
||||
{"Moderators Only","Solo moderadores"}.
|
||||
{"Module failed to handle the query","El módulo falló al gestionar la petición"}.
|
||||
{"Monal Logo","Logo de Monal"}.
|
||||
{"Monday","Lunes"}.
|
||||
{"Multicast","Multidifusión"}.
|
||||
{"Multiple <item/> elements are not allowed by RFC6121","No se permiten múltiples elementos <item/> en RFC6121"}.
|
||||
@@ -417,6 +426,7 @@
|
||||
{"Outgoing s2s Connections","Conexiones S2S salientes"}.
|
||||
{"Owner privileges required","Se requieren privilegios de propietario de la sala"}.
|
||||
{"Packet relay is denied by service policy","Se ha denegado el reenvío del paquete por política del servicio"}.
|
||||
{"Page navigation","Navegación de Página"}.
|
||||
{"Participant ID","ID del Participante"}.
|
||||
{"Participant","Participante"}.
|
||||
{"Password Verification","Verificación de la contraseña"}.
|
||||
@@ -432,6 +442,8 @@
|
||||
{"Ping query is incorrect","La petición de Ping es incorrecta"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Ten en cuenta que estas opciones solo harán copia de seguridad de la base de datos Mnesia embebida. Si estás usando ODBC tendrás que hacer también copia de seguridad de tu base de datos SQL."}.
|
||||
{"Please provide a password! Minimum length: {{ password_min_length }}","¡Por favor proporciona una contraseña! Longitud mínima: {{ password_min_length }}"}.
|
||||
{"Please provide a valid username!","¡Por favor proporciona un nombre de usuario válido!"}.
|
||||
{"Please, wait for a while before sending new voice request","Por favor, espera un poco antes de enviar otra petición de voz"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Possessing 'ask' attribute is not allowed by RFC6121","Poseer el atributo 'ask' no está permitido por RFC6121"}.
|
||||
@@ -441,6 +453,7 @@
|
||||
{"Previous session PID has exited","El proceso de la sesión previa ha terminado"}.
|
||||
{"Previous session PID is dead","El proceso de la sesión previa está muerto"}.
|
||||
{"Previous session timed out","La sesión previa ha caducado"}.
|
||||
{"Previous","Previo"}.
|
||||
{"private, ","privado, "}.
|
||||
{"Public","Público"}.
|
||||
{"Publish model","Modelo de publicación"}.
|
||||
@@ -448,7 +461,6 @@
|
||||
{"PubSub subscriber request","Petición de subscriptor de PubSub"}.
|
||||
{"Purge all items when the relevant publisher goes offline","Borra todos los elementos cuando el publicador relevante se desconecta"}.
|
||||
{"Push record not found","No se encontró registro Push"}.
|
||||
{"QR code icon","Icono de código QR"}.
|
||||
{"Queries to the conference members are not allowed in this room","En esta sala no se permiten solicitudes a los miembros de la sala"}.
|
||||
{"Query to another users is forbidden","Enviar solicitudes a otros usuarios está prohibido"}.
|
||||
{"RAM and disc copy","Copia en RAM y disco"}.
|
||||
@@ -463,10 +475,12 @@
|
||||
{"Register an XMPP account","Registrar una cuenta XMPP"}.
|
||||
{"Register on {{ site_name }}","Registrar en {{ site_name }}"}.
|
||||
{"Register","Registrar"}.
|
||||
{"Registration Error","Error al Registrar"}.
|
||||
{"Registration error","Error en el registro"}.
|
||||
{"Remote copy","Copia remota"}.
|
||||
{"Remove a hat from a user","Quitarle un sombrero a un usuario"}.
|
||||
{"Remove User","Eliminar usuario"}.
|
||||
{"Renga Logo","Logo de Renga"}.
|
||||
{"Replaced by new connection","Reemplazado por una nueva conexión"}.
|
||||
{"Request has timed out","La petición ha caducado"}.
|
||||
{"Request is ignored","La petición ha sido ignorada"}.
|
||||
@@ -520,6 +534,7 @@
|
||||
{"Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>","Mostrando aplicaciones para <span class='platform-name'>tu plataforma actual</span> nada más. También puedes <a href='#' id='show-all-clients-button'>mostrar todas las aplicaciones.</a>"}.
|
||||
{"Show","Mostrar"}.
|
||||
{"Shut Down Service","Detener el servicio"}.
|
||||
{"Siskin IM Logo","Logo de Siskin IM"}.
|
||||
{"SOCKS5 Bytestreams","SOCKS5 Bytestreams"}.
|
||||
{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","Algunos clientes XMPP pueden guardar tu contraseña en la máquina, pero solo deberías hacer esto en tu propia máquina personal, por razones de seguridad."}.
|
||||
{"Sorry, it looks like this invite code has expired!","Lo siento ¡parece que este código de invitación ha caducado!"}.
|
||||
@@ -543,7 +558,7 @@
|
||||
{"<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting using <strong>{{ app_name }}</strong> you need to first register an account.","<strong>{{ site_name }}</strong> es parte de XMPP, una red de mensajería segura y decentralizada. Para comenzar a charlar usando <strong>{{ app_name }}</strong>, primero créate una cuenta."}.
|
||||
{"<strong>{{ site_name }}</strong> is part of XMPP, a secure and decentralized messaging network. To begin chatting you need to first register an account.","<strong>{{ site_name }}</strong> es parte de XMPP, una red de mensajería segura y decentralizada. Para comenzar a charlar, primero has de registrar una cuenta."}.
|
||||
{"<strong>No suitable software installed right now?</strong> You can also log in to your account through our online web chat!","<strong>¿No tienes instalada ninguna aplicación ahora mismo?</strong> También puedes entrar en tu cuenta ¡usando el chat web en linea!"}.
|
||||
{"<strong>Tip:</strong> You can open this invite on your mobile device by scanning a barcode with your camera.","<strong>Truco:</strong> Puedes abrir esta invitación en tu móvil escaneando el código QR con la cámara de fotos."}.
|
||||
{"<strong>Tip:</strong> You can open this invite on your mobile device by scanning a barcode with your camera.","<strong>Truco:</strong> Puedes abrir esta invitación en tu móvil escaneando el código con la cámara de fotos."}.
|
||||
{"Subject","Asunto"}.
|
||||
{"Submit","Enviar"}.
|
||||
{"Submitted","Enviado"}.
|
||||
@@ -563,7 +578,7 @@
|
||||
{"The body text of the last received message","El contenido de texto del último mensaje recibido"}.
|
||||
{"The CAPTCHA is valid.","El CAPTCHA es válido."}.
|
||||
{"The CAPTCHA verification has failed","La verificación de CAPTCHA ha fallado"}.
|
||||
{"The captcha you entered is wrong","El CAPTCHA que has introducido es erróneo"}.
|
||||
{"The captcha you entered is wrong","El captcha que has introducido es erróneo"}.
|
||||
{"The child nodes (leaf or collection) associated with a collection","Los nodos hijos (ya sean hojas o colecciones) asociados con una colección"}.
|
||||
{"The collections with which a node is affiliated","Las colecciones a las que un nodo está afiliado"}.
|
||||
{"The DateTime at which a leased subscription will end or has ended","La FechayHora en la que una suscripción prestada acabará o ha terminado"}.
|
||||
@@ -702,7 +717,7 @@
|
||||
{"Who can send private messages","Quién puede enviar mensajes privados"}.
|
||||
{"Who may associate leaf nodes with a collection","Quien puede asociar nodos hoja con una colección"}.
|
||||
{"Wrong parameters in the web formulary","Parámetros incorrectos en el formulario web"}.
|
||||
{"Wrong xmlns","XMLNS incorrecto"}.
|
||||
{"Wrong xmlns","Xmlns incorrecto"}.
|
||||
{"XMPP Account Registration","Registro de Cuenta XMPP"}.
|
||||
{"XMPP client for Haiku","Cliente XMPP para Haiku"}.
|
||||
{"XMPP Domains","Dominios XMPP"}.
|
||||
@@ -718,7 +733,7 @@
|
||||
{"You can later change your password using an XMPP client.","Puedes cambiar tu contraseña después, usando un cliente XMPP."}.
|
||||
{"You can now set up {{ app_name }} and connect it to your new account.","Ahora puedes configurar {{ app_name }} y conectarte a tu nueva cuenta."}.
|
||||
{"You can start chatting right away with {{ app_name }}. Let's get started!","Puedes empezar ya a charlar usando {{ app_name }}. ¡Empecemos!"}.
|
||||
{"You can transfer this invite to your mobile device by scanning a code with your camera.","Puedes transferir esta invitación a tu móvil si escaneas el código QR con la cámara de fotos."}.
|
||||
{"You can transfer this invite to your mobile device by scanning a code with your camera.","Puedes transferir esta invitación a tu móvil si escaneas el código con la cámara de fotos."}.
|
||||
{"You have been banned from this room","Has sido bloqueado en esta sala"}.
|
||||
{"You have been invited to chat on {{ site_name }}, part of the XMPP secure and decentralized messaging network.","Te han invitado a charlar en {{ site_name }}, que forma parte de la red XMPP de mensajería segura y decentralizada."}.
|
||||
{"You have been invited to chat on <strong>{{ site_name }}</strong>, part of the XMPP secure and decentralized messaging network.","Te han invitado a charlar en <strong>{{ site_name }}</strong>, que forma parte de la red XMPP de mensajería segura y decentralizada."}.
|
||||
|
||||
+25
-10
@@ -24,11 +24,12 @@
|
||||
{"Account doesn't exist","账号不存在"}.
|
||||
{"Action on user","对用户的操作"}.
|
||||
{"Add {{ inviter }} to your contact list","将 {{ inviter }} 添加到您的联系人列表"}.
|
||||
{"Add Contact","添加联系人"}.
|
||||
{"Add User","添加用户"}.
|
||||
{"Administration of ","管理 "}.
|
||||
{"Administration","管理"}.
|
||||
{"Administrator privileges required","需要管理员权限"}.
|
||||
{"After clicking the button you will be taken to {{ app_name }} to finish setting up your new {{ site_name }} account.","点击按钮将跳转到 {{ app_name }}, 完成新 {{ site_name }} 账号的设置。"}.
|
||||
{"After clicking the button you will be taken to {{ app_name }} to finish setting up your new {{ site_name }} account.","点击按钮将跳转到 {{ app_name }},完成新 {{ site_name }} 账号的设置。"}.
|
||||
{"After successfully installing {{ app_name }}, come back to this page and <strong>continue with Step 2</strong>.","成功安装 {{ app_name }} 后,请返回此页面并<strong>继续执行步骤 2</strong>。"}.
|
||||
{"All activity","所有活动"}.
|
||||
{"All Users","所有用户"}.
|
||||
@@ -41,7 +42,7 @@
|
||||
{"Allow users to send private messages","允许用户发送私信"}.
|
||||
{"Allow visitors to change nickname","允许参观者更改昵称"}.
|
||||
{"Allow visitors to send private messages to","允许参观者发送私信至"}.
|
||||
{"Allow visitors to send status text in presence updates","允许参观者在在线状态更新中发送状态文字"}.
|
||||
{"Allow visitors to send status text in presence updates","允许参观者在在线状态更新中发送状态文本"}.
|
||||
{"Allow visitors to send voice requests","允许参观者发送发言权请求"}.
|
||||
{"An associated LDAP group that defines room membership; this should be an LDAP Distinguished Name according to an implementation-specific or deployment-specific definition of a group.","与定义房间成员资格相关联的 LDAP 组;根据组的特定实现或特定部署的定义,使用 LDAP 专有名称。"}.
|
||||
{"Announcements","公告"}.
|
||||
@@ -57,6 +58,7 @@
|
||||
{"Anyone with Voice","任何有发言权的人"}.
|
||||
{"Anyone","任何人"}.
|
||||
{"API Commands","API 命令"}.
|
||||
{"Apple Store Logo","Apple Store 徽标"}.
|
||||
{"April","四月"}.
|
||||
{"Arguments","参数"}.
|
||||
{"As a final reminder, your account details are shown below:","最终提醒,您的账号详情如下所示:"}.
|
||||
@@ -75,6 +77,7 @@
|
||||
{"Bad format","格式错误"}.
|
||||
{"BAD REQUEST","错误请求"}.
|
||||
{"Beagle IM by Tigase, Inc. is a lightweight and powerful XMPP client for macOS.","Beagle IM 由 Tigase, Inc. 开发,是适用于 macOS 的轻量高效 XMPP 客户端。"}.
|
||||
{"Beagle IM Logo","Beagle IM 徽标"}.
|
||||
{"Birthday","生日"}.
|
||||
{"Both the username and the resource are required","用户名和资源均为必填项"}.
|
||||
{"Bytestream already activated","字节流已激活"}.
|
||||
@@ -115,6 +118,7 @@
|
||||
{"Contact Addresses (normally, room owner or owners)","联系地址(通常为房间所有者)"}.
|
||||
{"Contacts","联系人"}.
|
||||
{"Conversations is a Jabber/XMPP client for Android 6.0+ smartphones that has been optimized to provide a unique mobile experience.","Conversations 是专为 Android 6.0 及更高版本智能手机优化的 Jabber/XMPP 客户端,提供独特的移动端体验。"}.
|
||||
{"Conversations Logo","Conversations 徽标"}.
|
||||
{"Country","国家/地区"}.
|
||||
{"Create a Hat","创建头衔"}.
|
||||
{"Create Account","创建账号"}.
|
||||
@@ -133,6 +137,7 @@
|
||||
{"Deliver event notifications","传递事件通知"}.
|
||||
{"Deliver payloads with event notifications","用事件通知传递有效负载"}.
|
||||
{"Destroy a Hat","删除头衔"}.
|
||||
{"Dino Logo","Dino 徽标"}.
|
||||
{"Disable User","禁用用户"}.
|
||||
{"Disc only copy","仅磁盘副本"}.
|
||||
{"Don't tell your password to anybody, not even the administrators of the XMPP server.","不要将您的密码告诉任何人,甚至是 XMPP 服务器的管理员。"}.
|
||||
@@ -168,7 +173,7 @@
|
||||
{"Enter path to jabberd14 spool dir","请输入 jabberd14 spool 目录路径"}.
|
||||
{"Enter path to jabberd14 spool file","请输入 jabberd14 spool 文件路径"}.
|
||||
{"Enter path to text file","请输入文本文件路径"}.
|
||||
{"Enter the text you see","请输入您看到的文字"}.
|
||||
{"Enter the text you see","请输入您看到的文本"}.
|
||||
{"Erlang XMPP Server","Erlang XMPP 服务器"}.
|
||||
{"Exclude Jabber IDs from CAPTCHA challenge","从验证码挑战中排除的 Jabber ID"}.
|
||||
{"Export all tables as SQL queries to a file:","将所有表以 SQL 查询导出到文件:"}.
|
||||
@@ -183,6 +188,7 @@
|
||||
{"Failed to process option '~s'","无法处理选项“~s”"}.
|
||||
{"Family Name","姓氏"}.
|
||||
{"FAQ Entry","常见问题条目"}.
|
||||
{"F-Droid Store Logo","F-Droid Store 徽标"}.
|
||||
{"February","二月"}.
|
||||
{"File larger than ~w bytes","文件大于 ~w 字节"}.
|
||||
{"Fill in the form to search for any matching XMPP User","填写表单以搜索任何匹配的 XMPP 用户"}.
|
||||
@@ -191,6 +197,7 @@
|
||||
{"Full List of Room Admins","房间管理员的完整列表"}.
|
||||
{"Full List of Room Owners","房间所有者的完整列表"}.
|
||||
{"Full Name","全名"}.
|
||||
{"Gajim Logo","Gajim 徽标"}.
|
||||
{"Get List of Active Users","获取活跃用户列表"}.
|
||||
{"Get List of Disabled Users","获取禁用用户列表"}.
|
||||
{"Get List of Idle Users","获取闲置用户列表"}.
|
||||
@@ -207,6 +214,7 @@
|
||||
{"Get User Roster","获取用户名册"}.
|
||||
{"Get User Statistics","获取用户统计数据"}.
|
||||
{"Given Name","名字"}.
|
||||
{"Google Play Store Logo","Google Play 商店徽标"}.
|
||||
{"Grant voice to this person?","是否授予此用户发言权?"}.
|
||||
{"has been banned","已被封禁"}.
|
||||
{"has been kicked because of a system shutdown","因系统关闭被踢出"}.
|
||||
@@ -277,7 +285,7 @@
|
||||
{"Last month","上个月"}.
|
||||
{"Last year","去年"}.
|
||||
{"Launch {{ app_name }} and sign in using your account credentials.","启动 {{ app_name }} 并使用您的账号凭据登录。"}.
|
||||
{"Launch Beagle IM, and select 'Yes' to add a new account. Click the '+' button under the empty account list and then enter your credentials.","启动 Beagle IM,然后选择“是”添加新账号。点击空白账号列表下方的“+”按钮,然后输入您的凭据。"}.
|
||||
{"Launch Beagle IM, and select \\'Yes\\' to add a new account. Click the \\'+\\' button under the empty account list and then enter your credentials.","启动 Beagle IM,然后选择“是”添加新账号。点击空白账号列表下方的“+”按钮,然后输入您的凭据。"}.
|
||||
{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","文本的 SHA-256 散列的最低有效位应等于十六进制标签"}.
|
||||
{"leaves the room","离开房间"}.
|
||||
{"List of Hats","头衔列表"}.
|
||||
@@ -318,6 +326,7 @@
|
||||
{"Moderators Only","仅主持人"}.
|
||||
{"Moderator","主持人"}.
|
||||
{"Module failed to handle the query","模块无法处理查询"}.
|
||||
{"Monal Logo","Monal 徽标"}.
|
||||
{"Monday","周一"}.
|
||||
{"Multicast","多播"}.
|
||||
{"Multiple <item/> elements are not allowed by RFC6121","按照 RFC6121,多个 <item/> 元素是不允许的"}.
|
||||
@@ -417,6 +426,7 @@
|
||||
{"Outgoing s2s Connections","传出 s2s 连接"}.
|
||||
{"Owner privileges required","需要所有者权限"}.
|
||||
{"Packet relay is denied by service policy","服务策略拒绝数据包中继"}.
|
||||
{"Page navigation","页面导航"}.
|
||||
{"Participant ID","参与者 ID"}.
|
||||
{"Participant","参与者"}.
|
||||
{"Password Verification","密码验证"}.
|
||||
@@ -432,6 +442,8 @@
|
||||
{"Ping query is incorrect","Ping 查询不正确"}.
|
||||
{"Ping","Ping"}.
|
||||
{"Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","注意:这些选项只会备份内置的 Mnesia 数据库。如果使用 ODBC 模块,还需要单独备份 SQL 数据库。"}.
|
||||
{"Please provide a password! Minimum length: {{ password_min_length }}","请提供密码!最小长度:{{ password_min_length }}"}.
|
||||
{"Please provide a valid username!","请提供有效的用户名!"}.
|
||||
{"Please, wait for a while before sending new voice request","请稍候再发送新的发言权请求"}.
|
||||
{"Pong","Pong"}.
|
||||
{"Possessing 'ask' attribute is not allowed by RFC6121","按照 RFC6121, 不允许有“ask”属性"}.
|
||||
@@ -441,6 +453,7 @@
|
||||
{"Previous session PID has exited","上一个会话 PID 已退出"}.
|
||||
{"Previous session PID is dead","上一个会话 PID 已失效"}.
|
||||
{"Previous session timed out","上一个会话超时"}.
|
||||
{"Previous","上一页"}.
|
||||
{"private, ","私人, "}.
|
||||
{"Public","公开"}.
|
||||
{"Publish model","发布模型"}.
|
||||
@@ -448,7 +461,6 @@
|
||||
{"PubSub subscriber request","PubSub 订阅者请求"}.
|
||||
{"Purge all items when the relevant publisher goes offline","相关发布者离线后清除所有项目"}.
|
||||
{"Push record not found","未找到推送记录"}.
|
||||
{"QR code icon","二维码图标"}.
|
||||
{"Queries to the conference members are not allowed in this room","此房间不允许向会议成员查询"}.
|
||||
{"Query to another users is forbidden","禁止查询其他用户"}.
|
||||
{"RAM and disc copy","RAM 和磁盘副本"}.
|
||||
@@ -464,9 +476,11 @@
|
||||
{"Register on {{ site_name }}","在 {{ site_name }} 注册"}.
|
||||
{"Register","注册"}.
|
||||
{"Registration error","注册错误"}.
|
||||
{"Registration Error","注册错误"}.
|
||||
{"Remote copy","远程副本"}.
|
||||
{"Remove a hat from a user","移除用户头衔"}.
|
||||
{"Remove User","移除用户"}.
|
||||
{"Renga Logo","Renga 徽标"}.
|
||||
{"Replaced by new connection","替换为新连接"}.
|
||||
{"Request has timed out","请求已超时"}.
|
||||
{"Request is ignored","请求被忽略"}.
|
||||
@@ -498,7 +512,7 @@
|
||||
{"Scan with mobile device","使用移动设备扫描"}.
|
||||
{"Search from the date","从日期搜索"}.
|
||||
{"Search Results for ","搜索结果 "}.
|
||||
{"Search the text","搜索文字"}.
|
||||
{"Search the text","搜索文本"}.
|
||||
{"Search until the date","搜索截至日期"}.
|
||||
{"Search users in ","在以下位置搜索用户 "}.
|
||||
{"Select","选择"}.
|
||||
@@ -520,6 +534,7 @@
|
||||
{"Showing apps for <span class='platform-name'>your current platform</span> only. You may also <a href='#' id='show-all-clients-button'>view all apps.</a>","仅显示适用于<span class='platform-name'>您当前平台</span>的应用。您也可以<a href='#' id='show-all-clients-button'>查看所有应用。</a>"}.
|
||||
{"Show","显示"}.
|
||||
{"Shut Down Service","关闭服务"}.
|
||||
{"Siskin IM Logo","Siskin IM 徽标"}.
|
||||
{"SOCKS5 Bytestreams","SOCKS5 字节流"}.
|
||||
{"Some XMPP clients can store your password in the computer, but you should do this only in your personal computer for safety reasons.","部分 XMPP 客户端可以将您的密码存储在计算机中,但出于安全考虑,您应该仅在个人计算机中存储密码。"}.
|
||||
{"Sorry, it looks like this invite code has expired!","抱歉,此邀请码似乎已过期!"}.
|
||||
@@ -552,10 +567,10 @@
|
||||
{"Subscription requests must be approved and only subscribers may retrieve items","订阅请求必须得到批准,只有订阅者才能检索项目"}.
|
||||
{"Subscriptions are not allowed","不允许订阅"}.
|
||||
{"Sunday","周日"}.
|
||||
{"Text associated with a picture","与图片相关的文字"}.
|
||||
{"Text associated with a sound","与声音相关的文字"}.
|
||||
{"Text associated with a video","与视频相关的文字"}.
|
||||
{"Text associated with speech","与语音相关的文字"}.
|
||||
{"Text associated with a picture","与图片相关的文本"}.
|
||||
{"Text associated with a sound","与声音相关的文本"}.
|
||||
{"Text associated with a video","与视频相关的文本"}.
|
||||
{"Text associated with speech","与语音相关的文本"}.
|
||||
{"That nickname is already in use by another occupant","该昵称已被其他使用者使用"}.
|
||||
{"That nickname is registered by another person","该昵称已被其他用户注册"}.
|
||||
{"The account already exists","此账号已存在"}.
|
||||
|
||||
+7
-7
@@ -34,12 +34,7 @@
|
||||
{if_rebar3,
|
||||
{eredis, "~> 1.7.1", {git, "https://github.com/Nordix/eredis/", {tag, "v1.7.1"}}}
|
||||
}},
|
||||
{if_not_rebar3,
|
||||
{erlydtl, "~> 0.14.0", {git, "https://github.com/sstrigler/erlydtl.git", {tag, "0.14.0-fix.1"}}}
|
||||
},
|
||||
{if_rebar3,
|
||||
{erlydtl, ".*", {git, "https://github.com/erlydtl/erlydtl.git", {branch, "master"}}}
|
||||
},
|
||||
{erlydtl, "~> 0.14.0", {git, "https://github.com/erlydtl/erlydtl", {tag, "0.15.0"}}},
|
||||
{if_var_true, sip,
|
||||
{esip, "~> 1.0.59", {git, "https://github.com/processone/esip", {tag, "1.0.59"}}}},
|
||||
{if_var_true, zlib,
|
||||
@@ -162,6 +157,10 @@
|
||||
%% Compiling Jose 1.11.10 with Erlang/OTP 27.0 throws warnings on public_key deprecated functions
|
||||
{if_rebar3, {overrides, [{del, jose, [{erl_opts, [warnings_as_errors]}]}]}}.
|
||||
|
||||
{if_not_rebar3,
|
||||
{overrides, [{del, erlydtl, [{require_otp_vsn, "18"}]}]}
|
||||
}.
|
||||
|
||||
{sub_dirs, ["rel"]}.
|
||||
|
||||
{keep_build_info, true}.
|
||||
@@ -205,12 +204,13 @@
|
||||
{dialyzer, [{get_warnings, false}, % Show warnings of dependencies
|
||||
{if_version_above, "25",
|
||||
{plt_extra_apps,
|
||||
[asn1, odbc, public_key, stdlib, syntax_tools,
|
||||
[asn1, public_key, stdlib, syntax_tools,
|
||||
idna, jose,
|
||||
cache_tab, eimp, erlydtl, fast_tls, fast_xml, fast_yaml,
|
||||
mqtree, p1_acme, p1_oauth2, p1_utils, pkix,
|
||||
stringprep, xmpp, yconf,
|
||||
{if_version_below, "27", jiffy},
|
||||
{if_var_true, odbc, odbc},
|
||||
{if_var_true, pam, epam},
|
||||
{if_var_true, redis, eredis},
|
||||
{if_var_true, sip, esip},
|
||||
|
||||
+3
-4
@@ -4,10 +4,7 @@
|
||||
{<<"eimp">>,{pkg,<<"eimp">>,<<"1.0.26">>},0},
|
||||
{<<"epam">>,{pkg,<<"epam">>,<<"1.0.14">>},0},
|
||||
{<<"eredis">>,{pkg,<<"eredis">>,<<"1.7.1">>},0},
|
||||
{<<"erlydtl">>,
|
||||
{git,"https://github.com/erlydtl/erlydtl.git",
|
||||
{ref,"aae414692b6052e96d890e03bbeeeca0f4dc01c2"}},
|
||||
0},
|
||||
{<<"erlydtl">>,{pkg,<<"erlydtl">>,<<"0.14.0">>},0},
|
||||
{<<"esip">>,{pkg,<<"esip">>,<<"1.0.59">>},0},
|
||||
{<<"ezlib">>,{pkg,<<"ezlib">>,<<"1.0.15">>},0},
|
||||
{<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.25">>},0},
|
||||
@@ -37,6 +34,7 @@
|
||||
{<<"eimp">>, <<"C0B05F32E35629C4D9BCFB832FF879A92B0F92B19844BC7835E0A45635F2899A">>},
|
||||
{<<"epam">>, <<"AA0B85D27F4EF3A756AE995179DF952A0721237E83C6B79D644347B75016681A">>},
|
||||
{<<"eredis">>, <<"39E31AA02ADCD651C657F39AAFD4D31A9B2F63C6C700DC9CECE98D4BC3C897AB">>},
|
||||
{<<"erlydtl">>, <<"964B2DC84F8C17ACFAA69C59BA129EF26AC45D2BA898C3C6AD9B5BDC8BA13CED">>},
|
||||
{<<"esip">>, <<"EB202F8C62928193588091DFEDBC545FE3274C34ECD209961F86DCB6C9EBCE88">>},
|
||||
{<<"ezlib">>, <<"D74F5DF191784744726A5B1AE9062522C606334F11086363385EB3B772D91357">>},
|
||||
{<<"fast_tls">>, <<"DA8ED6F05A2452121B087158B17234749F36704C1F2B74DC51DB99A1E27ED5E8">>},
|
||||
@@ -65,6 +63,7 @@
|
||||
{<<"eimp">>, <<"D96D4E8572B9DFC40F271E47F0CB1D8849373BC98A21223268781765ED52044C">>},
|
||||
{<<"epam">>, <<"2F3449E72885A72A6C2A843F561ADD0FC2F70D7A21F61456930A547473D4D989">>},
|
||||
{<<"eredis">>, <<"7C2B54C566FED55FEEF3341CA79B0100A6348FD3F162184B7ED5118D258C3CC1">>},
|
||||
{<<"erlydtl">>, <<"D80EC044CD8F58809C19D29AC5605BE09E955040911B644505E31E9DD8143431">>},
|
||||
{<<"esip">>, <<"0BDF2E3C349DC0B144F173150329E675C6A51AC473D7A0B2E362245FAAD3FBE6">>},
|
||||
{<<"ezlib">>, <<"DD14BA6C12521AF5CFE6923E73E3D545F4A0897DC66BFAB5287FBB7AE3962EAB">>},
|
||||
{<<"fast_tls">>, <<"59E183B5740E670E02B8AA6BE673B5E7779E5FE5BFCC679FE2D4993D1949A821">>},
|
||||
|
||||
+1
-1
@@ -517,7 +517,7 @@ CREATE TABLE invite_token (
|
||||
expires timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
type character(1) NOT NULL,
|
||||
account_name text NOT NULL,
|
||||
PRIMARY KEY (token(191)),
|
||||
PRIMARY KEY (token(191))
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE INDEX i_invite_token_username USING BTREE ON invite_token(username(191), server_host(191));
|
||||
|
||||
@@ -50,6 +50,7 @@ start(normal, _Args) ->
|
||||
case ejabberd_config:load() of
|
||||
ok ->
|
||||
ejabberd_mnesia:start(),
|
||||
delete_unused_tables(),
|
||||
file_queue_init(),
|
||||
maybe_add_nameservers(),
|
||||
case ejabberd_sup:start_link() of
|
||||
@@ -166,6 +167,9 @@ delete_pid_file() ->
|
||||
file:delete(PidFilename)
|
||||
end.
|
||||
|
||||
delete_unused_tables() ->
|
||||
mnesia:delete_table(muc_occupant_id).
|
||||
|
||||
file_queue_init() ->
|
||||
QueueDir = case ejabberd_option:queue_dir() of
|
||||
undefined ->
|
||||
|
||||
@@ -454,7 +454,7 @@ get_version_mark(Note) ->
|
||||
XXYY = string:join([XX, YY], "."),
|
||||
case string:find(Note, XXYY) of
|
||||
nomatch -> "";
|
||||
_ -> " 🟤"
|
||||
_ -> " 🟠"
|
||||
end.
|
||||
|
||||
make_command_name(Name, Note) ->
|
||||
@@ -520,7 +520,7 @@ generate_md_output(File, RegExp, Languages, Cmds) ->
|
||||
Version = binary_to_list(ejabberd_config:version()),
|
||||
Header = ["# API Reference\n\n"
|
||||
"This section describes API commands of ejabberd ", Version, ". "
|
||||
"The commands that changed in this version are marked with 🟤.\n\n"],
|
||||
"The commands that changed in this version are marked with 🟠.\n\n"],
|
||||
Out = lists:map(fun(C) -> gen_doc(C, false, Langs) end, Cmds4),
|
||||
{ok, Fh} = file:open(File, [write, {encoding, utf8}]),
|
||||
io:format(Fh, "~ts~ts", [Header, Out]),
|
||||
|
||||
@@ -73,7 +73,7 @@ transform(Host, Y, Acc) ->
|
||||
|
||||
transform(Host, modules, ModOpts, Acc) ->
|
||||
{ModOpts1, Acc2} =
|
||||
lists:mapfoldr(
|
||||
filtermapfoldr(
|
||||
fun({Mod, Opts}, Acc1) ->
|
||||
Opts1 = transform_module_options(Opts),
|
||||
transform_module(Host, Mod, Opts1, Acc1)
|
||||
@@ -446,7 +446,7 @@ transform_module(_Host, mod_blocking, Opts, Acc) ->
|
||||
(_) ->
|
||||
true
|
||||
end, Opts),
|
||||
{{mod_blocking, Opts1}, Acc};
|
||||
{{true, {mod_blocking, Opts1}}, Acc};
|
||||
transform_module(_Host, mod_carboncopy, Opts, Acc) ->
|
||||
Opts1 = lists:filter(
|
||||
fun({Opt, _}) when Opt == ram_db_type;
|
||||
@@ -459,7 +459,7 @@ transform_module(_Host, mod_carboncopy, Opts, Acc) ->
|
||||
(_) ->
|
||||
true
|
||||
end, Opts),
|
||||
{{mod_carboncopy, Opts1}, Acc};
|
||||
{{true, {mod_carboncopy, Opts1}}, Acc};
|
||||
transform_module(_Host, mod_http_api, Opts, Acc) ->
|
||||
Opts1 = lists:filter(
|
||||
fun({admin_ip_access, _}) ->
|
||||
@@ -468,7 +468,7 @@ transform_module(_Host, mod_http_api, Opts, Acc) ->
|
||||
(_) ->
|
||||
true
|
||||
end, Opts),
|
||||
{{mod_http_api, Opts1}, Acc};
|
||||
{{true, {mod_http_api, Opts1}}, Acc};
|
||||
transform_module(_Host, mod_http_upload, Opts, Acc) ->
|
||||
Opts1 = lists:filter(
|
||||
fun({service_url, _}) ->
|
||||
@@ -477,7 +477,7 @@ transform_module(_Host, mod_http_upload, Opts, Acc) ->
|
||||
(_) ->
|
||||
true
|
||||
end, Opts),
|
||||
{{mod_http_upload, Opts1}, Acc};
|
||||
{{true, {mod_http_upload, Opts1}}, Acc};
|
||||
transform_module(_Host, mod_pubsub, Opts, Acc) ->
|
||||
Opts1 = lists:map(
|
||||
fun({plugins, Plugins}) ->
|
||||
@@ -505,9 +505,11 @@ transform_module(_Host, mod_pubsub, Opts, Acc) ->
|
||||
(Opt) ->
|
||||
Opt
|
||||
end, Opts),
|
||||
{{mod_pubsub, Opts1}, Acc};
|
||||
{{true, {mod_pubsub, Opts1}}, Acc};
|
||||
transform_module(_Host, mod_muc_occupantid, _Opts, Acc) ->
|
||||
{false, Acc};
|
||||
transform_module(_Host, Mod, Opts, Acc) ->
|
||||
{{Mod, Opts}, Acc}.
|
||||
{{true, {Mod, Opts}}, Acc}.
|
||||
|
||||
strip_odbc_suffix(M) ->
|
||||
[_|T] = lists:reverse(string:tokens(atom_to_list(M), "_")),
|
||||
|
||||
@@ -80,7 +80,7 @@ man(Lang) ->
|
||||
["TOP LEVEL OPTIONS",
|
||||
"-----------------",
|
||||
"This section describes top level options of ejabberd " ++ Version ++ ".",
|
||||
"The options that changed in this version are marked with 🟤.",
|
||||
"The options that changed in this version are marked with 🟠.",
|
||||
io_lib:nl()] ++
|
||||
lists:flatmap(
|
||||
fun(Opt) ->
|
||||
@@ -101,7 +101,7 @@ man(Lang) ->
|
||||
"-------",
|
||||
"[[modules]]",
|
||||
"This section describes modules options of ejabberd " ++ Version ++ ".",
|
||||
"The modules that changed in this version are marked with 🟤.",
|
||||
"The modules that changed in this version are marked with 🟠.",
|
||||
io_lib:nl()] ++
|
||||
lists:flatmap(
|
||||
fun({M, Descr, DocOpts, Backends, Example}) ->
|
||||
@@ -176,7 +176,7 @@ get_version_mark(#{note := Note}) ->
|
||||
XXYY = string:join([XX, YY], "."),
|
||||
case string:find(Note, XXYY) of
|
||||
nomatch -> "";
|
||||
_ -> " 🟤"
|
||||
_ -> " 🟠"
|
||||
end;
|
||||
get_version_mark(_) ->
|
||||
"".
|
||||
|
||||
+13
-16
@@ -395,16 +395,15 @@ extract_path_query(#state{request_method = Method,
|
||||
when Method =:= 'GET' orelse
|
||||
Method =:= 'HEAD' orelse
|
||||
Method =:= 'DELETE' orelse Method =:= 'OPTIONS' ->
|
||||
case catch url_decode_q_split_normalize(Path) of
|
||||
{'EXIT', Error} ->
|
||||
?DEBUG("Error decoding URL '~p': ~p", [Path, Error]),
|
||||
{State, false};
|
||||
try url_decode_q_split_normalize(Path) of
|
||||
{LPath, Query} ->
|
||||
LQuery = case catch parse_urlencoded(Query) of
|
||||
{'EXIT', _Reason} -> [];
|
||||
LQ -> LQ
|
||||
LQuery = try parse_urlencoded(Query)
|
||||
catch _:_ -> []
|
||||
end,
|
||||
{State, {LPath, LQuery, <<"">>, Path}}
|
||||
catch _:Error ->
|
||||
?DEBUG("Error decoding URL '~p': ~p", [Path, Error]),
|
||||
{State, false}
|
||||
end;
|
||||
extract_path_query(#state{request_method = Method,
|
||||
request_path = {abs_path, Path},
|
||||
@@ -413,10 +412,7 @@ extract_path_query(#state{request_method = Method,
|
||||
sockmod = _SockMod,
|
||||
socket = _Socket} = State)
|
||||
when (Method =:= 'POST' orelse Method =:= 'PUT') andalso Len>0 ->
|
||||
case catch url_decode_q_split_normalize(Path) of
|
||||
{'EXIT', Error} ->
|
||||
?DEBUG("Error decoding URL '~p': ~p", [Path, Error]),
|
||||
{State, false};
|
||||
try url_decode_q_split_normalize(Path) of
|
||||
{LPath, _Query} ->
|
||||
case Method of
|
||||
'PUT' ->
|
||||
@@ -424,15 +420,17 @@ extract_path_query(#state{request_method = Method,
|
||||
'POST' ->
|
||||
case recv_data(State) of
|
||||
{ok, Data} ->
|
||||
LQuery = case catch parse_urlencoded(Data) of
|
||||
{'EXIT', _Reason} -> [];
|
||||
LQ -> LQ
|
||||
LQuery = try parse_urlencoded(Data)
|
||||
catch _:_ -> []
|
||||
end,
|
||||
{State, {LPath, LQuery, Data, Path}};
|
||||
error ->
|
||||
{State, false}
|
||||
end
|
||||
end
|
||||
catch _:Error ->
|
||||
?DEBUG("Error decoding URL '~p': ~p", [Path, Error]),
|
||||
{State, false}
|
||||
end;
|
||||
extract_path_query(State) ->
|
||||
{State, false}.
|
||||
@@ -861,8 +859,7 @@ parse_urlencoded(<<$=, Tail/binary>>, _Last, Cur, key) ->
|
||||
parse_urlencoded(<<H, Tail/binary>>, Last, Cur, State) ->
|
||||
parse_urlencoded(Tail, Last, <<Cur/binary, H>>, State);
|
||||
parse_urlencoded(<<>>, Last, Cur, _State) ->
|
||||
[{Last, Cur}];
|
||||
parse_urlencoded(undefined, _, _, _) -> [].
|
||||
[{Last, Cur}].
|
||||
|
||||
apply_custom_headers(Headers, CustomHeaders) ->
|
||||
{Doctype, Headers2} = case Headers -- [html] of
|
||||
|
||||
+6
-1
@@ -367,7 +367,7 @@ prep_stop_module_keep_config(Host, Module) ->
|
||||
|
||||
-spec stop_module_keep_config(binary(), atom()) -> error | ok.
|
||||
stop_module_keep_config(Host, Module) ->
|
||||
?DEBUG("Stopping ~ts at ~ts", [Module, Host]),
|
||||
?INFO_MSG("Stopping ~ts at ~ts", [Module, Host]),
|
||||
Registrations =
|
||||
case ets:lookup(ejabberd_modules, {Module, Host}) of
|
||||
[M] ->
|
||||
@@ -421,6 +421,11 @@ del_registrations(Host, Module, Registrations) ->
|
||||
lists:foreach(
|
||||
fun({hook, Hook, Function, Seq}) ->
|
||||
ejabberd_hooks:delete(Hook, Host, Module, Function, Seq);
|
||||
({hook, Hook, Function, Seq, global}) when is_integer(Seq) ->
|
||||
case is_loaded_elsewhere(Host, Module) of
|
||||
false -> ejabberd_hooks:delete(Hook, global, Module, Function, Seq);
|
||||
true -> ok
|
||||
end;
|
||||
({hook, Hook, Function, Seq, Host1}) when is_integer(Seq) ->
|
||||
ejabberd_hooks:delete(Hook, Host1, Module, Function, Seq);
|
||||
({hook, Hook, Module1, Function, Seq}) when is_integer(Seq) ->
|
||||
|
||||
+35
-10
@@ -107,8 +107,8 @@ filter_subscription(Acc, #presence{from = From, to = To, lang = Lang,
|
||||
case mod_block_strangers_opt:drop(LServer) andalso
|
||||
mod_block_strangers_opt:captcha(LServer) andalso
|
||||
need_check(Pres) of
|
||||
true ->
|
||||
case check_subscription(From, To) of
|
||||
{true, Origin} ->
|
||||
case check_subscription(Origin, To) of
|
||||
false ->
|
||||
BFrom = jid:remove_resource(From),
|
||||
BTo = jid:remove_resource(To),
|
||||
@@ -164,18 +164,24 @@ handle_captcha_result(captcha_failed, #presence{lang = Lang} = Pres) ->
|
||||
check_message(#message{from = From, to = To, lang = Lang} = Msg) ->
|
||||
LServer = To#jid.lserver,
|
||||
case need_check(Msg) of
|
||||
true ->
|
||||
case check_subscription(From, To) of
|
||||
{true, Origin} ->
|
||||
case check_subscription(Origin, To) of
|
||||
false ->
|
||||
Drop = mod_block_strangers_opt:drop(LServer),
|
||||
Log = mod_block_strangers_opt:log(LServer),
|
||||
if
|
||||
Log ->
|
||||
Log andalso Origin == From ->
|
||||
?INFO_MSG("~ts message from stranger ~ts to ~ts",
|
||||
[if Drop -> "Rejecting";
|
||||
true -> "Allow"
|
||||
end,
|
||||
jid:encode(From), jid:encode(To)]);
|
||||
Log ->
|
||||
?INFO_MSG("~ts message from stranger ~ts to ~ts (via ~ts)",
|
||||
[if Drop -> "Rejecting";
|
||||
true -> "Allow"
|
||||
end,
|
||||
jid:encode(Origin), jid:encode(To), jid:encode(From)]);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
@@ -202,7 +208,7 @@ maybe_adjust_from(#message{type = groupchat, from = From} = Msg) ->
|
||||
maybe_adjust_from(#message{} = Msg) ->
|
||||
Msg.
|
||||
|
||||
-spec need_check(presence() | message()) -> boolean().
|
||||
-spec need_check(presence() | message()) -> {true, #jid{}} | false.
|
||||
need_check(Pkt) ->
|
||||
To = xmpp:get_to(Pkt),
|
||||
From = xmpp:get_from(Pkt),
|
||||
@@ -218,10 +224,29 @@ need_check(Pkt) ->
|
||||
IsError = (error == xmpp:get_type(Pkt)),
|
||||
AllowLocalUsers = mod_block_strangers_opt:allow_local_users(LServer),
|
||||
Access = mod_block_strangers_opt:access(LServer),
|
||||
not (IsSelf orelse IsEmpty orelse IsError
|
||||
orelse acl:match_rule(LServer, Access, From) == allow
|
||||
orelse ((AllowLocalUsers orelse From#jid.luser == <<"">>)
|
||||
andalso ejabberd_router:is_my_host(From#jid.lserver))).
|
||||
NeedCheck = not (IsSelf orelse IsEmpty orelse IsError
|
||||
orelse acl:match_rule(LServer, Access, From) == allow
|
||||
orelse ((AllowLocalUsers orelse From#jid.luser == <<"">>)
|
||||
andalso ejabberd_router:is_my_host(From#jid.lserver))),
|
||||
case {NeedCheck, Pkt} of
|
||||
{false, _} ->
|
||||
false;
|
||||
{_, #message{}} ->
|
||||
case xmpp:get_subtag(Pkt, #muc_user{}) of
|
||||
#muc_user{invites = [#muc_invite{from = #jid{} = InvFrom}]}->
|
||||
case acl:match_rule(LServer, Access, InvFrom) == allow orelse
|
||||
(AllowLocalUsers andalso ejabberd_router:is_my_host(InvFrom#jid.lserver)) of
|
||||
true ->
|
||||
false;
|
||||
_ ->
|
||||
{true, InvFrom}
|
||||
end;
|
||||
_ ->
|
||||
{true, From}
|
||||
end;
|
||||
_ ->
|
||||
{true, From}
|
||||
end.
|
||||
|
||||
-spec check_subscription(jid(), jid()) -> boolean().
|
||||
check_subscription(From, To) ->
|
||||
|
||||
+41
-6
@@ -54,11 +54,14 @@ reload(_Host, _NewOpts, _OldOpts) ->
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
process(LocalPath, #request{auth = Auth, path = Path} = Request) ->
|
||||
process(LocalPath, #request{auth = Auth, path = Path, opts = Opts} = Request) ->
|
||||
AutologinPath = lists:member(?AUTOLOGIN_PATH, Path),
|
||||
case {AutologinPath, Auth} of
|
||||
{true, undefined} ->
|
||||
HasWebsocket = has_websocket(Opts),
|
||||
case {AutologinPath, Auth, HasWebsocket} of
|
||||
{true, undefined, _} ->
|
||||
ejabberd_web:error(not_found);
|
||||
{true, _, false} ->
|
||||
process_websocket();
|
||||
_ ->
|
||||
process2(LocalPath, Request)
|
||||
end.
|
||||
@@ -66,7 +69,7 @@ process(LocalPath, #request{auth = Auth, path = Path} = Request) ->
|
||||
process2([], #request{method = 'GET', host = Host, auth = Auth, raw_path = RawPath1}) ->
|
||||
[RawPath | _] = string:split(RawPath1, "?"),
|
||||
ExtraOptions = get_auth_options(Host)
|
||||
++ get_autologin_options(Auth)
|
||||
++ get_autologin_options(Auth, Host)
|
||||
++ get_register_options(Host)
|
||||
++ get_extra_options(Host),
|
||||
Domain = mod_conversejs_opt:default_domain(Host),
|
||||
@@ -117,6 +120,29 @@ process2(LocalPath, #request{host = Host}) ->
|
||||
false -> ejabberd_web:error(not_found)
|
||||
end.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% WebSocket
|
||||
%%----------------------------------------------------------------------
|
||||
|
||||
has_websocket(Opts) ->
|
||||
maybe
|
||||
{_, Handlers} ?= lists:keyfind(request_handlers, 1, Opts),
|
||||
true ?= lists:keymember(ejabberd_web_admin, 2, Handlers),
|
||||
true ?= lists:keymember(ejabberd_http_ws, 2, Handlers)
|
||||
else
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
process_websocket() ->
|
||||
{200, [html],
|
||||
[<<"<!DOCTYPE html>">>,
|
||||
<<"<html><body>">>,
|
||||
<<"<p>To use Conversejs, please enable WebSocket as a request_handler in this port, like:</p>">>,
|
||||
<<"<pre> request_handlers:</pre>">>,
|
||||
<<"<pre> /admin: ejabberd_web_admin</pre>">>,
|
||||
<<"<pre> /websocket: ejabberd_http_ws</pre>">>,
|
||||
<<"</body></html>">>]}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% File server
|
||||
%%----------------------------------------------------------------------
|
||||
@@ -196,9 +222,15 @@ get_auth_options(Domain) ->
|
||||
{<<"jid">>, Domain}]
|
||||
end.
|
||||
|
||||
get_autologin_options({Jid, Password}) ->
|
||||
get_autologin_options({Jid1, Password}, Host) ->
|
||||
Jid = case jid:decode(Jid1) of
|
||||
#jid{luser = <<>>} ->
|
||||
jid:encode(jid:make(Jid1, Host));
|
||||
_ ->
|
||||
Jid1
|
||||
end,
|
||||
[{<<"auto_login">>, <<"true">>}, {<<"jid">>, Jid}, {<<"password">>, Password}];
|
||||
get_autologin_options(undefined) ->
|
||||
get_autologin_options(undefined, _) ->
|
||||
[].
|
||||
|
||||
get_register_options(Server) ->
|
||||
@@ -344,6 +376,9 @@ mod_doc() ->
|
||||
"are enabled in at least one 'request_handlers'."), "",
|
||||
?T("When 'conversejs_css' and 'conversejs_script' are 'auto', "
|
||||
"by default they point to the public Converse client."), "",
|
||||
?T("When this module is enabled in 'modules', "
|
||||
"it adds automatically a requesthandler and link in WebAdmin. "
|
||||
"."), "",
|
||||
?T("This module is available since ejabberd 21.12.")
|
||||
],
|
||||
note => "improved in 25.07",
|
||||
|
||||
+84
-34
@@ -43,7 +43,7 @@
|
||||
-export([get_local_identity/5, get_local_features/5]).
|
||||
|
||||
%% commands
|
||||
-export([cleanup_expired/0, expire_tokens/2, gen_invite/1, gen_invite/2, list_invites/1]).
|
||||
-export([cleanup_expired/0, expire_tokens/2, generate_invite/1, generate_invite/2, list_invites/1]).
|
||||
|
||||
%% helpers
|
||||
-export([create_account_allowed/2, get_invite/2, get_invites/2, get_max_invites/2, is_create_allowed/2,
|
||||
@@ -54,7 +54,7 @@
|
||||
-export([process/2]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-export([create_roster_invite/2, create_account_invite/4, is_token_valid/3]).
|
||||
-export([create_roster_invite/2, create_account_invite/4, gen_invite/1, gen_invite/2, is_token_valid/3]).
|
||||
-endif.
|
||||
|
||||
-include("logger.hrl").
|
||||
@@ -126,12 +126,13 @@ mod_doc() ->
|
||||
"",
|
||||
?T("In order to use the included landing page feature, you have to"),
|
||||
"",
|
||||
?T(" * have a copy of https://jquery.com[jQuery 3] and "
|
||||
" https://getbootstrap.com/docs/4.6/getting-started/introduction/[Bootstrap 4] "
|
||||
?T(" * have a copy of https://code.jquery.com/jquery-3.7.1.min.js[jQuery 3] and "
|
||||
" https://github.com/twbs/bootstrap/releases/download/v4.6.2/bootstrap-4.6.2-dist.zip[Bootstrap 4] "
|
||||
" in a shared directory on your system. If you're using Debian or "
|
||||
" derivatives this is easiest accomplished by installing both "
|
||||
" `libjs-jquery` and `libjs-bootstrap4` which will put them under "
|
||||
" `/usr/share/javascript/{jquery,bootstrap4}`"),
|
||||
" `/usr/share/javascript/{jquery,bootstrap4}`. Alternatively you can use "
|
||||
" `tools/dl_invites_page_deps.sh <outdir>`."),
|
||||
?T(" * in `ejabberd.yml` configure a listener for module `ejabberd_http` "
|
||||
" with a request handler for `/share: mod_http_fileserver`"),
|
||||
?T(" * in the `modules` section configure `mod_http_fileserver` so that "
|
||||
@@ -186,7 +187,7 @@ mod_doc() ->
|
||||
?T("A human readable name for your site. E.g. `\"My Beautiful Laundrette\"`. "
|
||||
"Used in landing page templates.")}},
|
||||
{templates_dir,
|
||||
#{value => ?T("binary()"),
|
||||
#{value => ?T("Path"),
|
||||
desc =>
|
||||
?T("The directory containing templates and static files used "
|
||||
"for landing page and web registration form. Only needs to "
|
||||
@@ -290,7 +291,8 @@ mod_opt_type(access_create_account) ->
|
||||
mod_opt_type(db_type) ->
|
||||
econf:db_type(?MODULE);
|
||||
mod_opt_type(landing_page) ->
|
||||
econf:either(none, econf:binary());
|
||||
econf:either(
|
||||
econf:enum([none, auto]), econf:binary());
|
||||
mod_opt_type(max_invites) ->
|
||||
econf:pos_int(infinity);
|
||||
mod_opt_type(site_name) ->
|
||||
@@ -329,7 +331,7 @@ get_commands_spec() ->
|
||||
tags = [accounts],
|
||||
desc = "Create a new 'create account' invite",
|
||||
module = ?MODULE,
|
||||
function = gen_invite,
|
||||
function = generate_invite,
|
||||
note = "added in 26.01",
|
||||
args = [{host, binary}],
|
||||
args_desc = ["Hostname to generate 'create account' invite for."],
|
||||
@@ -344,7 +346,7 @@ get_commands_spec() ->
|
||||
"Create a new 'create account' invite token with a preselected "
|
||||
"username",
|
||||
module = ?MODULE,
|
||||
function = gen_invite,
|
||||
function = generate_invite,
|
||||
note = "added in 26.01",
|
||||
args = [{username, binary}, {host, binary}],
|
||||
args_desc =
|
||||
@@ -397,12 +399,24 @@ cleanup_expired() ->
|
||||
expire_tokens(User0, Server0) ->
|
||||
User = jid:nodeprep(User0),
|
||||
Server = jid:nameprep(Server0),
|
||||
db_call(Server, expire_tokens, [User, Server]).
|
||||
pretty_format_command_result(try_db_call(Server, expire_tokens, [User, Server])).
|
||||
|
||||
-spec generate_invite(binary()) -> binary() | {error, any()}.
|
||||
generate_invite(Host) ->
|
||||
generate_invite(<<>>, Host).
|
||||
|
||||
-spec generate_invite(binary(), binary()) -> binary() | {error, any()}.
|
||||
generate_invite(AccountName, Host) ->
|
||||
pretty_format_command_result(gen_invite(AccountName, Host)).
|
||||
|
||||
-ifdef(TEST).
|
||||
|
||||
-spec gen_invite(binary()) -> binary() | {error, any()}.
|
||||
gen_invite(Host) ->
|
||||
gen_invite(<<>>, Host).
|
||||
|
||||
-endif.
|
||||
|
||||
-spec gen_invite(binary(), binary()) -> binary() | {error, any()}.
|
||||
gen_invite(AccountName, Host0) ->
|
||||
Host = jid:nameprep(Host0),
|
||||
@@ -416,29 +430,32 @@ gen_invite(AccountName, Host0) ->
|
||||
end.
|
||||
|
||||
list_invites(Host) ->
|
||||
Invites = db_call(Host, list_invites, [Host]),
|
||||
Format =
|
||||
fun(#invite_token{token = TO,
|
||||
inviter = {IU, IS},
|
||||
invitee = IE,
|
||||
created_at = CA,
|
||||
expires = Exp,
|
||||
type = TY,
|
||||
account_name = AN} =
|
||||
Invite) ->
|
||||
{TO,
|
||||
is_token_valid(Host, TO),
|
||||
encode_datetime(CA),
|
||||
encode_datetime(Exp),
|
||||
TY,
|
||||
jid:encode(
|
||||
jid:make(IU, IS)),
|
||||
IE,
|
||||
AN,
|
||||
token_uri(Invite),
|
||||
landing_page(Host, Invite)}
|
||||
end,
|
||||
[Format(Invite) || Invite <- Invites].
|
||||
Res = maybe
|
||||
{ok, Invites} ?= try_db_call(Host, list_invites, [Host]),
|
||||
[format_invite(Host, Invite) || Invite <- Invites]
|
||||
end,
|
||||
pretty_format_command_result(Res).
|
||||
|
||||
format_invite(Host,
|
||||
#invite_token{token = TO,
|
||||
inviter = {IU, IS},
|
||||
invitee = IE,
|
||||
created_at = CA,
|
||||
expires = Exp,
|
||||
type = TY,
|
||||
account_name = AN} =
|
||||
Invite) ->
|
||||
{TO,
|
||||
is_token_valid(Host, TO),
|
||||
encode_datetime(CA),
|
||||
encode_datetime(Exp),
|
||||
TY,
|
||||
jid:encode(
|
||||
jid:make(IU, IS)),
|
||||
IE,
|
||||
AN,
|
||||
token_uri(Invite),
|
||||
landing_page(Host, Invite)}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%| hooks and callbacks
|
||||
@@ -902,11 +919,31 @@ maybe_add_ibr_allowed(User, Host) ->
|
||||
landing_page(Host, Invite) ->
|
||||
mod_invites_http:landing_page(Host, Invite).
|
||||
|
||||
-spec db_call(binary(), atom(), list()) -> any().
|
||||
-spec db_call(binary(), atom(), [any()]) -> any().
|
||||
db_call(Host, Fun, Args) ->
|
||||
Mod = gen_mod:db_mod(Host, ?MODULE),
|
||||
apply(Mod, Fun, Args).
|
||||
|
||||
%% father forgive me
|
||||
lift({error, _R} = E) ->
|
||||
E;
|
||||
lift({ok, _V} = R) ->
|
||||
R;
|
||||
lift(Res) ->
|
||||
{ok, Res}.
|
||||
|
||||
-spec try_db_call(Host :: binary(), Fun :: atom(), Args :: [any()]) ->
|
||||
{ok, any()} | {error, any()}.
|
||||
try_db_call(Host, Fun, Args) ->
|
||||
try
|
||||
lift(db_call(Host, Fun, Args))
|
||||
catch
|
||||
error:({error, _Reason} = Error) ->
|
||||
Error;
|
||||
error:Error ->
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
-spec trans(binary(), binary()) -> binary().
|
||||
trans(Lang, Msg) ->
|
||||
translate:translate(Lang, Msg).
|
||||
@@ -1008,3 +1045,16 @@ send_presence(From, To, Type) ->
|
||||
to = To,
|
||||
type = Type},
|
||||
ejabberd_router:route(Presence).
|
||||
|
||||
pretty_format_command_result({error, {module_not_loaded, ?MODULE, Host}}) ->
|
||||
{error,
|
||||
lists:flatten(
|
||||
io_lib:format("Virtual host not known: ~s", [binary_to_list(Host)]))};
|
||||
pretty_format_command_result({error, host_unknown}) ->
|
||||
{error, "Virtual host not known"};
|
||||
pretty_format_command_result({error, user_exists}) ->
|
||||
{error, "Username already taken"};
|
||||
pretty_format_command_result({ok, Result}) ->
|
||||
Result;
|
||||
pretty_format_command_result(Result) ->
|
||||
Result.
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
-define(REGISTRATION, <<"registration">>).
|
||||
-define(STATIC_CTX, {static, <<"/", Base/binary, "/", ?STATIC/binary>>}).
|
||||
-define(SITE_NAME_CTX(Name), {site_name, Name}).
|
||||
-define(LANG(Lang), {lang, Lang}).
|
||||
|
||||
%% @format-begin
|
||||
|
||||
@@ -65,7 +66,7 @@ landing_page(Host, Invite) ->
|
||||
case mod_invites_opt:landing_page(Host) of
|
||||
none ->
|
||||
<<>>;
|
||||
<<"auto">> ->
|
||||
auto ->
|
||||
try ejabberd_http:get_auto_url(any, mod_invites) of
|
||||
AutoURL0 ->
|
||||
AutoURL = misc:expand_keyword(<<"@HOST@">>, AutoURL0, Host),
|
||||
@@ -167,7 +168,17 @@ process_register_form(Invite,
|
||||
end.
|
||||
|
||||
render_register_form(#request{host = Host, lang = Lang}, Ctx, AdditionalCtx) ->
|
||||
render(Host, Lang, <<"register.html">>, Ctx ++ AdditionalCtx).
|
||||
MinLength =
|
||||
case mod_register_opt:password_strength(Host) of
|
||||
0 ->
|
||||
0;
|
||||
_ ->
|
||||
6
|
||||
end,
|
||||
render(Host,
|
||||
Lang,
|
||||
<<"register.html">>,
|
||||
[{password_min_length, MinLength} | Ctx] ++ AdditionalCtx).
|
||||
|
||||
process_register_post(Invite,
|
||||
AppID,
|
||||
@@ -190,7 +201,11 @@ process_register_post(Invite,
|
||||
{ok, _UpdatedInvite} ->
|
||||
Ctx = [{username, Username}, {password, Password} | AppCtx],
|
||||
render_ok(Host, Lang, <<"register_success.html">>, Ctx);
|
||||
{error, #stanza_error{text = Text, type = Type} = Error} ->
|
||||
{error,
|
||||
#stanza_error{text = Text,
|
||||
type = Type,
|
||||
reason = Reason} =
|
||||
Error} ->
|
||||
?DEBUG("registration failed with error: ~p", [Error]),
|
||||
Msg = xmpp:get_text(Text, xmpp:prep_lang(Lang)),
|
||||
case Type of
|
||||
@@ -199,9 +214,9 @@ process_register_post(Invite,
|
||||
render_register_form(Request,
|
||||
AppCtx,
|
||||
[{username, Username},
|
||||
{message,
|
||||
{error,
|
||||
[{text, Msg},
|
||||
{class, <<"alert-warning">>}]}]),
|
||||
{class, error_class(Reason)}]}]),
|
||||
?BAD_REQUEST(Body);
|
||||
_ ->
|
||||
render_bad_request(Host,
|
||||
@@ -216,6 +231,17 @@ process_register_post(Invite,
|
||||
?BAD_REQUEST
|
||||
end.
|
||||
|
||||
error_class('jid-malformed') ->
|
||||
username;
|
||||
error_class('not-allowed') ->
|
||||
username;
|
||||
error_class(conflict) ->
|
||||
username;
|
||||
error_class('not-acceptable') ->
|
||||
password;
|
||||
error_class(_) ->
|
||||
undefined.
|
||||
|
||||
process_roster_token([_Token] = LocalPath,
|
||||
#request{host = Host, lang = Lang} = Request,
|
||||
Invite) ->
|
||||
@@ -255,12 +281,15 @@ app_ctx(Host, AppID, Lang, Ctx) ->
|
||||
throw(not_found)
|
||||
end.
|
||||
|
||||
ctx(#request{host = Host, path = Path}, LocalPath) ->
|
||||
ctx(#request{host = Host,
|
||||
path = Path,
|
||||
lang = Lang},
|
||||
LocalPath) ->
|
||||
Base =
|
||||
iolist_to_binary(uri_string:normalize(
|
||||
lists:join(<<"/">>, Path -- LocalPath))),
|
||||
SiteName = mod_invites_opt:site_name(Host),
|
||||
[?STATIC_CTX, ?SITE_NAME_CTX(SiteName)].
|
||||
[{base, Base}, ?STATIC_CTX, ?SITE_NAME_CTX(SiteName), ?LANG(Lang)].
|
||||
|
||||
ctx(Invite, #request{host = Host} = Request, LocalPath) ->
|
||||
[{invite, invite_to_proplist(Invite)},
|
||||
|
||||
@@ -23,7 +23,7 @@ db_type(Opts) when is_map(Opts) ->
|
||||
db_type(Host) ->
|
||||
gen_mod:get_module_opt(Host, mod_invites, db_type).
|
||||
|
||||
-spec landing_page(gen_mod:opts() | global | binary()) -> 'none' | binary().
|
||||
-spec landing_page(gen_mod:opts() | global | binary()) -> 'auto' | 'none' | binary().
|
||||
landing_page(Opts) when is_map(Opts) ->
|
||||
gen_mod:get_opt(landing_page, Opts);
|
||||
landing_page(Host) ->
|
||||
|
||||
@@ -213,6 +213,10 @@ try_register(Invite, User, Server, Password, Source, Lang) ->
|
||||
{error,
|
||||
xmpp:err_jid_malformed(
|
||||
mod_register:format_error(invalid_jid), Lang)};
|
||||
{_, false} ->
|
||||
{error,
|
||||
xmpp:err_not_allowed(
|
||||
mod_register:format_error(not_allowed), Lang)};
|
||||
{_, true} ->
|
||||
RegF =
|
||||
fun() ->
|
||||
|
||||
+19
-9
@@ -26,6 +26,7 @@
|
||||
-author('alexey@process-one.net').
|
||||
-protocol({xep, 45, '1.35.3', '0.5.0', "complete", ""}).
|
||||
-protocol({xep, 249, '1.2', '0.5.0', "complete", ""}).
|
||||
-protocol({xep, 421, '1.0.1', '23.10', "complete", ""}).
|
||||
-protocol({xep, 486, '0.1.0', '24.07', "complete", ""}).
|
||||
-ifndef(GEN_SERVER).
|
||||
-define(GEN_SERVER, gen_server).
|
||||
@@ -729,10 +730,6 @@ process_disco_info(#iq{type = get, from = From, to = To, lang = Lang,
|
||||
true -> [?NS_MAM_TMP, ?NS_MAM_0, ?NS_MAM_1, ?NS_MAM_2];
|
||||
false -> []
|
||||
end,
|
||||
OccupantIdFeatures = case gen_mod:is_loaded(ServerHost, mod_muc_occupantid) of
|
||||
true -> [?NS_OCCUPANT_ID];
|
||||
false -> []
|
||||
end,
|
||||
RSMFeatures = case RMod:rsm_supported() of
|
||||
true -> [?NS_RSM];
|
||||
false -> []
|
||||
@@ -743,8 +740,8 @@ process_disco_info(#iq{type = get, from = From, to = To, lang = Lang,
|
||||
end,
|
||||
Features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
|
||||
?NS_MUC, ?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE,
|
||||
?NS_MUC_STABLE_ID
|
||||
| RegisterFeatures ++ RSMFeatures ++ MAMFeatures ++ OccupantIdFeatures],
|
||||
?NS_MUC_STABLE_ID, ?NS_OCCUPANT_ID
|
||||
| RegisterFeatures ++ RSMFeatures ++ MAMFeatures],
|
||||
Name = mod_muc_opt:name(ServerHost),
|
||||
Identity = #identity{category = <<"conference">>,
|
||||
type = <<"text">>,
|
||||
@@ -1512,9 +1509,21 @@ mod_options(Host) ->
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
[?T("This module provides support for https://xmpp.org/extensions/xep-0045.html"
|
||||
"[XEP-0045: Multi-User Chat]. Users can discover existing rooms, "
|
||||
"join or create them. Occupants of a room can chat in public or have private chats."), "",
|
||||
[?T("This module provides support for "
|
||||
"https://xmpp.org/extensions/xep-0045.html[Multi-User Chat] (MUC). "
|
||||
"Users can discover existing rooms, join or create them. "
|
||||
"Occupants of a room can chat in public or have private chats."), "",
|
||||
?T("Protocols implemented in this module:"), "",
|
||||
"- https://xmpp.org/extensions/xep-0045.html"
|
||||
"[XEP-0045: Multi-User Chat]",
|
||||
"- https://xmpp.org/extensions/xep-0249.html"
|
||||
"[XEP-0249: Direct MUC Invitations]",
|
||||
"- https://xmpp.org/extensions/xep-0421.html"
|
||||
"[XEP-0421: Occupant identifiers for semi-anonymous MUCs]",
|
||||
"- https://xmpp.org/extensions/xep-0486.html"
|
||||
"[XEP-0486: MUC Avatars]",
|
||||
"- https://docs.ejabberd.im/developer/xmpp-clients-bots/extensions/muc-sub/"
|
||||
"[Muc/Sub: Multi-User Chat Subscriptions]", "",
|
||||
?T("The MUC service allows any Jabber ID to register a nickname, so "
|
||||
"nobody else can use that nickname in any room in the MUC "
|
||||
"service. To register a nickname, open the Service Discovery in "
|
||||
@@ -1531,6 +1540,7 @@ mod_doc() ->
|
||||
"are not clustered nor fault-tolerant: if the node managing a "
|
||||
"set of rooms goes down, the rooms disappear and they will be "
|
||||
"recreated on an available node on first connection attempt.")],
|
||||
note => "incorporated 'mod_muc_occupantid' in 26.02",
|
||||
opts =>
|
||||
[{access,
|
||||
#{value => ?T("AccessName"),
|
||||
|
||||
@@ -478,9 +478,11 @@ transform(#muc_room{opts = Opts} = R) ->
|
||||
Opts
|
||||
end,
|
||||
Opts4 =
|
||||
case lists:keyfind(hats_defs, 1, Opts2) of
|
||||
false ->
|
||||
{hats_users, HatsUsers} = lists:keyfind(hats_users, 1, Opts2),
|
||||
case {lists:keyfind(hats_defs, 1, Opts2),
|
||||
lists:keyfind(hats_users, 1, Opts2)} of
|
||||
{false, false} ->
|
||||
[{hats_defs, []}, {hats_users, []} | Opts2];
|
||||
{false, {hats_users, HatsUsers}} ->
|
||||
{HatsDefs, HatsUsers2} =
|
||||
lists:foldl(fun({Jid, UriTitleList}, {Defs, Assigns}) ->
|
||||
Defs2 =
|
||||
@@ -500,7 +502,7 @@ transform(#muc_room{opts = Opts} = R) ->
|
||||
Opts3 =
|
||||
lists:keyreplace(hats_users, 1, Opts2, {hats_users, maps:to_list(HatsUsers2)}),
|
||||
[{hats_defs, maps:to_list(HatsDefs)} | Opts3];
|
||||
{_, _} ->
|
||||
{{hats_defs, _}, {hats_users, _}} ->
|
||||
Opts2
|
||||
end,
|
||||
R#muc_room{opts = Opts4};
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_muc_occupantid.erl
|
||||
%%% Author : Badlop <badlop@process-one.net>
|
||||
%%% Purpose : Add Occupant Ids to stanzas in anonymous MUC rooms (XEP-0421)
|
||||
%%% Created :
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2026 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License along
|
||||
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(mod_muc_occupantid).
|
||||
|
||||
-author('badlop@process-one.net').
|
||||
|
||||
-protocol({xep, 421, '1.0.1', '23.10', "complete", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("translate.hrl").
|
||||
-include("mod_muc_room.hrl").
|
||||
|
||||
-export([start/2, stop/1,
|
||||
mod_options/1, mod_doc/0, depends/2]).
|
||||
-export([filter_packet/3, remove_room/3]).
|
||||
|
||||
%%%
|
||||
%%% gen_mod
|
||||
%%%
|
||||
|
||||
start(_Host, _Opts) ->
|
||||
create_table(),
|
||||
{ok, [{hook, muc_filter_presence, filter_packet, 10},
|
||||
{hook, muc_filter_message, filter_packet, 10},
|
||||
{hook, remove_room, remove_room, 50}]}.
|
||||
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
%%%
|
||||
%%% Hooks
|
||||
%%%
|
||||
|
||||
filter_packet(Packet, State, _Nick) ->
|
||||
add_occupantid_packet(Packet, State#state.jid).
|
||||
|
||||
remove_room(_LServer, _Name, Host) ->
|
||||
delete_salt(Host).
|
||||
|
||||
%%%
|
||||
%%% XEP-0421 Occupant-id
|
||||
%%%
|
||||
|
||||
add_occupantid_packet(Packet, RoomJid) ->
|
||||
From = xmpp:get_from(Packet),
|
||||
OccupantId = calculate_occupantid(From, RoomJid),
|
||||
OccupantElement = #occupant_id{id = OccupantId},
|
||||
xmpp:append_subtags(xmpp:remove_subtag(Packet, OccupantElement), [OccupantElement]).
|
||||
|
||||
calculate_occupantid(From, RoomJid) ->
|
||||
Term = {get_salt(RoomJid#jid.lserver), RoomJid, jid:remove_resource(From)},
|
||||
misc:term_to_base64(crypto:hash(sha256, io_lib:format("~p", [Term]))).
|
||||
|
||||
%%%
|
||||
%%% Table storing rooms' salt
|
||||
%%%
|
||||
|
||||
-record(muc_occupant_id, {service_jid, salt}).
|
||||
|
||||
create_table() ->
|
||||
ejabberd_mnesia:create(?MODULE, muc_occupant_id,
|
||||
[{ram_copies, [node()]},
|
||||
{local_content, true},
|
||||
{attributes, record_info(fields, muc_occupant_id)},
|
||||
{type, set}]).
|
||||
|
||||
|
||||
get_salt(ServiceJid) ->
|
||||
case mnesia:dirty_read(muc_occupant_id, ServiceJid) of
|
||||
[] ->
|
||||
Salt = p1_rand:get_string(),
|
||||
ok = write_salt(ServiceJid, Salt),
|
||||
Salt;
|
||||
[#muc_occupant_id{salt = Salt}] ->
|
||||
Salt
|
||||
end.
|
||||
|
||||
write_salt(ServiceJid, Salt) ->
|
||||
mnesia:dirty_write(#muc_occupant_id{service_jid = ServiceJid, salt = Salt}).
|
||||
|
||||
delete_salt(ServiceJid) ->
|
||||
mnesia:dirty_delete(muc_occupant_id, ServiceJid).
|
||||
|
||||
%%%
|
||||
%%% Doc
|
||||
%%%
|
||||
|
||||
mod_options(_Host) ->
|
||||
[].
|
||||
|
||||
mod_doc() ->
|
||||
#{desc =>
|
||||
[?T("This module implements "
|
||||
"https://xmpp.org/extensions/xep-0421.html"
|
||||
"[XEP-0421: Anonymous unique occupant identifiers for MUCs]."), "",
|
||||
?T("When the module is enabled, the feature is enabled "
|
||||
"in all semi-anonymous rooms.")],
|
||||
note => "added in 23.10"
|
||||
}.
|
||||
|
||||
depends(_, _) ->
|
||||
[{mod_muc, hard}].
|
||||
+61
-37
@@ -310,6 +310,7 @@ init([Host, ServerHost, Access, Room, HistorySize,
|
||||
history = lqueue_new(HistorySize, QueueType),
|
||||
jid = jid:make(Room, Host),
|
||||
just_created = true,
|
||||
salt = p1_rand:get_string(),
|
||||
room_queue = RoomQueue,
|
||||
room_shaper = Shaper}),
|
||||
State1 = set_affiliation(Creator, owner, State),
|
||||
@@ -334,6 +335,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts, QueueType])
|
||||
room = Room,
|
||||
history = lqueue_new(HistorySize, QueueType),
|
||||
jid = Jid,
|
||||
salt = p1_rand:get_string(),
|
||||
room_queue = RoomQueue,
|
||||
room_shaper = Shaper}),
|
||||
add_to_log(room_existence, started, State),
|
||||
@@ -638,11 +640,9 @@ normal_state({route, ToNick,
|
||||
FromNick),
|
||||
X = #muc_user{},
|
||||
Packet2 = xmpp:set_subtag(Packet, X),
|
||||
case ejabberd_hooks:run_fold(muc_filter_message,
|
||||
StateData#state.server_host,
|
||||
xmpp:put_meta(Packet2, mam_ignore, true),
|
||||
[StateData, FromNick]) of
|
||||
drop ->
|
||||
case filter_message_hook(StateData, FromNick,
|
||||
xmpp:put_meta(Packet2, mam_ignore, true)) of
|
||||
drop ->
|
||||
ok;
|
||||
Packet3 ->
|
||||
PrivMsg = xmpp:set_from(xmpp:del_meta(Packet3, mam_ignore), FromNickJID),
|
||||
@@ -1092,12 +1092,8 @@ process_groupchat_message(#message{from = From, lang = Lang} = Packet, StateData
|
||||
end,
|
||||
case IsAllowed of
|
||||
true ->
|
||||
case
|
||||
ejabberd_hooks:run_fold(muc_filter_message,
|
||||
StateData#state.server_host,
|
||||
Packet,
|
||||
[StateData, FromNick])
|
||||
of
|
||||
case filter_message_hook(StateData, FromNick,
|
||||
Packet) of
|
||||
drop ->
|
||||
{next_state, normal_state, StateData};
|
||||
NewPacket1 ->
|
||||
@@ -1401,10 +1397,7 @@ process_presence(Nick, #presence{from = From, type = Type0} = Packet0, StateData
|
||||
IsOnline = is_user_online(From, StateData),
|
||||
if Type0 == available;
|
||||
IsOnline and ((Type0 == unavailable) or (Type0 == error)) ->
|
||||
case ejabberd_hooks:run_fold(muc_filter_presence,
|
||||
StateData#state.server_host,
|
||||
Packet0,
|
||||
[StateData, Nick]) of
|
||||
case filter_presence_hook(StateData, Nick, Packet0) of
|
||||
drop ->
|
||||
{next_state, normal_state, StateData};
|
||||
#presence{} = Packet ->
|
||||
@@ -1561,7 +1554,8 @@ get_users_and_subscribers_aux(Subscribers, StateData) ->
|
||||
#user{jid = jid:make(LBareJID),
|
||||
nick = Nick,
|
||||
role = none,
|
||||
last_presence = undefined},
|
||||
last_presence = undefined,
|
||||
occupant_id = <<>>},
|
||||
Acc);
|
||||
true ->
|
||||
Acc
|
||||
@@ -2130,10 +2124,44 @@ set_subscriber(JID, Nick, Nodes,
|
||||
end,
|
||||
NewStateData.
|
||||
|
||||
-spec calculate_occupant_id(jid(), state()) -> binary().
|
||||
calculate_occupant_id(Jid, #state{salt = Salt, jid = RoomJid}) ->
|
||||
JidS = jid:encode(jid:remove_resource(Jid)),
|
||||
RoomJidS = jid:encode(RoomJid),
|
||||
Term = <<Salt/binary, ":", RoomJidS/binary, ":", JidS/binary>>,
|
||||
misc:term_to_base64(crypto:hash(sha256, Term)).
|
||||
|
||||
-spec filter_message_hook(state(), binary(), #message{}) -> drop | #message{}.
|
||||
filter_message_hook(#state{users = Users} = StateData, Nick, #message{from = From} = Message) ->
|
||||
OccupantId = case maps:find(jid:tolower(From), Users) of
|
||||
{ok, #user{occupant_id = Id}} -> Id;
|
||||
_ -> calculate_occupant_id(From, StateData)
|
||||
end,
|
||||
Message2 = xmpp:append_subtags(xmpp:remove_subtag(Message, #occupant_id{}),
|
||||
[#occupant_id{id = OccupantId}]),
|
||||
ejabberd_hooks:run_fold(muc_filter_message,
|
||||
StateData#state.server_host,
|
||||
Message2,
|
||||
[StateData, Nick]).
|
||||
|
||||
-spec filter_presence_hook(state(), binary(), #presence{}) -> drop | #presence{}.
|
||||
filter_presence_hook(#state{users = Users} = StateData, Nick, #presence{from = From} = Pres) ->
|
||||
OccupantId = case maps:find(jid:tolower(From), Users) of
|
||||
{ok, #user{occupant_id = Id}} -> Id;
|
||||
_ -> calculate_occupant_id(From, StateData)
|
||||
end,
|
||||
Pres2 = xmpp:append_subtags(xmpp:remove_subtag(Pres, #occupant_id{}),
|
||||
[#occupant_id{id = OccupantId}]),
|
||||
ejabberd_hooks:run_fold(muc_filter_message,
|
||||
StateData#state.server_host,
|
||||
Pres2,
|
||||
[StateData, Nick]).
|
||||
|
||||
|
||||
-spec add_online_user(jid(), binary(), role(), state()) -> state().
|
||||
add_online_user(JID, Nick, Role, StateData) ->
|
||||
tab_add_online_user(JID, StateData),
|
||||
User = #user{jid = JID, nick = Nick, role = Role},
|
||||
User = #user{jid = JID, nick = Nick, role = Role, occupant_id = calculate_occupant_id(JID, StateData)},
|
||||
reset_hibernate_timer(update_online_user(JID, User, StateData)).
|
||||
|
||||
-spec remove_online_user(jid(), state()) -> state().
|
||||
@@ -3043,10 +3071,8 @@ send_subject(JID, #state{subject_author = {Nick, AuthorJID}} = StateData) ->
|
||||
end,
|
||||
Packet = #message{from = AuthorJID,
|
||||
to = JID, type = groupchat, subject = Subject},
|
||||
case ejabberd_hooks:run_fold(muc_filter_message,
|
||||
StateData#state.server_host,
|
||||
xmpp:put_meta(Packet, mam_ignore, true),
|
||||
[StateData, Nick]) of
|
||||
case filter_message_hook(StateData, Nick,
|
||||
xmpp:put_meta(Packet, mam_ignore, true)) of
|
||||
drop ->
|
||||
ok;
|
||||
NewPacket1 ->
|
||||
@@ -4271,6 +4297,8 @@ set_opts2([{Opt, Val} | Opts], StateData) ->
|
||||
hats_users ->
|
||||
StateData#state{hats_users = maps:from_list(Val)};
|
||||
hibernation_time -> StateData;
|
||||
salt ->
|
||||
StateData#state{salt = Val};
|
||||
Other ->
|
||||
?INFO_MSG("Unknown MUC room option, will be discarded: ~p", [Other]),
|
||||
StateData
|
||||
@@ -4353,6 +4381,7 @@ make_opts(StateData, Hibernation) ->
|
||||
{hats_defs, maps:to_list(StateData#state.hats_defs)},
|
||||
{hats_users, maps:to_list(StateData#state.hats_users)},
|
||||
{hibernation_time, if Hibernation -> erlang:system_time(microsecond); true -> undefined end},
|
||||
{salt, StateData#state.salt},
|
||||
{subscribers, Subscribers}].
|
||||
|
||||
expand_opts(CompactOpts) ->
|
||||
@@ -4377,14 +4406,16 @@ expand_opts(CompactOpts) ->
|
||||
Subject = proplists:get_value(subject, CompactOpts, <<"">>),
|
||||
Subscribers = proplists:get_value(subscribers, CompactOpts, []),
|
||||
HibernationTime = proplists:get_value(hibernation_time, CompactOpts, 0),
|
||||
Salt = proplists:get_value(hibernation_time, CompactOpts, <<>>),
|
||||
[{subject, Subject},
|
||||
{subject_author, SubjectAuthor},
|
||||
{subscribers, Subscribers},
|
||||
{hibernation_time, HibernationTime}
|
||||
{hibernation_time, HibernationTime},
|
||||
{salt, Salt}
|
||||
| lists:reverse(Opts1)].
|
||||
|
||||
config_fields() ->
|
||||
[subject, subject_author, subscribers, hibernate_time | record_info(fields, config)].
|
||||
[subject, subject_author, subscribers, hibernate_time, salt | record_info(fields, config)].
|
||||
|
||||
-spec destroy_room(muc_destroy(), state()) -> {result, undefined, stop}.
|
||||
destroy_room(DEl, StateData) ->
|
||||
@@ -4447,7 +4478,7 @@ make_disco_info(From, StateData) ->
|
||||
?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
|
||||
?NS_COMMANDS,
|
||||
?NS_MESSAGE_MODERATE_0, ?NS_MESSAGE_MODERATE_1,
|
||||
?NS_MESSAGE_RETRACT,
|
||||
?NS_MESSAGE_RETRACT, ?NS_OCCUPANT_ID,
|
||||
?CONFIG_OPT_TO_FEATURE((Config#config.public),
|
||||
<<"muc_public">>, <<"muc_hidden">>),
|
||||
?CONFIG_OPT_TO_FEATURE((Config#config.persistent),
|
||||
@@ -4472,12 +4503,6 @@ make_disco_info(From, StateData) ->
|
||||
true -> [?NS_HATS];
|
||||
false -> []
|
||||
end
|
||||
++ case gen_mod:is_loaded(StateData#state.server_host, mod_muc_occupantid) of
|
||||
true ->
|
||||
[?NS_OCCUPANT_ID];
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
++ case {gen_mod:is_loaded(StateData#state.server_host, mod_mam),
|
||||
Config#config.mam} of
|
||||
{true, true} ->
|
||||
@@ -5370,9 +5395,10 @@ add_presence_hats(JID, Pres, StateData) ->
|
||||
false ->
|
||||
false;
|
||||
{URI, Title, Hue} ->
|
||||
#muc_hat{uri = URI,
|
||||
title = Title,
|
||||
hue = Hue}
|
||||
{true,
|
||||
#muc_hat{uri = URI,
|
||||
title = Title,
|
||||
hue = Hue}}
|
||||
end
|
||||
end,
|
||||
UserHats),
|
||||
@@ -5423,10 +5449,8 @@ process_iq_moderate(From, #iq{type = set, lang = Lang}, Id, Reason,
|
||||
from = From,
|
||||
sub_els = SubEl},
|
||||
{FromNick, _Role} = get_participant_data(From, StateData),
|
||||
Packet = ejabberd_hooks:run_fold(muc_filter_message,
|
||||
StateData#state.server_host,
|
||||
xmpp:put_meta(Packet0, mam_ignore, true),
|
||||
[StateData, FromNick]),
|
||||
Packet = filter_message_hook(StateData, FromNick,
|
||||
xmpp:put_meta(Packet0, mam_ignore, true)),
|
||||
send_wrapped_multiple(JID,
|
||||
get_users_and_subscribers_with_node(?NS_MUCSUB_NODES_MESSAGES, StateData),
|
||||
Packet, ?NS_MUCSUB_NODES_MESSAGES, StateData),
|
||||
|
||||
@@ -135,7 +135,7 @@ handle_call(_Request, _From, State) ->
|
||||
handle_info({iq_reply, IQReply, {LServer, RServer}}, #state{monitors = Mons} = State) ->
|
||||
case IQReply of
|
||||
#iq{type = result, sub_els = [El]} ->
|
||||
case xmpp:decode(El) of
|
||||
try xmpp:decode(El) of
|
||||
#disco_info{features = Features} ->
|
||||
case lists:member(?NS_URN_SERVERINFO, Features) of
|
||||
true ->
|
||||
@@ -156,6 +156,9 @@ handle_info({iq_reply, IQReply, {LServer, RServer}}, #state{monitors = Mons} = S
|
||||
end;
|
||||
_ ->
|
||||
{noreply, State}
|
||||
catch
|
||||
_:{xmpp_codec, _Reason} ->
|
||||
{noreply, State}
|
||||
end;
|
||||
_ ->
|
||||
{noreply, State}
|
||||
|
||||
@@ -638,8 +638,9 @@ mod_doc() ->
|
||||
"important to include the last / character in the URL, "
|
||||
"otherwise the subpages URL will be incorrect."), "",
|
||||
?T("This module is enabled in 'listen' -> 'ejabberd_http' -> "
|
||||
"_`listen-options.md#request_handlers|request_handlers`_, "
|
||||
"no need to enable in 'modules'."),
|
||||
"_`listen-options.md#request_handlers|request_handlers`_."), "",
|
||||
?T("There is no need to enable this module in 'modules', "
|
||||
"but it adds a link to the register page in WebAdmin menu."),
|
||||
?T("The module depends on _`mod_register`_ where all the "
|
||||
"configuration is performed.")],
|
||||
example =>
|
||||
|
||||
@@ -25,7 +25,6 @@ define_macro:
|
||||
mod_muc:
|
||||
db_type: internal
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_offline:
|
||||
db_type: internal
|
||||
mod_privacy:
|
||||
|
||||
@@ -25,7 +25,6 @@ define_macro:
|
||||
db_type: sql
|
||||
ram_db_type: sql
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_offline:
|
||||
use_cache: true
|
||||
db_type: sql
|
||||
|
||||
@@ -25,7 +25,6 @@ define_macro:
|
||||
db_type: sql
|
||||
ram_db_type: sql
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_offline:
|
||||
use_cache: true
|
||||
db_type: sql
|
||||
|
||||
@@ -25,7 +25,6 @@ define_macro:
|
||||
db_type: sql
|
||||
ram_db_type: sql
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_offline:
|
||||
use_cache: true
|
||||
db_type: sql
|
||||
|
||||
@@ -26,7 +26,6 @@ define_macro:
|
||||
mod_muc:
|
||||
db_type: internal
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_offline:
|
||||
db_type: internal
|
||||
mod_privacy:
|
||||
|
||||
@@ -23,7 +23,6 @@ define_macro:
|
||||
db_type: sql
|
||||
ram_db_type: sql
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_offline:
|
||||
db_type: sql
|
||||
mod_privacy:
|
||||
|
||||
@@ -126,7 +126,6 @@ modules:
|
||||
vcard: VCARD
|
||||
mod_muc:
|
||||
vcard: VCARD
|
||||
mod_muc_occupantid: []
|
||||
mod_muc_admin: []
|
||||
mod_carboncopy: []
|
||||
mod_jidprep: []
|
||||
|
||||
+76
-2
@@ -153,7 +153,7 @@ service_features(Config) ->
|
||||
RequiredFeatures = sets:from_list(
|
||||
[?NS_DISCO_INFO, ?NS_DISCO_ITEMS,
|
||||
?NS_REGISTER, ?NS_MUC,
|
||||
?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE
|
||||
?NS_VCARD, ?NS_MUCSUB, ?NS_MUC_UNIQUE, ?NS_OCCUPANT_ID
|
||||
| MAMFeatures]),
|
||||
ct:comment("Checking if all needed disco features are set"),
|
||||
true = sets:is_subset(RequiredFeatures, Features),
|
||||
@@ -305,15 +305,84 @@ master_slave_cases() ->
|
||||
master_slave_test(config_voice_request_interval),
|
||||
master_slave_test(config_visitor_nickchange),
|
||||
master_slave_test(join_conflict),
|
||||
master_slave_test(duplicate_occupantid)
|
||||
master_slave_test(duplicate_occupantid),
|
||||
master_slave_test(hats)
|
||||
]}.
|
||||
|
||||
hats_master(Config) ->
|
||||
Room = muc_room_jid(Config),
|
||||
PeerJID = ?config(slave, Config),
|
||||
PeerNick = ?config(slave_nick, Config),
|
||||
PeerNickJID = jid:replace_resource(Room, PeerNick),
|
||||
ok = master_join(Config),
|
||||
CommandCreate =
|
||||
#adhoc_command{action = complete, node = <<"urn:xmpp:hats:commands:create">>, xdata = #xdata{
|
||||
type = form, fields = [
|
||||
#xdata_field{var = <<"FORM_TYPE">>, values = [<<"urn:xmpp:hats:commands">>]},
|
||||
#xdata_field{var = <<"hats#title">>, values = [<<"Test">>]},
|
||||
#xdata_field{var = <<"hats#uri">>, values = [<<"https://example.com/Test">>]},
|
||||
#xdata_field{var = <<"hats#hue">>, values = [<<"100">>]}
|
||||
]}},
|
||||
#iq{type = result,
|
||||
sub_els =
|
||||
[#adhoc_command{status = completed}]} =
|
||||
send_recv(Config,
|
||||
#iq{type = set,
|
||||
to = Room,
|
||||
sub_els = [CommandCreate]}),
|
||||
[104] = recv_only_config_change_message(Config),
|
||||
put_event(Config, post_hat_setup),
|
||||
post_hat_setup = get_event(Config),
|
||||
CommandAssign =
|
||||
#adhoc_command{action = complete, node = <<"urn:xmpp:hats:commands:assign">>, xdata = #xdata{
|
||||
type = form, fields = [
|
||||
#xdata_field{var = <<"FORM_TYPE">>, values = [<<"urn:xmpp:hats:commands">>]},
|
||||
#xdata_field{var = <<"hats#jid">>, values = [jid:encode(PeerJID)]},
|
||||
#xdata_field{var = <<"hat">>, values = [<<"https://example.com/Test">>]}
|
||||
]}},
|
||||
#iq{type = result,
|
||||
sub_els =
|
||||
[#adhoc_command{status = completed}]} =
|
||||
send_recv(Config,
|
||||
#iq{type = set,
|
||||
to = Room,
|
||||
sub_els = [CommandAssign]}),
|
||||
#presence{from = PeerNickJID} = PresHat = recv_presence(Config),
|
||||
?match(#muc_hats{hats = [#muc_hat{title = <<"Test">>,
|
||||
uri = <<"https://example.com/Test">>,
|
||||
hue = <<"100">>}]},
|
||||
xmpp:get_subtag(PresHat, #muc_hats{})),
|
||||
put_event(Config, post_hat_assign),
|
||||
post_hat_assign = get_event(Config),
|
||||
recv_muc_presence(Config, PeerNickJID, unavailable),
|
||||
ok = leave(Config),
|
||||
disconnect(Config).
|
||||
|
||||
hats_slave(Config) ->
|
||||
Room = muc_room_jid(Config),
|
||||
MyNick = ?config(nick, Config),
|
||||
MyNickJID = jid:replace_resource(Room, MyNick),
|
||||
{[], _, _} = slave_join(Config),
|
||||
[104] = recv_only_config_change_message(Config),
|
||||
post_hat_setup = get_event(Config),
|
||||
put_event(Config, post_hat_setup),
|
||||
#presence{from = MyNickJID} = PresHat = recv_presence(Config),
|
||||
?match(#muc_hats{hats = [#muc_hat{title = <<"Test">>,
|
||||
uri = <<"https://example.com/Test">>,
|
||||
hue = <<"100">>}]},
|
||||
xmpp:get_subtag(PresHat, #muc_hats{})),
|
||||
post_hat_assign = get_event(Config),
|
||||
put_event(Config, post_hat_assign),
|
||||
ok = leave(Config),
|
||||
disconnect(Config).
|
||||
|
||||
duplicate_occupantid_master(Config) ->
|
||||
Room = muc_room_jid(Config),
|
||||
PeerJID = ?config(slave, Config),
|
||||
PeerNick = ?config(slave_nick, Config),
|
||||
PeerNickJID = jid:replace_resource(Room, PeerNick),
|
||||
ok = join_new(Config),
|
||||
?match(true, lists:member(?NS_OCCUPANT_ID, get_features(Config, Room))),
|
||||
wait_for_slave(Config),
|
||||
Pres = ?match(#presence{from = PeerNickJID, type = available} = Pres,
|
||||
recv_presence(Config), Pres),
|
||||
@@ -1950,6 +2019,11 @@ recv_config_change_message(Config) ->
|
||||
ct:comment("Receiving configuration change notification message"),
|
||||
Room = muc_room_jid(Config),
|
||||
#presence{from = Room, type = available} = recv_presence(Config),
|
||||
recv_only_config_change_message(Config).
|
||||
|
||||
recv_only_config_change_message(Config) ->
|
||||
ct:comment("Receiving configuration change notification message"),
|
||||
Room = muc_room_jid(Config),
|
||||
#message{type = groupchat, from = Room} = Msg = recv_message(Config),
|
||||
#muc_user{status_codes = Codes} = xmpp:get_subtag(Msg, #muc_user{}),
|
||||
lists:sort(Codes).
|
||||
|
||||
+2
-2
@@ -67,10 +67,10 @@ rel_vsn=$(git describe --tags | sed -e 's/-g.*//' -e 's/-/./' | tr -d '[:space:]
|
||||
mix_vsn=$(mix_version "$rel_vsn")
|
||||
crosstool_vsn='1.27.0'
|
||||
termcap_vsn='1.3.1'
|
||||
expat_vsn='2.7.3'
|
||||
expat_vsn='2.7.4'
|
||||
zlib_vsn='1.3.1'
|
||||
yaml_vsn='0.2.5'
|
||||
ssl_vsn='3.5.4'
|
||||
ssl_vsn='3.5.5'
|
||||
otp_vsn='28.3.1'
|
||||
elixir_vsn='1.19.5'
|
||||
pam_vsn='1.6.1' # Newer Linux-PAM versions use Meson, we don't support that yet.
|
||||
|
||||
@@ -594,6 +594,8 @@ is_behaviour(AbsCode, Mod) ->
|
||||
true;
|
||||
{attribute, {behaviour, Mod}} ->
|
||||
true;
|
||||
{attribute, {behavior, Mod}} ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user