aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in3
-rw-r--r--configure.ac9
-rw-r--r--ejabberd.service.template1
-rw-r--r--ejabberd.yml.example80
-rw-r--r--include/ejabberd_auth.hrl22
-rw-r--r--include/ejabberd_sql_pt.hrl3
-rw-r--r--include/mod_push.hrl24
-rw-r--r--mix.exs13
-rw-r--r--priv/msgs/ca.po632
-rw-r--r--priv/msgs/el.po774
-rw-r--r--priv/msgs/gl.po290
-rw-r--r--priv/msgs/he.po520
-rw-r--r--priv/msgs/zh.po260
-rw-r--r--rebar.config6
-rw-r--r--rebar.config.script21
-rw-r--r--sql/lite.sql25
-rw-r--r--sql/mssql.sql28
-rw-r--r--sql/mysql.sql23
-rw-r--r--sql/pg.new.sql604
-rw-r--r--sql/pg.sql25
-rw-r--r--src/ejabberd.erl28
-rw-r--r--src/ejabberd_auth.erl9
-rw-r--r--src/ejabberd_auth_mnesia.erl30
-rw-r--r--src/ejabberd_auth_riak.erl13
-rw-r--r--src/ejabberd_auth_sql.erl81
-rw-r--r--src/ejabberd_c2s.erl26
-rw-r--r--src/ejabberd_config.erl7
-rw-r--r--src/ejabberd_http.erl13
-rw-r--r--src/ejabberd_pkix.erl390
-rw-r--r--src/ejabberd_redis.erl2
-rw-r--r--src/ejabberd_s2s.erl27
-rw-r--r--src/ejabberd_s2s_in.erl4
-rw-r--r--src/ejabberd_sm_sql.erl6
-rw-r--r--src/ejabberd_sql_pt.erl209
-rw-r--r--src/ejd2sql.erl15
-rw-r--r--src/mod_admin_update_sql.erl365
-rw-r--r--src/mod_announce_sql.erl27
-rw-r--r--src/mod_carboncopy_sql.erl5
-rw-r--r--src/mod_irc_sql.erl14
-rw-r--r--src/mod_last_sql.erl14
-rw-r--r--src/mod_mam_mnesia.erl4
-rw-r--r--src/mod_mam_sql.erl119
-rw-r--r--src/mod_muc.erl37
-rw-r--r--src/mod_muc_mnesia.erl10
-rw-r--r--src/mod_muc_riak.erl10
-rw-r--r--src/mod_muc_room.erl72
-rw-r--r--src/mod_muc_sql.erl132
-rw-r--r--src/mod_offline_sql.erl39
-rw-r--r--src/mod_privacy_sql.erl83
-rw-r--r--src/mod_private_sql.erl20
-rw-r--r--src/mod_pubsub.erl53
-rw-r--r--src/mod_push.erl99
-rw-r--r--src/mod_push_mnesia.erl77
-rw-r--r--src/mod_push_sql.erl233
-rw-r--r--src/mod_roster.erl8
-rw-r--r--src/mod_roster_sql.erl115
-rw-r--r--src/mod_s2s_dialback.erl8
-rw-r--r--src/mod_shared_roster_sql.erl53
-rw-r--r--src/mod_stream_mgmt.erl2
-rw-r--r--src/mod_vcard_sql.erl91
-rw-r--r--src/node_flat.erl24
-rw-r--r--src/nodetree_tree_sql.erl2
-rw-r--r--src/xmpp_stream_in.erl10
-rw-r--r--src/xmpp_stream_out.erl151
-rw-r--r--test/ejabberd_SUITE.erl4
-rw-r--r--test/ejabberd_SUITE_data/ejabberd.yml15
-rw-r--r--test/pubsub_tests.erl4
-rw-r--r--vars.config.in1
68 files changed, 4134 insertions, 1990 deletions
diff --git a/Makefile.in b/Makefile.in
index 0edd8c844..86d4ca6d1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -93,6 +93,7 @@ deps: deps/.got
deps/.got:
rm -rf deps/.got
rm -rf deps/.built
+ mkdir deps
$(REBAR) get-deps && :> deps/.got
deps/.built: deps/.got
@@ -132,7 +133,7 @@ FILES_WILDCARD=$(call FILTER_DIRS,$(foreach w,$(1),$(wildcard $(w))))
ifeq ($(MAKECMDGOALS),copy-files-sub)
-DEPS:=$(sort $(shell $(REBAR) -q list-deps|$(SED) -e '/[a-z0-9_-]+\s/d;s/ .*//'))
+DEPS:=$(sort $(shell $(REBAR) -q list-deps|$(SED) -ne '/^[a-zA-Z0-9_-]\{1,\} \(TAG\|REV\)/s/^\([^ ]*\).*/\1/p'))
DEPS_FILES=$(call FILES_WILDCARD,$(foreach DEP,$(DEPS),deps/$(DEP)/ebin/*.beam deps/$(DEP)/ebin/*.app deps/$(DEP)/priv/* deps/$(DEP)/priv/lib/* deps/$(DEP)/priv/bin/* deps/$(DEP)/include/*.hrl deps/$(DEP)/COPY* deps/$(DEP)/LICENSE* deps/$(DEP)/lib/*/ebin/*.beam deps/$(DEP)/lib/*/ebin/*.app))
DEPS_FILES_FILTERED=$(filter-out %/epam %/eimp deps/elixir/ebin/elixir.app,$(DEPS_FILES))
diff --git a/configure.ac b/configure.ac
index 1fdf30293..17d32ac18 100644
--- a/configure.ac
+++ b/configure.ac
@@ -84,6 +84,14 @@ AC_ARG_ENABLE(roster_gateway_workaround,
*) AC_MSG_ERROR(bad value ${enableval} for --enable-roster-gateway-workaround) ;;
esac],[roster_gateway_workaround=false])
+AC_ARG_ENABLE(new_sql_schema,
+[AC_HELP_STRING([--enable-new-sql-schema], [use new SQL schema (default: no)])],
+[case "${enableval}" in
+ yes) new_sql_schema=true ;;
+ no) new_sql_schema=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-new-sql-schema) ;;
+esac],[new_sql_schema=false])
+
AC_ARG_ENABLE(full_xml,
[AC_HELP_STRING([--enable-full-xml], [use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)])],
[case "${enableval}" in
@@ -273,6 +281,7 @@ fi
AC_SUBST(hipe)
AC_SUBST(roster_gateway_workaround)
+AC_SUBST(new_sql_schema)
AC_SUBST(full_xml)
AC_SUBST(db_type)
AC_SUBST(odbc)
diff --git a/ejabberd.service.template b/ejabberd.service.template
index 542f57a3d..63100cb5e 100644
--- a/ejabberd.service.template
+++ b/ejabberd.service.template
@@ -13,7 +13,6 @@ ExecStart=/bin/sh -c '@ctlscriptpath@/ejabberdctl start && @ctlscriptpath@/ejabb
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
PrivateDevices=true
-ProtectSystem=full
[Install]
WantedBy=multi-user.target
diff --git a/ejabberd.yml.example b/ejabberd.yml.example
index 99892823b..ffc6a26c7 100644
--- a/ejabberd.yml.example
+++ b/ejabberd.yml.example
@@ -88,7 +88,7 @@ log_rate_limit: 100
##
## hosts: Domains served by ejabberd.
## You can define one or several, for example:
-## hosts:
+## hosts:
## - "example.net"
## - "example.com"
## - "example.org"
@@ -108,7 +108,6 @@ hosts:
## Define common macros used by listeners
## define_macro:
-## 'CERTFILE': "/path/to/xmpp.pem"
## 'CIPHERS': "ECDH:DH:!3DES:!aNULL:!eNULL:!MEDIUM@STRENGTH"
## 'TLSOPTS':
## - "no_sslv2"
@@ -123,18 +122,16 @@ hosts:
## listen: The ports ejabberd will listen on, which service each is handled
## by and what options to start it with.
##
-listen:
- -
+listen:
+ -
port: 5222
ip: "::"
module: ejabberd_c2s
##
## If TLS is compiled in and you installed a SSL
- ## certificate, specify the full path to the
- ## file and uncomment these lines:
+ ## certificate, uncomment these lines:
##
## starttls: true
- ## certfile: 'CERTFILE'
## protocol_options: 'TLSOPTS'
## dhfile: 'DHFILE'
## ciphers: 'CIPHERS'
@@ -151,11 +148,11 @@ listen:
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s
- -
+ -
port: 5269
ip: "::"
module: ejabberd_s2s_in
- -
+ -
port: 5280
ip: "::"
module: ejabberd_http
@@ -170,14 +167,14 @@ listen:
##
## ejabberd_service: Interact with external components (transports, ...)
##
- ## -
+ ## -
## port: 8888
## ip: "::"
## module: ejabberd_service
## access: all
## shaper_rule: fast
## ip: "127.0.0.1"
- ## privilege_access:
+ ## privilege_access:
## roster: "both"
## message: "outgoing"
## presence: "roster"
@@ -195,7 +192,7 @@ listen:
##
## ejabberd_stun: Handles STUN Binding requests
##
- ## -
+ ## -
## port: 3478
## transport: udp
## module: ejabberd_stun
@@ -203,7 +200,7 @@ listen:
##
## To handle XML-RPC requests that provide admin credentials:
##
- ## -
+ ## -
## port: 4560
## ip: "::"
## module: ejabberd_xmlrpc
@@ -212,14 +209,14 @@ listen:
##
## To enable secure http upload
##
- ## -
+ ## -
## port: 5444
## ip: "::"
## module: ejabberd_http
## request_handlers:
## "": mod_http_upload
## tls: true
- ## certfile: 'CERTFILE'
+ ## certfile: "/path/to/xmpp.pem"
## protocol_options: 'TLSOPTS'
## dhfile: 'DHFILE'
## ciphers: 'CIPHERS'
@@ -228,35 +225,32 @@ listen:
## password storage (see auth_password_format option).
## disable_sasl_mechanisms: "digest-md5"
+###. ============
+###' Certificates
+
+## List all available PEM files containing certificates for your domains,
+## chains of certificates or certificate keys. Full chains will be built
+## automatically by ejabberd.
+##
+## certfiles:
+## - "/etc/letsencrypt/live/example.org/*.pem"
+## - "/etc/letsencrypt/live/example.com/*.pem"
+
###. ==================
###' S2S GLOBAL OPTIONS
##
## s2s_use_starttls: Enable STARTTLS for S2S connections.
## Allowed values are: false, optional or required
-## You must specify a certificate file.
+## You must specify 'certfiles' option
##
## s2s_use_starttls: required
-##
-## s2s_certfile: Specify a certificate file.
-##
-## s2s_certfile: 'CERTFILE'
-
## Custom OpenSSL options
##
## s2s_protocol_options: 'TLSOPTS'
##
-## domain_certfile: Specify a different certificate for each served hostname.
-##
-## host_config:
-## "example.org":
-## domain_certfile: "/path/to/example_org.pem"
-## "example.com":
-## domain_certfile: "/path/to/example_com.pem"
-
-##
## S2S whitelist or blacklist
##
## Default s2s policy for undefined hosts.
@@ -444,7 +438,7 @@ shaper:
## This option specifies the maximum number of elements in the queue
## of the FSM. Refer to the documentation for details.
##
-max_fsm_queue: 1000
+max_fsm_queue: 10000
###. ====================
###' ACCESS CONTROL LISTS
@@ -467,7 +461,7 @@ acl:
## Local users: don't modify this.
##
- local:
+ local:
user_regexp: ""
##
@@ -541,24 +535,24 @@ access_rules:
announce:
- allow: admin
## Only admins can use the configuration interface:
- configure:
+ configure:
- allow: admin
## Only accounts of the local ejabberd server can create rooms:
- muc_create:
+ muc_create:
- allow: local
## Only accounts on the local ejabberd server can create Pubsub nodes:
- pubsub_createnode:
+ pubsub_createnode:
- allow: local
## In-band registration allows registration of any possible username.
## To disable in-band registration, replace 'allow' with 'deny'.
- register:
+ register:
- allow
## Only allow to register from localhost
- trusted_network:
+ trusted_network:
- allow: loopback
## Do not establish S2S connections with bad servers
## If you enable this you also have to uncomment "s2s_access: s2s"
- ## s2s:
+ ## s2s:
## - deny:
## - ip: "XXX.XXX.XXX.XXX/32"
## - deny:
@@ -667,7 +661,7 @@ language: "en"
##
## Modules enabled in all ejabberd virtual hosts.
##
-modules:
+modules:
mod_adhoc: {}
mod_admin_extra: {}
mod_announce: # recommends mod_adhoc
@@ -696,7 +690,7 @@ modules:
## You might want to setup a SQL backend for MAM because the mnesia database is
## limited to 2GB which might be exceeded on large servers
## mod_mam: {} # for xep0313, mnesia is limited to 2GB, better use an SQL backend
- mod_muc:
+ mod_muc:
## host: "conference.@HOST@"
access:
- allow
@@ -707,7 +701,7 @@ modules:
mod_muc_admin: {}
## mod_muc_log: {}
## mod_multicast: {}
- mod_offline:
+ mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
## mod_pres_counter:
@@ -716,14 +710,14 @@ modules:
mod_privacy: {}
mod_private: {}
## mod_proxy65: {}
- mod_pubsub:
+ mod_pubsub:
access_createnode: pubsub_createnode
## reduces resource comsumption, but XEP incompliant
ignore_pep_from_offline: true
## XEP compliant, but increases resource comsumption
## ignore_pep_from_offline: false
last_item_cache: false
- plugins:
+ plugins:
- "flat"
- "hometree"
- "pep" # pep requires mod_caps
diff --git a/include/ejabberd_auth.hrl b/include/ejabberd_auth.hrl
new file mode 100644
index 000000000..48fa785e3
--- /dev/null
+++ b/include/ejabberd_auth.hrl
@@ -0,0 +1,22 @@
+%%%----------------------------------------------------------------------
+%%%
+%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
+
+-record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1',
+ password = <<"">> :: binary() | scram() | '_'}).
diff --git a/include/ejabberd_sql_pt.hrl b/include/ejabberd_sql_pt.hrl
index 8e5e5c38c..438a6563d 100644
--- a/include/ejabberd_sql_pt.hrl
+++ b/include/ejabberd_sql_pt.hrl
@@ -27,6 +27,9 @@
-define(SQL_UPSERT_T(Table, Fields),
ejabberd_sql:sql_query_t(?SQL_UPSERT_MARK(Table, Fields))).
+-define(SQL_INSERT_MARK, sql_insert__mark_).
+-define(SQL_INSERT(Table, Fields), ?SQL_INSERT_MARK(Table, Fields)).
+
-record(sql_query, {hash, format_query, format_res, args, loc}).
-record(sql_escape, {string, integer, boolean}).
diff --git a/include/mod_push.hrl b/include/mod_push.hrl
new file mode 100644
index 000000000..9ca6af05d
--- /dev/null
+++ b/include/mod_push.hrl
@@ -0,0 +1,24 @@
+%%%----------------------------------------------------------------------
+%%% ejabberd, Copyright (C) 2017 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
+-record(push_session,
+ {us = {<<"">>, <<"">>} :: {binary(), binary()},
+ timestamp = p1_time_compat:timestamp() :: erlang:timestamp(),
+ service = {<<"">>, <<"">>, <<"">>} :: ljid(),
+ node = <<"">> :: binary(),
+ xml :: undefined | xmlel()}).
diff --git a/mix.exs b/mix.exs
index 2580cf9cf..2ac1992cf 100644
--- a/mix.exs
+++ b/mix.exs
@@ -35,7 +35,12 @@ defmodule Ejabberd.Mixfile do
defp erlc_options do
# Use our own includes + includes from all dependencies
includes = ["include"] ++ deps_include(["fast_xml", "xmpp", "p1_utils"])
- [:debug_info, {:d, :ELIXIR_ENABLED}] ++ Enum.map(includes, fn(path) -> {:i, path} end)
+ [:debug_info, {:d, :ELIXIR_ENABLED}] ++ cond_options() ++ Enum.map(includes, fn(path) -> {:i, path} end)
+ end
+
+ defp cond_options do
+ for {:true, option} <- [{config(:graphics), {:d, :GRAPHICS}}], do:
+ option
end
defp deps do
@@ -75,7 +80,8 @@ defmodule Ejabberd.Mixfile do
{config(:pam), {:epam, "~> 1.0"}},
{config(:tools), {:luerl, github: "rvirding/luerl", tag: "v0.2"}},
{config(:tools), {:meck, "~> 0.8.4"}},
- {config(:tools), {:moka, github: "processone/moka", tag: "1.0.5c"}}], do:
+ {config(:tools), {:moka, github: "processone/moka", tag: "1.0.5c"}},
+ {config(:graphics), {:eimp, github: "processone/eimp", tag: "1.0.1"}}], do:
dep
end
@@ -85,7 +91,8 @@ defmodule Ejabberd.Mixfile do
{config(:pgsql), :p1_pgsql},
{config(:sqlite), :sqlite3},
{config(:zlib), :ezlib},
- {config(:iconv), :iconv}], do:
+ {config(:iconv), :iconv},
+ {config(:graphics), :eimp}], do:
app
end
diff --git a/priv/msgs/ca.po b/priv/msgs/ca.po
index 171f9a5c9..e306d848a 100644
--- a/priv/msgs/ca.po
+++ b/priv/msgs/ca.po
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 2.1.0-alpha\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2016-01-15 12:25+0100\n"
+"PO-Revision-Date: 2017-10-11 16:20+0200\n"
"Last-Translator: Badlop <badlop@process-one.net>\n"
"Language-Team: \n"
"Language: ca\n"
@@ -13,13 +13,13 @@ msgstr ""
"X-Language: Catalan (català)\n"
"X-Additional-Translator: Vicent Alberola Canet\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.6.10\n"
+"X-Generator: Poedit 1.8.7.1\n"
-#: mod_muc_log:413 mod_muc_log:752
+#: mod_muc_log:413 mod_muc_log:588
msgid " has set the subject to: "
msgstr " ha posat l'assumpte: "
-#: mod_muc_room:1893
+#: mod_muc_room:1896
msgid "A password is required to enter this room"
msgstr "Es necessita contrasenya per a entrar en aquesta sala"
@@ -35,12 +35,12 @@ msgstr "Configuració d'accesos"
msgid "Access Control List Configuration"
msgstr "Configuració de la Llista de Control d'Accés"
-#: ejabberd_web_admin:758 ejabberd_web_admin:797 mod_configure:185
+#: ejabberd_web_admin:484 ejabberd_web_admin:523 mod_configure:185
#: mod_configure:514
msgid "Access Control Lists"
msgstr "Llista de Control d'Accés"
-#: ejabberd_web_admin:863 ejabberd_web_admin:896 mod_configure:187
+#: ejabberd_web_admin:589 ejabberd_web_admin:622 mod_configure:187
#: mod_configure:515
msgid "Access Rules"
msgstr "Regles d'Accés"
@@ -84,16 +84,16 @@ msgstr "Acció en l'usuari"
msgid "Add Jabber ID"
msgstr "Afegir Jabber ID"
-#: ejabberd_web_admin:1277 mod_shared_roster:825
+#: ejabberd_web_admin:1003 mod_shared_roster:825
msgid "Add New"
msgstr "Afegir nou"
-#: ejabberd_web_admin:1444 mod_configure:166 mod_configure:521
+#: ejabberd_web_admin:1170 mod_configure:166 mod_configure:521
#: mod_configure:1118
msgid "Add User"
msgstr "Afegir usuari"
-#: ejabberd_web_admin:687 ejabberd_web_admin:698
+#: ejabberd_web_admin:413 ejabberd_web_admin:424
msgid "Administration"
msgstr "Administració"
@@ -101,7 +101,7 @@ msgstr "Administració"
msgid "Administration of "
msgstr "Administració de "
-#: mod_muc_room:2528
+#: mod_muc_room:2540
msgid "Administrator privileges required"
msgstr "Es necessita tenir privilegis d'administrador"
@@ -109,35 +109,35 @@ msgstr "Es necessita tenir privilegis d'administrador"
msgid "All Users"
msgstr "Tots els usuaris"
-#: ejabberd_web_admin:1010
+#: ejabberd_web_admin:736
msgid "All activity"
msgstr "Tota l'activitat"
-#: mod_muc_log:1046
+#: mod_muc_log:809
msgid "Allow users to change the subject"
msgstr "Permetre que els usuaris canviin el tema"
-#: mod_muc_log:1052
+#: mod_muc_log:815
msgid "Allow users to query other users"
msgstr "Permetre que els usuaris fagen peticions a altres usuaris"
-#: mod_muc_log:1054
+#: mod_muc_log:817
msgid "Allow users to send invites"
msgstr "Permetre que els usuaris envien invitacions"
-#: mod_muc_log:1048
+#: mod_muc_log:811
msgid "Allow users to send private messages"
msgstr "Permetre que els usuaris envien missatges privats"
-#: mod_muc_log:1057
+#: mod_muc_log:820
msgid "Allow visitors to change nickname"
msgstr "Permetre als visitants canviar el sobrenom"
-#: mod_muc_log:1050
+#: mod_muc_log:813
msgid "Allow visitors to send private messages to"
msgstr "Permetre als visitants enviar missatges privats a"
-#: mod_muc_log:1059
+#: mod_muc_log:822
msgid "Allow visitors to send status text in presence updates"
msgstr ""
"Permetre als visitants enviar text d'estat en les actualitzacions de "
@@ -157,9 +157,9 @@ msgstr "Agost"
#: mod_pubsub:1842
msgid "Automatic node creation is not enabled"
-msgstr ""
+msgstr "La creació automàtica de nodes no està activada"
-#: ejabberd_web_admin:1867 mod_configure:148 mod_configure:617
+#: ejabberd_web_admin:1593 mod_configure:148 mod_configure:617
msgid "Backup"
msgstr "Guardar còpia de seguretat"
@@ -167,7 +167,7 @@ msgstr "Guardar còpia de seguretat"
msgid "Backup Management"
msgstr "Gestió de còpia de seguretat"
-#: ejabberd_web_admin:1979
+#: ejabberd_web_admin:1705
msgid "Backup of ~p"
msgstr "Còpia de seguretat de ~p"
@@ -175,10 +175,10 @@ msgstr "Còpia de seguretat de ~p"
msgid "Backup to File at "
msgstr "Desar còpia de seguretat a fitxer en "
-#: ejabberd_web_admin:763 ejabberd_web_admin:802 ejabberd_web_admin:868
-#: ejabberd_web_admin:901 ejabberd_web_admin:937 ejabberd_web_admin:1422
-#: ejabberd_web_admin:1705 ejabberd_web_admin:1861 ejabberd_web_admin:2145
-#: ejabberd_web_admin:2174 mod_roster:972 mod_shared_roster:831
+#: ejabberd_web_admin:489 ejabberd_web_admin:528 ejabberd_web_admin:594
+#: ejabberd_web_admin:627 ejabberd_web_admin:663 ejabberd_web_admin:1148
+#: ejabberd_web_admin:1431 ejabberd_web_admin:1587 ejabberd_web_admin:1871
+#: ejabberd_web_admin:1900 mod_roster:972 mod_shared_roster:831
#: mod_shared_roster:926
msgid "Bad format"
msgstr "Format erroni"
@@ -190,30 +190,30 @@ msgstr "Aniversari"
#: mod_legacy_auth:102
msgid "Both the username and the resource are required"
-msgstr ""
+msgstr "Es requereixen tant el nom d'usuari com el recurs"
#: mod_proxy65_service:226
msgid "Bytestream already activated"
-msgstr ""
+msgstr "El Bytestream ja està activat"
#: ejabberd_captcha:135
msgid "CAPTCHA web page"
msgstr "Pàgina web del CAPTCHA"
-#: ejabberd_web_admin:2207
+#: ejabberd_web_admin:1933
msgid "CPU Time:"
msgstr "Temps de CPU"
#: mod_privacy:334
msgid "Cannot remove active list"
-msgstr ""
+msgstr "No es pot eliminar la llista activa"
#: mod_privacy:341
msgid "Cannot remove default list"
-msgstr ""
+msgstr "No es pot eliminar la llista per defecte"
-#: ejabberd_web_admin:1679 mod_register_web:194 mod_register_web:353
-#: mod_register_web:361 mod_register_web:386
+#: ejabberd_web_admin:1405 mod_register_web:212 mod_register_web:373
+#: mod_register_web:381 mod_register_web:406
msgid "Change Password"
msgstr "Canviar Contrasenya"
@@ -222,16 +222,14 @@ msgid "Change User Password"
msgstr "Canviar Contrasenya d'Usuari"
#: mod_register:295
-#, fuzzy
msgid "Changing password is not allowed"
-msgstr "Caràcters no permesos:"
+msgstr "No està permès canviar la contrasenya"
-#: mod_muc_room:2764
-#, fuzzy
+#: mod_muc_room:2776
msgid "Changing role/affiliation is not allowed"
-msgstr "Caràcters no permesos:"
+msgstr "No està permès canviar el rol/afiliació"
-#: mod_register_web:239
+#: mod_register_web:258
msgid "Characters not allowed:"
msgstr "Caràcters no permesos:"
@@ -292,11 +290,11 @@ msgstr "La sala de conferències no existeix"
msgid "Configuration"
msgstr "Configuració"
-#: mod_muc_room:3163
+#: mod_muc_room:3175
msgid "Configuration of room ~s"
msgstr "Configuració de la sala ~s"
-#: ejabberd_web_admin:1711
+#: ejabberd_web_admin:1437
msgid "Connected Resources:"
msgstr "Recursos connectats:"
@@ -309,7 +307,7 @@ msgstr "Paràmetres de connexió"
msgid "Country"
msgstr "Pais"
-#: ejabberd_web_admin:1866 mod_configure:139 mod_configure:580
+#: ejabberd_web_admin:1592 mod_configure:139 mod_configure:580
msgid "Database"
msgstr "Base de dades"
@@ -317,7 +315,7 @@ msgstr "Base de dades"
msgid "Database Tables Configuration at "
msgstr "Configuració de la base de dades en "
-#: ejabberd_web_admin:1941
+#: ejabberd_web_admin:1667
msgid "Database Tables at ~p"
msgstr "Taules de la base de dades en ~p"
@@ -329,19 +327,18 @@ msgstr "Taules de la base de dades en ~p"
#: mod_pubsub:3598 mod_pubsub:3604 mod_pubsub:3607 mod_vcard:226
#: node_flat_sql:801 nodetree_tree_sql:128 nodetree_tree_sql:142
#: nodetree_tree_sql:257
-#, fuzzy
msgid "Database failure"
-msgstr "Base de dades"
+msgstr "Error a la base de dades"
#: mod_muc_log:484
msgid "December"
msgstr "Decembre"
-#: mod_muc_log:1044
+#: mod_muc_log:807
msgid "Default users as participants"
msgstr "Els usuaris són participants per defecte"
-#: ejabberd_web_admin:811 ejabberd_web_admin:911 mod_offline:703
+#: ejabberd_web_admin:537 ejabberd_web_admin:637 mod_offline:703
#: mod_shared_roster:839
msgid "Delete Selected"
msgstr "Eliminar els seleccionats"
@@ -370,7 +367,7 @@ msgstr "Còpia sols en disc"
msgid "Displayed Groups:"
msgstr "Mostrar grups:"
-#: mod_register_web:251
+#: mod_register_web:270
msgid ""
"Don't tell your password to anybody, not even the administrators of the "
"Jabber server."
@@ -388,17 +385,17 @@ msgstr "Exportar a fitxer de text"
#: mod_roster:180
msgid "Duplicated groups are not allowed by RFC6121"
-msgstr ""
+msgstr "No estan permesos els grups duplicats al RFC6121"
#: mod_configure:1776
msgid "Edit Properties"
msgstr "Editar propietats"
-#: mod_muc_room:3881
+#: mod_muc_room:3893
msgid "Either approve or decline the voice request."
msgstr "Aprova o denega la petició de veu"
-#: ejabberd_web_admin:1953
+#: ejabberd_web_admin:1679
msgid "Elements"
msgstr "Elements"
@@ -408,17 +405,16 @@ msgid "Email"
msgstr "Email"
#: mod_register:292
-#, fuzzy
msgid "Empty password"
-msgstr "la contrasenya és"
+msgstr "Contrasenya buida"
-#: mod_muc_log:1055
+#: mod_muc_log:818
msgid "Enable logging"
msgstr "Habilitar el registre de la conversa"
#: mod_push:252
msgid "Enabling push without 'node' attribute is not supported"
-msgstr ""
+msgstr "No està suportat activar Push sense l'atribut 'node'"
#: mod_irc:834
msgid "Encoding for server ~b"
@@ -478,7 +474,7 @@ msgstr ""
msgid "Erlang Jabber Server"
msgstr "Servidor Erlang Jabber"
-#: ejabberd_web_admin:1976 ejabberd_web_admin:2147
+#: ejabberd_web_admin:1702 ejabberd_web_admin:1873
msgid "Error"
msgstr "Error"
@@ -490,30 +486,30 @@ msgstr ""
"Exemple: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef."
"net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}]."
-#: ejabberd_web_admin:2084
+#: ejabberd_web_admin:1810
msgid "Export all tables as SQL queries to a file:"
msgstr "Exporta totes les taules a un fitxer SQL:"
-#: ejabberd_web_admin:2056
+#: ejabberd_web_admin:1782
msgid "Export data of all users in the server to PIEFXIS files (XEP-0227):"
msgstr ""
"Exportar dades de tots els usuaris del servidor a arxius PIEFXIS (XEP-0227):"
-#: ejabberd_web_admin:2068
+#: ejabberd_web_admin:1794
msgid "Export data of users in a host to PIEFXIS files (XEP-0227):"
msgstr "Exportar dades d'usuaris d'un host a arxius PIEFXIS (XEP-0227):"
#: mod_delegation:275
msgid "External component failure"
-msgstr ""
+msgstr "Error al component extern"
#: mod_delegation:283
msgid "External component timeout"
-msgstr ""
+msgstr "Temps esgotat al component extern"
#: mod_proxy65_service:218
msgid "Failed to activate bytestream"
-msgstr ""
+msgstr "Errada al activar bytestream"
#: mod_muc_room:910
msgid "Failed to extract JID from your voice request approval"
@@ -521,19 +517,19 @@ msgstr "No s'ha pogut extraure el JID de la teva aprovació de petició de veu"
#: mod_delegation:257
msgid "Failed to map delegated namespace to external component"
-msgstr ""
+msgstr "Ha fallat mapejar la delegació de l'espai de noms al component extern"
#: mod_http_upload:602
msgid "Failed to parse HTTP response"
-msgstr ""
+msgstr "Ha fallat el processat de la resposta HTTP"
#: mod_irc:426
msgid "Failed to parse chanserv"
-msgstr ""
+msgstr "Ha fallat el processat de Chanserv"
-#: mod_muc_room:3297
+#: mod_muc_room:3309
msgid "Failed to process option '~s'"
-msgstr ""
+msgstr "H fallat el processat de la opció '~s'"
#: mod_vcard_ldap:332 mod_vcard_ldap:345 mod_vcard_mnesia:103
#: mod_vcard_mnesia:117 mod_vcard_sql:158 mod_vcard_sql:172
@@ -546,7 +542,7 @@ msgstr "Febrer"
#: mod_http_upload:555
msgid "File larger than ~w bytes"
-msgstr ""
+msgstr "El fitxer es més gran que ~w bytes"
#: mod_vcard:437
msgid ""
@@ -594,9 +590,8 @@ msgid "Get User Statistics"
msgstr "Obtenir Estadístiques d'Usuari"
#: mod_vcard_ldap:330 mod_vcard_ldap:343
-#, fuzzy
msgid "Given Name"
-msgstr "Segon nom"
+msgstr "Nom propi"
#: mod_shared_roster:923
msgid "Group "
@@ -606,15 +601,15 @@ msgstr "Grup "
msgid "Groups"
msgstr "Grups"
-#: ejabberd_web_admin:1365
+#: ejabberd_web_admin:1091
msgid "Host"
msgstr "Host"
#: mod_s2s_dialback:325
msgid "Host unknown"
-msgstr ""
+msgstr "Host desconegut"
-#: ejabberd_web_admin:2463
+#: ejabberd_web_admin:2189
msgid "IP"
msgstr "IP"
@@ -635,9 +630,8 @@ msgid "IRC channel (don't put the first #)"
msgstr "Canal d'IRC (no posis la primera #)"
#: mod_irc:417
-#, fuzzy
msgid "IRC connection not found"
-msgstr "Node no trobat"
+msgstr "Connexió IRC no trobada"
#: mod_irc:673
msgid "IRC server"
@@ -687,90 +681,88 @@ msgstr "Importar usuaris de jabberd14"
msgid "Import Users from Dir at "
msgstr "Importar usuaris des del directori en "
-#: ejabberd_web_admin:2100
+#: ejabberd_web_admin:1826
msgid "Import user data from jabberd14 spool file:"
msgstr "Importar dades d'usuaris de l'arxiu de spool de jabberd14"
-#: ejabberd_web_admin:2043
+#: ejabberd_web_admin:1769
msgid "Import users data from a PIEFXIS file (XEP-0227):"
msgstr "Importar dades d'usuaris des d'un arxiu PIEFXIS (XEP-0227):"
-#: ejabberd_web_admin:2111
+#: ejabberd_web_admin:1837
msgid "Import users data from jabberd14 spool directory:"
msgstr "Importar dades d'usuaris del directori de spool de jabberd14:"
#: xmpp_stream_in:983
msgid "Improper 'from' attribute"
-msgstr ""
+msgstr "Atribut 'from' impropi"
#: xmpp_stream_in:477
msgid "Improper 'to' attribute"
-msgstr ""
+msgstr "Atribut 'to' impropi"
#: ejabberd_service:189
msgid "Improper domain part of 'from' attribute"
-msgstr ""
+msgstr "La part de domini de l'atribut 'from' es impròpia"
#: mod_muc_room:260
msgid "Improper message type"
msgstr "Tipus de missatge incorrecte"
-#: ejabberd_web_admin:1586
+#: ejabberd_web_admin:1312
msgid "Incoming s2s Connections:"
msgstr "Connexions s2s d'entrada"
-#: mod_muc_room:3669 mod_register:187
+#: mod_muc_room:3681 mod_register:187
msgid "Incorrect CAPTCHA submit"
-msgstr ""
+msgstr "El CAPTCHA proporcionat és incorrecte"
-#: mod_muc:772 mod_muc_room:3052 mod_pubsub:1194 mod_register:183 mod_vcard:256
-#, fuzzy
+#: mod_muc:772 mod_muc_room:3064 mod_pubsub:1194 mod_register:183 mod_vcard:256
msgid "Incorrect data form"
-msgstr "Contrasenya incorrecta"
+msgstr "El formulari de dades és incorrecte"
-#: mod_muc_room:1943 mod_register:300 mod_register:350
+#: mod_muc_room:1946 mod_register:300 mod_register:350
msgid "Incorrect password"
msgstr "Contrasenya incorrecta"
#: mod_irc:585
msgid "Incorrect value in data form"
-msgstr ""
+msgstr "Valor al formulari de dades incorrecte"
#: mod_adhoc:276
msgid "Incorrect value of 'action' attribute"
-msgstr ""
+msgstr "Valor incorrecte del atribut 'action'"
#: mod_configure:1806
msgid "Incorrect value of 'action' in data form"
-msgstr ""
+msgstr "Valor incorrecte de 'action' al formulari de dades"
#: mod_configure:1335 mod_configure:1367 mod_configure:1399 mod_configure:1419
#: mod_configure:1439
msgid "Incorrect value of 'path' in data form"
-msgstr ""
+msgstr "Valor incorrecte de 'path' al formulari de dades"
#: mod_irc:331
msgid "Incorrect value of 'type' attribute"
-msgstr ""
+msgstr "Valor incorrecte del atribut 'type'"
#: mod_privilege:100
msgid "Insufficient privilege"
-msgstr ""
+msgstr "Privilegi insuficient"
#: mod_privilege:286
msgid "Invalid 'from' attribute in forwarded message"
-msgstr ""
+msgstr "Atribut 'from' invàlid al missatge reenviat"
#: mod_privilege:300
msgid "Invalid <forwarded/> element"
-msgstr ""
+msgstr "Element <forwarded/> invàlid"
-#: mod_muc_room:3926
-#, fuzzy
+#: mod_muc_room:3938
msgid "Invitations are not allowed in this conference"
-msgstr "Les peticions de veu es troben desactivades en aquesta conferència"
+msgstr "Les invitacions no estan permeses en aquesta sala de conferència"
-#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1046
+#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1052
msgid ""
"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"
@@ -790,7 +782,7 @@ msgstr "No està permés enviar missatges del tipus \"groupchat\""
msgid "It is not allowed to send private messages to the conference"
msgstr "No està permès l'enviament de missatges privats a la sala"
-#: mod_register_web:181 mod_register_web:189
+#: mod_register_web:199 mod_register_web:207
msgid "Jabber Account Registration"
msgstr "Registre de compte Jabber"
@@ -825,7 +817,7 @@ msgstr "Juliol"
msgid "June"
msgstr "Juny"
-#: ejabberd_web_admin:1488 ejabberd_web_admin:1715
+#: ejabberd_web_admin:1214 ejabberd_web_admin:1441
msgid "Last Activity"
msgstr "Última activitat"
@@ -833,11 +825,11 @@ msgstr "Última activitat"
msgid "Last login"
msgstr "Últim login"
-#: ejabberd_web_admin:1007
+#: ejabberd_web_admin:733
msgid "Last month"
msgstr "Últim mes"
-#: ejabberd_web_admin:1008
+#: ejabberd_web_admin:734
msgid "Last year"
msgstr "Últim any"
@@ -849,56 +841,55 @@ msgstr "Llista de mòduls a iniciar"
msgid "List of rooms"
msgstr "Llista de sales"
-#: ejabberd_web_admin:1869
+#: ejabberd_web_admin:1595
msgid "Listened Ports"
msgstr "Ports a l'escolta"
-#: ejabberd_web_admin:2139
+#: ejabberd_web_admin:1865
msgid "Listened Ports at "
msgstr "Ports a la escolta en "
-#: ejabberd_web_admin:2281
+#: ejabberd_web_admin:2007
msgid "Low level update script"
msgstr "Script d'actualització de baix nivell"
-#: mod_muc_log:1033
+#: mod_muc_log:796
msgid "Make participants list public"
msgstr "Crear una llista de participants pública"
-#: mod_muc_log:1062
+#: mod_muc_log:825
msgid "Make room CAPTCHA protected"
msgstr "Crear una sala protegida per CAPTCHA"
-#: mod_muc_log:1040
+#: mod_muc_log:803
msgid "Make room members-only"
msgstr "Crear una sala de \"només membres\""
-#: mod_muc_log:1042
+#: mod_muc_log:805
msgid "Make room moderated"
msgstr "Crear una sala moderada"
-#: mod_muc_log:1035
+#: mod_muc_log:798
msgid "Make room password protected"
msgstr "Crear una sala amb contrasenya"
-#: mod_muc_log:1029
+#: mod_muc_log:792
msgid "Make room persistent"
msgstr "Crear una sala persistent"
-#: mod_muc_log:1031
+#: mod_muc_log:794
msgid "Make room public searchable"
msgstr "Crear una sala pública"
#: mod_register:317
-#, fuzzy
msgid "Malformed username"
-msgstr "Nom d'usuari al IRC"
+msgstr "Nom d'usuari mal format"
#: mod_muc_log:475
msgid "March"
msgstr "Març"
-#: mod_muc_log:1068
+#: mod_muc_log:831
msgid "Maximum Number of Occupants"
msgstr "Número màxim d'ocupants"
@@ -910,11 +901,11 @@ msgstr "Maig"
msgid "Members:"
msgstr "Membre:"
-#: mod_muc_room:1833
+#: mod_muc_room:1839
msgid "Membership is required to enter this room"
msgstr "Necessites ser membre d'aquesta sala per a poder entrar"
-#: mod_register_web:262
+#: mod_register_web:281
msgid ""
"Memorize your password, or write it in a paper placed in a safe place. In "
"Jabber there isn't an automated way to recover your password if you forget "
@@ -924,7 +915,7 @@ msgstr ""
"segur.A Jabber no hi ha una forma automatitzada de recuperar la teva "
"contrasenya si la oblides."
-#: ejabberd_web_admin:1954
+#: ejabberd_web_admin:1680
msgid "Memory"
msgstr "Memòria"
@@ -934,7 +925,7 @@ msgstr "Missatge"
#: mod_privilege:291
msgid "Message not found in forwarded payload"
-msgstr ""
+msgstr "Missatge no trobat al contingut reenviat"
#: mod_vcard_ldap:331 mod_vcard_ldap:344 mod_vcard_mnesia:102
#: mod_vcard_mnesia:116 mod_vcard_sql:157 mod_vcard_sql:171
@@ -943,37 +934,37 @@ msgstr "Segon nom"
#: mod_irc:704
msgid "Missing 'channel' or 'server' in the data form"
-msgstr ""
+msgstr "Falten 'channel' o 'server' al formulari de dades"
#: xmpp_stream_in:990
msgid "Missing 'from' attribute"
-msgstr ""
+msgstr "Falta l'atribut 'from'"
#: xmpp_stream_in:472 xmpp_stream_in:993
msgid "Missing 'to' attribute"
-msgstr ""
+msgstr "Falta l'atribut 'to'"
-#: mod_muc_room:2536 mod_muc_room:3721 mod_muc_room:3765 mod_muc_room:3798
+#: mod_muc_room:2548 mod_muc_room:3733 mod_muc_room:3777 mod_muc_room:3810
msgid "Moderator privileges required"
msgstr "Es necessita tenir privilegis de moderador"
-#: ejabberd_web_admin:2279
+#: ejabberd_web_admin:2005
msgid "Modified modules"
msgstr "Mòduls modificats"
-#: ejabberd_web_admin:2465 ejabberd_web_admin:2620
+#: ejabberd_web_admin:2191 ejabberd_web_admin:2346
msgid "Module"
msgstr "Mòdul"
#: gen_iq_handler:153
msgid "Module failed to handle the query"
-msgstr ""
+msgstr "El modul ha fallat al gestionar la petició"
-#: ejabberd_web_admin:1885 mod_configure:582 mod_configure:595
+#: ejabberd_web_admin:1611 mod_configure:582 mod_configure:595
msgid "Modules"
msgstr "Mòduls"
-#: ejabberd_web_admin:2168
+#: ejabberd_web_admin:1894
msgid "Modules at ~p"
msgstr "Mòduls en ~p"
@@ -991,9 +982,9 @@ msgstr "Multicast"
#: mod_roster:195
msgid "Multiple <item/> elements are not allowed by RFC6121"
-msgstr ""
+msgstr "No estan permesos múltiples elements <item/> per RFC6121"
-#: ejabberd_web_admin:1951 mod_vcard_mnesia:101 mod_vcard_mnesia:115
+#: ejabberd_web_admin:1677 mod_vcard_mnesia:101 mod_vcard_mnesia:115
#: mod_vcard_sql:156 mod_vcard_sql:170
msgid "Name"
msgstr "Nom"
@@ -1002,19 +993,19 @@ msgstr "Nom"
msgid "Name:"
msgstr "Nom:"
-#: mod_muc_room:2696
+#: mod_muc_room:2708
msgid "Neither 'jid' nor 'nick' attribute found"
-msgstr ""
+msgstr "No s'han trobat els atributs 'jid' ni 'nick'"
-#: mod_muc_room:2518 mod_muc_room:2701
+#: mod_muc_room:2530 mod_muc_room:2713
msgid "Neither 'role' nor 'affiliation' attribute found"
-msgstr ""
+msgstr "No s'han trobat els atributs 'role' ni 'affiliation'"
-#: ejabberd_web_admin:1506 ejabberd_web_admin:1687 mod_configure:1629
+#: ejabberd_web_admin:1232 ejabberd_web_admin:1413 mod_configure:1629
msgid "Never"
msgstr "Mai"
-#: mod_register_web:377
+#: mod_register_web:397
msgid "New Password:"
msgstr "Nova Contrasenya:"
@@ -1027,158 +1018,154 @@ msgstr "Sobrenom"
msgid "Nickname Registration at "
msgstr "Registre del sobrenom en "
-#: mod_muc_room:2713
+#: mod_muc_room:2725
msgid "Nickname ~s does not exist in the room"
msgstr "El sobrenom ~s no existeix a la sala"
#: mod_configure:1496
msgid "No 'access' found in data form"
-msgstr ""
+msgstr "No s'ha trobat 'access' al formulari de dades"
#: mod_configure:1455
msgid "No 'acls' found in data form"
-msgstr ""
+msgstr "No s'ha trobat 'acls' al formulari de dades"
-#: mod_muc_room:3075
+#: mod_muc_room:3087
msgid "No 'affiliation' attribute found"
-msgstr ""
+msgstr "No s'ha trobat l'atribut 'affiliation'"
-#: mod_muc_room:2505
-#, fuzzy
+#: mod_muc_room:2517
msgid "No 'item' element found"
-msgstr "Node no trobat"
+msgstr "No s'ha trobat l'element 'item'"
#: mod_configure:1280
msgid "No 'modules' found in data form"
-msgstr ""
+msgstr "No s'ha trobat 'modules' al formulari de dades"
#: mod_configure:1799
msgid "No 'password' found in data form"
-msgstr ""
+msgstr "No s'ha trobat 'password' al formulari de dades"
#: mod_register:148
msgid "No 'password' found in this query"
-msgstr ""
+msgstr "No s'ha trobat 'password' en esta petició"
#: mod_configure:1319 mod_configure:1350 mod_configure:1382 mod_configure:1413
#: mod_configure:1433
msgid "No 'path' found in data form"
-msgstr ""
+msgstr "No s'ha trobat 'path' en el formulari de dades"
-#: mod_muc_room:3922
+#: mod_muc_room:3934
msgid "No 'to' attribute found in the invitation"
-msgstr ""
+msgstr "No s'ha trobat l'atribut 'to' en la invitació"
-#: ejabberd_web_admin:1767
+#: ejabberd_web_admin:1493
msgid "No Data"
msgstr "No hi ha dades"
#: ejabberd_local:181
msgid "No available resource found"
-msgstr ""
+msgstr "No s'ha trobat un recurs disponible"
#: mod_announce:575
msgid "No body provided for announce message"
msgstr "No hi ha proveedor per al missatge anunci"
#: mod_irc:335 mod_pubsub:1183 mod_pubsub:3289
-#, fuzzy
msgid "No data form found"
-msgstr "Node no trobat"
+msgstr "No s'ha trobat el formulari de dades"
#: mod_disco:224 mod_vcard:282
msgid "No features available"
-msgstr ""
+msgstr "No n'hi ha característiques disponibles"
#: mod_adhoc:239
msgid "No hook has processed this command"
-msgstr ""
+msgstr "Cap event ha processat este comandament"
#: mod_last:218
msgid "No info about last activity found"
-msgstr ""
+msgstr "No s'ha trobat informació de l'ultima activitat"
#: mod_blocking:99
msgid "No items found in this query"
-msgstr ""
+msgstr "Cap element ha sigut trobat a la petició "
#: ejabberd_local:90 ejabberd_sm:863 mod_blocking:92 mod_blocking:110
#: mod_http_upload:513 mod_muc:482 mod_muc:534 mod_muc:556 mod_muc:580
#: mod_offline:303 mod_privacy:168 mod_privacy:285 mod_roster:207
msgid "No module is handling this query"
-msgstr ""
+msgstr "Cap element està manegant esta petició"
#: mod_pubsub:1541
msgid "No node specified"
-msgstr ""
+msgstr "No s'ha especificat node"
#: mod_pubsub:1426
msgid "No pending subscriptions found"
-msgstr ""
+msgstr "No s'han trobat subscripcions pendents"
#: mod_privacy:201 mod_privacy:295 mod_privacy:311 mod_privacy:344
msgid "No privacy list with this name found"
-msgstr ""
+msgstr "No s'ha trobat cap llista de privacitat amb aquest nom"
#: mod_private:96
msgid "No private data found in this query"
-msgstr ""
+msgstr "No s'ha trobat dades privades en esta petició"
#: mod_configure:869 mod_configure:908 mod_configure:1222 mod_configure:1254
#: mod_configure:1275 mod_configure:1314 mod_configure:1345 mod_configure:1377
#: mod_configure:1408 mod_configure:1428 mod_stats:93
-#, fuzzy
msgid "No running node found"
-msgstr "Node no trobat"
+msgstr "No s'ha trobat node en marxa"
#: mod_disco:252 mod_vcard:265
msgid "No services available"
-msgstr ""
+msgstr "No n'hi ha serveis disponibles"
#: mod_stats:101
msgid "No statistics found for this item"
-msgstr ""
+msgstr "No n'hi ha estadístiques disponibles per a aquest element"
#: nodetree_dag:72 nodetree_tree:181 nodetree_tree_sql:255
msgid "Node already exists"
-msgstr ""
+msgstr "El node ja existeix"
#: nodetree_tree_sql:99
-#, fuzzy
msgid "Node index not found"
-msgstr "Node no trobat"
+msgstr "Index de node no trobat"
-#: ejabberd_web_admin:1046 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
+#: ejabberd_web_admin:772 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
#: nodetree_dag:78 nodetree_dag:102 nodetree_dag:118 nodetree_dag:142
#: nodetree_dag:229 nodetree_tree:74 nodetree_tree:80 nodetree_tree_sql:130
#: nodetree_tree_sql:144
msgid "Node not found"
msgstr "Node no trobat"
-#: ejabberd_web_admin:1857 ejabberd_web_admin:1882
+#: ejabberd_web_admin:1583 ejabberd_web_admin:1608
msgid "Node ~p"
msgstr "Node ~p"
#: mod_vcard:385
msgid "Nodeprep has failed"
-msgstr ""
+msgstr "Ha fallat Nodeprep"
-#: ejabberd_web_admin:1837
+#: ejabberd_web_admin:1563
msgid "Nodes"
msgstr "Nodes"
-#: ejabberd_web_admin:1622 ejabberd_web_admin:1818 ejabberd_web_admin:1828
-#: ejabberd_web_admin:2238 mod_roster:907
+#: ejabberd_web_admin:1348 ejabberd_web_admin:1544 ejabberd_web_admin:1554
+#: ejabberd_web_admin:1964 mod_roster:907
msgid "None"
msgstr "Cap"
-#: ejabberd_web_admin:1033
+#: ejabberd_web_admin:759
msgid "Not Found"
msgstr "No Trobat"
#: mod_disco:296 mod_disco:370 mod_last:159
msgid "Not subscribed"
-msgstr ""
+msgstr "No subscrit"
#: mod_muc_log:483
msgid "November"
@@ -1192,10 +1179,10 @@ msgstr "Número d'usuaris connectats"
msgid "Number of registered users"
msgstr "Número d'Usuaris Registrats"
-#: ejabberd_web_admin:2000 ejabberd_web_admin:2010 ejabberd_web_admin:2021
-#: ejabberd_web_admin:2030 ejabberd_web_admin:2040 ejabberd_web_admin:2053
-#: ejabberd_web_admin:2065 ejabberd_web_admin:2081 ejabberd_web_admin:2097
-#: ejabberd_web_admin:2108 ejabberd_web_admin:2118
+#: ejabberd_web_admin:1726 ejabberd_web_admin:1736 ejabberd_web_admin:1747
+#: ejabberd_web_admin:1756 ejabberd_web_admin:1766 ejabberd_web_admin:1779
+#: ejabberd_web_admin:1791 ejabberd_web_admin:1807 ejabberd_web_admin:1823
+#: ejabberd_web_admin:1834 ejabberd_web_admin:1844
msgid "OK"
msgstr "Acceptar"
@@ -1203,7 +1190,7 @@ msgstr "Acceptar"
msgid "October"
msgstr "Octubre"
-#: ejabberd_web_admin:1487
+#: ejabberd_web_admin:1213
msgid "Offline Messages"
msgstr "Missatges offline"
@@ -1211,29 +1198,29 @@ msgstr "Missatges offline"
msgid "Offline Messages:"
msgstr "Missatges fora de línia:"
-#: mod_register_web:373
+#: mod_register_web:393
msgid "Old Password:"
msgstr "Antiga contrasenya:"
-#: ejabberd_web_admin:1524 ejabberd_web_admin:1698 mod_configure:1639
+#: ejabberd_web_admin:1250 ejabberd_web_admin:1424 mod_configure:1639
msgid "Online"
msgstr "Connectat"
-#: ejabberd_web_admin:974 ejabberd_web_admin:1367 mod_configure:506
+#: ejabberd_web_admin:700 ejabberd_web_admin:1093 mod_configure:506
msgid "Online Users"
msgstr "Usuaris conectats"
-#: ejabberd_web_admin:1580 ejabberd_web_admin:1599 ejabberd_web_admin:2211
+#: ejabberd_web_admin:1306 ejabberd_web_admin:1325 ejabberd_web_admin:1937
msgid "Online Users:"
msgstr "Usuaris en línia:"
#: mod_carboncopy:141
msgid "Only <enable/> or <disable/> tags are allowed"
-msgstr ""
+msgstr "Només es permeten etiquetes <enable/> o <disable/>"
#: mod_privacy:154
msgid "Only <list/> element is allowed in this query"
-msgstr ""
+msgstr "En esta petició només es permet l'element <list/>"
#: mod_mam:379
msgid "Only members may query archives of this room"
@@ -1254,7 +1241,7 @@ msgstr "Només els moderadors poden canviar l'assumpte d'aquesta sala"
msgid "Only moderators can approve voice requests"
msgstr "Només els moderadors poden aprovar les peticions de veu"
-#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:3989
+#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:4001
msgid "Only occupants are allowed to send messages to the conference"
msgstr "Sols els ocupants poden enviar missatges a la sala"
@@ -1268,7 +1255,7 @@ msgstr ""
"Sols els administradors del servei tenen permís per a enviar missatges de "
"servei"
-#: ejabberd_web_admin:2466 ejabberd_web_admin:2621
+#: ejabberd_web_admin:2192 ejabberd_web_admin:2347
msgid "Options"
msgstr "Opcions"
@@ -1286,11 +1273,11 @@ msgstr "Unitat de la organizació"
msgid "Outgoing s2s Connections"
msgstr "Connexions s2s d'eixida"
-#: ejabberd_web_admin:1583
+#: ejabberd_web_admin:1309
msgid "Outgoing s2s Connections:"
msgstr "Connexions d'eixida s2s"
-#: mod_muc_room:3023 mod_muc_room:3067 mod_muc_room:3697 mod_pubsub:1302
+#: mod_muc_room:3035 mod_muc_room:3079 mod_muc_room:3709 mod_pubsub:1302
#: mod_pubsub:1394 mod_pubsub:1553 mod_pubsub:2118 mod_pubsub:2184
#: mod_pubsub:2383 mod_pubsub:2464 mod_pubsub:3063 mod_pubsub:3206
msgid "Owner privileges required"
@@ -1302,14 +1289,14 @@ msgstr "Paquet"
#: mod_irc:578
msgid "Parse error"
-msgstr ""
+msgstr "Error en el processat"
#: mod_configure:1299 mod_configure:1468 mod_configure:1513
msgid "Parse failed"
-msgstr ""
+msgstr "El processat ha fallat"
-#: ejabberd_oauth:431 ejabberd_web_admin:1435 mod_configure:1126
-#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:1036
+#: ejabberd_oauth:431 ejabberd_web_admin:1161 mod_configure:1126
+#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:799
#: mod_register:229
msgid "Password"
msgstr "Contrasenya"
@@ -1318,7 +1305,7 @@ msgstr "Contrasenya"
msgid "Password Verification"
msgstr "Verificació de la Contrasenya"
-#: mod_register_web:268 mod_register_web:381
+#: mod_register_web:287 mod_register_web:401
msgid "Password Verification:"
msgstr "Verificació de la Contrasenya:"
@@ -1326,7 +1313,7 @@ msgstr "Verificació de la Contrasenya:"
msgid "Password ~b"
msgstr "Contrasenya ~b"
-#: ejabberd_web_admin:1713 mod_register_web:245 mod_register_web:483
+#: ejabberd_web_admin:1439 mod_register_web:264 mod_register_web:504
msgid "Password:"
msgstr "Contrasenya:"
@@ -1342,7 +1329,7 @@ msgstr "Ruta al fitxer"
msgid "Pending"
msgstr "Pendent"
-#: ejabberd_web_admin:994
+#: ejabberd_web_admin:720
msgid "Period: "
msgstr "Període: "
@@ -1356,9 +1343,9 @@ msgstr "Ping"
#: mod_ping:180
msgid "Ping query is incorrect"
-msgstr ""
+msgstr "La petició de Ping es incorrecta"
-#: ejabberd_web_admin:1983
+#: ejabberd_web_admin:1709
msgid ""
"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 "
@@ -1376,7 +1363,7 @@ msgstr "Si us plau, espera una mica abans d'enviar una nova petició de veu"
msgid "Pong"
msgstr "Pong"
-#: ejabberd_web_admin:2463
+#: ejabberd_web_admin:2189
msgid "Port"
msgstr "Port"
@@ -1386,9 +1373,9 @@ msgstr "Port ~b"
#: mod_roster:173
msgid "Possessing 'ask' attribute is not allowed by RFC6121"
-msgstr ""
+msgstr "Processar l'atribut 'ask' no està permès per RFC6121"
-#: ejabberd_web_admin:2464
+#: ejabberd_web_admin:2190
msgid "Protocol"
msgstr "Protocol"
@@ -1402,7 +1389,7 @@ msgstr "Publicar-subscriure't"
#: node_dag:81
msgid "Publishing items to collection node is not allowed"
-msgstr ""
+msgstr "Publicar elements en una col·lecció de nodes no està permès"
#: mod_muc_room:462
msgid "Queries to the conference members are not allowed in this room"
@@ -1412,7 +1399,7 @@ msgstr ""
#: mod_blocking:85 mod_disco:325 mod_disco:393 mod_offline:270 mod_privacy:146
#: mod_private:118 mod_roster:163 mod_sic:90
msgid "Query to another users is forbidden"
-msgstr ""
+msgstr "Enviar peticions a altres usuaris no està permès"
#: mod_configure:889
msgid "RAM and disc copy"
@@ -1422,11 +1409,11 @@ msgstr "Còpia en RAM i disc"
msgid "RAM copy"
msgstr "Còpia en RAM"
-#: ejabberd_web_admin:1890
+#: ejabberd_web_admin:1616
msgid "RPC Call Error"
msgstr "Error de cridada RPC"
-#: ejabberd_web_admin:806 ejabberd_web_admin:905
+#: ejabberd_web_admin:532 ejabberd_web_admin:631
msgid "Raw"
msgstr "en format text"
@@ -1438,19 +1425,19 @@ msgstr "Segur que vols eliminar el missatge del dia?"
msgid "Recipient is not in the conference room"
msgstr "El receptor no està en la sala de conferència"
-#: mod_register_web:275
+#: mod_register_web:294
msgid "Register"
msgstr "Registrar"
-#: mod_register_web:192 mod_register_web:210 mod_register_web:218
+#: mod_register_web:210 mod_register_web:229 mod_register_web:237
msgid "Register a Jabber account"
msgstr "Registrar un compte Jabber"
-#: ejabberd_web_admin:1366
+#: ejabberd_web_admin:1092
msgid "Registered Users"
msgstr "Usuaris registrats"
-#: ejabberd_web_admin:1577 ejabberd_web_admin:1596
+#: ejabberd_web_admin:1303 ejabberd_web_admin:1322
msgid "Registered Users:"
msgstr "Usuaris registrats:"
@@ -1474,7 +1461,7 @@ msgstr "Borrar"
msgid "Remove All Offline Messages"
msgstr "Eliminar tots els missatges offline"
-#: ejabberd_web_admin:1720 mod_configure:1779
+#: ejabberd_web_admin:1446 mod_configure:1779
msgid "Remove User"
msgstr "Eliminar usuari"
@@ -1486,7 +1473,7 @@ msgstr "Reemplaçat per una nova connexió"
msgid "Resources"
msgstr "Recursos"
-#: ejabberd_web_admin:1876 ejabberd_web_admin:2494 ejabberd_web_admin:2638
+#: ejabberd_web_admin:1602 ejabberd_web_admin:2220 ejabberd_web_admin:2364
msgid "Restart"
msgstr "Reiniciar"
@@ -1502,26 +1489,26 @@ msgstr "Restaurar"
msgid "Restore Backup from File at "
msgstr "Restaura còpia de seguretat des del fitxer en "
-#: ejabberd_web_admin:2013
+#: ejabberd_web_admin:1739
msgid ""
"Restore binary backup after next ejabberd restart (requires less memory):"
msgstr ""
"Restaurar una còpia de seguretat binària després de reiniciar el ejabberd "
"(requereix menys memòria:"
-#: ejabberd_web_admin:2003
+#: ejabberd_web_admin:1729
msgid "Restore binary backup immediately:"
msgstr "Restaurar una còpia de seguretat binària ara mateix."
-#: ejabberd_web_admin:2033
+#: ejabberd_web_admin:1759
msgid "Restore plain text backup immediately:"
msgstr "Restaurar una còpia de seguretat en format de text pla ara mateix:"
-#: mod_muc_log:872
+#: mod_muc_log:635
msgid "Room Configuration"
msgstr "Configuració de la sala"
-#: mod_muc_log:892
+#: mod_muc_log:655
msgid "Room Occupants"
msgstr "Nombre d'ocupants"
@@ -1529,11 +1516,11 @@ msgstr "Nombre d'ocupants"
msgid "Room creation is denied by service policy"
msgstr "Se t'ha denegat el crear la sala per política del servei"
-#: mod_muc_log:1064
+#: mod_muc_log:827
msgid "Room description"
msgstr "Descripció de la sala:"
-#: mod_muc_log:1027
+#: mod_muc_log:790
msgid "Room title"
msgstr "Títol de la sala"
@@ -1543,7 +1530,7 @@ msgstr "Llista de contactes"
#: mod_roster:334
msgid "Roster module has failed"
-msgstr ""
+msgstr "El modul de Roster ha fallat"
#: mod_roster:968
msgid "Roster of "
@@ -1553,13 +1540,13 @@ msgstr "Llista de contactes de "
msgid "Roster size"
msgstr "Tamany de la llista"
-#: ejabberd_web_admin:1838 mod_configure:510
+#: ejabberd_web_admin:1564 mod_configure:510
msgid "Running Nodes"
msgstr "Nodes funcionant"
#: xmpp_stream_in:541 xmpp_stream_in:549
msgid "SASL negotiation is not allowed in this state"
-msgstr ""
+msgstr "La negociació SASL no està permesa en aquest estat"
#: mod_muc_log:468
msgid "Saturday"
@@ -1567,14 +1554,13 @@ msgstr "Dissabte"
#: mod_irc:582
msgid "Scan error"
-msgstr ""
+msgstr "Error en el escanejat"
#: mod_configure:1303 mod_configure:1472 mod_configure:1517
-#, fuzzy
msgid "Scan failed"
-msgstr "El CAPTCHA es vàlid."
+msgstr "L'escanejat ha fallat"
-#: ejabberd_web_admin:2282
+#: ejabberd_web_admin:2008
msgid "Script check"
msgstr "Comprovar script"
@@ -1608,17 +1594,17 @@ msgstr "Setembre"
#: mod_irc_connection:648
msgid "Server Connect Failed"
-msgstr ""
+msgstr "Connexió al servidor ha fallat"
#: ejabberd_s2s:369
msgid "Server connections to local subdomains are forbidden"
-msgstr ""
+msgstr "Les connexions de servidor a subdominis locals estan prohibides"
#: mod_irc:842
msgid "Server ~b"
msgstr "Servidor ~b"
-#: mod_register_web:242 mod_register_web:370 mod_register_web:480
+#: mod_register_web:261 mod_register_web:390 mod_register_web:501
msgid "Server:"
msgstr "Servidor:"
@@ -1636,11 +1622,11 @@ msgstr ""
msgid "Shared Roster Groups"
msgstr "Grups de contactes compartits"
-#: ejabberd_web_admin:1016
+#: ejabberd_web_admin:742
msgid "Show Integral Table"
msgstr "Mostrar Taula Integral"
-#: ejabberd_web_admin:1013
+#: ejabberd_web_admin:739
msgid "Show Ordinary Table"
msgstr "Mostrar Taula Ordinaria"
@@ -1648,7 +1634,7 @@ msgstr "Mostrar Taula Ordinaria"
msgid "Shut Down Service"
msgstr "Apager el Servei"
-#: mod_register_web:258
+#: mod_register_web:277
msgid ""
"Some Jabber clients can store your password in the computer, but you should "
"do this only in your personal computer for safety reasons."
@@ -1657,7 +1643,7 @@ msgstr ""
"ordinador. Fes servir aquesta característica només si saps que el teu "
"ordinador és segur."
-#: ejabberd_web_admin:2518 ejabberd_web_admin:2654
+#: ejabberd_web_admin:2244 ejabberd_web_admin:2380
msgid "Start"
msgstr "Iniciar"
@@ -1669,15 +1655,15 @@ msgstr "Iniciar mòduls"
msgid "Start Modules at "
msgstr "Iniciar mòduls en "
-#: ejabberd_web_admin:1023 ejabberd_web_admin:1871 mod_muc_admin:366
+#: ejabberd_web_admin:749 ejabberd_web_admin:1597 mod_muc_admin:366
msgid "Statistics"
msgstr "Estadístiques"
-#: ejabberd_web_admin:2199
+#: ejabberd_web_admin:1925
msgid "Statistics of ~p"
msgstr "Estadístiques de ~p"
-#: ejabberd_web_admin:1878 ejabberd_web_admin:2498 ejabberd_web_admin:2642
+#: ejabberd_web_admin:1604 ejabberd_web_admin:2224 ejabberd_web_admin:2368
msgid "Stop"
msgstr "Detindre"
@@ -1689,19 +1675,19 @@ msgstr "Parar mòduls"
msgid "Stop Modules at "
msgstr "Detindre mòduls en "
-#: ejabberd_web_admin:1839 mod_configure:511
+#: ejabberd_web_admin:1565 mod_configure:511
msgid "Stopped Nodes"
msgstr "Nodes parats"
-#: ejabberd_web_admin:1952
+#: ejabberd_web_admin:1678
msgid "Storage Type"
msgstr "Tipus d'emmagatzematge"
-#: ejabberd_web_admin:1993
+#: ejabberd_web_admin:1719
msgid "Store binary backup:"
msgstr "Guardar una còpia de seguretat binària:"
-#: ejabberd_web_admin:2023
+#: ejabberd_web_admin:1749
msgid "Store plain text backup:"
msgstr "Guardar una còpia de seguretat en format de text pla:"
@@ -1709,16 +1695,16 @@ msgstr "Guardar una còpia de seguretat en format de text pla:"
msgid "Subject"
msgstr "Assumpte"
-#: ejabberd_web_admin:774 ejabberd_web_admin:814 ejabberd_web_admin:879
-#: ejabberd_web_admin:944 ejabberd_web_admin:1963 mod_shared_roster:933
+#: ejabberd_web_admin:500 ejabberd_web_admin:540 ejabberd_web_admin:605
+#: ejabberd_web_admin:670 ejabberd_web_admin:1689 mod_shared_roster:933
msgid "Submit"
msgstr "Enviar"
-#: ejabberd_web_admin:762 ejabberd_web_admin:801 ejabberd_web_admin:867
-#: ejabberd_web_admin:900 ejabberd_web_admin:936 ejabberd_web_admin:1421
-#: ejabberd_web_admin:1704 ejabberd_web_admin:1860 ejabberd_web_admin:1894
-#: ejabberd_web_admin:1974 ejabberd_web_admin:2144 ejabberd_web_admin:2173
-#: ejabberd_web_admin:2270 mod_offline:681 mod_roster:971 mod_shared_roster:830
+#: ejabberd_web_admin:488 ejabberd_web_admin:527 ejabberd_web_admin:593
+#: ejabberd_web_admin:626 ejabberd_web_admin:662 ejabberd_web_admin:1147
+#: ejabberd_web_admin:1430 ejabberd_web_admin:1586 ejabberd_web_admin:1620
+#: ejabberd_web_admin:1700 ejabberd_web_admin:1870 ejabberd_web_admin:1899
+#: ejabberd_web_admin:1996 mod_offline:681 mod_roster:971 mod_shared_roster:830
#: mod_shared_roster:925
msgid "Submitted"
msgstr "Enviat"
@@ -1727,19 +1713,19 @@ msgstr "Enviat"
msgid "Subscription"
msgstr "Subscripció"
-#: mod_muc_room:3708
+#: mod_muc_room:3720
msgid "Subscriptions are not allowed"
-msgstr ""
+msgstr "Les subscripcions no estan permeses"
#: mod_muc_log:469
msgid "Sunday"
msgstr "Diumenge"
-#: mod_muc_room:998 mod_muc_room:1843 mod_muc_room:3737
+#: mod_muc_room:998 mod_muc_room:1849 mod_muc_room:3749
msgid "That nickname is already in use by another occupant"
msgstr "El Nickname està siguent utilitzat per una altra persona"
-#: mod_muc:745 mod_muc_room:1004 mod_muc_room:1852 mod_muc_room:3740
+#: mod_muc:745 mod_muc_room:1004 mod_muc_room:1858 mod_muc_room:3752
msgid "That nickname is registered by another person"
msgstr "El nickname ja està registrat per una altra persona"
@@ -1747,17 +1733,18 @@ msgstr "El nickname ja està registrat per una altra persona"
msgid "The CAPTCHA is valid."
msgstr "El CAPTCHA es vàlid."
-#: mod_muc_room:653 mod_muc_room:3672 mod_register:190
+#: mod_muc_room:653 mod_muc_room:3684 mod_register:190
msgid "The CAPTCHA verification has failed"
msgstr "La verificació CAPTCHA ha fallat"
#: mod_muc_room:302
msgid "The feature requested is not supported by the conference"
msgstr ""
+"La característica sol·licitada no està suportada per la sala de conferència"
#: mod_register:308 mod_register:366
msgid "The password contains unacceptable characters"
-msgstr ""
+msgstr "La contrasenya conté caràcters inacceptables"
#: mod_register:311 mod_register:370
msgid "The password is too weak"
@@ -1769,17 +1756,19 @@ msgstr "La contrasenya del teu compte Jabber s'ha canviat correctament."
#: mod_register:160 mod_vcard:219
msgid "The query is only allowed from local users"
-msgstr ""
+msgstr "La petició està permesa només d'usuaris locals"
#: mod_roster:203
msgid "The query must not contain <item/> elements"
-msgstr ""
+msgstr "La petició no pot contenir elements <item/>"
#: mod_privacy:280
msgid ""
"The stanza MUST contain only one <active/> element, one <default/> element, "
"or one <list/> element"
msgstr ""
+"El paquet DEU contindre només un element <active/>, un element <default/>, o "
+"un element <list/>"
#: mod_register_web:146
msgid "There was an error changing the password: "
@@ -1793,13 +1782,13 @@ msgstr "Hi ha hagut un error creant el compte: "
msgid "There was an error deleting the account: "
msgstr "Hi ha hagut un error esborrant el compte: "
-#: mod_register_web:236
+#: mod_register_web:255
msgid "This is case insensitive: macbeth is the same that MacBeth and Macbeth."
msgstr ""
"Això no distingeix majúscules de minúscules: macbeth es el mateix que "
"MacBeth i Macbeth."
-#: mod_register_web:220
+#: mod_register_web:239
msgid ""
"This page allows to create a Jabber account in this Jabber server. Your JID "
"(Jabber IDentifier) will be of the form: username@server. Please read "
@@ -1810,13 +1799,13 @@ msgstr ""
"usuari@servidor. Si us plau, llegeix amb cura les instruccions per emplenar "
"correctament els camps."
-#: mod_register_web:470
+#: mod_register_web:491
msgid "This page allows to unregister a Jabber account in this Jabber server."
msgstr ""
"Aquesta pàgina permet anul·lar el registre d'un compte Jabber en aquest "
"servidor Jabber."
-#: mod_muc_log:1038
+#: mod_muc_log:801
msgid "This room is not anonymous"
msgstr "Aquesta sala no és anònima"
@@ -1838,7 +1827,7 @@ msgstr "Per a"
#: mod_register:215
msgid "To register, visit ~s"
-msgstr ""
+msgstr "Per a registrar-te, visita ~s"
#: mod_configure:709
msgid "To ~s"
@@ -1846,41 +1835,39 @@ msgstr "A ~s"
#: ejabberd_oauth:439
msgid "Token TTL"
-msgstr ""
+msgstr "Token TTL"
#: xmpp_stream_in:463
msgid "Too long value of 'xml:lang' attribute"
-msgstr ""
+msgstr "El valor de l'atribut 'xml:lang' és massa llarg"
-#: mod_muc_room:2541 mod_muc_room:3081
+#: mod_muc_room:2553 mod_muc_room:3093
msgid "Too many <item/> elements"
-msgstr ""
+msgstr "N'hi ha massa elements <item/>"
#: mod_privacy:164
msgid "Too many <list/> elements"
-msgstr ""
+msgstr "N'hi ha massa elements <list/>"
-#: mod_muc_room:1924 mod_register:240
+#: mod_muc_room:1927 mod_register:240
msgid "Too many CAPTCHA requests"
msgstr "Massa peticions de CAPTCHA"
#: mod_proxy65_service:223
-#, fuzzy
msgid "Too many active bytestreams"
-msgstr "Massa missatges sense haver reconegut la seva recepció"
+msgstr "N'hi ha massa Bytestreams actius"
#: mod_stream_mgmt:205
msgid "Too many unacked stanzas"
msgstr "Massa missatges sense haver reconegut la seva recepció"
-#: mod_muc_room:1802
-#, fuzzy
+#: mod_muc_room:1808
msgid "Too many users in this conference"
-msgstr "Les peticions de veu es troben desactivades en aquesta conferència"
+msgstr "N'hi ha massa usuaris en esta sala de conferència"
#: mod_register:355
msgid "Too many users registered"
-msgstr ""
+msgstr "Massa usuaris registrats"
#: mod_muc_admin:368
msgid "Total rooms"
@@ -1890,19 +1877,19 @@ msgstr "Nombre total de sales"
msgid "Traffic rate limit is exceeded"
msgstr "El llímit de tràfic ha sigut sobrepassat"
-#: ejabberd_web_admin:2219
+#: ejabberd_web_admin:1945
msgid "Transactions Aborted:"
msgstr "Transaccions Avortades"
-#: ejabberd_web_admin:2215
+#: ejabberd_web_admin:1941
msgid "Transactions Committed:"
msgstr "Transaccions Realitzades:"
-#: ejabberd_web_admin:2227
+#: ejabberd_web_admin:1953
msgid "Transactions Logged:"
msgstr "Transaccions registrades"
-#: ejabberd_web_admin:2223
+#: ejabberd_web_admin:1949
msgid "Transactions Restarted:"
msgstr "Transaccions reiniciades"
@@ -1910,13 +1897,13 @@ msgstr "Transaccions reiniciades"
msgid "Tuesday"
msgstr "Dimarts"
-#: mod_muc_room:1933 mod_register:244
+#: mod_muc_room:1936 mod_register:244
msgid "Unable to generate a CAPTCHA"
msgstr "No s'ha pogut generar un CAPTCHA"
#: ejabberd_service:120
msgid "Unable to register route on existing local domain"
-msgstr ""
+msgstr "No s'ha pogut registrar la ruta al domini local existent"
#: ejabberd_web_admin:209 ejabberd_web_admin:221 ejabberd_web_admin:241
#: ejabberd_web_admin:253
@@ -1925,25 +1912,25 @@ msgstr "No autoritzat"
#: mod_announce:485 mod_configure:830 mod_configure:1758
msgid "Unexpected action"
-msgstr ""
+msgstr "Acció inesperada"
-#: mod_register_web:488
+#: mod_register_web:509
msgid "Unregister"
msgstr "Anul·lar el registre"
-#: mod_register_web:197 mod_register_web:460 mod_register_web:468
+#: mod_register_web:215 mod_register_web:481 mod_register_web:489
msgid "Unregister a Jabber account"
msgstr "Anul·lar el registre d'un compte Jabber"
#: mod_mam:526
msgid "Unsupported <index/> element"
-msgstr ""
+msgstr "Element <index/> no soportat"
#: mod_mix:119
msgid "Unsupported MIX query"
-msgstr ""
+msgstr "Petició MIX no soportada"
-#: ejabberd_web_admin:1872 ejabberd_web_admin:2285
+#: ejabberd_web_admin:1598 ejabberd_web_admin:2011
msgid "Update"
msgstr "Actualitzar"
@@ -1955,39 +1942,38 @@ msgstr "Actualitzar el missatge del dia (no enviar)"
msgid "Update message of the day on all hosts (don't send)"
msgstr "Actualitza el missatge del dia en tots els hosts (no enviar)"
-#: ejabberd_web_admin:2278
+#: ejabberd_web_admin:2004
msgid "Update plan"
msgstr "Pla d'actualització"
-#: ejabberd_web_admin:2280
+#: ejabberd_web_admin:2006
msgid "Update script"
msgstr "Script d'actualització"
-#: ejabberd_web_admin:2267
+#: ejabberd_web_admin:1993
msgid "Update ~p"
msgstr "Actualitzar ~p"
-#: ejabberd_web_admin:2203
+#: ejabberd_web_admin:1929
msgid "Uptime:"
msgstr "Temps en marxa"
#: xmpp_stream_out:533
-#, fuzzy
msgid "Use of STARTTLS forbidden"
-msgstr "És obligatori utilitzar STARTTLS"
+msgstr "No està permès utilitzar STARTTLS"
#: xmpp_stream_in:573 xmpp_stream_out:527 xmpp_stream_out:603
msgid "Use of STARTTLS required"
msgstr "És obligatori utilitzar STARTTLS"
-#: ejabberd_web_admin:1430 ejabberd_web_admin:1486 mod_register:225
+#: ejabberd_web_admin:1156 ejabberd_web_admin:1212 mod_register:225
#: mod_vcard_ldap:328 mod_vcard_mnesia:99 mod_vcard_sql:154
msgid "User"
msgstr "Usuari"
#: ejabberd_oauth:428
msgid "User (jid)"
-msgstr ""
+msgstr "Usuari (jid)"
#: mod_configure:308 mod_configure:505
msgid "User Management"
@@ -1995,34 +1981,33 @@ msgstr "Gestió d'Usuaris"
#: mod_register:345
msgid "User already exists"
-msgstr ""
+msgstr "El usuari ja existeix"
#: mod_echo:138
msgid "User part of JID in 'from' is empty"
-msgstr ""
+msgstr "La part d'usuari del JID a 'from' està buida"
#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_sic:106
-#, fuzzy
msgid "User session not found"
-msgstr "Node no trobat"
+msgstr "Sessió d'usuari no trobada"
#: mod_stream_mgmt:561 mod_stream_mgmt:583
msgid "User session terminated"
-msgstr ""
+msgstr "Sessió d'usuari terminada"
-#: ejabberd_web_admin:1700
+#: ejabberd_web_admin:1426
msgid "User ~s"
msgstr "Usuari ~s"
-#: mod_register_web:230 mod_register_web:366 mod_register_web:476
+#: mod_register_web:249 mod_register_web:386 mod_register_web:497
msgid "Username:"
msgstr "Nom d'usuari:"
-#: ejabberd_web_admin:959 ejabberd_web_admin:967
+#: ejabberd_web_admin:685 ejabberd_web_admin:693
msgid "Users"
msgstr "Usuaris"
-#: ejabberd_web_admin:990
+#: ejabberd_web_admin:716
msgid "Users Last Activity"
msgstr "Última activitat d'usuari"
@@ -2034,34 +2019,34 @@ msgstr "Els usuaris no tenen permís per a crear comptes tan depresa"
msgid "Validate"
msgstr "Validar"
-#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3662 mod_muc_room:3802
+#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3674 mod_muc_room:3814
#: mod_pubsub:895 mod_push:249
msgid "Value 'get' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "El valor 'get' a l'atribut 'type' no és permès"
#: mod_disco:159 mod_disco:175 mod_disco:279 mod_disco:346 mod_irc:270
#: mod_irc:285 mod_irc:339 mod_last:118 mod_last:140 mod_muc:479 mod_muc:504
-#: mod_muc:539 mod_muc:561 mod_muc:571 mod_muc_room:3597 mod_muc_room:3641
+#: mod_muc:539 mod_muc:561 mod_muc:571 mod_muc_room:3609 mod_muc_room:3653
#: mod_proxy65_service:142 mod_proxy65_service:160 mod_proxy65_service:167
#: mod_pubsub:821 mod_pubsub:839 mod_pubsub:877 mod_sic:81 mod_sic:93
#: mod_stats:55 mod_time:62 mod_vcard:198 mod_vcard:236 mod_version:62
msgid "Value 'set' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "El valor 'set' a l'atribut 'type' no és permès"
#: pubsub_subscription:237 pubsub_subscription_sql:202
msgid "Value of '~s' should be boolean"
-msgstr ""
+msgstr "El valor de '~s' deuria ser booleà"
#: pubsub_subscription:215 pubsub_subscription_sql:180
msgid "Value of '~s' should be datetime string"
-msgstr ""
+msgstr "El valor de '~s' deuria ser una data"
#: pubsub_subscription:209 pubsub_subscription:227 pubsub_subscription_sql:174
#: pubsub_subscription_sql:192
msgid "Value of '~s' should be integer"
-msgstr ""
+msgstr "El valor de '~s' deuria ser un numero enter"
-#: ejabberd_web_admin:950
+#: ejabberd_web_admin:676
msgid "Virtual Hosts"
msgstr "Hosts virtuals"
@@ -2073,7 +2058,7 @@ msgstr "Els visitants no tenen permés canviar el seus Nicknames en esta sala"
msgid "Visitors are not allowed to send messages to all occupants"
msgstr "Els visitants no poden enviar missatges a tots els ocupants"
-#: mod_muc_room:3879
+#: mod_muc_room:3891
msgid "Voice request"
msgstr "Petició de veu"
@@ -2085,18 +2070,18 @@ msgstr "Les peticions de veu es troben desactivades en aquesta conferència"
msgid "Wednesday"
msgstr "Dimecres"
-#: mod_register_web:255
+#: mod_register_web:274
msgid "You can later change your password using a Jabber client."
msgstr ""
"Podràs canviar la teva contrasenya més endavant utilitzant un client Jabber."
-#: mod_muc_room:1830
+#: mod_muc_room:1836
msgid "You have been banned from this room"
msgstr "Has sigut bloquejat en aquesta sala"
-#: mod_muc_room:1811
+#: mod_muc_room:1817
msgid "You have joined too many conferences"
-msgstr ""
+msgstr "Has entrat en massa sales de conferència"
#: mod_muc:777
msgid "You must fill in field \"Nickname\" in the form"
@@ -2123,9 +2108,8 @@ msgid "You need an x:data capable client to search"
msgstr "Necessites un client amb suport x:data per a poder buscar"
#: mod_pubsub:1504
-#, fuzzy
msgid "You're not allowed to create nodes"
-msgstr "No està permés enviar missatges privats"
+msgstr "No tens permís per a crear nodes"
#: mod_register_web:111
msgid "Your Jabber account was successfully created."
@@ -2211,11 +2195,11 @@ msgstr "Entrar a la sala"
msgid "leaves the room"
msgstr "Deixar la sala"
-#: mod_muc_room:3856
+#: mod_muc_room:3868
msgid "private, "
msgstr "privat"
-#: mod_muc_room:3955
+#: mod_muc_room:3967
msgid "the password is"
msgstr "la contrasenya és"
@@ -2223,11 +2207,11 @@ msgstr "la contrasenya és"
msgid "vCard User Search"
msgstr "Recerca de vCard d'usuari"
-#: ejabberd_web_admin:932
+#: ejabberd_web_admin:658
msgid "~s access rule configuration"
msgstr "Configuració de les Regles d'Accés ~s"
-#: mod_muc_room:3948
+#: mod_muc_room:3960
msgid "~s invites you to the room ~s"
msgstr "~s et convida a la sala ~s"
diff --git a/priv/msgs/el.po b/priv/msgs/el.po
index 79f13e34f..bfeca6a5d 100644
--- a/priv/msgs/el.po
+++ b/priv/msgs/el.po
@@ -2,26 +2,27 @@ msgid ""
msgstr ""
"Project-Id-Version: el\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2012-04-18 12:50-0000\n"
+"PO-Revision-Date: 2017-10-27 12:33+0100\n"
"Last-Translator: James Iakovos Mandelis <ebuggerd@008.clara.co.uk>\n"
"Language-Team: \n"
-"Language: \n"
+"Language: el\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Language: Greek (ελληνικά)\n"
+"X-Generator: Poedit 2.0.4\n"
-#: mod_muc_log:413 mod_muc_log:752
+#: mod_muc_log:413 mod_muc_log:588
msgid " has set the subject to: "
msgstr " έχει θέσει το θέμα σε: "
-#: mod_muc_room:1893
+#: mod_muc_room:1904
msgid "A password is required to enter this room"
msgstr "Απαιτείται κωδικός πρόσβασης για είσοδο σε αυτή την αίθουσα"
#: ejabberd_oauth:448
msgid "Accept"
-msgstr ""
+msgstr "Αποδοχή"
#: mod_configure:1109
msgid "Access Configuration"
@@ -31,12 +32,12 @@ msgstr "Διαμόρφωση Πρόσβασης"
msgid "Access Control List Configuration"
msgstr "Διαχείριση στις Λίστες Ελέγχου Πρόσβασης"
-#: ejabberd_web_admin:758 ejabberd_web_admin:797 mod_configure:185
+#: ejabberd_web_admin:484 ejabberd_web_admin:523 mod_configure:185
#: mod_configure:514
msgid "Access Control Lists"
msgstr "Λίστες Ελέγχου Πρόσβασης"
-#: ejabberd_web_admin:863 ejabberd_web_admin:896 mod_configure:187
+#: ejabberd_web_admin:589 ejabberd_web_admin:622 mod_configure:187
#: mod_configure:515
msgid "Access Rules"
msgstr "Κανόνες Πρόσβασης"
@@ -80,24 +81,24 @@ msgstr "Eνέργεια για το χρήστη"
msgid "Add Jabber ID"
msgstr "Προσθήκη Jabber Ταυτότητας"
-#: ejabberd_web_admin:1277 mod_shared_roster:825
+#: ejabberd_web_admin:1003 mod_shared_roster:825
msgid "Add New"
msgstr "Προσθήκη νέου"
-#: ejabberd_web_admin:1444 mod_configure:166 mod_configure:521
+#: ejabberd_web_admin:1170 mod_configure:166 mod_configure:521
#: mod_configure:1118
msgid "Add User"
msgstr "Προσθήκη Χρήστη"
-#: ejabberd_web_admin:687 ejabberd_web_admin:698
+#: ejabberd_web_admin:413 ejabberd_web_admin:424
msgid "Administration"
msgstr "Διαχείριση"
#: mod_configure:1767
msgid "Administration of "
-msgstr "Διαχείριση του"
+msgstr "Διαχείριση του "
-#: mod_muc_room:2528
+#: mod_muc_room:2548
msgid "Administrator privileges required"
msgstr "Aπαιτούνται προνόμια διαχειριστή"
@@ -105,35 +106,35 @@ msgstr "Aπαιτούνται προνόμια διαχειριστή"
msgid "All Users"
msgstr "Όλοι οι χρήστες"
-#: ejabberd_web_admin:1010
+#: ejabberd_web_admin:736
msgid "All activity"
msgstr "Όλες οι δραστηριότητες"
-#: mod_muc_log:1046
+#: mod_muc_log:809
msgid "Allow users to change the subject"
msgstr "Επιτρέψετε στους χρήστες να αλλάζουν το θέμα"
-#: mod_muc_log:1052
+#: mod_muc_log:815
msgid "Allow users to query other users"
msgstr "Επιτρέπστε στους χρήστες να ερωτούν άλλους χρήστες"
-#: mod_muc_log:1054
+#: mod_muc_log:817
msgid "Allow users to send invites"
msgstr "Επιτρέψετε στους χρήστες να αποστέλλουν προσκλήσεις"
-#: mod_muc_log:1048
+#: mod_muc_log:811
msgid "Allow users to send private messages"
msgstr "Επιτρέψετε στους χρήστες να αποστέλλουν ιδιωτικά μηνύματα"
-#: mod_muc_log:1057
+#: mod_muc_log:820
msgid "Allow visitors to change nickname"
msgstr "Επιτρέψετε στους επισκέπτες να αλλάζου ψευδώνυμο"
-#: mod_muc_log:1050
+#: mod_muc_log:813
msgid "Allow visitors to send private messages to"
msgstr "Επιτρέψετε στους χρήστες να αποστέλλουν ιδιωτικά μηνύματα σε"
-#: mod_muc_log:1059
+#: mod_muc_log:822
msgid "Allow visitors to send status text in presence updates"
msgstr ""
"Επιτρέψτε στους επισκέπτες να αποστέλλουν κατάσταση στις ενημερώσεις "
@@ -151,11 +152,11 @@ msgstr "Απρίλιος"
msgid "August"
msgstr "Αύγουστος"
-#: mod_pubsub:1842
+#: mod_pubsub:1848
msgid "Automatic node creation is not enabled"
-msgstr ""
+msgstr "Η αυτόματη δημιουργία κόμβων δεν είναι ενεργοποιημένη"
-#: ejabberd_web_admin:1867 mod_configure:148 mod_configure:617
+#: ejabberd_web_admin:1593 mod_configure:148 mod_configure:617
msgid "Backup"
msgstr "Αποθήκευση Αντιγράφου Ασφαλείας"
@@ -163,19 +164,18 @@ msgstr "Αποθήκευση Αντιγράφου Ασφαλείας"
msgid "Backup Management"
msgstr "Διαχείριση Αντιγράφου Ασφαλείας"
-#: ejabberd_web_admin:1979
-#, fuzzy
+#: ejabberd_web_admin:1705
msgid "Backup of ~p"
-msgstr "Αντιγράφο Ασφαλείας του "
+msgstr "Αντιγράφο Ασφαλείας του ~p"
#: mod_configure:948
msgid "Backup to File at "
msgstr "Αποθήκευση Αντιγράφου Ασφαλείας σε Αρχείο στο "
-#: ejabberd_web_admin:763 ejabberd_web_admin:802 ejabberd_web_admin:868
-#: ejabberd_web_admin:901 ejabberd_web_admin:937 ejabberd_web_admin:1422
-#: ejabberd_web_admin:1705 ejabberd_web_admin:1861 ejabberd_web_admin:2145
-#: ejabberd_web_admin:2174 mod_roster:972 mod_shared_roster:831
+#: ejabberd_web_admin:489 ejabberd_web_admin:528 ejabberd_web_admin:594
+#: ejabberd_web_admin:627 ejabberd_web_admin:663 ejabberd_web_admin:1148
+#: ejabberd_web_admin:1431 ejabberd_web_admin:1587 ejabberd_web_admin:1871
+#: ejabberd_web_admin:1900 mod_roster:972 mod_shared_roster:831
#: mod_shared_roster:926
msgid "Bad format"
msgstr "Ακατάλληλη μορφή"
@@ -187,30 +187,30 @@ msgstr "Γενέθλια"
#: mod_legacy_auth:102
msgid "Both the username and the resource are required"
-msgstr ""
+msgstr "Τόσο το όνομα χρήστη όσο και ο πόρος είναι απαραίτητα"
#: mod_proxy65_service:226
msgid "Bytestream already activated"
-msgstr ""
+msgstr "Το Bytestream έχει ήδη ενεργοποιηθε"
#: ejabberd_captcha:135
msgid "CAPTCHA web page"
-msgstr "Ιστοσελίδα CAPTCHA "
+msgstr "Ιστοσελίδα CAPTCHA"
-#: ejabberd_web_admin:2207
+#: ejabberd_web_admin:1933
msgid "CPU Time:"
msgstr "Ώρα CPU:"
#: mod_privacy:334
msgid "Cannot remove active list"
-msgstr ""
+msgstr "Δεν είναι δυνατή η κατάργηση της ενεργής λίστας"
#: mod_privacy:341
msgid "Cannot remove default list"
-msgstr ""
+msgstr "Δεν μπορείτε να καταργήσετε την προεπιλεγμένη λίστα"
-#: ejabberd_web_admin:1679 mod_register_web:194 mod_register_web:353
-#: mod_register_web:361 mod_register_web:386
+#: ejabberd_web_admin:1405 mod_register_web:212 mod_register_web:373
+#: mod_register_web:381 mod_register_web:406
msgid "Change Password"
msgstr "Αλλαγή κωδικού"
@@ -219,16 +219,14 @@ msgid "Change User Password"
msgstr "Αλλαγή Κωδικού Πρόσβασης Χρήστη"
#: mod_register:295
-#, fuzzy
msgid "Changing password is not allowed"
-msgstr "Χαρακτήρες δεν επιτρέπονται:"
+msgstr "Η αλλαγή του κωδικού πρόσβασης δεν επιτρέπεται"
-#: mod_muc_room:2764
-#, fuzzy
+#: mod_muc_room:2784
msgid "Changing role/affiliation is not allowed"
-msgstr "Χαρακτήρες δεν επιτρέπονται:"
+msgstr "Η αλλαγή ρόλου/ομάδας δεν επιτρέπεται"
-#: mod_register_web:239
+#: mod_register_web:258
msgid "Characters not allowed:"
msgstr "Χαρακτήρες δεν επιτρέπονται:"
@@ -270,7 +268,7 @@ msgstr "Επιλέξτε modules για να σταματήσουν"
msgid "Choose storage type of tables"
msgstr "Επιλέξτε τύπο αποθήκευσης των πινάκων"
-#: mod_pubsub:1338
+#: mod_pubsub:1344
msgid "Choose whether to approve this entity's subscription."
msgstr "Επιλέξτε αν θα εγκρίθεί η εγγραφή αυτής της οντότητας."
@@ -291,11 +289,11 @@ msgstr "Αίθουσα σύνεδριασης δεν υπάρχει"
msgid "Configuration"
msgstr "Διαμόρφωση"
-#: mod_muc_room:3163
+#: mod_muc_room:3183
msgid "Configuration of room ~s"
msgstr "Διαμόρφωση Αίθουσας σύνεδριασης ~s"
-#: ejabberd_web_admin:1711
+#: ejabberd_web_admin:1437
msgid "Connected Resources:"
msgstr "Συνδεδεμένοι Πόροι:"
@@ -308,7 +306,7 @@ msgstr "Παράμετροι Συνδέσης"
msgid "Country"
msgstr "Χώρα"
-#: ejabberd_web_admin:1866 mod_configure:139 mod_configure:580
+#: ejabberd_web_admin:1592 mod_configure:139 mod_configure:580
msgid "Database"
msgstr "Βάση δεδομένων"
@@ -316,32 +314,30 @@ msgstr "Βάση δεδομένων"
msgid "Database Tables Configuration at "
msgstr "Διαμόρφωση Πίνακων βάσης δεδομένων στο "
-#: ejabberd_web_admin:1941
-#, fuzzy
+#: ejabberd_web_admin:1667
msgid "Database Tables at ~p"
-msgstr "Πίνακες βάσης δεδομένων στο "
+msgstr "Πίνακες βάσης δεδομένων στο ~p"
#: mod_blocking:267 mod_carboncopy:137 mod_irc:486 mod_irc:574 mod_irc:739
#: mod_last:215 mod_mam:501 mod_muc:749 mod_offline:291 mod_offline:582
#: mod_privacy:186 mod_privacy:204 mod_privacy:298 mod_privacy:314
#: mod_privacy:347 mod_privacy:364 mod_private:103 mod_private:110
-#: mod_proxy65_service:231 mod_pubsub:3506 mod_pubsub:3513 mod_pubsub:3573
-#: mod_pubsub:3598 mod_pubsub:3604 mod_pubsub:3607 mod_vcard:226
-#: node_flat_sql:801 nodetree_tree_sql:128 nodetree_tree_sql:142
+#: mod_proxy65_service:231 mod_pubsub:3512 mod_pubsub:3519 mod_pubsub:3579
+#: mod_pubsub:3604 mod_pubsub:3610 mod_pubsub:3613 mod_push:265 mod_push:280
+#: mod_vcard:226 node_flat_sql:801 nodetree_tree_sql:128 nodetree_tree_sql:142
#: nodetree_tree_sql:257
-#, fuzzy
msgid "Database failure"
-msgstr "Βάση δεδομένων"
+msgstr "Αποτυχία βάσης δεδομένων"
#: mod_muc_log:484
msgid "December"
msgstr "Δεκέμβριος"
-#: mod_muc_log:1044
+#: mod_muc_log:807
msgid "Default users as participants"
msgstr "Προεπιλογη χρήστων ως συμμετέχοντες"
-#: ejabberd_web_admin:811 ejabberd_web_admin:911 mod_offline:703
+#: ejabberd_web_admin:537 ejabberd_web_admin:637 mod_offline:703
#: mod_shared_roster:839
msgid "Delete Selected"
msgstr "Διαγραφή επιλεγμένων"
@@ -370,7 +366,7 @@ msgstr "Αντίγραφο μόνο σε δίσκο"
msgid "Displayed Groups:"
msgstr "Εμφανίσμενες Ομάδες:"
-#: mod_register_web:251
+#: mod_register_web:270
msgid ""
"Don't tell your password to anybody, not even the administrators of the "
"Jabber server."
@@ -386,19 +382,20 @@ msgstr "Αποθήκευση Αντιγράφου Ασφαλείας σε αρχ
msgid "Dump to Text File"
msgstr "Αποθήκευση σε αρχείο κειμένου"
+# Should be "Duplicate" not "Duplicated"
#: mod_roster:180
msgid "Duplicated groups are not allowed by RFC6121"
-msgstr ""
+msgstr "Δεν επιτρέπονται διπλότυπες ομάδες από το RFC6121"
#: mod_configure:1776
msgid "Edit Properties"
msgstr "Επεξεργασία ιδιοτήτων"
-#: mod_muc_room:3881
+#: mod_muc_room:3901
msgid "Either approve or decline the voice request."
msgstr "Είτε εγκρίνετε ή απορρίψτε το αίτημα φωνής."
-#: ejabberd_web_admin:1953
+#: ejabberd_web_admin:1679
msgid "Elements"
msgstr "Στοιχεία"
@@ -408,17 +405,17 @@ msgid "Email"
msgstr "Email"
#: mod_register:292
-#, fuzzy
msgid "Empty password"
-msgstr "ο κωδικός πρόσβασης είναι"
+msgstr "Ο κωδικός πρόσβασης είναι κενός"
-#: mod_muc_log:1055
+#: mod_muc_log:818
msgid "Enable logging"
msgstr "Ενεργοποίηση καταγραφής"
-#: mod_push:252
+#: mod_push:253
msgid "Enabling push without 'node' attribute is not supported"
msgstr ""
+"Η ενεργοποίηση της ώθησης χωρίς το χαρακτηριστικό 'κόμβος' δεν υποστηρίζεται"
#: mod_irc:834
msgid "Encoding for server ~b"
@@ -430,7 +427,7 @@ msgstr "Τερματισμός Συνεδρίας Χρήστη"
#: mod_configure:938
msgid "Enter list of {Module, [Options]}"
-msgstr "Εισάγετε κατάλογο των (Module, [Επιλογές])"
+msgstr "Εισάγετε κατάλογο των (Module, [Options])"
#: mod_muc:723
msgid "Enter nickname you want to register"
@@ -479,7 +476,7 @@ msgstr ""
msgid "Erlang Jabber Server"
msgstr "Erlang Jabber Διακομιστής"
-#: ejabberd_web_admin:1976 ejabberd_web_admin:2147
+#: ejabberd_web_admin:1702 ejabberd_web_admin:1873
msgid "Error"
msgstr "Σφάλμα"
@@ -491,17 +488,17 @@ msgstr ""
"Παράδειγμα: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta."
"fef.net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}]."
-#: ejabberd_web_admin:2084
+#: ejabberd_web_admin:1810
msgid "Export all tables as SQL queries to a file:"
-msgstr ""
+msgstr "Εξαγωγή όλων των πινάκων ως ερωτημάτων SQL σε ένα αρχείο:"
-#: ejabberd_web_admin:2056
+#: ejabberd_web_admin:1782
msgid "Export data of all users in the server to PIEFXIS files (XEP-0227):"
msgstr ""
"Εξαγωγή δεδομένων όλων των χρηστών του διακομιστή σε PIEFXIS αρχεία "
"(XEP-0227):"
-#: ejabberd_web_admin:2068
+#: ejabberd_web_admin:1794
msgid "Export data of users in a host to PIEFXIS files (XEP-0227):"
msgstr ""
"Εξαγωγή δεδομένων των χρηστών κεντρικού υπολογιστή σε PIEFXIS αρχεία "
@@ -509,15 +506,15 @@ msgstr ""
#: mod_delegation:275
msgid "External component failure"
-msgstr ""
+msgstr "Βλάβη εξωτερικού στοιχείου"
#: mod_delegation:283
msgid "External component timeout"
-msgstr ""
+msgstr "Τέλος χρονικού όριου εξωτερικού στοιχείου"
#: mod_proxy65_service:218
msgid "Failed to activate bytestream"
-msgstr ""
+msgstr "Απέτυχε η ενεργοποίηση του bytestream"
#: mod_muc_room:910
msgid "Failed to extract JID from your voice request approval"
@@ -526,18 +523,19 @@ msgstr "Απέτυχε η εξαγωγή JID από την έγκριση του
#: mod_delegation:257
msgid "Failed to map delegated namespace to external component"
msgstr ""
+"Αποτυχία ταξιθέτησης μεταγεγραμμένου χώρου ονομάτων σε εξωτερικό στοιχείο"
#: mod_http_upload:602
msgid "Failed to parse HTTP response"
-msgstr ""
+msgstr "Αποτυχία ανάλυσης της απόκρισης HTTP"
#: mod_irc:426
msgid "Failed to parse chanserv"
-msgstr ""
+msgstr "Δεν ήταν δυνατή η ανάλυση του chanserv"
-#: mod_muc_room:3297
+#: mod_muc_room:3317
msgid "Failed to process option '~s'"
-msgstr ""
+msgstr "Αποτυχία επεξεργασίας της επιλογής '~ s'"
#: mod_vcard_ldap:332 mod_vcard_ldap:345 mod_vcard_mnesia:103
#: mod_vcard_mnesia:117 mod_vcard_sql:158 mod_vcard_sql:172
@@ -550,7 +548,7 @@ msgstr "Φεβρουάριος"
#: mod_http_upload:555
msgid "File larger than ~w bytes"
-msgstr ""
+msgstr "Αρχείο μεγαλύτερο από ~w bytes"
#: mod_vcard:437
msgid ""
@@ -599,27 +597,26 @@ msgid "Get User Statistics"
msgstr "Έκθεση Στατιστικών Χρήστη"
#: mod_vcard_ldap:330 mod_vcard_ldap:343
-#, fuzzy
msgid "Given Name"
-msgstr "Πατρώνυμο"
+msgstr "Ονομα"
#: mod_shared_roster:923
msgid "Group "
-msgstr "Ομάδα"
+msgstr "Ομάδα "
#: mod_roster:916
msgid "Groups"
msgstr "Ομάδες"
-#: ejabberd_web_admin:1365
+#: ejabberd_web_admin:1091
msgid "Host"
msgstr "Κεντρικός Υπολογιστής"
#: mod_s2s_dialback:325
msgid "Host unknown"
-msgstr ""
+msgstr "Ο κεντρικός διακομιστής είναι άγνωστος"
-#: ejabberd_web_admin:2463
+#: ejabberd_web_admin:2189
msgid "IP"
msgstr "IP"
@@ -637,12 +634,11 @@ msgstr "IRC Όνομα χρήστη"
#: mod_irc:669
msgid "IRC channel (don't put the first #)"
-msgstr "IRC κανάλι (μην τεθεί το πρώτο #)"
+msgstr "IRC δίαυλος (μη βάλεται το πρώτο #)"
#: mod_irc:417
-#, fuzzy
msgid "IRC connection not found"
-msgstr "Κόμβος δεν βρέθηκε"
+msgstr "Δεν βρέθηκε σύνδεση IRC"
#: mod_irc:673
msgid "IRC server"
@@ -693,95 +689,95 @@ msgstr "Εισαγωγή Χρηστών από αρχεία σειράς jabberd
msgid "Import Users from Dir at "
msgstr "Εισαγωγή χρηστών από κατάλογο αρχείων στο "
-#: ejabberd_web_admin:2100
+#: ejabberd_web_admin:1826
msgid "Import user data from jabberd14 spool file:"
msgstr "Εισαγωγή δεδομένων χρήστη από το αρχείο σειράς jabberd14:"
-#: ejabberd_web_admin:2043
+#: ejabberd_web_admin:1769
msgid "Import users data from a PIEFXIS file (XEP-0227):"
msgstr "Εισαγωγή δεδομένων χρηστών από ένα αρχείο PIEFXIS (XEP-0227):"
-#: ejabberd_web_admin:2111
+#: ejabberd_web_admin:1837
msgid "Import users data from jabberd14 spool directory:"
msgstr "Εισαγωγή δεδομένων χρηστών από κατάλογο αρχείων σειράς jabberd14:"
#: xmpp_stream_in:983
msgid "Improper 'from' attribute"
-msgstr ""
+msgstr "Ακατάλληλο χαρακτηριστικό 'from'"
#: xmpp_stream_in:477
msgid "Improper 'to' attribute"
-msgstr ""
+msgstr "Ακατάλληλο χαρακτηριστικό 'to'"
#: ejabberd_service:189
msgid "Improper domain part of 'from' attribute"
-msgstr ""
+msgstr "Ανάρμοστο τμήμα τομέα του χαρακτηριστικού 'from'"
#: mod_muc_room:260
msgid "Improper message type"
msgstr "Ακατάλληλο είδος μηνύματος"
-#: ejabberd_web_admin:1586
-#, fuzzy
+#: ejabberd_web_admin:1312
msgid "Incoming s2s Connections:"
-msgstr "Εξερχόμενες S2S Συνδέσεις:"
+msgstr "Εισερχόμενες συνδέσεις s2s:"
-#: mod_muc_room:3669 mod_register:187
+#: mod_muc_room:3689 mod_register:187
msgid "Incorrect CAPTCHA submit"
-msgstr ""
+msgstr "Λάθος υποβολή CAPTCHA"
-#: mod_muc:772 mod_muc_room:3052 mod_pubsub:1194 mod_register:183 mod_vcard:256
-#, fuzzy
+#: mod_muc:772 mod_muc_room:3072 mod_pubsub:1200 mod_register:183 mod_vcard:256
msgid "Incorrect data form"
-msgstr "Εσφαλμένος κωδικός πρόσβασης"
+msgstr "Εσφαλμένη φόρμα δεδομένων"
-#: mod_muc_room:1943 mod_register:300 mod_register:350
+#: mod_muc_room:1954 mod_register:300 mod_register:350
msgid "Incorrect password"
msgstr "Εσφαλμένος κωδικός πρόσβασης"
#: mod_irc:585
msgid "Incorrect value in data form"
-msgstr ""
+msgstr "Λανθασμένη τιμή στη φόρμα δεδομένων"
#: mod_adhoc:276
msgid "Incorrect value of 'action' attribute"
-msgstr ""
+msgstr "Λανθασμένη τιμή του χαρακτηριστικού 'action'"
#: mod_configure:1806
msgid "Incorrect value of 'action' in data form"
-msgstr ""
+msgstr "Λανθασμένη τιμή 'action' στη φόρμα δεδομένων"
#: mod_configure:1335 mod_configure:1367 mod_configure:1399 mod_configure:1419
#: mod_configure:1439
msgid "Incorrect value of 'path' in data form"
-msgstr ""
+msgstr "Λανθασμένη τιμή 'path' στη φόρμα δεδομένων"
#: mod_irc:331
msgid "Incorrect value of 'type' attribute"
-msgstr ""
+msgstr "Λανθασμένη τιμή του χαρακτηριστικού 'type'"
#: mod_privilege:100
msgid "Insufficient privilege"
-msgstr ""
+msgstr "Ανεπαρκές προνόμια"
#: mod_privilege:286
msgid "Invalid 'from' attribute in forwarded message"
-msgstr ""
+msgstr "Μη έγκυρο χαρακτηριστικό 'από' στο προωθούμενο μήνυμα"
#: mod_privilege:300
msgid "Invalid <forwarded/> element"
-msgstr ""
+msgstr "Μη έγκυρο στοιχείο <forwarded/>"
-#: mod_muc_room:3926
-#, fuzzy
+#: mod_muc_room:3946
msgid "Invitations are not allowed in this conference"
-msgstr "Τα αιτήματα φωνής είναι απενεργοποιημένα, σε αυτό το συνέδριο"
+msgstr "Οι προσκλήσεις δεν επιτρέπονται σε αυτή τη διάσκεψη"
-#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1046
+#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1052
msgid ""
"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"
msgstr ""
+"Δεν επιτρέπεται η αποστολή μηνυμάτων σφάλματος στο δωμάτιο. Ο συμμετέχων (~ "
+"s) έχει στείλει ένα μήνυμα σφάλματος (~ s) και έχει πέταχτεί έξω από την "
+"αίθουσα"
#: mod_muc_room:418 mod_muc_room:429
msgid "It is not allowed to send private messages"
@@ -795,7 +791,7 @@ msgstr "Δεν επιτρέπεται να στείλει προσωπικά μ
msgid "It is not allowed to send private messages to the conference"
msgstr "Δεν επιτρέπεται να στείλει προσωπικά μηνύματα για τη διάσκεψη"
-#: mod_register_web:181 mod_register_web:189
+#: mod_register_web:199 mod_register_web:207
msgid "Jabber Account Registration"
msgstr "Εγγραφή λογαριασμού Jabber"
@@ -812,15 +808,15 @@ msgstr "Ιανουάριος"
#: mod_irc:665
msgid "Join IRC channel"
-msgstr "Είσοδος στο IRC κανάλι"
+msgstr "Είσοδος στον IRC δίαυλος"
#: mod_irc:689
msgid "Join the IRC channel here."
-msgstr "Είσοδος στο κανάλι IRC εδώ."
+msgstr "Είσοδος στον δίαυλο IRC εδώ."
#: mod_irc:690
msgid "Join the IRC channel in this Jabber ID: ~s"
-msgstr "Είσοδος στο κανάλι IRC αυτής της Jabber Ταυτότητας: ~s"
+msgstr "Είσοδος στο δίαυλο IRC αυτής της Jabber Ταυτότητας: ~s"
#: mod_muc_log:479
msgid "July"
@@ -830,7 +826,7 @@ msgstr "Ιούλιος"
msgid "June"
msgstr "Ιούνιος"
-#: ejabberd_web_admin:1488 ejabberd_web_admin:1715
+#: ejabberd_web_admin:1214 ejabberd_web_admin:1441
msgid "Last Activity"
msgstr "Τελευταία Δραστηριότητα"
@@ -838,11 +834,11 @@ msgstr "Τελευταία Δραστηριότητα"
msgid "Last login"
msgstr "Τελευταία σύνδεση"
-#: ejabberd_web_admin:1007
+#: ejabberd_web_admin:733
msgid "Last month"
msgstr "Περασμένο μήνα"
-#: ejabberd_web_admin:1008
+#: ejabberd_web_admin:734
msgid "Last year"
msgstr "Πέρυσι"
@@ -852,58 +848,57 @@ msgstr "Λίστα των Module για Εκκίνηση"
#: mod_muc_admin:373
msgid "List of rooms"
-msgstr ""
+msgstr "Κατάλογος αιθουσών"
-#: ejabberd_web_admin:1869
+#: ejabberd_web_admin:1595
msgid "Listened Ports"
msgstr "Παρακολουθούμενες Θύρες"
-#: ejabberd_web_admin:2139
+#: ejabberd_web_admin:1865
msgid "Listened Ports at "
msgstr "Παρακολουθούμενες Θύρες στο "
-#: ejabberd_web_admin:2281
+#: ejabberd_web_admin:2007
msgid "Low level update script"
-msgstr "Προγράμα ενημέρωσης χαμηλού επίπεδου "
+msgstr "Προγράμα ενημέρωσης χαμηλού επίπεδου"
-#: mod_muc_log:1033
+#: mod_muc_log:796
msgid "Make participants list public"
msgstr "Κάντε κοινό τον κατάλογο συμμετεχόντων"
-#: mod_muc_log:1062
+#: mod_muc_log:825
msgid "Make room CAPTCHA protected"
msgstr "Κάντε την αίθουσα CAPTCHA προστατεύονομενη"
-#: mod_muc_log:1040
+#: mod_muc_log:803
msgid "Make room members-only"
msgstr "Κάντε την αίθουσα μόνο για μέλη"
-#: mod_muc_log:1042
+#: mod_muc_log:805
msgid "Make room moderated"
msgstr "Κάντε την αίθουσα εποπτεύονομενη"
-#: mod_muc_log:1035
+#: mod_muc_log:798
msgid "Make room password protected"
msgstr "Κάντε την αίθουσα προστατεύομενη με κωδικό πρόσβασης"
-#: mod_muc_log:1029
+#: mod_muc_log:792
msgid "Make room persistent"
msgstr "Κάντε αίθουσα μόνιμη"
-#: mod_muc_log:1031
+#: mod_muc_log:794
msgid "Make room public searchable"
msgstr "Κάντε την δημόσια αναζήτηση δυνατή για αυτή την αίθουσα"
#: mod_register:317
-#, fuzzy
msgid "Malformed username"
-msgstr "IRC όνομα χρήστη"
+msgstr "Λανθασμένη μορφή ονόματος χρήστη"
#: mod_muc_log:475
msgid "March"
msgstr "Μάρτιος"
-#: mod_muc_log:1068
+#: mod_muc_log:831
msgid "Maximum Number of Occupants"
msgstr "Μέγιστος αριθμός συμετεχόντων"
@@ -915,11 +910,11 @@ msgstr "Μάιος"
msgid "Members:"
msgstr "Μέλη:"
-#: mod_muc_room:1833
+#: mod_muc_room:1847
msgid "Membership is required to enter this room"
msgstr "Απαιτείται αίτηση συμετοχής για είσοδο σε αυτή την αίθουσα"
-#: mod_register_web:262
+#: mod_register_web:281
msgid ""
"Memorize your password, or write it in a paper placed in a safe place. In "
"Jabber there isn't an automated way to recover your password if you forget "
@@ -929,7 +924,7 @@ msgstr ""
"τοποθετηθεί σε ασφαλές μέρος. Στο Jabber δεν υπάρχει αυτοματοποιημένος "
"τρόπος για να ανακτήσετε τον κωδικό σας αν τον ξεχάσετε."
-#: ejabberd_web_admin:1954
+#: ejabberd_web_admin:1680
msgid "Memory"
msgstr "Μνήμη"
@@ -939,7 +934,7 @@ msgstr "Περιεχόμενο μηνυμάτως"
#: mod_privilege:291
msgid "Message not found in forwarded payload"
-msgstr ""
+msgstr "Δεν βρέθηκε μήνυμα στο προωθημένο ωφέλιμο φορτίο"
#: mod_vcard_ldap:331 mod_vcard_ldap:344 mod_vcard_mnesia:102
#: mod_vcard_mnesia:116 mod_vcard_sql:157 mod_vcard_sql:171
@@ -948,40 +943,39 @@ msgstr "Πατρώνυμο"
#: mod_irc:704
msgid "Missing 'channel' or 'server' in the data form"
-msgstr ""
+msgstr "Δεν υπάρχει \"δίαυλος\" ή \"διακομιστής\" στη φόρμα δεδομένων"
#: xmpp_stream_in:990
msgid "Missing 'from' attribute"
-msgstr ""
+msgstr "Λείπει χαρακτηριστικό 'from'"
#: xmpp_stream_in:472 xmpp_stream_in:993
msgid "Missing 'to' attribute"
-msgstr ""
+msgstr "Λείπει χαρακτηριστικό 'to'"
-#: mod_muc_room:2536 mod_muc_room:3721 mod_muc_room:3765 mod_muc_room:3798
+#: mod_muc_room:2556 mod_muc_room:3741 mod_muc_room:3785 mod_muc_room:3818
msgid "Moderator privileges required"
msgstr "Aπαιτούνται προνόμια συντονιστή"
-#: ejabberd_web_admin:2279
+#: ejabberd_web_admin:2005
msgid "Modified modules"
msgstr "Τροποποιημένα modules"
-#: ejabberd_web_admin:2465 ejabberd_web_admin:2620
+#: ejabberd_web_admin:2191 ejabberd_web_admin:2346
msgid "Module"
msgstr "Module"
#: gen_iq_handler:153
msgid "Module failed to handle the query"
-msgstr ""
+msgstr "Το μodule απέτυχε να χειριστεί το ερώτημα"
-#: ejabberd_web_admin:1885 mod_configure:582 mod_configure:595
+#: ejabberd_web_admin:1611 mod_configure:582 mod_configure:595
msgid "Modules"
msgstr "Modules"
-#: ejabberd_web_admin:2168
-#, fuzzy
+#: ejabberd_web_admin:1894
msgid "Modules at ~p"
-msgstr "Modules στο "
+msgstr "Modules στο ~p"
#: mod_muc_log:463
msgid "Monday"
@@ -989,17 +983,17 @@ msgstr "Δευτέρα"
#: mod_muc_admin:346 mod_muc_admin:349 mod_muc_admin:365 mod_muc_admin:439
msgid "Multi-User Chat"
-msgstr ""
+msgstr "Συνομιλία με πολλούς χρήστες"
#: mod_multicast:267
msgid "Multicast"
-msgstr ""
+msgstr "Multicast"
#: mod_roster:195
msgid "Multiple <item/> elements are not allowed by RFC6121"
-msgstr ""
+msgstr "Πολλαπλά στοιχεία <item/> δεν επιτρέπονται από το RFC6121"
-#: ejabberd_web_admin:1951 mod_vcard_mnesia:101 mod_vcard_mnesia:115
+#: ejabberd_web_admin:1677 mod_vcard_mnesia:101 mod_vcard_mnesia:115
#: mod_vcard_sql:156 mod_vcard_sql:170
msgid "Name"
msgstr "Όνομα"
@@ -1008,19 +1002,19 @@ msgstr "Όνομα"
msgid "Name:"
msgstr "Όνομα:"
-#: mod_muc_room:2696
+#: mod_muc_room:2716
msgid "Neither 'jid' nor 'nick' attribute found"
-msgstr ""
+msgstr "Δεν βρέθηκε κανένα χαρακτηριστικό 'jid' ούτε 'nick'"
-#: mod_muc_room:2518 mod_muc_room:2701
+#: mod_muc_room:2538 mod_muc_room:2721
msgid "Neither 'role' nor 'affiliation' attribute found"
-msgstr ""
+msgstr "Δεν βρέθηκε ούτε χαρακτηριστικό 'role' ούτε 'affiliation'"
-#: ejabberd_web_admin:1506 ejabberd_web_admin:1687 mod_configure:1629
+#: ejabberd_web_admin:1232 ejabberd_web_admin:1413 mod_configure:1629
msgid "Never"
msgstr "Ποτέ"
-#: mod_register_web:377
+#: mod_register_web:397
msgid "New Password:"
msgstr "Νέος κωδικός πρόσβασης:"
@@ -1033,159 +1027,154 @@ msgstr "Ψευδώνυμο"
msgid "Nickname Registration at "
msgstr "Εγγραφή με Ψευδώνυμο στο "
-#: mod_muc_room:2713
+#: mod_muc_room:2733
msgid "Nickname ~s does not exist in the room"
msgstr "Ψευδώνυμο ~s δεν υπάρχει σε αυτή την αίθουσα"
#: mod_configure:1496
msgid "No 'access' found in data form"
-msgstr ""
+msgstr "Δεν υπάρχει 'access' στη φόρμα δεδομένων"
#: mod_configure:1455
msgid "No 'acls' found in data form"
-msgstr ""
+msgstr "Δεν υπάρχει 'acls' στη φόρμα δεδομένων"
-#: mod_muc_room:3075
+#: mod_muc_room:3095
msgid "No 'affiliation' attribute found"
-msgstr ""
+msgstr "Δεν βρέθηκε χαρακτηριστικό 'affiliation'"
-#: mod_muc_room:2505
-#, fuzzy
+#: mod_muc_room:2525
msgid "No 'item' element found"
-msgstr "Κόμβος δεν βρέθηκε"
+msgstr "Δεν βρέθηκε στοιχείο 'item'"
#: mod_configure:1280
msgid "No 'modules' found in data form"
-msgstr ""
+msgstr "Δεν υπάρχει 'modules' στη φόρμα δεδομένων"
#: mod_configure:1799
msgid "No 'password' found in data form"
-msgstr ""
+msgstr "Δεν υπάρχει 'password' στη φόρμα δεδομένων"
#: mod_register:148
msgid "No 'password' found in this query"
-msgstr ""
+msgstr "Δεν βρέθηκε \"password\" σε αυτό το ερώτημα"
#: mod_configure:1319 mod_configure:1350 mod_configure:1382 mod_configure:1413
#: mod_configure:1433
msgid "No 'path' found in data form"
-msgstr ""
+msgstr "Δεν υπάρχει 'path' στη φόρμα δεδομένων"
-#: mod_muc_room:3922
+#: mod_muc_room:3942
msgid "No 'to' attribute found in the invitation"
-msgstr ""
+msgstr "Δεν υπάρχει χαρακτηριστικό 'to' που βρέθηκε στην πρόσκληση"
-#: ejabberd_web_admin:1767
+#: ejabberd_web_admin:1493
msgid "No Data"
msgstr "Κανένα στοιχείο"
#: ejabberd_local:181
msgid "No available resource found"
-msgstr ""
+msgstr "Δεν βρέθηκε διαθέσιμος πόρος"
#: mod_announce:575
msgid "No body provided for announce message"
msgstr "Δεν προμηθεύτικε περιεχόμενο ανακοινώσης"
-#: mod_irc:335 mod_pubsub:1183 mod_pubsub:3289
-#, fuzzy
+#: mod_irc:335 mod_pubsub:1189 mod_pubsub:3295
msgid "No data form found"
-msgstr "Κόμβος δεν βρέθηκε"
+msgstr "Δεν βρέθηκε φόρμα δεδομένων"
#: mod_disco:224 mod_vcard:282
msgid "No features available"
-msgstr ""
+msgstr "Δεν υπάρχουν διαθέσιμες λειτουργίες"
#: mod_adhoc:239
msgid "No hook has processed this command"
-msgstr ""
+msgstr "Κανένα άγκιστρο δεν έχει επεξεργαστεί αυτήν την εντολή"
#: mod_last:218
msgid "No info about last activity found"
-msgstr ""
+msgstr "Δεν βρέθηκαν πληροφορίες για την τελευταία δραστηριότητα"
#: mod_blocking:99
msgid "No items found in this query"
-msgstr ""
+msgstr "Δεν βρέθηκαν στοιχεία σε αυτό το ερώτημα"
#: ejabberd_local:90 ejabberd_sm:863 mod_blocking:92 mod_blocking:110
#: mod_http_upload:513 mod_muc:482 mod_muc:534 mod_muc:556 mod_muc:580
#: mod_offline:303 mod_privacy:168 mod_privacy:285 mod_roster:207
msgid "No module is handling this query"
-msgstr ""
+msgstr "Καμνένα module δεν χειρίζεται αυτό το ερώτημα"
-#: mod_pubsub:1541
+#: mod_pubsub:1547
msgid "No node specified"
-msgstr ""
+msgstr "Δεν καθορίστηκε κόμβος"
-#: mod_pubsub:1426
+#: mod_pubsub:1432
msgid "No pending subscriptions found"
-msgstr ""
+msgstr "Δεν βρέθηκαν εκκρεμείς συνδρομές"
#: mod_privacy:201 mod_privacy:295 mod_privacy:311 mod_privacy:344
msgid "No privacy list with this name found"
-msgstr ""
+msgstr "Δεν βρέθηκε κατάλογος απορρήτου με αυτό το όνομα"
#: mod_private:96
msgid "No private data found in this query"
-msgstr ""
+msgstr "Δεν βρέθηκαν ιδιωτικά δεδομένα σε αυτό το ερώτημα"
#: mod_configure:869 mod_configure:908 mod_configure:1222 mod_configure:1254
#: mod_configure:1275 mod_configure:1314 mod_configure:1345 mod_configure:1377
#: mod_configure:1408 mod_configure:1428 mod_stats:93
-#, fuzzy
msgid "No running node found"
-msgstr "Κόμβος δεν βρέθηκε"
+msgstr "Δεν βρέθηκε ενεργός κόμβος"
#: mod_disco:252 mod_vcard:265
msgid "No services available"
-msgstr ""
+msgstr "Δεν υπάρχουν διαθέσιμες υπηρεσίες"
#: mod_stats:101
msgid "No statistics found for this item"
-msgstr ""
+msgstr "Δεν βρέθηκαν στατιστικά στοιχεία για αυτό το στοιχείο"
#: nodetree_dag:72 nodetree_tree:181 nodetree_tree_sql:255
msgid "Node already exists"
-msgstr ""
+msgstr "Ο κόμβος υπάρχει ήδη"
#: nodetree_tree_sql:99
-#, fuzzy
msgid "Node index not found"
-msgstr "Κόμβος δεν βρέθηκε"
+msgstr "Ο δείκτης κόμβου δεν βρέθηκε"
-#: ejabberd_web_admin:1046 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
+#: ejabberd_web_admin:772 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
#: nodetree_dag:78 nodetree_dag:102 nodetree_dag:118 nodetree_dag:142
#: nodetree_dag:229 nodetree_tree:74 nodetree_tree:80 nodetree_tree_sql:130
#: nodetree_tree_sql:144
msgid "Node not found"
msgstr "Κόμβος δεν βρέθηκε"
-#: ejabberd_web_admin:1857 ejabberd_web_admin:1882
-#, fuzzy
+#: ejabberd_web_admin:1583 ejabberd_web_admin:1608
msgid "Node ~p"
-msgstr "Κόμβος"
+msgstr "Κόμβος ~p"
#: mod_vcard:385
msgid "Nodeprep has failed"
-msgstr ""
+msgstr "Το Nodeprep απέτυχε"
-#: ejabberd_web_admin:1837
+#: ejabberd_web_admin:1563
msgid "Nodes"
msgstr "Κόμβοι"
-#: ejabberd_web_admin:1622 ejabberd_web_admin:1818 ejabberd_web_admin:1828
-#: ejabberd_web_admin:2238 mod_roster:907
+#: ejabberd_web_admin:1348 ejabberd_web_admin:1544 ejabberd_web_admin:1554
+#: ejabberd_web_admin:1964 mod_roster:907
msgid "None"
msgstr "Κανένα"
-#: ejabberd_web_admin:1033
+#: ejabberd_web_admin:759
msgid "Not Found"
msgstr "Δεν Βρέθηκε"
#: mod_disco:296 mod_disco:370 mod_last:159
msgid "Not subscribed"
-msgstr ""
+msgstr "Δεν έχετε εγγραφεί"
#: mod_muc_log:483
msgid "November"
@@ -1199,10 +1188,10 @@ msgstr "Αριθμός συνδεδεμένων χρηστών"
msgid "Number of registered users"
msgstr "Αριθμός εγγεγραμμένων χρηστών"
-#: ejabberd_web_admin:2000 ejabberd_web_admin:2010 ejabberd_web_admin:2021
-#: ejabberd_web_admin:2030 ejabberd_web_admin:2040 ejabberd_web_admin:2053
-#: ejabberd_web_admin:2065 ejabberd_web_admin:2081 ejabberd_web_admin:2097
-#: ejabberd_web_admin:2108 ejabberd_web_admin:2118
+#: ejabberd_web_admin:1726 ejabberd_web_admin:1736 ejabberd_web_admin:1747
+#: ejabberd_web_admin:1756 ejabberd_web_admin:1766 ejabberd_web_admin:1779
+#: ejabberd_web_admin:1791 ejabberd_web_admin:1807 ejabberd_web_admin:1823
+#: ejabberd_web_admin:1834 ejabberd_web_admin:1844
msgid "OK"
msgstr "Όλλα Καλά"
@@ -1210,7 +1199,7 @@ msgstr "Όλλα Καλά"
msgid "October"
msgstr "Οκτώβριος"
-#: ejabberd_web_admin:1487
+#: ejabberd_web_admin:1213
msgid "Offline Messages"
msgstr "Χωρίς Σύνδεση Μηνύματα"
@@ -1218,34 +1207,33 @@ msgstr "Χωρίς Σύνδεση Μηνύματα"
msgid "Offline Messages:"
msgstr "Χωρίς Σύνδεση Μηνύματα:"
-#: mod_register_web:373
+#: mod_register_web:393
msgid "Old Password:"
msgstr "Παλαιός κωδικός πρόσβασης:"
-#: ejabberd_web_admin:1524 ejabberd_web_admin:1698 mod_configure:1639
+#: ejabberd_web_admin:1250 ejabberd_web_admin:1424 mod_configure:1639
msgid "Online"
msgstr "Συνδεδεμένο"
-#: ejabberd_web_admin:974 ejabberd_web_admin:1367 mod_configure:506
+#: ejabberd_web_admin:700 ejabberd_web_admin:1093 mod_configure:506
msgid "Online Users"
msgstr "Συνδεμένοι χρήστες"
-#: ejabberd_web_admin:1580 ejabberd_web_admin:1599 ejabberd_web_admin:2211
+#: ejabberd_web_admin:1306 ejabberd_web_admin:1325 ejabberd_web_admin:1937
msgid "Online Users:"
msgstr "Online Χρήστες:"
#: mod_carboncopy:141
msgid "Only <enable/> or <disable/> tags are allowed"
-msgstr ""
+msgstr "Επιτρέπονται μόνο tags <enable /> ή <disable />"
#: mod_privacy:154
msgid "Only <list/> element is allowed in this query"
-msgstr ""
+msgstr "Στο ερώτημα αυτό επιτρέπεται μόνο το στοιχείο <list />"
#: mod_mam:379
-#, fuzzy
msgid "Only members may query archives of this room"
-msgstr "Μόνο οι συντονιστές μπορούν να αλλάξουν το θέμα αυτής της αίθουσας"
+msgstr "Μόνο μέλη μπορούν να δούνε τα αρχεία αυτής της αίθουσας"
#: mod_muc_room:773
msgid ""
@@ -1263,7 +1251,7 @@ msgstr "Μόνο οι συντονιστές μπορούν να αλλάξου
msgid "Only moderators can approve voice requests"
msgstr "Μόνο οι συντονιστές μπορούν να εγκρίνουν τις αιτήσεις φωνής"
-#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:3989
+#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:4009
msgid "Only occupants are allowed to send messages to the conference"
msgstr "Μόνο οι συμμετέχωντες μπορούν να στέλνουν μηνύματα στο συνέδριο"
@@ -1277,7 +1265,7 @@ msgstr ""
"Μόνο οι διαχειριστές των υπηρεσιών επιτρέπεται να στείλουν υπηρεσιακά "
"μηνύματα"
-#: ejabberd_web_admin:2466 ejabberd_web_admin:2621
+#: ejabberd_web_admin:2192 ejabberd_web_admin:2347
msgid "Options"
msgstr "Επιλογές"
@@ -1295,13 +1283,13 @@ msgstr "Μονάδα Οργανισμού"
msgid "Outgoing s2s Connections"
msgstr "Εξερχόμενες S2S Συνδέσεις"
-#: ejabberd_web_admin:1583
+#: ejabberd_web_admin:1309
msgid "Outgoing s2s Connections:"
msgstr "Εξερχόμενες S2S Συνδέσεις:"
-#: mod_muc_room:3023 mod_muc_room:3067 mod_muc_room:3697 mod_pubsub:1302
-#: mod_pubsub:1394 mod_pubsub:1553 mod_pubsub:2118 mod_pubsub:2184
-#: mod_pubsub:2383 mod_pubsub:2464 mod_pubsub:3063 mod_pubsub:3206
+#: mod_muc_room:3043 mod_muc_room:3087 mod_muc_room:3717 mod_pubsub:1308
+#: mod_pubsub:1400 mod_pubsub:1559 mod_pubsub:2124 mod_pubsub:2190
+#: mod_pubsub:2389 mod_pubsub:2470 mod_pubsub:3069 mod_pubsub:3212
msgid "Owner privileges required"
msgstr "Aπαιτούνται προνόμια ιδιοκτήτη"
@@ -1311,14 +1299,14 @@ msgstr "Πακέτο"
#: mod_irc:578
msgid "Parse error"
-msgstr ""
+msgstr "Σφάλμα ανάλυσης"
#: mod_configure:1299 mod_configure:1468 mod_configure:1513
msgid "Parse failed"
-msgstr ""
+msgstr "Η ανάλυση απέτυχε"
-#: ejabberd_oauth:431 ejabberd_web_admin:1435 mod_configure:1126
-#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:1036
+#: ejabberd_oauth:431 ejabberd_web_admin:1161 mod_configure:1126
+#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:799
#: mod_register:229
msgid "Password"
msgstr "Κωδικός Πρόσβασης"
@@ -1327,7 +1315,7 @@ msgstr "Κωδικός Πρόσβασης"
msgid "Password Verification"
msgstr "Επαλήθευση κωδικού πρόσβασης"
-#: mod_register_web:268 mod_register_web:381
+#: mod_register_web:287 mod_register_web:401
msgid "Password Verification:"
msgstr "Επαλήθευση κωδικού πρόσβασης:"
@@ -1335,7 +1323,7 @@ msgstr "Επαλήθευση κωδικού πρόσβασης:"
msgid "Password ~b"
msgstr "Κωδικός πρόσβασης ~b"
-#: ejabberd_web_admin:1713 mod_register_web:245 mod_register_web:483
+#: ejabberd_web_admin:1439 mod_register_web:264 mod_register_web:504
msgid "Password:"
msgstr "Κωδικός πρόσβασης:"
@@ -1351,14 +1339,13 @@ msgstr "Τοποθεσία Αρχείου"
msgid "Pending"
msgstr "Εκκρεμεί"
-#: ejabberd_web_admin:994
+#: ejabberd_web_admin:720
msgid "Period: "
msgstr "Περίοδος: "
#: mod_muc_admin:369
-#, fuzzy
msgid "Permanent rooms"
-msgstr "εγκαταλείπει την αίθουσα"
+msgstr "Μόνιμες αίθουσες"
#: mod_adhoc:168 mod_adhoc:259
msgid "Ping"
@@ -1366,9 +1353,9 @@ msgstr "Πινγκ"
#: mod_ping:180
msgid "Ping query is incorrect"
-msgstr ""
+msgstr "Το Ping είναι λανθασμένο"
-#: ejabberd_web_admin:1983
+#: ejabberd_web_admin:1709
msgid ""
"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 "
@@ -1385,9 +1372,9 @@ msgstr "Παρακαλώ, περιμένετε για λίγο πριν την
#: mod_adhoc:274
msgid "Pong"
-msgstr "Πονγκ"
+msgstr "Pong"
-#: ejabberd_web_admin:2463
+#: ejabberd_web_admin:2189
msgid "Port"
msgstr "Θύρα"
@@ -1397,23 +1384,28 @@ msgstr "Θύρα ~b"
#: mod_roster:173
msgid "Possessing 'ask' attribute is not allowed by RFC6121"
-msgstr ""
+msgstr "Η ιδιότητα 'ask' δεν επιτρέπεται από το RFC6121"
-#: ejabberd_web_admin:2464
+#: ejabberd_web_admin:2190
msgid "Protocol"
msgstr "Πρωτόκολλο"
-#: mod_pubsub:1335
+#: mod_pubsub:1341
msgid "PubSub subscriber request"
msgstr "Αίτηση συνδρομητή Δημοσίευσης-Εγγραφής"
-#: mod_pubsub:970
+#: mod_pubsub:976
msgid "Publish-Subscribe"
msgstr "Δημοσίευση-Εγγραφή"
#: node_dag:81
msgid "Publishing items to collection node is not allowed"
-msgstr ""
+msgstr "Η δημοσίευση στοιχείων σε κόμβους συλλογής δεν επιτρέπεται"
+
+#: mod_push:283
+#, fuzzy
+msgid "Push record not found"
+msgstr "Κόμβος δεν βρέθηκε"
#: mod_muc_room:462
msgid "Queries to the conference members are not allowed in this room"
@@ -1423,7 +1415,7 @@ msgstr ""
#: mod_blocking:85 mod_disco:325 mod_disco:393 mod_offline:270 mod_privacy:146
#: mod_private:118 mod_roster:163 mod_sic:90
msgid "Query to another users is forbidden"
-msgstr ""
+msgstr "Το ερώτημα σε άλλους χρήστες είναι απαγορευμένο"
#: mod_configure:889
msgid "RAM and disc copy"
@@ -1433,14 +1425,15 @@ msgstr "Αντίγραφο μόνο σε RAM καί δίσκο"
msgid "RAM copy"
msgstr "Αντίγραφο σε RAM"
-#: ejabberd_web_admin:1890
+#: ejabberd_web_admin:1616
msgid "RPC Call Error"
msgstr "Σφάλμα RPC Κλήσης"
-#: ejabberd_web_admin:806 ejabberd_web_admin:905
+#: ejabberd_web_admin:532 ejabberd_web_admin:631
msgid "Raw"
msgstr "Ακατέργαστο"
+# ; is question mark in Greek
#: mod_announce:511
msgid "Really delete message of the day?"
msgstr "Πραγματικά να διαγράψετε το μήνυμα της ημέρας;"
@@ -1449,26 +1442,25 @@ msgstr "Πραγματικά να διαγράψετε το μήνυμα της
msgid "Recipient is not in the conference room"
msgstr "Παραλήπτης δεν είναι στην αίθουσα συνεδριάσεων"
-#: mod_register_web:275
+#: mod_register_web:294
msgid "Register"
msgstr "Καταχωρήστε"
-#: mod_register_web:192 mod_register_web:210 mod_register_web:218
+#: mod_register_web:210 mod_register_web:229 mod_register_web:237
msgid "Register a Jabber account"
msgstr "Καταχωρήστε έναν λογαριασμό Jabber"
-#: ejabberd_web_admin:1366
+#: ejabberd_web_admin:1092
msgid "Registered Users"
msgstr "Εγγεγραμμένοι Χρήστες"
-#: ejabberd_web_admin:1577 ejabberd_web_admin:1596
+#: ejabberd_web_admin:1303 ejabberd_web_admin:1322
msgid "Registered Users:"
msgstr "Εγγεγραμμένοι Χρήστες:"
#: mod_muc_admin:370
-#, fuzzy
msgid "Registered nicknames"
-msgstr "Εγγεγραμμένοι Χρήστες"
+msgstr "Καταχωρημένα ψευδώνυμα"
#: mod_irc:535
msgid "Registration in mod_irc for "
@@ -1486,7 +1478,7 @@ msgstr "Αφαίρεστε"
msgid "Remove All Offline Messages"
msgstr "Αφαίρεση Όλων των Χωρίς Σύνδεση Μηνύματων"
-#: ejabberd_web_admin:1720 mod_configure:1779
+#: ejabberd_web_admin:1446 mod_configure:1779
msgid "Remove User"
msgstr "Αφαίρεση χρήστη"
@@ -1498,7 +1490,7 @@ msgstr "Αντικαταστάθικε από νέα σύνδεση"
msgid "Resources"
msgstr "Πόροι"
-#: ejabberd_web_admin:1876 ejabberd_web_admin:2494 ejabberd_web_admin:2638
+#: ejabberd_web_admin:1602 ejabberd_web_admin:2220 ejabberd_web_admin:2364
msgid "Restart"
msgstr "Επανεκκίνηση"
@@ -1514,26 +1506,26 @@ msgstr "Επαναφορά Αντιγράφου Ασφαλείας"
msgid "Restore Backup from File at "
msgstr "Επαναφορά Αντιγράφου Ασφαλείας από αρχείο στο "
-#: ejabberd_web_admin:2013
+#: ejabberd_web_admin:1739
msgid ""
"Restore binary backup after next ejabberd restart (requires less memory):"
msgstr ""
"Επαναφορά δυαδικού αντιγράφου ασφαλείας μετά την επόμενη επανεκκίνηση του "
"ejabberd (απαιτεί λιγότερη μνήμη):"
-#: ejabberd_web_admin:2003
+#: ejabberd_web_admin:1729
msgid "Restore binary backup immediately:"
msgstr "Επαναφορά δυαδικού αντιγράφου ασφαλείας αμέσως:"
-#: ejabberd_web_admin:2033
+#: ejabberd_web_admin:1759
msgid "Restore plain text backup immediately:"
msgstr "Επαναφορά αντιγράφου ασφαλείας από αρχείο κειμένου αμέσως:"
-#: mod_muc_log:872
+#: mod_muc_log:635
msgid "Room Configuration"
msgstr "Διαμόρφωση Αίθουσας σύνεδριασης"
-#: mod_muc_log:892
+#: mod_muc_log:655
msgid "Room Occupants"
msgstr "Συμετεχόντες Αίθουσας σύνεδριασης"
@@ -1541,13 +1533,13 @@ msgstr "Συμετεχόντες Αίθουσας σύνεδριασης"
msgid "Room creation is denied by service policy"
msgstr "Άρνηση δημιουργίας αίθουσας , λόγω τακτικής παροχής υπηρεσιών"
-#: mod_muc_log:1064
+#: mod_muc_log:827
msgid "Room description"
msgstr "Περιγραφή Αίθουσας"
-#: mod_muc_log:1027
+#: mod_muc_log:790
msgid "Room title"
-msgstr "Τίτλος Αίθουσας "
+msgstr "Τίτλος Αίθουσας"
#: mod_roster:1082
msgid "Roster"
@@ -1555,23 +1547,23 @@ msgstr "Καταλόγος Επαφών"
#: mod_roster:334
msgid "Roster module has failed"
-msgstr ""
+msgstr "Το Roster module απέτυχε"
#: mod_roster:968
msgid "Roster of "
-msgstr "Καταλόγος Επαφών τού"
+msgstr "Καταλόγος Επαφών τού "
#: mod_configure:1671
msgid "Roster size"
msgstr "Μέγεθος Καταλόγου Επαφών"
-#: ejabberd_web_admin:1838 mod_configure:510
+#: ejabberd_web_admin:1564 mod_configure:510
msgid "Running Nodes"
msgstr "Ενεργοί Κόμβοι"
#: xmpp_stream_in:541 xmpp_stream_in:549
msgid "SASL negotiation is not allowed in this state"
-msgstr ""
+msgstr "Η διαπραγμάτευση SASL δεν επιτρέπεται σε αυτή την κατάσταση"
#: mod_muc_log:468
msgid "Saturday"
@@ -1579,14 +1571,13 @@ msgstr "Σάββατο"
#: mod_irc:582
msgid "Scan error"
-msgstr ""
+msgstr "Σφάλμα σάρωσης"
#: mod_configure:1303 mod_configure:1472 mod_configure:1517
-#, fuzzy
msgid "Scan failed"
-msgstr "Το CAPTCHA είναι έγκυρο."
+msgstr "Η σάρωση απέτυχε"
-#: ejabberd_web_admin:2282
+#: ejabberd_web_admin:2008
msgid "Script check"
msgstr "Script ελέγχου"
@@ -1596,7 +1587,7 @@ msgstr "Αποτελέσματα αναζήτησης για "
#: mod_vcard:427
msgid "Search users in "
-msgstr "Αναζήτηση χρηστών στο"
+msgstr "Αναζήτηση χρηστών στο "
#: mod_announce:617
msgid "Send announcement to all online users"
@@ -1624,17 +1615,17 @@ msgstr "Σεπτέμβριος"
#: mod_irc_connection:648
msgid "Server Connect Failed"
-msgstr ""
+msgstr "Η σύνδεση διακομιστή απέτυχε"
#: ejabberd_s2s:369
msgid "Server connections to local subdomains are forbidden"
-msgstr ""
+msgstr "Οι συνδέσεις διακομιστή με τοπικούς υποτομείς απαγορεύονται"
#: mod_irc:842
msgid "Server ~b"
msgstr "Διακομιστής ~b"
-#: mod_register_web:242 mod_register_web:370 mod_register_web:480
+#: mod_register_web:261 mod_register_web:390 mod_register_web:501
msgid "Server:"
msgstr "Διακομιστής:"
@@ -1652,11 +1643,11 @@ msgstr ""
msgid "Shared Roster Groups"
msgstr "Κοινές Ομάδες Καταλόγων Επαφών"
-#: ejabberd_web_admin:1016
+#: ejabberd_web_admin:742
msgid "Show Integral Table"
msgstr "Δείτε Ολοκληρωτικό Πίνακα"
-#: ejabberd_web_admin:1013
+#: ejabberd_web_admin:739
msgid "Show Ordinary Table"
msgstr "Δείτε Κοινό Πίνακα"
@@ -1664,7 +1655,7 @@ msgstr "Δείτε Κοινό Πίνακα"
msgid "Shut Down Service"
msgstr "Κλείσιμο Υπηρεσίας"
-#: mod_register_web:258
+#: mod_register_web:277
msgid ""
"Some Jabber clients can store your password in the computer, but you should "
"do this only in your personal computer for safety reasons."
@@ -1673,7 +1664,7 @@ msgstr ""
"υπολογιστή σας. Χρησιμοποιήστε αυτό το χαρακτηριστικό μόνο εάν εμπιστεύεστε "
"την ασφάλεια του υπολογιστή σας."
-#: ejabberd_web_admin:2518 ejabberd_web_admin:2654
+#: ejabberd_web_admin:2244 ejabberd_web_admin:2380
msgid "Start"
msgstr "Εκκίνηση"
@@ -1685,15 +1676,15 @@ msgstr "Εκκίνηση Modules"
msgid "Start Modules at "
msgstr "Εκκίνηση Modules στο "
-#: ejabberd_web_admin:1023 ejabberd_web_admin:1871 mod_muc_admin:366
+#: ejabberd_web_admin:749 ejabberd_web_admin:1597 mod_muc_admin:366
msgid "Statistics"
msgstr "Στατιστικές"
-#: ejabberd_web_admin:2199
+#: ejabberd_web_admin:1925
msgid "Statistics of ~p"
msgstr "Στατιστικές του ~p"
-#: ejabberd_web_admin:1878 ejabberd_web_admin:2498 ejabberd_web_admin:2642
+#: ejabberd_web_admin:1604 ejabberd_web_admin:2224 ejabberd_web_admin:2368
msgid "Stop"
msgstr "Σταμάτημα"
@@ -1705,19 +1696,19 @@ msgstr "ΠαύσηModules"
msgid "Stop Modules at "
msgstr "Παύση Modules στο "
-#: ejabberd_web_admin:1839 mod_configure:511
+#: ejabberd_web_admin:1565 mod_configure:511
msgid "Stopped Nodes"
msgstr "Σταματημένοι Κόμβοι"
-#: ejabberd_web_admin:1952
+#: ejabberd_web_admin:1678
msgid "Storage Type"
msgstr "Τύπος Αποθήκευσης"
-#: ejabberd_web_admin:1993
+#: ejabberd_web_admin:1719
msgid "Store binary backup:"
msgstr "Αποθηκεύση δυαδικού αντιγράφου ασφαλείας:"
-#: ejabberd_web_admin:2023
+#: ejabberd_web_admin:1749
msgid "Store plain text backup:"
msgstr "Αποθηκεύση αντιγράφου ασφαλείας σε αρχείο κειμένου:"
@@ -1725,16 +1716,16 @@ msgstr "Αποθηκεύση αντιγράφου ασφαλείας σε αρχ
msgid "Subject"
msgstr "Θέμα"
-#: ejabberd_web_admin:774 ejabberd_web_admin:814 ejabberd_web_admin:879
-#: ejabberd_web_admin:944 ejabberd_web_admin:1963 mod_shared_roster:933
+#: ejabberd_web_admin:500 ejabberd_web_admin:540 ejabberd_web_admin:605
+#: ejabberd_web_admin:670 ejabberd_web_admin:1689 mod_shared_roster:933
msgid "Submit"
msgstr "Υποβοβολή"
-#: ejabberd_web_admin:762 ejabberd_web_admin:801 ejabberd_web_admin:867
-#: ejabberd_web_admin:900 ejabberd_web_admin:936 ejabberd_web_admin:1421
-#: ejabberd_web_admin:1704 ejabberd_web_admin:1860 ejabberd_web_admin:1894
-#: ejabberd_web_admin:1974 ejabberd_web_admin:2144 ejabberd_web_admin:2173
-#: ejabberd_web_admin:2270 mod_offline:681 mod_roster:971 mod_shared_roster:830
+#: ejabberd_web_admin:488 ejabberd_web_admin:527 ejabberd_web_admin:593
+#: ejabberd_web_admin:626 ejabberd_web_admin:662 ejabberd_web_admin:1147
+#: ejabberd_web_admin:1430 ejabberd_web_admin:1586 ejabberd_web_admin:1620
+#: ejabberd_web_admin:1700 ejabberd_web_admin:1870 ejabberd_web_admin:1899
+#: ejabberd_web_admin:1996 mod_offline:681 mod_roster:971 mod_shared_roster:830
#: mod_shared_roster:925
msgid "Submitted"
msgstr "Υποβλήθηκε"
@@ -1743,19 +1734,19 @@ msgstr "Υποβλήθηκε"
msgid "Subscription"
msgstr "Συνδρομή"
-#: mod_muc_room:3708
+#: mod_muc_room:3728
msgid "Subscriptions are not allowed"
-msgstr ""
+msgstr "Οι συνδρομές δεν επιτρέπονται"
#: mod_muc_log:469
msgid "Sunday"
msgstr "Κυριακή"
-#: mod_muc_room:998 mod_muc_room:1843 mod_muc_room:3737
+#: mod_muc_room:998 mod_muc_room:1857 mod_muc_room:3757
msgid "That nickname is already in use by another occupant"
msgstr "Αυτό το ψευδώνυμο είναι ήδη σε χρήση από άλλον συμμετέχων"
-#: mod_muc:745 mod_muc_room:1004 mod_muc_room:1852 mod_muc_room:3740
+#: mod_muc:745 mod_muc_room:1004 mod_muc_room:1866 mod_muc_room:3760
msgid "That nickname is registered by another person"
msgstr "Αυτό το ψευδώνυμο είναι καταχωρημένο από άλλο πρόσωπο"
@@ -1763,17 +1754,17 @@ msgstr "Αυτό το ψευδώνυμο είναι καταχωρημένο α
msgid "The CAPTCHA is valid."
msgstr "Το CAPTCHA είναι έγκυρο."
-#: mod_muc_room:653 mod_muc_room:3672 mod_register:190
+#: mod_muc_room:653 mod_muc_room:3692 mod_register:190
msgid "The CAPTCHA verification has failed"
msgstr "Η επαλήθευση της εικόνας CAPTCHA απέτυχε"
#: mod_muc_room:302
msgid "The feature requested is not supported by the conference"
-msgstr ""
+msgstr "Η λειτουργία που ζητήθηκε δεν υποστηρίζεται από τη διάσκεψη"
#: mod_register:308 mod_register:366
msgid "The password contains unacceptable characters"
-msgstr ""
+msgstr "Ο κωδικός πρόσβασης περιέχει μη αποδεκτούς χαρακτήρες"
#: mod_register:311 mod_register:370
msgid "The password is too weak"
@@ -1785,37 +1776,39 @@ msgstr "Ο κωδικός πρόσβασης του Jabber λογαριασμο
#: mod_register:160 mod_vcard:219
msgid "The query is only allowed from local users"
-msgstr ""
+msgstr "Το ερώτημα επιτρέπεται μόνο από τοπικούς χρήστες"
#: mod_roster:203
msgid "The query must not contain <item/> elements"
-msgstr ""
+msgstr "Το ερώτημα δεν πρέπει να περιέχει στοιχείο <item/>"
#: mod_privacy:280
msgid ""
"The stanza MUST contain only one <active/> element, one <default/> element, "
"or one <list/> element"
msgstr ""
+"Η stanza ΠΡΕΠΕΙ να περιέχει μόνο ένα στοιχείο <active />, ένα στοιχείο "
+"<default /> ή ένα στοιχείο <list />"
#: mod_register_web:146
msgid "There was an error changing the password: "
-msgstr "Υπήρξε ένα σφάλμα κατά την αλλαγή του κωδικού πρόσβασης:"
+msgstr "Υπήρξε ένα σφάλμα κατά την αλλαγή του κωδικού πρόσβασης: "
#: mod_register_web:116
msgid "There was an error creating the account: "
-msgstr "Υπήρξε ένα σφάλμα κατά τη δημιουργία του λογαριασμού:"
+msgstr "Υπήρξε ένα σφάλμα κατά τη δημιουργία του λογαριασμού: "
#: mod_register_web:130
msgid "There was an error deleting the account: "
-msgstr "Υπήρξε ένα σφάλμα κατά τη διαγραφή του λογαριασμού:"
+msgstr "Υπήρξε ένα σφάλμα κατά τη διαγραφή του λογαριασμού: "
-#: mod_register_web:236
+#: mod_register_web:255
msgid "This is case insensitive: macbeth is the same that MacBeth and Macbeth."
msgstr ""
"Ανεξαρτήτως με πεζά ή κεφαλαία: 'μιαλεξη' είναι το ίδιο με 'ΜιαΛέξη' και "
"'Μιαλέξη'."
-#: mod_register_web:220
+#: mod_register_web:239
msgid ""
"This page allows to create a Jabber account in this Jabber server. Your JID "
"(Jabber IDentifier) will be of the form: username@server. Please read "
@@ -1826,13 +1819,13 @@ msgstr ""
"όνομα_χρήστη@διακομιστής_Jabber. Παρακαλώ διαβάστε προσεκτικά τις οδηγίες "
"για να συμπληρώσετε σωστά τα πεδία."
-#: mod_register_web:470
+#: mod_register_web:491
msgid "This page allows to unregister a Jabber account in this Jabber server."
msgstr ""
"Η σελίδα αυτή δίνει τη δυνατότητα να καταργήσετε την καταχώρηση ενός "
"λογαριασμό Jabber σε αυτόν το διακομιστή Jabber."
-#: mod_muc_log:1038
+#: mod_muc_log:801
msgid "This room is not anonymous"
msgstr "Η αίθουσα αυτή δεν είναι ανώνυμη"
@@ -1854,7 +1847,7 @@ msgstr "Πρώς"
#: mod_register:215
msgid "To register, visit ~s"
-msgstr ""
+msgstr "Για να εγγραφείτε, επισκεφθείτε το ~ s"
#: mod_configure:709
msgid "To ~s"
@@ -1862,63 +1855,61 @@ msgstr "Πρώς ~s"
#: ejabberd_oauth:439
msgid "Token TTL"
-msgstr ""
+msgstr "Token TTL"
#: xmpp_stream_in:463
msgid "Too long value of 'xml:lang' attribute"
-msgstr ""
+msgstr "Πολύ μακριά η τιμή του χαρακτηριστικού 'xml: lang'"
-#: mod_muc_room:2541 mod_muc_room:3081
+#: mod_muc_room:2561 mod_muc_room:3101
msgid "Too many <item/> elements"
-msgstr ""
+msgstr "Πάρα πολλά στοιχεία <item/>"
#: mod_privacy:164
msgid "Too many <list/> elements"
-msgstr ""
+msgstr "Πάρα πολλά στοιχεία <list/>"
-#: mod_muc_room:1924 mod_register:240
+#: mod_muc_room:1935 mod_register:240
msgid "Too many CAPTCHA requests"
msgstr "Πάρα πολλά αιτήματα CAPTCHA"
#: mod_proxy65_service:223
msgid "Too many active bytestreams"
-msgstr ""
+msgstr "Πάρα πολλά ενεργά bytestreams"
#: mod_stream_mgmt:205
msgid "Too many unacked stanzas"
-msgstr ""
+msgstr "Πάρα πολλές μη αναγνωρισμένες stanzas"
-#: mod_muc_room:1802
-#, fuzzy
+#: mod_muc_room:1816
msgid "Too many users in this conference"
-msgstr "Τα αιτήματα φωνής είναι απενεργοποιημένα, σε αυτό το συνέδριο"
+msgstr "Πάρα πολλοί χρήστες σε αυτή τη διάσκεψη"
#: mod_register:355
msgid "Too many users registered"
-msgstr ""
+msgstr "Πάρα πολλοί εγγεγραμένοι χρήστες"
#: mod_muc_admin:368
-#, fuzzy
msgid "Total rooms"
-msgstr "Αίθουσες σύνεδριασης"
+msgstr "Συνολικές Αίθουσες σύνεδριασης"
#: mod_muc_room:173
msgid "Traffic rate limit is exceeded"
msgstr "Υπέρφορτωση"
-#: ejabberd_web_admin:2219
+#: ejabberd_web_admin:1945
msgid "Transactions Aborted:"
msgstr "Αποτυχημένες συναλλαγές:"
-#: ejabberd_web_admin:2215
+#: ejabberd_web_admin:1941
msgid "Transactions Committed:"
msgstr "Παραδοθείς συναλλαγές:"
-#: ejabberd_web_admin:2227
+#: ejabberd_web_admin:1953
msgid "Transactions Logged:"
msgstr "Καταγραμμένες συναλλαγές:"
-#: ejabberd_web_admin:2223
+#: ejabberd_web_admin:1949
msgid "Transactions Restarted:"
msgstr "Επανειλημμένες συναλλαγές:"
@@ -1926,13 +1917,13 @@ msgstr "Επανειλημμένες συναλλαγές:"
msgid "Tuesday"
msgstr "Τρίτη"
-#: mod_muc_room:1933 mod_register:244
+#: mod_muc_room:1944 mod_register:244
msgid "Unable to generate a CAPTCHA"
msgstr "Αδήνατο να δημιουργηθεί CAPTCHA"
#: ejabberd_service:120
msgid "Unable to register route on existing local domain"
-msgstr ""
+msgstr "Δεν είναι δυνατή η καταχώρηση της διαδρομής σε υπάρχοντα τοπικό τομέα"
#: ejabberd_web_admin:209 ejabberd_web_admin:221 ejabberd_web_admin:241
#: ejabberd_web_admin:253
@@ -1941,25 +1932,25 @@ msgstr "Χορίς Εξουσιοδότηση"
#: mod_announce:485 mod_configure:830 mod_configure:1758
msgid "Unexpected action"
-msgstr ""
+msgstr "Απροσδόκητη ενέργεια"
-#: mod_register_web:488
+#: mod_register_web:509
msgid "Unregister"
msgstr "Καταργήση εγγραφής"
-#: mod_register_web:197 mod_register_web:460 mod_register_web:468
+#: mod_register_web:215 mod_register_web:481 mod_register_web:489
msgid "Unregister a Jabber account"
msgstr "Καταργήστε την εγγραφή ενός λογαριασμού Jabber"
#: mod_mam:526
msgid "Unsupported <index/> element"
-msgstr ""
+msgstr "Μη υποστηριζόμενο στοιχείο <index />"
#: mod_mix:119
msgid "Unsupported MIX query"
-msgstr ""
+msgstr "Μη υποστηριζόμενο ερώτημα MIX"
-#: ejabberd_web_admin:1872 ejabberd_web_admin:2285
+#: ejabberd_web_admin:1598 ejabberd_web_admin:2011
msgid "Update"
msgstr "Ενημέρωση"
@@ -1973,40 +1964,38 @@ msgstr ""
"Ενημέρωση μηνύματως ημέρας σε όλους τους κεντρικούς υπολογιστές (χωρίς άμεση "
"αποστολή)"
-#: ejabberd_web_admin:2278
+#: ejabberd_web_admin:2004
msgid "Update plan"
msgstr "Σχέδιο ενημέρωσης"
-#: ejabberd_web_admin:2280
+#: ejabberd_web_admin:2006
msgid "Update script"
msgstr "Προγράμα ενημέρωσης"
-#: ejabberd_web_admin:2267
-#, fuzzy
+#: ejabberd_web_admin:1993
msgid "Update ~p"
-msgstr "Ενημέρωση"
+msgstr "Ενημέρωση ~p"
-#: ejabberd_web_admin:2203
+#: ejabberd_web_admin:1929
msgid "Uptime:"
msgstr "Uptime:"
-#: xmpp_stream_out:533
-#, fuzzy
+#: xmpp_stream_out:535
msgid "Use of STARTTLS forbidden"
-msgstr "Απαιτείται χρήση STARTTLS "
+msgstr "Η χρήση του STARTTLS είναι απαγορευμένη"
-#: xmpp_stream_in:573 xmpp_stream_out:527 xmpp_stream_out:603
+#: xmpp_stream_in:573 xmpp_stream_out:529 xmpp_stream_out:605
msgid "Use of STARTTLS required"
-msgstr "Απαιτείται χρήση STARTTLS "
+msgstr "Απαιτείται χρήση STARTTLS"
-#: ejabberd_web_admin:1430 ejabberd_web_admin:1486 mod_register:225
+#: ejabberd_web_admin:1156 ejabberd_web_admin:1212 mod_register:225
#: mod_vcard_ldap:328 mod_vcard_mnesia:99 mod_vcard_sql:154
msgid "User"
msgstr "Χρήστης"
#: ejabberd_oauth:428
msgid "User (jid)"
-msgstr ""
+msgstr "Χρήστη (jid)"
#: mod_configure:308 mod_configure:505
msgid "User Management"
@@ -2014,35 +2003,33 @@ msgstr "Διαχείριση χρηστών"
#: mod_register:345
msgid "User already exists"
-msgstr ""
+msgstr "Ο χρήστης υπάρχει ήδη"
#: mod_echo:138
msgid "User part of JID in 'from' is empty"
-msgstr ""
+msgstr "Το τμήμα χρήστη του JID στο 'from' είναι άδειο"
-#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_sic:106
-#, fuzzy
+#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_push:268 mod_sic:106
msgid "User session not found"
-msgstr "Κόμβος δεν βρέθηκε"
+msgstr "Η συνάντηση χρήστη δεν βρέθηκε"
#: mod_stream_mgmt:561 mod_stream_mgmt:583
msgid "User session terminated"
-msgstr ""
+msgstr "Η σύνδεση χρήστη τερματίστηκε"
-#: ejabberd_web_admin:1700
-#, fuzzy
+#: ejabberd_web_admin:1426
msgid "User ~s"
-msgstr "Χρήστης"
+msgstr "Ο Χρήστης ~s"
-#: mod_register_web:230 mod_register_web:366 mod_register_web:476
+#: mod_register_web:249 mod_register_web:386 mod_register_web:497
msgid "Username:"
-msgstr "Όνομα χρήστη"
+msgstr "Όνομα χρήστη:"
-#: ejabberd_web_admin:959 ejabberd_web_admin:967
+#: ejabberd_web_admin:685 ejabberd_web_admin:693
msgid "Users"
msgstr "Χρήστες"
-#: ejabberd_web_admin:990
+#: ejabberd_web_admin:716
msgid "Users Last Activity"
msgstr "Τελευταία Δραστηριότητα Χρήστη"
@@ -2054,36 +2041,36 @@ msgstr "Οι χρήστες δεν επιτρέπεται να εγγραφού
msgid "Validate"
msgstr "Επαληθεύστε"
-#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3662 mod_muc_room:3802
-#: mod_pubsub:895 mod_push:249
+#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3682 mod_muc_room:3822
+#: mod_pubsub:890 mod_push:250
msgid "Value 'get' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "Η τιμή 'get' του 'type' δεν επιτρέπεται"
#: mod_disco:159 mod_disco:175 mod_disco:279 mod_disco:346 mod_irc:270
#: mod_irc:285 mod_irc:339 mod_last:118 mod_last:140 mod_muc:479 mod_muc:504
-#: mod_muc:539 mod_muc:561 mod_muc:571 mod_muc_room:3597 mod_muc_room:3641
+#: mod_muc:539 mod_muc:561 mod_muc:571 mod_muc_room:3617 mod_muc_room:3661
#: mod_proxy65_service:142 mod_proxy65_service:160 mod_proxy65_service:167
-#: mod_pubsub:821 mod_pubsub:839 mod_pubsub:877 mod_sic:81 mod_sic:93
+#: mod_pubsub:815 mod_pubsub:834 mod_pubsub:872 mod_sic:81 mod_sic:93
#: mod_stats:55 mod_time:62 mod_vcard:198 mod_vcard:236 mod_version:62
msgid "Value 'set' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "Δεν επιτρέπεται η παράμετρος 'set' του 'type'"
#: pubsub_subscription:237 pubsub_subscription_sql:202
msgid "Value of '~s' should be boolean"
-msgstr ""
+msgstr "Η τιμή του '~ s' πρέπει να είναι boolean"
#: pubsub_subscription:215 pubsub_subscription_sql:180
msgid "Value of '~s' should be datetime string"
-msgstr ""
+msgstr "Η τιμή του '~ s' θα πρέπει να είναι χρονοσειρά"
#: pubsub_subscription:209 pubsub_subscription:227 pubsub_subscription_sql:174
#: pubsub_subscription_sql:192
msgid "Value of '~s' should be integer"
-msgstr ""
+msgstr "Η τιμή του '~ s' θα πρέπει να είναι ακέραιος"
-#: ejabberd_web_admin:950
+#: ejabberd_web_admin:676
msgid "Virtual Hosts"
-msgstr "εικονικοί κεντρικοί υπολογιστές"
+msgstr "Eεικονικοί κεντρικοί υπολογιστές"
#: mod_muc_room:992
msgid "Visitors are not allowed to change their nicknames in this room"
@@ -2097,7 +2084,7 @@ msgstr ""
"Οι επισκέπτες δεν επιτρέπεται να στείλουν μηνύματα σε όλους τους "
"συμμετέχωντες"
-#: mod_muc_room:3879
+#: mod_muc_room:3899
msgid "Voice request"
msgstr "Αίτημα φωνής"
@@ -2109,23 +2096,23 @@ msgstr "Τα αιτήματα φωνής είναι απενεργοποιημέ
msgid "Wednesday"
msgstr "Τετάρτη"
-#: mod_register_web:255
+#: mod_register_web:274
msgid "You can later change your password using a Jabber client."
msgstr ""
"Μπορείτε αργότερα να αλλάξετε τον κωδικό πρόσβασής σας χρησιμοποιώντας έναν "
"πελάτη Jabber."
-#: mod_muc_room:1830
+#: mod_muc_room:1844
msgid "You have been banned from this room"
msgstr "Σας έχει απαγορευθεί η είσοδος σε αυτή την αίθουσα"
-#: mod_muc_room:1811
+#: mod_muc_room:1825
msgid "You have joined too many conferences"
-msgstr ""
+msgstr "Είσθε σε πάρα πολλά συνέδρια"
#: mod_muc:777
msgid "You must fill in field \"Nickname\" in the form"
-msgstr "Θα πρέπει να συμπληρώσετε το πεδίο \"Ψευδώνυμο\" στη φόρμα"
+msgstr "Θα πρέπει να συμπληρώσετε το πεδίο \"Nickname\" στη φόρμα"
#: mod_register:222
msgid "You need a client that supports x:data and CAPTCHA to register"
@@ -2143,10 +2130,9 @@ msgstr "Χρειάζεστε ένα x:data ικανό πελάτη για να
msgid "You need an x:data capable client to search"
msgstr "Χρειάζεστε ένα x:data ικανό πελάτη για αναζήτηση"
-#: mod_pubsub:1504
-#, fuzzy
+#: mod_pubsub:1510
msgid "You're not allowed to create nodes"
-msgstr "Δεν επιτρέπεται η αποστολή προσωπικών μηνυμάτων"
+msgstr "Δεν σου επιτρέπεται η δημιουργία κόμβων"
#: mod_register_web:111
msgid "Your Jabber account was successfully created."
@@ -2183,9 +2169,9 @@ msgstr "ejabberd MUC module"
#: mod_multicast:272
msgid "ejabberd Multicast service"
-msgstr ""
+msgstr "υπηρεσία ejabberd Multicast"
-#: mod_pubsub:1067
+#: mod_pubsub:1073
msgid "ejabberd Publish-Subscribe module"
msgstr "ejabberd module Δημοσίευσης-Εγγραφής"
@@ -2207,7 +2193,7 @@ msgstr "έχει απαγορευθεί"
#: ejabberd_sm:407 mod_configure:1559 mod_muc_log:387 mod_muc_log:390
msgid "has been kicked"
-msgstr "αποβλήθηκε "
+msgstr "αποβλήθηκε"
#: mod_muc_log:405
msgid "has been kicked because of a system shutdown"
@@ -2215,7 +2201,7 @@ msgstr "αποβλήθηκε λόγω τερματισμού συστήματο
#: mod_muc_log:395
msgid "has been kicked because of an affiliation change"
-msgstr "Έχει αποβληθεί λόγω αλλαγής υπαγωγής"
+msgstr "έχει αποβληθεί λόγω αλλαγής υπαγωγής"
#: mod_muc_log:400
msgid "has been kicked because the room has been changed to members-only"
@@ -2233,11 +2219,11 @@ msgstr "συνδέετε στην αίθουσα"
msgid "leaves the room"
msgstr "εγκαταλείπει την αίθουσα"
-#: mod_muc_room:3856
+#: mod_muc_room:3876
msgid "private, "
-msgstr "ιδιωτικό,"
+msgstr "ιδιωτικό, "
-#: mod_muc_room:3955
+#: mod_muc_room:3975
msgid "the password is"
msgstr "ο κωδικός πρόσβασης είναι"
@@ -2245,11 +2231,11 @@ msgstr "ο κωδικός πρόσβασης είναι"
msgid "vCard User Search"
msgstr "vCard Αναζήτηση χρηστών"
-#: ejabberd_web_admin:932
+#: ejabberd_web_admin:658
msgid "~s access rule configuration"
msgstr "~s διαμόρφωση κανόνα πρόσβασης"
-#: mod_muc_room:3948
+#: mod_muc_room:3968
msgid "~s invites you to the room ~s"
msgstr "~s σας προσκαλεί στην αίθουσα ~s"
diff --git a/priv/msgs/gl.po b/priv/msgs/gl.po
index 234dac702..e3a64c51d 100644
--- a/priv/msgs/gl.po
+++ b/priv/msgs/gl.po
@@ -1,11 +1,16 @@
msgid ""
msgstr ""
"Project-Id-Version: 16.02\n"
-"Last-Translator: Carlos E. Lopez - carlos AT suchat.org\n"
+"Last-Translator: Carlos E. Lopez <lopez@galicia.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Language: Galician (galego)\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: \n"
+"Language-Team: \n"
+"Language: gl\n"
+"X-Generator: Poedit 2.0.4\n"
#: mod_muc_log:413 mod_muc_log:752
msgid " has set the subject to: "
@@ -148,7 +153,7 @@ msgstr "Agosto"
#: mod_pubsub:1842
msgid "Automatic node creation is not enabled"
-msgstr ""
+msgstr "A creación automática de nodos non está habilitada"
#: ejabberd_web_admin:1867 mod_configure:148 mod_configure:617
msgid "Backup"
@@ -181,11 +186,11 @@ msgstr "Aniversario"
#: mod_legacy_auth:102
msgid "Both the username and the resource are required"
-msgstr ""
+msgstr "Tanto o nome de usuario como o recurso son necesarios"
#: mod_proxy65_service:226
msgid "Bytestream already activated"
-msgstr ""
+msgstr "Bytestream xa está activado"
#: ejabberd_captcha:135
msgid "CAPTCHA web page"
@@ -193,15 +198,15 @@ msgstr "CAPTCHA páxina Web"
#: ejabberd_web_admin:2207
msgid "CPU Time:"
-msgstr "Tempo consumido de CPU:"
+msgstr "Tempo da CPU:"
#: mod_privacy:334
msgid "Cannot remove active list"
-msgstr ""
+msgstr "Non se pode eliminar a lista activa"
#: mod_privacy:341
msgid "Cannot remove default list"
-msgstr ""
+msgstr "Non se pode eliminar a lista predeterminada"
#: ejabberd_web_admin:1679 mod_register_web:194 mod_register_web:353
#: mod_register_web:361 mod_register_web:386
@@ -213,14 +218,12 @@ msgid "Change User Password"
msgstr "Cambiar contrasinal de usuario"
#: mod_register:295
-#, fuzzy
msgid "Changing password is not allowed"
-msgstr "Caracteres non permitidos:"
+msgstr "Non se permite cambiar o contrasinal"
#: mod_muc_room:2764
-#, fuzzy
msgid "Changing role/affiliation is not allowed"
-msgstr "Caracteres non permitidos:"
+msgstr "O cambio de rol/afiliación non está permitido"
#: mod_register_web:239
msgid "Characters not allowed:"
@@ -321,9 +324,8 @@ msgstr "Táboas da base de datos en ~p"
#: mod_pubsub:3598 mod_pubsub:3604 mod_pubsub:3607 mod_vcard:226
#: node_flat_sql:801 nodetree_tree_sql:128 nodetree_tree_sql:142
#: nodetree_tree_sql:257
-#, fuzzy
msgid "Database failure"
-msgstr "Base de datos"
+msgstr "Erro na base de datos"
#: mod_muc_log:484
msgid "December"
@@ -363,13 +365,12 @@ msgid "Displayed Groups:"
msgstr "Mostrar grupos:"
#: mod_register_web:251
-#, fuzzy
msgid ""
"Don't tell your password to anybody, not even the administrators of the "
"Jabber server."
msgstr ""
-"Non lle diga o seu contrasinal a ninguén, nin sequera os administradores do "
-"Servidor Jabber."
+"Non digas o teu contrasinal a ninguén, nin sequera os administradores do "
+"servidor Jabber."
#: mod_configure:971
msgid "Dump Backup to Text File at "
@@ -381,11 +382,11 @@ msgstr "Exportar a ficheiro de texto"
#: mod_roster:180
msgid "Duplicated groups are not allowed by RFC6121"
-msgstr ""
+msgstr "Os grupos duplicados non están permitidos por RFC6121"
#: mod_configure:1776
msgid "Edit Properties"
-msgstr "Editar propiedades"
+msgstr "Editar Propiedades"
#: mod_muc_room:3881
msgid "Either approve or decline the voice request."
@@ -401,9 +402,8 @@ msgid "Email"
msgstr "Email"
#: mod_register:292
-#, fuzzy
msgid "Empty password"
-msgstr "a contrasinal é"
+msgstr "Contrasinal baleiro"
#: mod_muc_log:1055
msgid "Enable logging"
@@ -411,7 +411,7 @@ msgstr "Gardar históricos"
#: mod_push:252
msgid "Enabling push without 'node' attribute is not supported"
-msgstr ""
+msgstr "Non se admite a activación do empuxe sen o atributo 'nodo'"
#: mod_irc:834
msgid "Encoding for server ~b"
@@ -500,15 +500,15 @@ msgstr ""
#: mod_delegation:275
msgid "External component failure"
-msgstr ""
+msgstr "Fallo de compoñente externo"
#: mod_delegation:283
msgid "External component timeout"
-msgstr ""
+msgstr "Paso o tempo de espera do compoñente externo"
#: mod_proxy65_service:218
msgid "Failed to activate bytestream"
-msgstr ""
+msgstr "Fallo ao activar bytestream"
#: mod_muc_room:910
msgid "Failed to extract JID from your voice request approval"
@@ -516,19 +516,19 @@ msgstr "Fallo ao extraer o Jabber ID da túa aprobación de petición de voz"
#: mod_delegation:257
msgid "Failed to map delegated namespace to external component"
-msgstr ""
+msgstr "O mapeo de espazo de nomes delegado fallou ao compoñente externo"
#: mod_http_upload:602
msgid "Failed to parse HTTP response"
-msgstr ""
+msgstr "Non se puido analizar a resposta HTTP"
#: mod_irc:426
msgid "Failed to parse chanserv"
-msgstr ""
+msgstr "Non se puido analizar o chanserv"
#: mod_muc_room:3297
msgid "Failed to process option '~s'"
-msgstr ""
+msgstr "Fallo ao procesar a opción '~s'"
#: mod_vcard_ldap:332 mod_vcard_ldap:345 mod_vcard_mnesia:103
#: mod_vcard_mnesia:117 mod_vcard_sql:158 mod_vcard_sql:172
@@ -541,7 +541,7 @@ msgstr "Febreiro"
#: mod_http_upload:555
msgid "File larger than ~w bytes"
-msgstr ""
+msgstr "O ficheiro é maior que ~w bytes"
#: mod_vcard:437
msgid ""
@@ -589,9 +589,8 @@ msgid "Get User Statistics"
msgstr "Ver estatísticas de usuario"
#: mod_vcard_ldap:330 mod_vcard_ldap:343
-#, fuzzy
msgid "Given Name"
-msgstr "Segundo nome"
+msgstr "Nome"
#: mod_shared_roster:923
msgid "Group "
@@ -607,7 +606,7 @@ msgstr "Host"
#: mod_s2s_dialback:325
msgid "Host unknown"
-msgstr ""
+msgstr "Dominio descoñecido"
#: ejabberd_web_admin:2463
msgid "IP"
@@ -630,9 +629,8 @@ msgid "IRC channel (don't put the first #)"
msgstr "Canle de IRC (non poñer o primeiro #)"
#: mod_irc:417
-#, fuzzy
msgid "IRC connection not found"
-msgstr "Nodo non atopado"
+msgstr "Conexión IRC non atopada"
#: mod_irc:673
msgid "IRC server"
@@ -696,15 +694,15 @@ msgstr "Importar usuarios do directorio spool de jabberd14:"
#: xmpp_stream_in:983
msgid "Improper 'from' attribute"
-msgstr ""
+msgstr "Atributo 'from' impropio"
#: xmpp_stream_in:477
msgid "Improper 'to' attribute"
-msgstr ""
+msgstr "Atributo 'to' impropio"
#: ejabberd_service:189
msgid "Improper domain part of 'from' attribute"
-msgstr ""
+msgstr "Parte de dominio impropio no atributo 'from'"
#: mod_muc_room:260
msgid "Improper message type"
@@ -716,12 +714,11 @@ msgstr "Conexións S2S saíntes:"
#: mod_muc_room:3669 mod_register:187
msgid "Incorrect CAPTCHA submit"
-msgstr ""
+msgstr "O CAPTCHA proporcionado é incorrecto"
#: mod_muc:772 mod_muc_room:3052 mod_pubsub:1194 mod_register:183 mod_vcard:256
-#, fuzzy
msgid "Incorrect data form"
-msgstr "Contrasinal incorrecta"
+msgstr "Formulario de datos incorrecto"
#: mod_muc_room:1943 mod_register:300 mod_register:350
msgid "Incorrect password"
@@ -729,41 +726,40 @@ msgstr "Contrasinal incorrecta"
#: mod_irc:585
msgid "Incorrect value in data form"
-msgstr ""
+msgstr "Valor incorrecto no formulario de datos"
#: mod_adhoc:276
msgid "Incorrect value of 'action' attribute"
-msgstr ""
+msgstr "Valor incorrecto do atributo 'action'"
#: mod_configure:1806
msgid "Incorrect value of 'action' in data form"
-msgstr ""
+msgstr "Valor incorrecto de 'action' no formulario de datos"
#: mod_configure:1335 mod_configure:1367 mod_configure:1399 mod_configure:1419
#: mod_configure:1439
msgid "Incorrect value of 'path' in data form"
-msgstr ""
+msgstr "Valor incorrecto de 'path' no formulario de datos"
#: mod_irc:331
msgid "Incorrect value of 'type' attribute"
-msgstr ""
+msgstr "Valor incorrecto do atributo 'type'"
#: mod_privilege:100
msgid "Insufficient privilege"
-msgstr ""
+msgstr "Privilexio insuficiente"
#: mod_privilege:286
msgid "Invalid 'from' attribute in forwarded message"
-msgstr ""
+msgstr "Atributo 'from'' non é válido na mensaxe reenviada"
#: mod_privilege:300
msgid "Invalid <forwarded/> element"
-msgstr ""
+msgstr "Elemento <forwarded/> non válido"
#: mod_muc_room:3926
-#, fuzzy
msgid "Invitations are not allowed in this conference"
-msgstr "As peticións de voz están desactivadas nesta sala"
+msgstr "As invitacións non están permitidas nesta sala"
#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1046
msgid ""
@@ -885,9 +881,8 @@ msgid "Make room public searchable"
msgstr "Sala publicamente visible"
#: mod_register:317
-#, fuzzy
msgid "Malformed username"
-msgstr "Nome de usuario en IRC"
+msgstr "Nome de usuario mal formado"
#: mod_muc_log:475
msgid "March"
@@ -917,7 +912,7 @@ msgid ""
msgstr ""
"Memorice o seu contrasinal ou escribilo nun papel colocado nun lugar seguro. "
"En Jabber non hai unha forma automatizada para recuperar o seu contrasinal "
-"si a esquece"
+"si a esquece."
#: ejabberd_web_admin:1954
msgid "Memory"
@@ -929,7 +924,7 @@ msgstr "Corpo da mensaxe"
#: mod_privilege:291
msgid "Message not found in forwarded payload"
-msgstr ""
+msgstr "Mensaxe non atopada no contido reenviado"
#: mod_vcard_ldap:331 mod_vcard_ldap:344 mod_vcard_mnesia:102
#: mod_vcard_mnesia:116 mod_vcard_sql:157 mod_vcard_sql:171
@@ -938,15 +933,15 @@ msgstr "Segundo nome"
#: mod_irc:704
msgid "Missing 'channel' or 'server' in the data form"
-msgstr ""
+msgstr "Non se atopa 'channel' ou 'server' no formulario de datos"
#: xmpp_stream_in:990
msgid "Missing 'from' attribute"
-msgstr ""
+msgstr "Non se atopa o atributo 'from'"
#: xmpp_stream_in:472 xmpp_stream_in:993
msgid "Missing 'to' attribute"
-msgstr ""
+msgstr "Non se atopa o atributo 'to'"
#: mod_muc_room:2536 mod_muc_room:3721 mod_muc_room:3765 mod_muc_room:3798
msgid "Moderator privileges required"
@@ -962,7 +957,7 @@ msgstr "Módulo"
#: gen_iq_handler:153
msgid "Module failed to handle the query"
-msgstr ""
+msgstr "O módulo non puido xestionar a consulta"
#: ejabberd_web_admin:1885 mod_configure:582 mod_configure:595
msgid "Modules"
@@ -986,7 +981,7 @@ msgstr "Multicast"
#: mod_roster:195
msgid "Multiple <item/> elements are not allowed by RFC6121"
-msgstr ""
+msgstr "Múltiples elementos <item/> non están permitidos por RFC6121"
#: ejabberd_web_admin:1951 mod_vcard_mnesia:101 mod_vcard_mnesia:115
#: mod_vcard_sql:156 mod_vcard_sql:170
@@ -999,11 +994,11 @@ msgstr "Nome:"
#: mod_muc_room:2696
msgid "Neither 'jid' nor 'nick' attribute found"
-msgstr ""
+msgstr "Non se atopou o atributo 'jid' nin 'nick'"
#: mod_muc_room:2518 mod_muc_room:2701
msgid "Neither 'role' nor 'affiliation' attribute found"
-msgstr ""
+msgstr "Non se atopou o atributo 'role' nin 'affiliation'"
#: ejabberd_web_admin:1506 ejabberd_web_admin:1687 mod_configure:1629
msgid "Never"
@@ -1028,41 +1023,40 @@ msgstr "O alcume ~s non existe na sala"
#: mod_configure:1496
msgid "No 'access' found in data form"
-msgstr ""
+msgstr "Non se atopou 'access' no formulario de datos"
#: mod_configure:1455
msgid "No 'acls' found in data form"
-msgstr ""
+msgstr "Non se atopou 'acls' no formulario de datos"
#: mod_muc_room:3075
msgid "No 'affiliation' attribute found"
-msgstr ""
+msgstr "Non se atopou o atributo de 'affiliation'"
#: mod_muc_room:2505
-#, fuzzy
msgid "No 'item' element found"
-msgstr "Nodo non atopado"
+msgstr "Non se atopou o elemento 'item'"
#: mod_configure:1280
msgid "No 'modules' found in data form"
-msgstr ""
+msgstr "Non se atopan 'modules' no formulario de datos"
#: mod_configure:1799
msgid "No 'password' found in data form"
-msgstr ""
+msgstr "Non se atopou 'password' no formulario de datos"
#: mod_register:148
msgid "No 'password' found in this query"
-msgstr ""
+msgstr "Non se atopou 'password' nesta solicitude"
#: mod_configure:1319 mod_configure:1350 mod_configure:1382 mod_configure:1413
#: mod_configure:1433
msgid "No 'path' found in data form"
-msgstr ""
+msgstr "Non se atopou 'path' neste formulario de datos"
#: mod_muc_room:3922
msgid "No 'to' attribute found in the invitation"
-msgstr ""
+msgstr "O atributo 'to' non se atopou na invitación"
#: ejabberd_web_admin:1767
msgid "No Data"
@@ -1070,78 +1064,75 @@ msgstr "Sen datos"
#: ejabberd_local:181
msgid "No available resource found"
-msgstr ""
+msgstr "Non se atopou ningún recurso"
#: mod_announce:575
msgid "No body provided for announce message"
msgstr "Non se proporcionou corpo de mensaxe para o anuncio"
#: mod_irc:335 mod_pubsub:1183 mod_pubsub:3289
-#, fuzzy
msgid "No data form found"
-msgstr "Nodo non atopado"
+msgstr "Non se atopou formulario de datos"
#: mod_disco:224 mod_vcard:282
msgid "No features available"
-msgstr ""
+msgstr "Non hai características dispoñibles"
#: mod_adhoc:239
msgid "No hook has processed this command"
-msgstr ""
+msgstr "Ningún evento procesou este comando"
#: mod_last:218
msgid "No info about last activity found"
-msgstr ""
+msgstr "Non se atopou información sobre a última actividade"
#: mod_blocking:99
msgid "No items found in this query"
-msgstr ""
+msgstr "Non se atoparon elementos nesta consulta"
#: ejabberd_local:90 ejabberd_sm:863 mod_blocking:92 mod_blocking:110
#: mod_http_upload:513 mod_muc:482 mod_muc:534 mod_muc:556 mod_muc:580
#: mod_offline:303 mod_privacy:168 mod_privacy:285 mod_roster:207
msgid "No module is handling this query"
-msgstr ""
+msgstr "Ningún módulo manexa esta consulta"
#: mod_pubsub:1541
msgid "No node specified"
-msgstr ""
+msgstr "Non se especificou nodo"
#: mod_pubsub:1426
msgid "No pending subscriptions found"
-msgstr ""
+msgstr "Non se atoparon subscricións pendentes"
#: mod_privacy:201 mod_privacy:295 mod_privacy:311 mod_privacy:344
msgid "No privacy list with this name found"
-msgstr ""
+msgstr "Non se atopou ningunha lista de privacidade con este nome"
#: mod_private:96
msgid "No private data found in this query"
-msgstr ""
+msgstr "Non se atopou ningún elemento de datos privado nesta solicitude"
#: mod_configure:869 mod_configure:908 mod_configure:1222 mod_configure:1254
#: mod_configure:1275 mod_configure:1314 mod_configure:1345 mod_configure:1377
#: mod_configure:1408 mod_configure:1428 mod_stats:93
-#, fuzzy
msgid "No running node found"
-msgstr "Nodo non atopado"
+msgstr "Non se atoparon nodos activos"
#: mod_disco:252 mod_vcard:265
msgid "No services available"
-msgstr ""
+msgstr "Non hai servizos dispoñibles"
#: mod_stats:101
msgid "No statistics found for this item"
-msgstr ""
+msgstr "Non se atopou ningunha estatística para este elemento"
#: nodetree_dag:72 nodetree_tree:181 nodetree_tree_sql:255
msgid "Node already exists"
-msgstr ""
+msgstr "O nodo xa existe"
#: nodetree_tree_sql:99
-#, fuzzy
msgid "Node index not found"
-msgstr "Nodo non atopado"
+msgstr "Non se atopou índice de nodo"
#: ejabberd_web_admin:1046 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
#: nodetree_dag:78 nodetree_dag:102 nodetree_dag:118 nodetree_dag:142
@@ -1156,7 +1147,7 @@ msgstr "Nodo ~p"
#: mod_vcard:385
msgid "Nodeprep has failed"
-msgstr ""
+msgstr "Nodeprep fallou"
#: ejabberd_web_admin:1837
msgid "Nodes"
@@ -1173,7 +1164,7 @@ msgstr "Non atopado"
#: mod_disco:296 mod_disco:370 mod_last:159
msgid "Not subscribed"
-msgstr ""
+msgstr "Non subscrito"
#: mod_muc_log:483
msgid "November"
@@ -1224,11 +1215,11 @@ msgstr "Usuarios conectados:"
#: mod_carboncopy:141
msgid "Only <enable/> or <disable/> tags are allowed"
-msgstr ""
+msgstr "Só se permiten etiquetas <enable/> ou <disable/>"
#: mod_privacy:154
msgid "Only <list/> element is allowed in this query"
-msgstr ""
+msgstr "Só se admite o elemento <list/> nesta consulta"
#: mod_mam:379
msgid "Only members may query archives of this room"
@@ -1298,11 +1289,11 @@ msgstr "Paquete"
#: mod_irc:578
msgid "Parse error"
-msgstr ""
+msgstr "Erro no procesado"
#: mod_configure:1299 mod_configure:1468 mod_configure:1513
msgid "Parse failed"
-msgstr ""
+msgstr "Fallou o procesamento"
#: ejabberd_oauth:431 ejabberd_web_admin:1435 mod_configure:1126
#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:1036
@@ -1316,7 +1307,7 @@ msgstr "Verificación da contrasinal"
#: mod_register_web:268 mod_register_web:381
msgid "Password Verification:"
-msgstr "Verificación da contrasinal"
+msgstr "Verificación da Contrasinal:"
#: mod_irc:822
msgid "Password ~b"
@@ -1352,7 +1343,7 @@ msgstr "Ping"
#: mod_ping:180
msgid "Ping query is incorrect"
-msgstr ""
+msgstr "A solicitude de Ping é incorrecta"
#: ejabberd_web_admin:1983
msgid ""
@@ -1382,7 +1373,7 @@ msgstr "Porto ~b"
#: mod_roster:173
msgid "Possessing 'ask' attribute is not allowed by RFC6121"
-msgstr ""
+msgstr "Posuír o atributo 'ask' non está permitido por RFC6121"
#: ejabberd_web_admin:2464
msgid "Protocol"
@@ -1398,7 +1389,7 @@ msgstr "Publicar-Subscribir"
#: node_dag:81
msgid "Publishing items to collection node is not allowed"
-msgstr ""
+msgstr "Non se permite a publicación de elementos no nodo de colección"
#: mod_muc_room:462
msgid "Queries to the conference members are not allowed in this room"
@@ -1407,7 +1398,7 @@ msgstr "Nesta sala non se permiten solicitudes aos membros da sala"
#: mod_blocking:85 mod_disco:325 mod_disco:393 mod_offline:270 mod_privacy:146
#: mod_private:118 mod_roster:163 mod_sic:90
msgid "Query to another users is forbidden"
-msgstr ""
+msgstr "É prohibido enviar solicitudes a outros usuarios"
#: mod_configure:889
msgid "RAM and disc copy"
@@ -1455,7 +1446,7 @@ msgstr "Alcumes rexistrados"
#: mod_irc:535
msgid "Registration in mod_irc for "
-msgstr "Rexistro en mod_irc para"
+msgstr "Rexistro en mod_irc para "
#: mod_configure:889
msgid "Remote copy"
@@ -1538,7 +1529,7 @@ msgstr "Lista de contactos"
#: mod_roster:334
msgid "Roster module has failed"
-msgstr ""
+msgstr "O módulo de Roster fallou"
#: mod_roster:968
msgid "Roster of "
@@ -1554,7 +1545,7 @@ msgstr "Nodos funcionando"
#: xmpp_stream_in:541 xmpp_stream_in:549
msgid "SASL negotiation is not allowed in this state"
-msgstr ""
+msgstr "A negociación SASL non se permite neste estado"
#: mod_muc_log:468
msgid "Saturday"
@@ -1562,11 +1553,11 @@ msgstr "Sábado"
#: mod_irc:582
msgid "Scan error"
-msgstr ""
+msgstr "Erro de escaneo"
#: mod_configure:1303 mod_configure:1472 mod_configure:1517
msgid "Scan failed"
-msgstr ""
+msgstr "O escaneo Fallou"
#: ejabberd_web_admin:2282
msgid "Script check"
@@ -1602,11 +1593,11 @@ msgstr "Setembro"
#: mod_irc_connection:648
msgid "Server Connect Failed"
-msgstr ""
+msgstr "Conexión ao Servidor Fallou"
#: ejabberd_s2s:369
msgid "Server connections to local subdomains are forbidden"
-msgstr ""
+msgstr "Non se permiten conexións de servidor a subdominios locais"
#: mod_irc:842
msgid "Server ~b"
@@ -1721,7 +1712,7 @@ msgstr "Subscripción"
#: mod_muc_room:3708
msgid "Subscriptions are not allowed"
-msgstr ""
+msgstr "Non se permiten subscricións"
#: mod_muc_log:469
msgid "Sunday"
@@ -1745,11 +1736,11 @@ msgstr "A verificación de CAPTCHA fallou"
#: mod_muc_room:302
msgid "The feature requested is not supported by the conference"
-msgstr ""
+msgstr "A sala de conferencias non admite a función solicitada"
#: mod_register:308 mod_register:366
msgid "The password contains unacceptable characters"
-msgstr ""
+msgstr "O contrasinal contén caracteres inaceptables"
#: mod_register:311 mod_register:370
msgid "The password is too weak"
@@ -1761,17 +1752,19 @@ msgstr "O contrasinal da súa conta Jabber cambiouse correctamente."
#: mod_register:160 mod_vcard:219
msgid "The query is only allowed from local users"
-msgstr ""
+msgstr "A solicitude só se permite para usuarios locais"
#: mod_roster:203
msgid "The query must not contain <item/> elements"
-msgstr ""
+msgstr "A solicitude non debe conter elementos <item/>"
#: mod_privacy:280
msgid ""
"The stanza MUST contain only one <active/> element, one <default/> element, "
"or one <list/> element"
msgstr ""
+"A estroa DEBEN conter un elemento <active/>, un elemento <default/> ou un "
+"elemento <list/>"
#: mod_register_web:146
msgid "There was an error changing the password: "
@@ -1827,7 +1820,7 @@ msgstr "Para"
#: mod_register:215
msgid "To register, visit ~s"
-msgstr ""
+msgstr "Para rexistrarse, visita ~s"
#: mod_configure:709
msgid "To ~s"
@@ -1835,41 +1828,39 @@ msgstr "A ~s"
#: ejabberd_oauth:439
msgid "Token TTL"
-msgstr ""
+msgstr "Token TTL"
#: xmpp_stream_in:463
msgid "Too long value of 'xml:lang' attribute"
-msgstr ""
+msgstr "Valor demasiado longo do atributo 'xml:lang'"
#: mod_muc_room:2541 mod_muc_room:3081
msgid "Too many <item/> elements"
-msgstr ""
+msgstr "Demasiados elementos <item/>"
#: mod_privacy:164
msgid "Too many <list/> elements"
-msgstr ""
+msgstr "Demasiados elementos <list/>"
#: mod_muc_room:1924 mod_register:240
msgid "Too many CAPTCHA requests"
-msgstr "Demasiadas peticións de CAPTCHA"
+msgstr "Demasiadas solicitudes CAPTCHA"
#: mod_proxy65_service:223
-#, fuzzy
msgid "Too many active bytestreams"
-msgstr "Demasiadas mensaxes sen recoñecer recibilos"
+msgstr "Demasiados bytestreams activos"
#: mod_stream_mgmt:205
msgid "Too many unacked stanzas"
msgstr "Demasiadas mensaxes sen recoñecer recibilos"
#: mod_muc_room:1802
-#, fuzzy
msgid "Too many users in this conference"
-msgstr "As peticións de voz están desactivadas nesta sala"
+msgstr "Demasiados usuarios nesta sala"
#: mod_register:355
msgid "Too many users registered"
-msgstr ""
+msgstr "Demasiados usuarios rexistrados"
#: mod_muc_admin:368
msgid "Total rooms"
@@ -1905,7 +1896,7 @@ msgstr "No se pudo generar un CAPTCHA"
#: ejabberd_service:120
msgid "Unable to register route on existing local domain"
-msgstr ""
+msgstr "Non se pode rexistrar a ruta no dominio local existente"
#: ejabberd_web_admin:209 ejabberd_web_admin:221 ejabberd_web_admin:241
#: ejabberd_web_admin:253
@@ -1914,7 +1905,7 @@ msgstr "Non autorizado"
#: mod_announce:485 mod_configure:830 mod_configure:1758
msgid "Unexpected action"
-msgstr ""
+msgstr "Acción inesperada"
#: mod_register_web:488
msgid "Unregister"
@@ -1926,11 +1917,11 @@ msgstr "Eliminar o rexistro dunha conta Jabber"
#: mod_mam:526
msgid "Unsupported <index/> element"
-msgstr ""
+msgstr "Elemento <index/> non soportado"
#: mod_mix:119
msgid "Unsupported MIX query"
-msgstr ""
+msgstr "Petición MIX non soportada"
#: ejabberd_web_admin:1872 ejabberd_web_admin:2285
msgid "Update"
@@ -1961,9 +1952,8 @@ msgid "Uptime:"
msgstr "Tempo desde o inicio:"
#: xmpp_stream_out:533
-#, fuzzy
msgid "Use of STARTTLS forbidden"
-msgstr "Requírese o uso de STARTTLS"
+msgstr "Prohibido o uso de STARTTLS"
#: xmpp_stream_in:573 xmpp_stream_out:527 xmpp_stream_out:603
msgid "Use of STARTTLS required"
@@ -1976,7 +1966,7 @@ msgstr "Usuario"
#: ejabberd_oauth:428
msgid "User (jid)"
-msgstr ""
+msgstr "Usuario (jid)"
#: mod_configure:308 mod_configure:505
msgid "User Management"
@@ -1984,20 +1974,19 @@ msgstr "Administración de usuarios"
#: mod_register:345
msgid "User already exists"
-msgstr ""
+msgstr "O usuario xa existe"
#: mod_echo:138
msgid "User part of JID in 'from' is empty"
-msgstr ""
+msgstr "A parte do usuario do JID en 'from' está baleira"
#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_sic:106
-#, fuzzy
msgid "User session not found"
-msgstr "Nodo non atopado"
+msgstr "Sesión de usuario non atopada"
#: mod_stream_mgmt:561 mod_stream_mgmt:583
msgid "User session terminated"
-msgstr ""
+msgstr "Sesión de usuario completada"
#: ejabberd_web_admin:1700
msgid "User ~s"
@@ -2026,7 +2015,7 @@ msgstr "Validar"
#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3662 mod_muc_room:3802
#: mod_pubsub:895 mod_push:249
msgid "Value 'get' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "O valor \"get\" do atributo 'type' non está permitido"
#: mod_disco:159 mod_disco:175 mod_disco:279 mod_disco:346 mod_irc:270
#: mod_irc:285 mod_irc:339 mod_last:118 mod_last:140 mod_muc:479 mod_muc:504
@@ -2035,20 +2024,20 @@ msgstr ""
#: mod_pubsub:821 mod_pubsub:839 mod_pubsub:877 mod_sic:81 mod_sic:93
#: mod_stats:55 mod_time:62 mod_vcard:198 mod_vcard:236 mod_version:62
msgid "Value 'set' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "O valor \"set\" do atributo 'type' non está permitido"
#: pubsub_subscription:237 pubsub_subscription_sql:202
msgid "Value of '~s' should be boolean"
-msgstr ""
+msgstr "O valor de '~s' debería ser booleano"
#: pubsub_subscription:215 pubsub_subscription_sql:180
msgid "Value of '~s' should be datetime string"
-msgstr ""
+msgstr "O valor de '~s' debería ser unha data"
#: pubsub_subscription:209 pubsub_subscription:227 pubsub_subscription_sql:174
#: pubsub_subscription_sql:192
msgid "Value of '~s' should be integer"
-msgstr ""
+msgstr "O valor de '~s' debería ser un enteiro"
#: ejabberd_web_admin:950
msgid "Virtual Hosts"
@@ -2081,11 +2070,11 @@ msgstr ""
#: mod_muc_room:1830
msgid "You have been banned from this room"
-msgstr "fuches bloqueado nesta sala"
+msgstr "Fuches bloqueado nesta sala"
#: mod_muc_room:1811
msgid "You have joined too many conferences"
-msgstr ""
+msgstr "Entrou en demasiadas salas de conferencia"
#: mod_muc:777
msgid "You must fill in field \"Nickname\" in the form"
@@ -2111,9 +2100,8 @@ msgid "You need an x:data capable client to search"
msgstr "Necesitas un cliente con soporte de x:data para poder buscar"
#: mod_pubsub:1504
-#, fuzzy
msgid "You're not allowed to create nodes"
-msgstr "Non está permitido enviar mensaxes privadas"
+msgstr "Non tes permiso para crear nodos"
#: mod_register_web:111
msgid "Your Jabber account was successfully created."
@@ -2162,7 +2150,7 @@ msgstr "Módulo SOCKS5 Bytestreams para ejabberd"
#: ejabberd_web_admin:311 ejabberd_web_admin:343
msgid "ejabberd Web Admin"
-msgstr "Ejabberd Administrador Web"
+msgstr "ejabberd Administrador Web"
#: mod_vcard:239
msgid "ejabberd vCard module"
@@ -2190,7 +2178,7 @@ msgstr "foi expulsado, porque a sala cambiouse a só-membros"
#: mod_muc_log:410
msgid "is now known as"
-msgstr "cámbiase o nome a"
+msgstr "agora coñécese como"
#: mod_muc_log:370
msgid "joins the room"
@@ -2202,7 +2190,7 @@ msgstr "sae da sala"
#: mod_muc_room:3856
msgid "private, "
-msgstr "privado"
+msgstr "privado, "
#: mod_muc_room:3955
msgid "the password is"
@@ -2214,7 +2202,7 @@ msgstr "vCard busqueda de usuario"
#: ejabberd_web_admin:932
msgid "~s access rule configuration"
-msgstr "Configuración das Regra de Acceso ~s"
+msgstr "Configuración das regra de acceso ~s"
#: mod_muc_room:3948
msgid "~s invites you to the room ~s"
@@ -2402,7 +2390,7 @@ msgstr "Cola de mensaxes diferidas de ~s"
#~ "presenza"
#~ msgid "CAPTCHA test failed"
-#~ msgstr "O CAPTCHA é válido."
+#~ msgstr "Fallou a proba de CAPTCHA"
#~ msgid "Encodings"
#~ msgstr "Codificaciones"
@@ -2411,7 +2399,7 @@ msgstr "Cola de mensaxes diferidas de ~s"
#~ msgstr "(Cru)"
#~ msgid "Specified nickname is already registered"
-#~ msgstr "O alcume especificado xa está rexistrado, terás que buscar outro"
+#~ msgstr "O alcume especificado xa está rexistrado"
#~ msgid "Size"
#~ msgstr "Tamaño"
diff --git a/priv/msgs/he.po b/priv/msgs/he.po
index d237e853f..8121c6c4a 100644
--- a/priv/msgs/he.po
+++ b/priv/msgs/he.po
@@ -15,12 +15,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Source-Language: en\n"
-#: mod_muc_log:413 mod_muc_log:752
+#: mod_muc_log:413 mod_muc_log:588
msgid " has set the subject to: "
msgstr " הגדיר/ה את הנושא אל: "
# מילת־מעבר
-#: mod_muc_room:1893
+#: mod_muc_room:1904
msgid "A password is required to enter this room"
msgstr "נדרשת סיסמה כדי להיכנס אל חדר זה"
@@ -36,13 +36,13 @@ msgstr "תצורת גישה"
msgid "Access Control List Configuration"
msgstr "תצורת רשימת בקרת גישה"
-#: ejabberd_web_admin:758 ejabberd_web_admin:797 mod_configure:185
+#: ejabberd_web_admin:484 ejabberd_web_admin:523 mod_configure:185
#: mod_configure:514
msgid "Access Control Lists"
msgstr "רשימות בקרת גישה"
# חוקי
-#: ejabberd_web_admin:863 ejabberd_web_admin:896 mod_configure:187
+#: ejabberd_web_admin:589 ejabberd_web_admin:622 mod_configure:187
#: mod_configure:515
msgid "Access Rules"
msgstr "כללי גישה"
@@ -86,16 +86,16 @@ msgstr "פעולה על משתמש"
msgid "Add Jabber ID"
msgstr "הוסף מזהה Jabber"
-#: ejabberd_web_admin:1277 mod_shared_roster:825
+#: ejabberd_web_admin:1003 mod_shared_roster:825
msgid "Add New"
msgstr "הוסף חדש"
-#: ejabberd_web_admin:1444 mod_configure:166 mod_configure:521
+#: ejabberd_web_admin:1170 mod_configure:166 mod_configure:521
#: mod_configure:1118
msgid "Add User"
msgstr "הוסף משתמש"
-#: ejabberd_web_admin:687 ejabberd_web_admin:698
+#: ejabberd_web_admin:413 ejabberd_web_admin:424
msgid "Administration"
msgstr "הנהלה"
@@ -103,7 +103,7 @@ msgstr "הנהלה"
msgid "Administration of "
msgstr "ניהול של "
-#: mod_muc_room:2528
+#: mod_muc_room:2548
msgid "Administrator privileges required"
msgstr "נדרשות הרשאות מנהל"
@@ -111,35 +111,35 @@ msgstr "נדרשות הרשאות מנהל"
msgid "All Users"
msgstr "כל המשתמשים"
-#: ejabberd_web_admin:1010
+#: ejabberd_web_admin:736
msgid "All activity"
msgstr "כל פעילות"
-#: mod_muc_log:1046
+#: mod_muc_log:809
msgid "Allow users to change the subject"
msgstr "התר למשתמשים לשנות את הנושא"
-#: mod_muc_log:1052
+#: mod_muc_log:815
msgid "Allow users to query other users"
msgstr "התר למשתמשים לתשאל משתמשים אחרים"
-#: mod_muc_log:1054
+#: mod_muc_log:817
msgid "Allow users to send invites"
msgstr "התר למשתמשים לשלוח הזמנות"
-#: mod_muc_log:1048
+#: mod_muc_log:811
msgid "Allow users to send private messages"
msgstr "התר למשתמשים לשלוח הודעות פרטיות"
-#: mod_muc_log:1057
+#: mod_muc_log:820
msgid "Allow visitors to change nickname"
msgstr "התר למבקרים לשנות שם כינוי"
-#: mod_muc_log:1050
+#: mod_muc_log:813
msgid "Allow visitors to send private messages to"
msgstr "התר למבקרים לשלוח הודעות פרטיות אל"
-#: mod_muc_log:1059
+#: mod_muc_log:822
msgid "Allow visitors to send status text in presence updates"
msgstr "התר למבקרים לשלוח טקסט מצב בתוך עדכוני נוכחות"
@@ -157,9 +157,9 @@ msgstr "אוגוסט"
#: mod_pubsub:1842
msgid "Automatic node creation is not enabled"
-msgstr ""
+msgstr "יצירה אוטומטית של צומת אינה מאופשרת"
-#: ejabberd_web_admin:1867 mod_configure:148 mod_configure:617
+#: ejabberd_web_admin:1593 mod_configure:148 mod_configure:617
msgid "Backup"
msgstr "גיבוי"
@@ -167,7 +167,7 @@ msgstr "גיבוי"
msgid "Backup Management"
msgstr "ניהול גיבוי"
-#: ejabberd_web_admin:1979
+#: ejabberd_web_admin:1705
msgid "Backup of ~p"
msgstr "גיבוי של ~p"
@@ -176,10 +176,10 @@ msgid "Backup to File at "
msgstr "גבה לקובץ אצל "
# פגום
-#: ejabberd_web_admin:763 ejabberd_web_admin:802 ejabberd_web_admin:868
-#: ejabberd_web_admin:901 ejabberd_web_admin:937 ejabberd_web_admin:1422
-#: ejabberd_web_admin:1705 ejabberd_web_admin:1861 ejabberd_web_admin:2145
-#: ejabberd_web_admin:2174 mod_roster:972 mod_shared_roster:831
+#: ejabberd_web_admin:489 ejabberd_web_admin:528 ejabberd_web_admin:594
+#: ejabberd_web_admin:627 ejabberd_web_admin:663 ejabberd_web_admin:1148
+#: ejabberd_web_admin:1431 ejabberd_web_admin:1587 ejabberd_web_admin:1871
+#: ejabberd_web_admin:1900 mod_roster:972 mod_shared_roster:831
#: mod_shared_roster:926
msgid "Bad format"
msgstr "פורמט רע"
@@ -201,20 +201,20 @@ msgstr ""
msgid "CAPTCHA web page"
msgstr "עמוד רשת CAPTCHA"
-#: ejabberd_web_admin:2207
+#: ejabberd_web_admin:1933
msgid "CPU Time:"
msgstr "זמן מחשב (CPU):"
#: mod_privacy:334
msgid "Cannot remove active list"
-msgstr ""
+msgstr "לא ניתן להסיר רשימה פעילה"
#: mod_privacy:341
msgid "Cannot remove default list"
-msgstr ""
+msgstr "לא ניתן להסיר רשימה שגרתית"
-#: ejabberd_web_admin:1679 mod_register_web:194 mod_register_web:353
-#: mod_register_web:361 mod_register_web:386
+#: ejabberd_web_admin:1405 mod_register_web:212 mod_register_web:373
+#: mod_register_web:381 mod_register_web:406
msgid "Change Password"
msgstr "שנה סיסמה"
@@ -223,16 +223,14 @@ msgid "Change User Password"
msgstr "שנה סיסמת משתמש"
#: mod_register:295
-#, fuzzy
msgid "Changing password is not allowed"
-msgstr "תווים לא מורשים:"
+msgstr "שינוי סיסמה אינו מותר"
-#: mod_muc_room:2764
-#, fuzzy
+#: mod_muc_room:2784
msgid "Changing role/affiliation is not allowed"
-msgstr "תווים לא מורשים:"
+msgstr "שינוי תפקיד/שיוך אינו מותר"
-#: mod_register_web:239
+#: mod_register_web:258
msgid "Characters not allowed:"
msgstr "תווים לא מורשים:"
@@ -294,11 +292,11 @@ msgid "Configuration"
msgstr "תצורה"
# תצורה של חדר
-#: mod_muc_room:3163
+#: mod_muc_room:3183
msgid "Configuration of room ~s"
msgstr "תצורת חדר ~s"
-#: ejabberd_web_admin:1711
+#: ejabberd_web_admin:1437
msgid "Connected Resources:"
msgstr "משאבים מחוברים:"
@@ -312,7 +310,7 @@ msgstr "פרמטרים של חיבור"
msgid "Country"
msgstr "ארץ"
-#: ejabberd_web_admin:1866 mod_configure:139 mod_configure:580
+#: ejabberd_web_admin:1592 mod_configure:139 mod_configure:580
msgid "Database"
msgstr "מסד נתונים"
@@ -320,7 +318,7 @@ msgstr "מסד נתונים"
msgid "Database Tables Configuration at "
msgstr "תצורת טבלאות מסד נתונים אצל "
-#: ejabberd_web_admin:1941
+#: ejabberd_web_admin:1667
msgid "Database Tables at ~p"
msgstr "טבלאות מסד נתונים אצל ~p"
@@ -332,20 +330,19 @@ msgstr "טבלאות מסד נתונים אצל ~p"
#: mod_pubsub:3598 mod_pubsub:3604 mod_pubsub:3607 mod_vcard:226
#: node_flat_sql:801 nodetree_tree_sql:128 nodetree_tree_sql:142
#: nodetree_tree_sql:257
-#, fuzzy
msgid "Database failure"
-msgstr "מסד נתונים"
+msgstr "כשל מסד נתונים"
#: mod_muc_log:484
msgid "December"
msgstr "דצמבר"
-#: mod_muc_log:1044
+#: mod_muc_log:807
msgid "Default users as participants"
msgstr "משתמשים שגרתיים כמשתתפים"
# נבחרים
-#: ejabberd_web_admin:811 ejabberd_web_admin:911 mod_offline:703
+#: ejabberd_web_admin:537 ejabberd_web_admin:637 mod_offline:703
#: mod_shared_roster:839
msgid "Delete Selected"
msgstr "מחק נבחרות"
@@ -374,7 +371,7 @@ msgstr "העתק של תקליטור בלבד"
msgid "Displayed Groups:"
msgstr "קבוצות מוצגות:"
-#: mod_register_web:251
+#: mod_register_web:270
msgid ""
"Don't tell your password to anybody, not even the administrators of the "
"Jabber server."
@@ -397,11 +394,11 @@ msgstr ""
msgid "Edit Properties"
msgstr "ערוך מאפיינים"
-#: mod_muc_room:3881
+#: mod_muc_room:3901
msgid "Either approve or decline the voice request."
msgstr "אשר או דחה בקשת ביטוי."
-#: ejabberd_web_admin:1953
+#: ejabberd_web_admin:1679
msgid "Elements"
msgstr "אלמנטים"
@@ -411,11 +408,10 @@ msgid "Email"
msgstr "דוא״ל"
#: mod_register:292
-#, fuzzy
msgid "Empty password"
-msgstr "הסיסמה היא"
+msgstr "סיסמה ריקה"
-#: mod_muc_log:1055
+#: mod_muc_log:818
msgid "Enable logging"
msgstr "אפשר רישום פעילות"
@@ -481,7 +477,7 @@ msgstr ""
msgid "Erlang Jabber Server"
msgstr "שרת ג׳אבּר Erlang"
-#: ejabberd_web_admin:1976 ejabberd_web_admin:2147
+#: ejabberd_web_admin:1702 ejabberd_web_admin:1873
msgid "Error"
msgstr "שגיאה"
@@ -493,15 +489,15 @@ msgstr ""
"דוגמא: [{\"irc.lucky.net\", \"koi8-r\", 6667, \"secret\"}, {\"vendetta.fef."
"net\", \"iso8859-1\", 7000}, {\"irc.sometestserver.net\", \"utf-8\"}]."
-#: ejabberd_web_admin:2084
+#: ejabberd_web_admin:1810
msgid "Export all tables as SQL queries to a file:"
msgstr "יצא את כל הטבלאות בתור שאילתות SQL לתוך קובץ:"
-#: ejabberd_web_admin:2056
+#: ejabberd_web_admin:1782
msgid "Export data of all users in the server to PIEFXIS files (XEP-0227):"
msgstr "יצא מידע של כל המשתמשים שבתוך שרת זה לתוך קבצי PIEFXIS ‏(XEP-0227):"
-#: ejabberd_web_admin:2068
+#: ejabberd_web_admin:1794
msgid "Export data of users in a host to PIEFXIS files (XEP-0227):"
msgstr "יצא מידע של כל המשתמשים שבתוך מארח לתוך קבצי PIEFXIS ‏(XEP-0227):"
@@ -515,7 +511,7 @@ msgstr ""
#: mod_proxy65_service:218
msgid "Failed to activate bytestream"
-msgstr ""
+msgstr "נכשל להפעיל bytestream"
#: mod_muc_room:910
msgid "Failed to extract JID from your voice request approval"
@@ -527,15 +523,15 @@ msgstr ""
#: mod_http_upload:602
msgid "Failed to parse HTTP response"
-msgstr ""
+msgstr "נכשל לפענח תגובת HTTP"
#: mod_irc:426
msgid "Failed to parse chanserv"
-msgstr ""
+msgstr "נכשל לפענח chanserv"
-#: mod_muc_room:3297
+#: mod_muc_room:3317
msgid "Failed to process option '~s'"
-msgstr ""
+msgstr "נכשל לעבד אפשרות '~s'"
#: mod_vcard_ldap:332 mod_vcard_ldap:345 mod_vcard_mnesia:103
#: mod_vcard_mnesia:117 mod_vcard_sql:158 mod_vcard_sql:172
@@ -548,7 +544,7 @@ msgstr "פברואר"
#: mod_http_upload:555
msgid "File larger than ~w bytes"
-msgstr ""
+msgstr "קובץ גדול יותר משיעור של ~w בייטים"
#: mod_vcard:437
msgid ""
@@ -597,9 +593,8 @@ msgid "Get User Statistics"
msgstr "השג סטטיסטיקת משתמש"
#: mod_vcard_ldap:330 mod_vcard_ldap:343
-#, fuzzy
msgid "Given Name"
-msgstr "שם אמצעי"
+msgstr "שם פרטי"
#: mod_shared_roster:923
msgid "Group "
@@ -609,15 +604,15 @@ msgstr "קבוצה "
msgid "Groups"
msgstr "קבוצות"
-#: ejabberd_web_admin:1365
+#: ejabberd_web_admin:1091
msgid "Host"
msgstr "מארח"
#: mod_s2s_dialback:325
msgid "Host unknown"
-msgstr ""
+msgstr "מארח לא ידוע"
-#: ejabberd_web_admin:2463
+#: ejabberd_web_admin:2189
msgid "IP"
msgstr "‫IP"
@@ -638,9 +633,8 @@ msgid "IRC channel (don't put the first #)"
msgstr "ערוץ IRC (אל תשים סימן # ראשון)"
#: mod_irc:417
-#, fuzzy
msgid "IRC connection not found"
-msgstr "צומת לא נמצא"
+msgstr "חיבור IRC לא נמצא"
#: mod_irc:673
msgid "IRC server"
@@ -689,15 +683,15 @@ msgstr "יבא משתמשים מתוך קבצי סליל (Spool Files) של jabb
msgid "Import Users from Dir at "
msgstr "ייבוא משתמשים מתוך מדור אצל "
-#: ejabberd_web_admin:2100
+#: ejabberd_web_admin:1826
msgid "Import user data from jabberd14 spool file:"
msgstr "יבא נתוני משתמש מתוך קובץ סליל (spool file) של jabberd14:"
-#: ejabberd_web_admin:2043
+#: ejabberd_web_admin:1769
msgid "Import users data from a PIEFXIS file (XEP-0227):"
msgstr "יבא מידע משתמשים מתוך קובץ PIEFXIS ‏(XEP-0227):"
-#: ejabberd_web_admin:2111
+#: ejabberd_web_admin:1837
msgid "Import users data from jabberd14 spool directory:"
msgstr "יבא נתוני משתמשים מתוך מדור סליל (spool directory) של jabberd14:"
@@ -718,26 +712,25 @@ msgstr ""
msgid "Improper message type"
msgstr "טיפוס הודעה לא מתאים"
-#: ejabberd_web_admin:1586
+#: ejabberd_web_admin:1312
msgid "Incoming s2s Connections:"
msgstr "חיבורי s2s נכנסים:"
-#: mod_muc_room:3669 mod_register:187
+#: mod_muc_room:3689 mod_register:187
msgid "Incorrect CAPTCHA submit"
-msgstr ""
+msgstr "נשלחה CAPTCHA שגויה"
-#: mod_muc:772 mod_muc_room:3052 mod_pubsub:1194 mod_register:183 mod_vcard:256
-#, fuzzy
+#: mod_muc:772 mod_muc_room:3072 mod_pubsub:1194 mod_register:183 mod_vcard:256
msgid "Incorrect data form"
-msgstr "מילת מעבר שגויה"
+msgstr "טופס מידע לא תקין"
-#: mod_muc_room:1943 mod_register:300 mod_register:350
+#: mod_muc_room:1954 mod_register:300 mod_register:350
msgid "Incorrect password"
msgstr "מילת מעבר שגויה"
#: mod_irc:585
msgid "Incorrect value in data form"
-msgstr ""
+msgstr "נשלח ערך שגוי בטופס מידע"
#: mod_adhoc:276
msgid "Incorrect value of 'action' attribute"
@@ -758,7 +751,7 @@ msgstr ""
#: mod_privilege:100
msgid "Insufficient privilege"
-msgstr ""
+msgstr "הרשאה לא מספיקה"
#: mod_privilege:286
msgid "Invalid 'from' attribute in forwarded message"
@@ -768,12 +761,11 @@ msgstr ""
msgid "Invalid <forwarded/> element"
msgstr ""
-#: mod_muc_room:3926
-#, fuzzy
+#: mod_muc_room:3946
msgid "Invitations are not allowed in this conference"
-msgstr "בקשות ביטוי מנוטרלות בועידה זו"
+msgstr "הזמנות אינן מותרות בועידה זו"
-#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1046
+#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1052
msgid ""
"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"
@@ -794,7 +786,7 @@ msgstr "אין זה מותר לשלוח הודעות פרטיות מן טיפו
msgid "It is not allowed to send private messages to the conference"
msgstr "אין זה מותר לשלוח הודעות פרטיות לועידה"
-#: mod_register_web:181 mod_register_web:189
+#: mod_register_web:199 mod_register_web:207
msgid "Jabber Account Registration"
msgstr "רישום חשבון Jabber"
@@ -829,7 +821,7 @@ msgstr "יולי"
msgid "June"
msgstr "יוני"
-#: ejabberd_web_admin:1488 ejabberd_web_admin:1715
+#: ejabberd_web_admin:1214 ejabberd_web_admin:1441
msgid "Last Activity"
msgstr "פעילות אחרונה"
@@ -837,11 +829,11 @@ msgstr "פעילות אחרונה"
msgid "Last login"
msgstr "כניסה אחרונה"
-#: ejabberd_web_admin:1007
+#: ejabberd_web_admin:733
msgid "Last month"
msgstr "חודש אחרון"
-#: ejabberd_web_admin:1008
+#: ejabberd_web_admin:734
msgid "Last year"
msgstr "שנה אחרונה"
@@ -853,56 +845,55 @@ msgstr "רשימה של מודולים להפעלה"
msgid "List of rooms"
msgstr "רשימה של חדרים"
-#: ejabberd_web_admin:1869
+#: ejabberd_web_admin:1595
msgid "Listened Ports"
msgstr "פורטים מואזנים"
-#: ejabberd_web_admin:2139
+#: ejabberd_web_admin:1865
msgid "Listened Ports at "
msgstr "פורטים מואזנים אצל "
-#: ejabberd_web_admin:2281
+#: ejabberd_web_admin:2007
msgid "Low level update script"
msgstr "תסריט עדכון Low level"
-#: mod_muc_log:1033
+#: mod_muc_log:796
msgid "Make participants list public"
msgstr "הפוך רשימת משתתפים לפומבית"
-#: mod_muc_log:1062
+#: mod_muc_log:825
msgid "Make room CAPTCHA protected"
msgstr "הפוך חדר לחדר מוגן CAPTCHA"
-#: mod_muc_log:1040
+#: mod_muc_log:803
msgid "Make room members-only"
msgstr "הפוך חדר לחדר עבור חברים-בלבד"
-#: mod_muc_log:1042
+#: mod_muc_log:805
msgid "Make room moderated"
msgstr "הפוך חדר לחדר מבוקר"
-#: mod_muc_log:1035
+#: mod_muc_log:798
msgid "Make room password protected"
msgstr "הפוך חדר לחדר מוגן במילת מעבר"
-#: mod_muc_log:1029
+#: mod_muc_log:792
msgid "Make room persistent"
msgstr "הפוך חדר לחדר קבוע"
-#: mod_muc_log:1031
+#: mod_muc_log:794
msgid "Make room public searchable"
msgstr "הפוך חדר לחדר שנתון לחיפוש פומבי"
#: mod_register:317
-#, fuzzy
msgid "Malformed username"
-msgstr "שם משתמש IRC"
+msgstr "שם משתמש פגום"
#: mod_muc_log:475
msgid "March"
msgstr "מרץ"
-#: mod_muc_log:1068
+#: mod_muc_log:831
msgid "Maximum Number of Occupants"
msgstr "מספר מרבי של נוכחים"
@@ -914,12 +905,12 @@ msgstr "מאי"
msgid "Members:"
msgstr "חברים:"
-#: mod_muc_room:1833
+#: mod_muc_room:1847
msgid "Membership is required to enter this room"
msgstr "נדרשת חברות כדי להיכנס אל חדר זה"
# תישכח
-#: mod_register_web:262
+#: mod_register_web:281
msgid ""
"Memorize your password, or write it in a paper placed in a safe place. In "
"Jabber there isn't an automated way to recover your password if you forget "
@@ -928,7 +919,7 @@ msgstr ""
"שנן את הסיסמה שלך, או רשום אותה בנייר שמור במקום בטוח. אצל Jabber אין דרך "
"אוטומטית לשחזר את הסיסמה שלך במידה וזו תישמט מתוך זיכרונך."
-#: ejabberd_web_admin:1954
+#: ejabberd_web_admin:1680
msgid "Memory"
msgstr "זיכרון"
@@ -957,28 +948,28 @@ msgstr ""
msgid "Missing 'to' attribute"
msgstr ""
-#: mod_muc_room:2536 mod_muc_room:3721 mod_muc_room:3765 mod_muc_room:3798
+#: mod_muc_room:2556 mod_muc_room:3741 mod_muc_room:3785 mod_muc_room:3818
msgid "Moderator privileges required"
msgstr "נדרשות הרשאות אחראי"
# adjusted
-#: ejabberd_web_admin:2279
+#: ejabberd_web_admin:2005
msgid "Modified modules"
msgstr "מודולים שהותאמו"
-#: ejabberd_web_admin:2465 ejabberd_web_admin:2620
+#: ejabberd_web_admin:2191 ejabberd_web_admin:2346
msgid "Module"
msgstr "מודול"
#: gen_iq_handler:153
msgid "Module failed to handle the query"
-msgstr ""
+msgstr "מודול נכשל לטפל בשאילתא"
-#: ejabberd_web_admin:1885 mod_configure:582 mod_configure:595
+#: ejabberd_web_admin:1611 mod_configure:582 mod_configure:595
msgid "Modules"
msgstr "מודולים"
-#: ejabberd_web_admin:2168
+#: ejabberd_web_admin:1894
msgid "Modules at ~p"
msgstr "מודולים אצל ~p"
@@ -998,7 +989,7 @@ msgstr "שידור מרובב"
msgid "Multiple <item/> elements are not allowed by RFC6121"
msgstr ""
-#: ejabberd_web_admin:1951 mod_vcard_mnesia:101 mod_vcard_mnesia:115
+#: ejabberd_web_admin:1677 mod_vcard_mnesia:101 mod_vcard_mnesia:115
#: mod_vcard_sql:156 mod_vcard_sql:170
msgid "Name"
msgstr "שם"
@@ -1007,19 +998,19 @@ msgstr "שם"
msgid "Name:"
msgstr "שם:"
-#: mod_muc_room:2696
+#: mod_muc_room:2716
msgid "Neither 'jid' nor 'nick' attribute found"
msgstr ""
-#: mod_muc_room:2518 mod_muc_room:2701
+#: mod_muc_room:2538 mod_muc_room:2721
msgid "Neither 'role' nor 'affiliation' attribute found"
msgstr ""
-#: ejabberd_web_admin:1506 ejabberd_web_admin:1687 mod_configure:1629
+#: ejabberd_web_admin:1232 ejabberd_web_admin:1413 mod_configure:1629
msgid "Never"
msgstr "אף פעם"
-#: mod_register_web:377
+#: mod_register_web:397
msgid "New Password:"
msgstr "סיסמה חדשה:"
@@ -1032,7 +1023,7 @@ msgstr "שם כינוי"
msgid "Nickname Registration at "
msgstr "רישום שם כינוי אצל "
-#: mod_muc_room:2713
+#: mod_muc_room:2733
msgid "Nickname ~s does not exist in the room"
msgstr "שם כינוי ~s לא קיים בחדר"
@@ -1044,11 +1035,11 @@ msgstr ""
msgid "No 'acls' found in data form"
msgstr ""
-#: mod_muc_room:3075
+#: mod_muc_room:3095
msgid "No 'affiliation' attribute found"
msgstr ""
-#: mod_muc_room:2505
+#: mod_muc_room:2525
#, fuzzy
msgid "No 'item' element found"
msgstr "צומת לא נמצא"
@@ -1070,17 +1061,17 @@ msgstr ""
msgid "No 'path' found in data form"
msgstr ""
-#: mod_muc_room:3922
+#: mod_muc_room:3942
msgid "No 'to' attribute found in the invitation"
msgstr ""
-#: ejabberd_web_admin:1767
+#: ejabberd_web_admin:1493
msgid "No Data"
msgstr "אין מידע"
#: ejabberd_local:181
msgid "No available resource found"
-msgstr ""
+msgstr "לא נמצא משאב זמין"
#: mod_announce:575
msgid "No body provided for announce message"
@@ -1093,7 +1084,7 @@ msgstr "צומת לא נמצא"
#: mod_disco:224 mod_vcard:282
msgid "No features available"
-msgstr ""
+msgstr "אין תכונות זמינות"
#: mod_adhoc:239
msgid "No hook has processed this command"
@@ -1105,85 +1096,83 @@ msgstr ""
#: mod_blocking:99
msgid "No items found in this query"
-msgstr ""
+msgstr "לא נמצאו פריטים בתוך שאילתא זו"
#: ejabberd_local:90 ejabberd_sm:863 mod_blocking:92 mod_blocking:110
#: mod_http_upload:513 mod_muc:482 mod_muc:534 mod_muc:556 mod_muc:580
#: mod_offline:303 mod_privacy:168 mod_privacy:285 mod_roster:207
msgid "No module is handling this query"
-msgstr ""
+msgstr "אין מודול אשר מטפל בשאילתא זו"
#: mod_pubsub:1541
msgid "No node specified"
-msgstr ""
+msgstr "לא צויין צומת"
#: mod_pubsub:1426
msgid "No pending subscriptions found"
-msgstr ""
+msgstr "לא נמצאו הרשמות ממתינות"
#: mod_privacy:201 mod_privacy:295 mod_privacy:311 mod_privacy:344
msgid "No privacy list with this name found"
-msgstr ""
+msgstr "לא נמצאה רשימת פרטיות בשם זה"
#: mod_private:96
msgid "No private data found in this query"
-msgstr ""
+msgstr "לא נמצא מידע פרטי בתוך שאילתא זו"
#: mod_configure:869 mod_configure:908 mod_configure:1222 mod_configure:1254
#: mod_configure:1275 mod_configure:1314 mod_configure:1345 mod_configure:1377
#: mod_configure:1408 mod_configure:1428 mod_stats:93
-#, fuzzy
msgid "No running node found"
-msgstr "צומת לא נמצא"
+msgstr "לא נמצא צומת מורץ"
#: mod_disco:252 mod_vcard:265
msgid "No services available"
-msgstr ""
+msgstr "אין שירות זמין"
#: mod_stats:101
msgid "No statistics found for this item"
-msgstr ""
+msgstr "לא נמצאה סטטיסטיקה לגבי פריט זה"
#: nodetree_dag:72 nodetree_tree:181 nodetree_tree_sql:255
msgid "Node already exists"
-msgstr ""
+msgstr "צומת כבר קיים"
#: nodetree_tree_sql:99
-#, fuzzy
msgid "Node index not found"
-msgstr "צומת לא נמצא"
+msgstr "מפתח צומת לא נמצא"
-#: ejabberd_web_admin:1046 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
+#: ejabberd_web_admin:772 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
#: nodetree_dag:78 nodetree_dag:102 nodetree_dag:118 nodetree_dag:142
#: nodetree_dag:229 nodetree_tree:74 nodetree_tree:80 nodetree_tree_sql:130
#: nodetree_tree_sql:144
msgid "Node not found"
msgstr "צומת לא נמצא"
-#: ejabberd_web_admin:1857 ejabberd_web_admin:1882
+#: ejabberd_web_admin:1583 ejabberd_web_admin:1608
msgid "Node ~p"
msgstr "צומת ~p"
#: mod_vcard:385
msgid "Nodeprep has failed"
-msgstr ""
+msgstr "‏Nodeprep נכשל"
-#: ejabberd_web_admin:1837
+#: ejabberd_web_admin:1563
msgid "Nodes"
msgstr "צמתים"
-#: ejabberd_web_admin:1622 ejabberd_web_admin:1818 ejabberd_web_admin:1828
-#: ejabberd_web_admin:2238 mod_roster:907
+#: ejabberd_web_admin:1348 ejabberd_web_admin:1544 ejabberd_web_admin:1554
+#: ejabberd_web_admin:1964 mod_roster:907
msgid "None"
msgstr "אין"
-#: ejabberd_web_admin:1033
+#: ejabberd_web_admin:759
msgid "Not Found"
msgstr "לא נמצא"
#: mod_disco:296 mod_disco:370 mod_last:159
msgid "Not subscribed"
-msgstr ""
+msgstr "לא רשום"
#: mod_muc_log:483
msgid "November"
@@ -1197,10 +1186,10 @@ msgstr "מספר של משתמשים מקוונים"
msgid "Number of registered users"
msgstr "מספר של משתמשים רשומים"
-#: ejabberd_web_admin:2000 ejabberd_web_admin:2010 ejabberd_web_admin:2021
-#: ejabberd_web_admin:2030 ejabberd_web_admin:2040 ejabberd_web_admin:2053
-#: ejabberd_web_admin:2065 ejabberd_web_admin:2081 ejabberd_web_admin:2097
-#: ejabberd_web_admin:2108 ejabberd_web_admin:2118
+#: ejabberd_web_admin:1726 ejabberd_web_admin:1736 ejabberd_web_admin:1747
+#: ejabberd_web_admin:1756 ejabberd_web_admin:1766 ejabberd_web_admin:1779
+#: ejabberd_web_admin:1791 ejabberd_web_admin:1807 ejabberd_web_admin:1823
+#: ejabberd_web_admin:1834 ejabberd_web_admin:1844
msgid "OK"
msgstr "אישור"
@@ -1208,7 +1197,7 @@ msgstr "אישור"
msgid "October"
msgstr "אוקטובר"
-#: ejabberd_web_admin:1487
+#: ejabberd_web_admin:1213
msgid "Offline Messages"
msgstr "הודעות לא מקוונות"
@@ -1216,25 +1205,25 @@ msgstr "הודעות לא מקוונות"
msgid "Offline Messages:"
msgstr "הודעות לא מקוונות:"
-#: mod_register_web:373
+#: mod_register_web:393
msgid "Old Password:"
msgstr "סיסמה ישנה:"
-#: ejabberd_web_admin:1524 ejabberd_web_admin:1698 mod_configure:1639
+#: ejabberd_web_admin:1250 ejabberd_web_admin:1424 mod_configure:1639
msgid "Online"
msgstr "מקוון"
-#: ejabberd_web_admin:974 ejabberd_web_admin:1367 mod_configure:506
+#: ejabberd_web_admin:700 ejabberd_web_admin:1093 mod_configure:506
msgid "Online Users"
msgstr "משתמשים מקוונים"
-#: ejabberd_web_admin:1580 ejabberd_web_admin:1599 ejabberd_web_admin:2211
+#: ejabberd_web_admin:1306 ejabberd_web_admin:1325 ejabberd_web_admin:1937
msgid "Online Users:"
msgstr "משתמשים מקוונים:"
#: mod_carboncopy:141
msgid "Only <enable/> or <disable/> tags are allowed"
-msgstr ""
+msgstr "רק תגיות <enable/> או <disable/> הינן מורשות"
#: mod_privacy:154
msgid "Only <list/> element is allowed in this query"
@@ -1258,7 +1247,7 @@ msgstr "רק אחראים רשאים לשנות את הנושא בחדר זה"
msgid "Only moderators can approve voice requests"
msgstr "רק אחראים יכולים לאשר בקשות ביטוי"
-#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:3989
+#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:4009
msgid "Only occupants are allowed to send messages to the conference"
msgstr "רק נוכחים רשאים לשלוח הודעות אל הועידה"
@@ -1270,7 +1259,7 @@ msgstr "רק נוכחים רשאים לשלוח שאילתות אל הועידה
msgid "Only service administrators are allowed to send service messages"
msgstr "רק מנהלי שירות רשאים לשלוח הודעות שירות"
-#: ejabberd_web_admin:2466 ejabberd_web_admin:2621
+#: ejabberd_web_admin:2192 ejabberd_web_admin:2347
msgid "Options"
msgstr "אפשרויות"
@@ -1288,11 +1277,11 @@ msgstr "יחידת איגוד"
msgid "Outgoing s2s Connections"
msgstr "חיבורי s2s יוצאים"
-#: ejabberd_web_admin:1583
+#: ejabberd_web_admin:1309
msgid "Outgoing s2s Connections:"
msgstr "חיבורי s2s יוצאים:"
-#: mod_muc_room:3023 mod_muc_room:3067 mod_muc_room:3697 mod_pubsub:1302
+#: mod_muc_room:3043 mod_muc_room:3087 mod_muc_room:3717 mod_pubsub:1302
#: mod_pubsub:1394 mod_pubsub:1553 mod_pubsub:2118 mod_pubsub:2184
#: mod_pubsub:2383 mod_pubsub:2464 mod_pubsub:3063 mod_pubsub:3206
msgid "Owner privileges required"
@@ -1304,14 +1293,14 @@ msgstr "חבילת מידע"
#: mod_irc:578
msgid "Parse error"
-msgstr ""
+msgstr "שגיאת פענוח"
#: mod_configure:1299 mod_configure:1468 mod_configure:1513
msgid "Parse failed"
-msgstr ""
+msgstr "פענוח הכשל"
-#: ejabberd_oauth:431 ejabberd_web_admin:1435 mod_configure:1126
-#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:1036
+#: ejabberd_oauth:431 ejabberd_web_admin:1161 mod_configure:1126
+#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:799
#: mod_register:229
msgid "Password"
msgstr "סיסמה"
@@ -1320,7 +1309,7 @@ msgstr "סיסמה"
msgid "Password Verification"
msgstr "אימות סיסמה"
-#: mod_register_web:268 mod_register_web:381
+#: mod_register_web:287 mod_register_web:401
msgid "Password Verification:"
msgstr "אימות סיסמה:"
@@ -1328,7 +1317,7 @@ msgstr "אימות סיסמה:"
msgid "Password ~b"
msgstr "סיסמה ~b"
-#: ejabberd_web_admin:1713 mod_register_web:245 mod_register_web:483
+#: ejabberd_web_admin:1439 mod_register_web:264 mod_register_web:504
msgid "Password:"
msgstr "סיסמה:"
@@ -1344,7 +1333,7 @@ msgstr "נתיב לקובץ"
msgid "Pending"
msgstr "ממתינות"
-#: ejabberd_web_admin:994
+#: ejabberd_web_admin:720
msgid "Period: "
msgstr "משך זמן: "
@@ -1358,10 +1347,10 @@ msgstr "פינג"
#: mod_ping:180
msgid "Ping query is incorrect"
-msgstr ""
+msgstr "שאילתת פינג הינה שגויה"
# האינטגרלי לחוד
-#: ejabberd_web_admin:1983
+#: ejabberd_web_admin:1709
msgid ""
"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 "
@@ -1379,7 +1368,7 @@ msgstr "אנא, המתן לזמן מה לפני שליחת בקשת ביטוי
msgid "Pong"
msgstr "פונג"
-#: ejabberd_web_admin:2463
+#: ejabberd_web_admin:2189
msgid "Port"
msgstr "פורט"
@@ -1391,7 +1380,7 @@ msgstr "פורט ~b"
msgid "Possessing 'ask' attribute is not allowed by RFC6121"
msgstr ""
-#: ejabberd_web_admin:2464
+#: ejabberd_web_admin:2190
msgid "Protocol"
msgstr "פרוטוקול"
@@ -1424,11 +1413,11 @@ msgstr "העתק RAM וגם תקליטור"
msgid "RAM copy"
msgstr "העתק RAM"
-#: ejabberd_web_admin:1890
+#: ejabberd_web_admin:1616
msgid "RPC Call Error"
msgstr "שגיאת קריאת RPC"
-#: ejabberd_web_admin:806 ejabberd_web_admin:905
+#: ejabberd_web_admin:532 ejabberd_web_admin:631
msgid "Raw"
msgstr "גולמי"
@@ -1441,20 +1430,20 @@ msgid "Recipient is not in the conference room"
msgstr "מקבל אינו מצוי בחדר הועידה"
# רשום
-#: mod_register_web:275
+#: mod_register_web:294
msgid "Register"
msgstr "הרשם"
# Why masculine form matters.
-#: mod_register_web:192 mod_register_web:210 mod_register_web:218
+#: mod_register_web:210 mod_register_web:229 mod_register_web:237
msgid "Register a Jabber account"
msgstr "רשום חשבון Jabber"
-#: ejabberd_web_admin:1366
+#: ejabberd_web_admin:1092
msgid "Registered Users"
msgstr "משתמשים רשומים"
-#: ejabberd_web_admin:1577 ejabberd_web_admin:1596
+#: ejabberd_web_admin:1303 ejabberd_web_admin:1322
msgid "Registered Users:"
msgstr "משתמשים רשומים:"
@@ -1478,7 +1467,7 @@ msgstr "הסר"
msgid "Remove All Offline Messages"
msgstr "הסר את כל ההודעות הלא מקוונות"
-#: ejabberd_web_admin:1720 mod_configure:1779
+#: ejabberd_web_admin:1446 mod_configure:1779
msgid "Remove User"
msgstr "הסר משתמש"
@@ -1490,7 +1479,7 @@ msgstr "הוחלף בחיבור חדש"
msgid "Resources"
msgstr "משאבים"
-#: ejabberd_web_admin:1876 ejabberd_web_admin:2494 ejabberd_web_admin:2638
+#: ejabberd_web_admin:1602 ejabberd_web_admin:2220 ejabberd_web_admin:2364
msgid "Restart"
msgstr "אתחל"
@@ -1506,25 +1495,25 @@ msgstr "שחזר"
msgid "Restore Backup from File at "
msgstr "שחזר גיבוי מתוך קובץ אצל "
-#: ejabberd_web_admin:2013
+#: ejabberd_web_admin:1739
msgid ""
"Restore binary backup after next ejabberd restart (requires less memory):"
msgstr "שחזר גיבוי בינארי לאחר האתחול הבא של ejabberd (מצריך פחות זיכרון):"
# ללא דיחוי
-#: ejabberd_web_admin:2003
+#: ejabberd_web_admin:1729
msgid "Restore binary backup immediately:"
msgstr "שחזר גיבוי בינארי לאלתר:"
-#: ejabberd_web_admin:2033
+#: ejabberd_web_admin:1759
msgid "Restore plain text backup immediately:"
msgstr "שחזר גיבוי טקסט גלוי (plain text) לאלתר:"
-#: mod_muc_log:872
+#: mod_muc_log:635
msgid "Room Configuration"
msgstr "תצורת חדר"
-#: mod_muc_log:892
+#: mod_muc_log:655
msgid "Room Occupants"
msgstr "נוכחי חדר"
@@ -1532,11 +1521,11 @@ msgstr "נוכחי חדר"
msgid "Room creation is denied by service policy"
msgstr "יצירת חדר נדחתה על ידי פוליסת שירות"
-#: mod_muc_log:1064
+#: mod_muc_log:827
msgid "Room description"
msgstr "תיאור חדר"
-#: mod_muc_log:1027
+#: mod_muc_log:790
msgid "Room title"
msgstr "כותרת חדר"
@@ -1546,7 +1535,7 @@ msgstr "רשימה"
#: mod_roster:334
msgid "Roster module has failed"
-msgstr ""
+msgstr "מודול רשימה נכשל"
#: mod_roster:968
msgid "Roster of "
@@ -1556,7 +1545,7 @@ msgstr "רשימה של "
msgid "Roster size"
msgstr "גודל רשימה"
-#: ejabberd_web_admin:1838 mod_configure:510
+#: ejabberd_web_admin:1564 mod_configure:510
msgid "Running Nodes"
msgstr "צמתים מורצים"
@@ -1570,13 +1559,13 @@ msgstr "יום שבת"
#: mod_irc:582
msgid "Scan error"
-msgstr ""
+msgstr "שגיאת סריקה"
#: mod_configure:1303 mod_configure:1472 mod_configure:1517
msgid "Scan failed"
-msgstr ""
+msgstr "סריקה נכשלה"
-#: ejabberd_web_admin:2282
+#: ejabberd_web_admin:2008
msgid "Script check"
msgstr "בדיקת תסריט"
@@ -1611,7 +1600,7 @@ msgstr "ספטמבר"
#: mod_irc_connection:648
msgid "Server Connect Failed"
-msgstr ""
+msgstr "חיבור שרת נכשל"
#: ejabberd_s2s:369
msgid "Server connections to local subdomains are forbidden"
@@ -1621,7 +1610,7 @@ msgstr ""
msgid "Server ~b"
msgstr "שרת ~b"
-#: mod_register_web:242 mod_register_web:370 mod_register_web:480
+#: mod_register_web:261 mod_register_web:390 mod_register_web:501
msgid "Server:"
msgstr "שרת:"
@@ -1637,11 +1626,11 @@ msgstr "קבע את בשורת היום בכל המארחים ושלח למשת
msgid "Shared Roster Groups"
msgstr "קבוצות רשימה משותפות"
-#: ejabberd_web_admin:1016
+#: ejabberd_web_admin:742
msgid "Show Integral Table"
msgstr "הצג טבלה אינטגרלית"
-#: ejabberd_web_admin:1013
+#: ejabberd_web_admin:739
msgid "Show Ordinary Table"
msgstr "הצג טבלה רגילה"
@@ -1652,7 +1641,7 @@ msgstr "כבה שירות"
# בוטח
# trust that your
-#: mod_register_web:258
+#: mod_register_web:277
msgid ""
"Some Jabber clients can store your password in the computer, but you should "
"do this only in your personal computer for safety reasons."
@@ -1660,7 +1649,7 @@ msgstr ""
"ישנם לקוחות Jabber אשר מסוגלים לאחסן את הסיסמה שלך בתוך המחשב, אולם עליך "
"לעשות זאת רק בתוך המחשב האישי שלך מסיבות ביטחוניות."
-#: ejabberd_web_admin:2518 ejabberd_web_admin:2654
+#: ejabberd_web_admin:2244 ejabberd_web_admin:2380
msgid "Start"
msgstr "התחל"
@@ -1673,15 +1662,15 @@ msgstr "התחל מודולים"
msgid "Start Modules at "
msgstr "התחל מודולים אצל "
-#: ejabberd_web_admin:1023 ejabberd_web_admin:1871 mod_muc_admin:366
+#: ejabberd_web_admin:749 ejabberd_web_admin:1597 mod_muc_admin:366
msgid "Statistics"
msgstr "סטטיסטיקה"
-#: ejabberd_web_admin:2199
+#: ejabberd_web_admin:1925
msgid "Statistics of ~p"
msgstr "סטטיסטיקות של ~p"
-#: ejabberd_web_admin:1878 ejabberd_web_admin:2498 ejabberd_web_admin:2642
+#: ejabberd_web_admin:1604 ejabberd_web_admin:2224 ejabberd_web_admin:2368
msgid "Stop"
msgstr "הפסק"
@@ -1694,20 +1683,20 @@ msgstr "הפסק מודולים"
msgid "Stop Modules at "
msgstr "הפסק מודולים אצל "
-#: ejabberd_web_admin:1839 mod_configure:511
+#: ejabberd_web_admin:1565 mod_configure:511
msgid "Stopped Nodes"
msgstr "צמתים שנפסקו"
-#: ejabberd_web_admin:1952
+#: ejabberd_web_admin:1678
msgid "Storage Type"
msgstr "טיפוס אחסון"
-#: ejabberd_web_admin:1993
+#: ejabberd_web_admin:1719
msgid "Store binary backup:"
msgstr "אחסן גיבוי בינארי:"
# תמליל ברור
-#: ejabberd_web_admin:2023
+#: ejabberd_web_admin:1749
msgid "Store plain text backup:"
msgstr "אחסן גיבוי טקסט גלוי (plain text):"
@@ -1715,16 +1704,16 @@ msgstr "אחסן גיבוי טקסט גלוי (plain text):"
msgid "Subject"
msgstr "נושא"
-#: ejabberd_web_admin:774 ejabberd_web_admin:814 ejabberd_web_admin:879
-#: ejabberd_web_admin:944 ejabberd_web_admin:1963 mod_shared_roster:933
+#: ejabberd_web_admin:500 ejabberd_web_admin:540 ejabberd_web_admin:605
+#: ejabberd_web_admin:670 ejabberd_web_admin:1689 mod_shared_roster:933
msgid "Submit"
msgstr "שלח"
-#: ejabberd_web_admin:762 ejabberd_web_admin:801 ejabberd_web_admin:867
-#: ejabberd_web_admin:900 ejabberd_web_admin:936 ejabberd_web_admin:1421
-#: ejabberd_web_admin:1704 ejabberd_web_admin:1860 ejabberd_web_admin:1894
-#: ejabberd_web_admin:1974 ejabberd_web_admin:2144 ejabberd_web_admin:2173
-#: ejabberd_web_admin:2270 mod_offline:681 mod_roster:971 mod_shared_roster:830
+#: ejabberd_web_admin:488 ejabberd_web_admin:527 ejabberd_web_admin:593
+#: ejabberd_web_admin:626 ejabberd_web_admin:662 ejabberd_web_admin:1147
+#: ejabberd_web_admin:1430 ejabberd_web_admin:1586 ejabberd_web_admin:1620
+#: ejabberd_web_admin:1700 ejabberd_web_admin:1870 ejabberd_web_admin:1899
+#: ejabberd_web_admin:1996 mod_offline:681 mod_roster:971 mod_shared_roster:830
#: mod_shared_roster:925
msgid "Submitted"
msgstr "נשלח"
@@ -1733,20 +1722,20 @@ msgstr "נשלח"
msgid "Subscription"
msgstr "הרשמה"
-#: mod_muc_room:3708
+#: mod_muc_room:3728
msgid "Subscriptions are not allowed"
-msgstr ""
+msgstr "הרשמות אינן מורשות"
#: mod_muc_log:469
msgid "Sunday"
msgstr "יום ראשון"
-#: mod_muc_room:998 mod_muc_room:1843 mod_muc_room:3737
+#: mod_muc_room:998 mod_muc_room:1857 mod_muc_room:3757
msgid "That nickname is already in use by another occupant"
msgstr "שם כינוי זה כבר מצוי בשימוש על ידי נוכח אחר"
# note: another person > someone else
-#: mod_muc:745 mod_muc_room:1004 mod_muc_room:1852 mod_muc_room:3740
+#: mod_muc:745 mod_muc_room:1004 mod_muc_room:1866 mod_muc_room:3760
msgid "That nickname is registered by another person"
msgstr "שם כינוי זה הינו רשום על ידי מישהו אחר"
@@ -1754,7 +1743,7 @@ msgstr "שם כינוי זה הינו רשום על ידי מישהו אחר"
msgid "The CAPTCHA is valid."
msgstr "‏CAPTCHA הינה תקפה."
-#: mod_muc_room:653 mod_muc_room:3672 mod_register:190
+#: mod_muc_room:653 mod_muc_room:3692 mod_register:190
msgid "The CAPTCHA verification has failed"
msgstr "אימות CAPTCHA נכשל"
@@ -1800,11 +1789,11 @@ msgstr "אירעה שגיאה ביצירת החשבון: "
msgid "There was an error deleting the account: "
msgstr "אירעה שגיאה במחיקת החשבון: "
-#: mod_register_web:236
+#: mod_register_web:255
msgid "This is case insensitive: macbeth is the same that MacBeth and Macbeth."
msgstr "חלק זה אינו ער לרישיות: macbeth הינה זהה למחרוזת MacBeth וגם Macbeth."
-#: mod_register_web:220
+#: mod_register_web:239
msgid ""
"This page allows to create a Jabber account in this Jabber server. Your JID "
"(Jabber IDentifier) will be of the form: username@server. Please read "
@@ -1814,11 +1803,11 @@ msgstr ""
"IDentifier) תגובש באופן של: username@server. אנא קרא בזהירות את ההוראות "
"למילוי נכון של השדות."
-#: mod_register_web:470
+#: mod_register_web:491
msgid "This page allows to unregister a Jabber account in this Jabber server."
msgstr "עמוד זה מתיר לך לבטל רישום של חשבון Jabber בתוך שרת Jabber זה."
-#: mod_muc_log:1038
+#: mod_muc_log:801
msgid "This room is not anonymous"
msgstr "חדר זה אינו אנונימי"
@@ -1840,7 +1829,7 @@ msgstr "לכבוד"
#: mod_register:215
msgid "To register, visit ~s"
-msgstr ""
+msgstr "כדי להירשם, בקרו ~s"
#: mod_configure:709
msgid "To ~s"
@@ -1848,13 +1837,13 @@ msgstr "אל ~s"
#: ejabberd_oauth:439
msgid "Token TTL"
-msgstr ""
+msgstr "סימן TTL"
#: xmpp_stream_in:463
msgid "Too long value of 'xml:lang' attribute"
msgstr ""
-#: mod_muc_room:2541 mod_muc_room:3081
+#: mod_muc_room:2561 mod_muc_room:3101
msgid "Too many <item/> elements"
msgstr ""
@@ -1862,27 +1851,25 @@ msgstr ""
msgid "Too many <list/> elements"
msgstr ""
-#: mod_muc_room:1924 mod_register:240
+#: mod_muc_room:1935 mod_register:240
msgid "Too many CAPTCHA requests"
msgstr "יותר מדי בקשות CAPTCHA"
#: mod_proxy65_service:223
-#, fuzzy
msgid "Too many active bytestreams"
-msgstr "יותר מדי סטנזות בלי אישורי קבלה"
+msgstr "יותר מדי יחידות bytestream פעילות"
#: mod_stream_mgmt:205
msgid "Too many unacked stanzas"
msgstr "יותר מדי סטנזות בלי אישורי קבלה"
-#: mod_muc_room:1802
-#, fuzzy
+#: mod_muc_room:1816
msgid "Too many users in this conference"
-msgstr "בקשות ביטוי מנוטרלות בועידה זו"
+msgstr "יותר מדי משתמשים בועידה זו"
#: mod_register:355
msgid "Too many users registered"
-msgstr ""
+msgstr "יותר מדי משתמשים רשומים"
#: mod_muc_admin:368
msgid "Total rooms"
@@ -1893,19 +1880,19 @@ msgstr "חדרים סה״כ"
msgid "Traffic rate limit is exceeded"
msgstr "מגבלת שיעור תעבורה נחצתה"
-#: ejabberd_web_admin:2219
+#: ejabberd_web_admin:1945
msgid "Transactions Aborted:"
msgstr "טרנזקציות שבוטלו:"
-#: ejabberd_web_admin:2215
+#: ejabberd_web_admin:1941
msgid "Transactions Committed:"
msgstr "טרנזקציות שבוצעו:"
-#: ejabberd_web_admin:2227
+#: ejabberd_web_admin:1953
msgid "Transactions Logged:"
msgstr "טרנזקציות שנרשמו:"
-#: ejabberd_web_admin:2223
+#: ejabberd_web_admin:1949
msgid "Transactions Restarted:"
msgstr "טרנזקציות שהותחלו מחדש:"
@@ -1913,7 +1900,7 @@ msgstr "טרנזקציות שהותחלו מחדש:"
msgid "Tuesday"
msgstr "יום שלישי"
-#: mod_muc_room:1933 mod_register:244
+#: mod_muc_room:1944 mod_register:244
msgid "Unable to generate a CAPTCHA"
msgstr "אין אפשרות להפיק CAPTCHA"
@@ -1928,13 +1915,13 @@ msgstr "לא מורשה"
#: mod_announce:485 mod_configure:830 mod_configure:1758
msgid "Unexpected action"
-msgstr ""
+msgstr "פעולה לא צפויה"
-#: mod_register_web:488
+#: mod_register_web:509
msgid "Unregister"
msgstr "בטל רישום"
-#: mod_register_web:197 mod_register_web:460 mod_register_web:468
+#: mod_register_web:215 mod_register_web:481 mod_register_web:489
msgid "Unregister a Jabber account"
msgstr "בטל רישום חשבון Jabber"
@@ -1944,9 +1931,9 @@ msgstr ""
#: mod_mix:119
msgid "Unsupported MIX query"
-msgstr ""
+msgstr "שאילתת MIX לא נתמכת"
-#: ejabberd_web_admin:1872 ejabberd_web_admin:2285
+#: ejabberd_web_admin:1598 ejabberd_web_admin:2011
msgid "Update"
msgstr "עדכן"
@@ -1958,39 +1945,38 @@ msgstr "עדכן את בשורת היום (אל תשלח)"
msgid "Update message of the day on all hosts (don't send)"
msgstr "עדכן את בשורת היום בכל המארחים (אל תשלח)"
-#: ejabberd_web_admin:2278
+#: ejabberd_web_admin:2004
msgid "Update plan"
msgstr "תכנית עדכון"
-#: ejabberd_web_admin:2280
+#: ejabberd_web_admin:2006
msgid "Update script"
msgstr "תסריט עדכון"
-#: ejabberd_web_admin:2267
+#: ejabberd_web_admin:1993
msgid "Update ~p"
msgstr "עדכון ~p"
-#: ejabberd_web_admin:2203
+#: ejabberd_web_admin:1929
msgid "Uptime:"
msgstr "זמן פעילות:"
#: xmpp_stream_out:533
-#, fuzzy
msgid "Use of STARTTLS forbidden"
-msgstr "נדרש שימוש של STARTTLS"
+msgstr "אסור שימוש בהרחבת STARTTLS"
#: xmpp_stream_in:573 xmpp_stream_out:527 xmpp_stream_out:603
msgid "Use of STARTTLS required"
-msgstr "נדרש שימוש של STARTTLS"
+msgstr "נדרש שימוש בהרחבת STARTTLS"
-#: ejabberd_web_admin:1430 ejabberd_web_admin:1486 mod_register:225
+#: ejabberd_web_admin:1156 ejabberd_web_admin:1212 mod_register:225
#: mod_vcard_ldap:328 mod_vcard_mnesia:99 mod_vcard_sql:154
msgid "User"
msgstr "משתמש"
#: ejabberd_oauth:428
msgid "User (jid)"
-msgstr ""
+msgstr "משתמש (jid)"
#: mod_configure:308 mod_configure:505
msgid "User Management"
@@ -1998,34 +1984,33 @@ msgstr "ניהול משתמשים"
#: mod_register:345
msgid "User already exists"
-msgstr ""
+msgstr "משתמש כבר קיים"
#: mod_echo:138
msgid "User part of JID in 'from' is empty"
msgstr ""
#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_sic:106
-#, fuzzy
msgid "User session not found"
-msgstr "צומת לא נמצא"
+msgstr "סשן משתמש לא נמצא"
#: mod_stream_mgmt:561 mod_stream_mgmt:583
msgid "User session terminated"
-msgstr ""
+msgstr "סשן משתמש הסתיים"
-#: ejabberd_web_admin:1700
+#: ejabberd_web_admin:1426
msgid "User ~s"
msgstr "משתמש ~s"
-#: mod_register_web:230 mod_register_web:366 mod_register_web:476
+#: mod_register_web:249 mod_register_web:386 mod_register_web:497
msgid "Username:"
msgstr "שם משתמש:"
-#: ejabberd_web_admin:959 ejabberd_web_admin:967
+#: ejabberd_web_admin:685 ejabberd_web_admin:693
msgid "Users"
msgstr "משתמשים"
-#: ejabberd_web_admin:990
+#: ejabberd_web_admin:716
msgid "Users Last Activity"
msgstr "פעילות משתמשים אחרונה"
@@ -2038,14 +2023,14 @@ msgstr "משתמשים אינם מורשים לרשום חשבונות כל כך
msgid "Validate"
msgstr "הענק תוקף"
-#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3662 mod_muc_room:3802
+#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3682 mod_muc_room:3822
#: mod_pubsub:895 mod_push:249
msgid "Value 'get' of 'type' attribute is not allowed"
msgstr ""
#: mod_disco:159 mod_disco:175 mod_disco:279 mod_disco:346 mod_irc:270
#: mod_irc:285 mod_irc:339 mod_last:118 mod_last:140 mod_muc:479 mod_muc:504
-#: mod_muc:539 mod_muc:561 mod_muc:571 mod_muc_room:3597 mod_muc_room:3641
+#: mod_muc:539 mod_muc:561 mod_muc:571 mod_muc_room:3617 mod_muc_room:3661
#: mod_proxy65_service:142 mod_proxy65_service:160 mod_proxy65_service:167
#: mod_pubsub:821 mod_pubsub:839 mod_pubsub:877 mod_sic:81 mod_sic:93
#: mod_stats:55 mod_time:62 mod_vcard:198 mod_vcard:236 mod_version:62
@@ -2054,19 +2039,19 @@ msgstr ""
#: pubsub_subscription:237 pubsub_subscription_sql:202
msgid "Value of '~s' should be boolean"
-msgstr ""
+msgstr "ערך של '~s' צריך להיות boolean"
#: pubsub_subscription:215 pubsub_subscription_sql:180
msgid "Value of '~s' should be datetime string"
-msgstr ""
+msgstr "ערך של '~s' צריך להיות מחרוזת datetime"
#: pubsub_subscription:209 pubsub_subscription:227 pubsub_subscription_sql:174
#: pubsub_subscription_sql:192
msgid "Value of '~s' should be integer"
-msgstr ""
+msgstr "ערך של '~s' צריך להיות integer"
# וירטואליים
-#: ejabberd_web_admin:950
+#: ejabberd_web_admin:676
msgid "Virtual Hosts"
msgstr "מארחים מדומים"
@@ -2079,7 +2064,7 @@ msgstr "מבקרים אינם מורשים לשנות את שמות הכינוי
msgid "Visitors are not allowed to send messages to all occupants"
msgstr "מבקרים אינם מורשים לשלוח הודעות אל כל הנוכחים"
-#: mod_muc_room:3879
+#: mod_muc_room:3899
msgid "Voice request"
msgstr "בקשת ביטוי"
@@ -2091,17 +2076,17 @@ msgstr "בקשות ביטוי מנוטרלות בועידה זו"
msgid "Wednesday"
msgstr "יום רביעי"
-#: mod_register_web:255
+#: mod_register_web:274
msgid "You can later change your password using a Jabber client."
msgstr "באפשרותך לשנות את הסיסמה שלך מאוחר יותר באמצעות לקוח Jabber."
-#: mod_muc_room:1830
+#: mod_muc_room:1844
msgid "You have been banned from this room"
msgstr "נאסרת מן חדר זה"
-#: mod_muc_room:1811
+#: mod_muc_room:1825
msgid "You have joined too many conferences"
-msgstr ""
+msgstr "הצטרפת ליותר מדי ועידות"
#: mod_muc:777
msgid "You must fill in field \"Nickname\" in the form"
@@ -2125,9 +2110,8 @@ msgid "You need an x:data capable client to search"
msgstr "עליך להשתמש בלקוח אשר מסוגל להבין x:data כדי לחפש"
#: mod_pubsub:1504
-#, fuzzy
msgid "You're not allowed to create nodes"
-msgstr "אין זה מותר לשלוח הודעות פרטיות"
+msgstr "אינך מורשה ליצור צמתים"
#: mod_register_web:111
msgid "Your Jabber account was successfully created."
@@ -2211,11 +2195,11 @@ msgstr "נכנס/ת אל החדר"
msgid "leaves the room"
msgstr "עוזב/ת את החדר"
-#: mod_muc_room:3856
+#: mod_muc_room:3876
msgid "private, "
msgstr "פרטי, "
-#: mod_muc_room:3955
+#: mod_muc_room:3975
msgid "the password is"
msgstr "הסיסמה היא"
@@ -2223,11 +2207,11 @@ msgstr "הסיסמה היא"
msgid "vCard User Search"
msgstr "חיפוש משתמש vCard"
-#: ejabberd_web_admin:932
+#: ejabberd_web_admin:658
msgid "~s access rule configuration"
msgstr "~s תצורת כללי גישה"
-#: mod_muc_room:3948
+#: mod_muc_room:3968
msgid "~s invites you to the room ~s"
msgstr "‫~s מזמינך לחדר ~s"
diff --git a/priv/msgs/zh.po b/priv/msgs/zh.po
index 8c892ee6b..da5fd590d 100644
--- a/priv/msgs/zh.po
+++ b/priv/msgs/zh.po
@@ -1,13 +1,18 @@
msgid ""
msgstr ""
"Project-Id-Version: 2.1.0-alpha\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: \n"
"Last-Translator: Shelley Shyan - shelleyshyan AT gmail DOT com\n"
+"Language-Team: \n"
+"Language: zh\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Language: Chinese (中文)\n"
"X-Additional-Translator: Zhan Caibao - zhancaibao AT gmail DOT com\n"
"X-Additional-Translator: Mike Wang\n"
+"X-Generator: Poedit 1.8.7.1\n"
#: mod_muc_log:413 mod_muc_log:752
msgid " has set the subject to: "
@@ -149,7 +154,7 @@ msgstr "八月"
#: mod_pubsub:1842
msgid "Automatic node creation is not enabled"
-msgstr ""
+msgstr "未启用自动节点创建"
#: ejabberd_web_admin:1867 mod_configure:148 mod_configure:617
msgid "Backup"
@@ -182,11 +187,11 @@ msgstr "出生日期"
#: mod_legacy_auth:102
msgid "Both the username and the resource are required"
-msgstr ""
+msgstr "用户名和资源均为必填项"
#: mod_proxy65_service:226
msgid "Bytestream already activated"
-msgstr ""
+msgstr "字节流已经被激活"
#: ejabberd_captcha:135
msgid "CAPTCHA web page"
@@ -198,11 +203,11 @@ msgstr "CPU时间:"
#: mod_privacy:334
msgid "Cannot remove active list"
-msgstr ""
+msgstr "无法移除活跃列表"
#: mod_privacy:341
msgid "Cannot remove default list"
-msgstr ""
+msgstr "无法移除缺省列表"
#: ejabberd_web_admin:1679 mod_register_web:194 mod_register_web:353
#: mod_register_web:361 mod_register_web:386
@@ -214,18 +219,16 @@ msgid "Change User Password"
msgstr "更改用户密码"
#: mod_register:295
-#, fuzzy
msgid "Changing password is not allowed"
-msgstr "禁用字符:"
+msgstr "不允许修改密码"
#: mod_muc_room:2764
-#, fuzzy
msgid "Changing role/affiliation is not allowed"
-msgstr "禁用字符:"
+msgstr "不允许修改角色/单位"
#: mod_register_web:239
msgid "Characters not allowed:"
-msgstr "禁用字符:"
+msgstr "不允许字符:"
#: mod_muc_log:358 mod_muc_log:367
msgid "Chatroom configuration modified"
@@ -321,9 +324,8 @@ msgstr "位于~p的数据库表"
#: mod_pubsub:3598 mod_pubsub:3604 mod_pubsub:3607 mod_vcard:226
#: node_flat_sql:801 nodetree_tree_sql:128 nodetree_tree_sql:142
#: nodetree_tree_sql:257
-#, fuzzy
msgid "Database failure"
-msgstr "数据库"
+msgstr "数据库失败"
#: mod_muc_log:484
msgid "December"
@@ -378,7 +380,7 @@ msgstr "转储到文本文件"
#: mod_roster:180
msgid "Duplicated groups are not allowed by RFC6121"
-msgstr ""
+msgstr "按照RFC6121,不允许有重复组"
#: mod_configure:1776
msgid "Edit Properties"
@@ -398,9 +400,8 @@ msgid "Email"
msgstr "电子邮件"
#: mod_register:292
-#, fuzzy
msgid "Empty password"
-msgstr "密码是"
+msgstr "空密码"
#: mod_muc_log:1055
msgid "Enable logging"
@@ -408,7 +409,7 @@ msgstr "启用服务器端聊天记录"
#: mod_push:252
msgid "Enabling push without 'node' attribute is not supported"
-msgstr ""
+msgstr "不支持未使用'node'属性就开启推送"
#: mod_irc:834
msgid "Encoding for server ~b"
@@ -491,15 +492,15 @@ msgstr "将某主机的用户数据导出到 PIEFXIS 文件 (XEP-0227):"
#: mod_delegation:275
msgid "External component failure"
-msgstr ""
+msgstr "外部组件失败"
#: mod_delegation:283
msgid "External component timeout"
-msgstr ""
+msgstr "外部组件超时"
#: mod_proxy65_service:218
msgid "Failed to activate bytestream"
-msgstr ""
+msgstr "激活字节流失败"
#: mod_muc_room:910
msgid "Failed to extract JID from your voice request approval"
@@ -507,19 +508,19 @@ msgstr "无法从你的声音请求确认信息中提取JID"
#: mod_delegation:257
msgid "Failed to map delegated namespace to external component"
-msgstr ""
+msgstr "未能将代理命名空间映射到外部组件"
#: mod_http_upload:602
msgid "Failed to parse HTTP response"
-msgstr ""
+msgstr "HTTP响应解析失败"
#: mod_irc:426
msgid "Failed to parse chanserv"
-msgstr ""
+msgstr "chanserv机器人解析失败"
#: mod_muc_room:3297
msgid "Failed to process option '~s'"
-msgstr ""
+msgstr "选项'~s'处理失败"
#: mod_vcard_ldap:332 mod_vcard_ldap:345 mod_vcard_mnesia:103
#: mod_vcard_mnesia:117 mod_vcard_sql:158 mod_vcard_sql:172
@@ -532,7 +533,7 @@ msgstr "二月"
#: mod_http_upload:555
msgid "File larger than ~w bytes"
-msgstr ""
+msgstr "文件大于 ~w 字节"
#: mod_vcard:437
msgid ""
@@ -578,7 +579,6 @@ msgid "Get User Statistics"
msgstr "获取用户统计"
#: mod_vcard_ldap:330 mod_vcard_ldap:343
-#, fuzzy
msgid "Given Name"
msgstr "中间名"
@@ -596,7 +596,7 @@ msgstr "主机"
#: mod_s2s_dialback:325
msgid "Host unknown"
-msgstr ""
+msgstr "主人未知"
#: ejabberd_web_admin:2463
msgid "IP"
@@ -619,9 +619,8 @@ msgid "IRC channel (don't put the first #)"
msgstr "IRC频道 (不要输入第一个#号)"
#: mod_irc:417
-#, fuzzy
msgid "IRC connection not found"
-msgstr "没有找到节点"
+msgstr "没有找到 IRC 连接"
#: mod_irc:673
msgid "IRC server"
@@ -684,15 +683,15 @@ msgstr "从jabberd14 Spool目录导入用户数据:"
#: xmpp_stream_in:983
msgid "Improper 'from' attribute"
-msgstr ""
+msgstr "不恰当的'from'属性"
#: xmpp_stream_in:477
msgid "Improper 'to' attribute"
-msgstr ""
+msgstr "不恰当的'to'属性"
#: ejabberd_service:189
msgid "Improper domain part of 'from' attribute"
-msgstr ""
+msgstr "不恰当的'from'属性域名部分"
#: mod_muc_room:260
msgid "Improper message type"
@@ -704,12 +703,11 @@ msgstr "入站 s2s 连接:"
#: mod_muc_room:3669 mod_register:187
msgid "Incorrect CAPTCHA submit"
-msgstr ""
+msgstr "提交的验证码不正确"
#: mod_muc:772 mod_muc_room:3052 mod_pubsub:1194 mod_register:183 mod_vcard:256
-#, fuzzy
msgid "Incorrect data form"
-msgstr "密码不正确"
+msgstr "数据形式不正确"
#: mod_muc_room:1943 mod_register:300 mod_register:350
msgid "Incorrect password"
@@ -717,41 +715,40 @@ msgstr "密码不正确"
#: mod_irc:585
msgid "Incorrect value in data form"
-msgstr ""
+msgstr "数据表单中有不正确的值"
#: mod_adhoc:276
msgid "Incorrect value of 'action' attribute"
-msgstr ""
+msgstr "'action' 属性的值不正确"
#: mod_configure:1806
msgid "Incorrect value of 'action' in data form"
-msgstr ""
+msgstr "数据表单中 'action' 的值不正确"
#: mod_configure:1335 mod_configure:1367 mod_configure:1399 mod_configure:1419
#: mod_configure:1439
msgid "Incorrect value of 'path' in data form"
-msgstr ""
+msgstr "数据表单中 'path' 的值不正确"
#: mod_irc:331
msgid "Incorrect value of 'type' attribute"
-msgstr ""
+msgstr "'type' 属性的值不正确"
#: mod_privilege:100
msgid "Insufficient privilege"
-msgstr ""
+msgstr "权限不足"
#: mod_privilege:286
msgid "Invalid 'from' attribute in forwarded message"
-msgstr ""
+msgstr "转发的信息中 'from' 属性的值无效"
#: mod_privilege:300
msgid "Invalid <forwarded/> element"
-msgstr ""
+msgstr "无效的 <forwarded/> 元素"
#: mod_muc_room:3926
-#, fuzzy
msgid "Invitations are not allowed in this conference"
-msgstr "该会议的声音请求以被禁用"
+msgstr "此会议不允许邀请"
#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1046
msgid ""
@@ -872,9 +869,8 @@ msgid "Make room public searchable"
msgstr "使房间可被公开搜索"
#: mod_register:317
-#, fuzzy
msgid "Malformed username"
-msgstr "IRC用户名"
+msgstr "用户名无效"
#: mod_muc_log:475
msgid "March"
@@ -915,7 +911,7 @@ msgstr "消息主体"
#: mod_privilege:291
msgid "Message not found in forwarded payload"
-msgstr ""
+msgstr "转发的有效载荷中找不到消息"
#: mod_vcard_ldap:331 mod_vcard_ldap:344 mod_vcard_mnesia:102
#: mod_vcard_mnesia:116 mod_vcard_sql:157 mod_vcard_sql:171
@@ -924,15 +920,15 @@ msgstr "中间名"
#: mod_irc:704
msgid "Missing 'channel' or 'server' in the data form"
-msgstr ""
+msgstr "数据表单中缺少 'channel' 或 'server'"
#: xmpp_stream_in:990
msgid "Missing 'from' attribute"
-msgstr ""
+msgstr "缺少 'from' 属性"
#: xmpp_stream_in:472 xmpp_stream_in:993
msgid "Missing 'to' attribute"
-msgstr ""
+msgstr "缺少 'to' 属性"
#: mod_muc_room:2536 mod_muc_room:3721 mod_muc_room:3765 mod_muc_room:3798
msgid "Moderator privileges required"
@@ -948,7 +944,7 @@ msgstr "模块"
#: gen_iq_handler:153
msgid "Module failed to handle the query"
-msgstr ""
+msgstr "模块未能处理查询"
#: ejabberd_web_admin:1885 mod_configure:582 mod_configure:595
msgid "Modules"
@@ -972,7 +968,7 @@ msgstr "多重映射"
#: mod_roster:195
msgid "Multiple <item/> elements are not allowed by RFC6121"
-msgstr ""
+msgstr "按照 RFC6121,多个 <item/> 元素是不允许的"
#: ejabberd_web_admin:1951 mod_vcard_mnesia:101 mod_vcard_mnesia:115
#: mod_vcard_sql:156 mod_vcard_sql:170
@@ -985,11 +981,11 @@ msgstr "姓名:"
#: mod_muc_room:2696
msgid "Neither 'jid' nor 'nick' attribute found"
-msgstr ""
+msgstr "属性 'jid' 或 'nick' 均未发现"
#: mod_muc_room:2518 mod_muc_room:2701
msgid "Neither 'role' nor 'affiliation' attribute found"
-msgstr ""
+msgstr "属性 'role' 或 'affiliation' 均未发现"
#: ejabberd_web_admin:1506 ejabberd_web_admin:1687 mod_configure:1629
msgid "Never"
@@ -1014,41 +1010,40 @@ msgstr "昵称~s不在该房间"
#: mod_configure:1496
msgid "No 'access' found in data form"
-msgstr ""
+msgstr "数据表单中未发现 'access'"
#: mod_configure:1455
msgid "No 'acls' found in data form"
-msgstr ""
+msgstr "数据表单中未发现 'acls'"
#: mod_muc_room:3075
msgid "No 'affiliation' attribute found"
-msgstr ""
+msgstr "未发现 'affiliation' 属性"
#: mod_muc_room:2505
-#, fuzzy
msgid "No 'item' element found"
-msgstr "没有找到节点"
+msgstr "没有找到 'item' 元素"
#: mod_configure:1280
msgid "No 'modules' found in data form"
-msgstr ""
+msgstr "数据表单中未发现 'module'"
#: mod_configure:1799
msgid "No 'password' found in data form"
-msgstr ""
+msgstr "数据表单中未发现 'password'"
#: mod_register:148
msgid "No 'password' found in this query"
-msgstr ""
+msgstr "此查询中未发现 'password'"
#: mod_configure:1319 mod_configure:1350 mod_configure:1382 mod_configure:1413
#: mod_configure:1433
msgid "No 'path' found in data form"
-msgstr ""
+msgstr "数据表单中未发现 'path'"
#: mod_muc_room:3922
msgid "No 'to' attribute found in the invitation"
-msgstr ""
+msgstr "邀请中未发现 'to' 标签"
#: ejabberd_web_admin:1767
msgid "No Data"
@@ -1056,78 +1051,75 @@ msgstr "没有数据"
#: ejabberd_local:181
msgid "No available resource found"
-msgstr ""
+msgstr "没发现可用资源"
#: mod_announce:575
msgid "No body provided for announce message"
msgstr "通知消息无正文内容"
#: mod_irc:335 mod_pubsub:1183 mod_pubsub:3289
-#, fuzzy
msgid "No data form found"
-msgstr "没有找到节点"
+msgstr "没有找到数据表单"
#: mod_disco:224 mod_vcard:282
msgid "No features available"
-msgstr ""
+msgstr "没有可用特征"
#: mod_adhoc:239
msgid "No hook has processed this command"
-msgstr ""
+msgstr "没有任何钩子已处理此命令"
#: mod_last:218
msgid "No info about last activity found"
-msgstr ""
+msgstr "未找到上次活动的信息"
#: mod_blocking:99
msgid "No items found in this query"
-msgstr ""
+msgstr "此查询中没发现任何项"
#: ejabberd_local:90 ejabberd_sm:863 mod_blocking:92 mod_blocking:110
#: mod_http_upload:513 mod_muc:482 mod_muc:534 mod_muc:556 mod_muc:580
#: mod_offline:303 mod_privacy:168 mod_privacy:285 mod_roster:207
msgid "No module is handling this query"
-msgstr ""
+msgstr "没有正在处理此查询的模块"
#: mod_pubsub:1541
msgid "No node specified"
-msgstr ""
+msgstr "无指定节点"
#: mod_pubsub:1426
msgid "No pending subscriptions found"
-msgstr ""
+msgstr "未发现挂起的订阅"
#: mod_privacy:201 mod_privacy:295 mod_privacy:311 mod_privacy:344
msgid "No privacy list with this name found"
-msgstr ""
+msgstr "未找到带此名称的隐私列表"
#: mod_private:96
msgid "No private data found in this query"
-msgstr ""
+msgstr "此查询中未发现私有数据"
#: mod_configure:869 mod_configure:908 mod_configure:1222 mod_configure:1254
#: mod_configure:1275 mod_configure:1314 mod_configure:1345 mod_configure:1377
#: mod_configure:1408 mod_configure:1428 mod_stats:93
-#, fuzzy
msgid "No running node found"
-msgstr "没有找到节点"
+msgstr "没有找到运行中的节点"
#: mod_disco:252 mod_vcard:265
msgid "No services available"
-msgstr ""
+msgstr "无可用服务"
#: mod_stats:101
msgid "No statistics found for this item"
-msgstr ""
+msgstr "未找到此项的统计数据"
#: nodetree_dag:72 nodetree_tree:181 nodetree_tree_sql:255
msgid "Node already exists"
-msgstr ""
+msgstr "节点已存在"
#: nodetree_tree_sql:99
-#, fuzzy
msgid "Node index not found"
-msgstr "没有找到节点"
+msgstr "没有找到节点索引"
#: ejabberd_web_admin:1046 mod_irc:303 mod_irc:366 mod_muc:532 mod_muc:680
#: nodetree_dag:78 nodetree_dag:102 nodetree_dag:118 nodetree_dag:142
@@ -1142,7 +1134,7 @@ msgstr "节点~p"
#: mod_vcard:385
msgid "Nodeprep has failed"
-msgstr ""
+msgstr "Nodeprep 已失效"
#: ejabberd_web_admin:1837
msgid "Nodes"
@@ -1159,7 +1151,7 @@ msgstr "没有找到"
#: mod_disco:296 mod_disco:370 mod_last:159
msgid "Not subscribed"
-msgstr ""
+msgstr "未订阅"
#: mod_muc_log:483
msgid "November"
@@ -1210,11 +1202,11 @@ msgstr "在线用户:"
#: mod_carboncopy:141
msgid "Only <enable/> or <disable/> tags are allowed"
-msgstr ""
+msgstr "仅允许 <enable/> 或 <disable/> 标签"
#: mod_privacy:154
msgid "Only <list/> element is allowed in this query"
-msgstr ""
+msgstr "此查询中只允许 <list/> 元素"
#: mod_mam:379
msgid "Only members may query archives of this room"
@@ -1280,11 +1272,11 @@ msgstr "数据包"
#: mod_irc:578
msgid "Parse error"
-msgstr ""
+msgstr "解析错误"
#: mod_configure:1299 mod_configure:1468 mod_configure:1513
msgid "Parse failed"
-msgstr ""
+msgstr "解析失败"
#: ejabberd_oauth:431 ejabberd_web_admin:1435 mod_configure:1126
#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:1036
@@ -1334,7 +1326,7 @@ msgstr "Ping"
#: mod_ping:180
msgid "Ping query is incorrect"
-msgstr ""
+msgstr "Ping 查询不正确"
#: ejabberd_web_admin:1983
msgid ""
@@ -1363,7 +1355,7 @@ msgstr "~b的端口"
#: mod_roster:173
msgid "Possessing 'ask' attribute is not allowed by RFC6121"
-msgstr ""
+msgstr "按照 RFC6121, 不允许有 'ask' 属性"
#: ejabberd_web_admin:2464
msgid "Protocol"
@@ -1379,7 +1371,7 @@ msgstr "发行-订阅"
#: node_dag:81
msgid "Publishing items to collection node is not allowed"
-msgstr ""
+msgstr "不允许"
#: mod_muc_room:462
msgid "Queries to the conference members are not allowed in this room"
@@ -1388,7 +1380,7 @@ msgstr "本房间不可以查询会议成员信息"
#: mod_blocking:85 mod_disco:325 mod_disco:393 mod_offline:270 mod_privacy:146
#: mod_private:118 mod_roster:163 mod_sic:90
msgid "Query to another users is forbidden"
-msgstr ""
+msgstr "禁止查询其他用户"
#: mod_configure:889
msgid "RAM and disc copy"
@@ -1517,7 +1509,7 @@ msgstr "花名册"
#: mod_roster:334
msgid "Roster module has failed"
-msgstr ""
+msgstr "花名册模块已失效"
#: mod_roster:968
msgid "Roster of "
@@ -1533,7 +1525,7 @@ msgstr "运行中的节点"
#: xmpp_stream_in:541 xmpp_stream_in:549
msgid "SASL negotiation is not allowed in this state"
-msgstr ""
+msgstr "此状态下不允许SASL协商"
#: mod_muc_log:468
msgid "Saturday"
@@ -1541,12 +1533,11 @@ msgstr "星期六"
#: mod_irc:582
msgid "Scan error"
-msgstr ""
+msgstr "扫描错误"
#: mod_configure:1303 mod_configure:1472 mod_configure:1517
-#, fuzzy
msgid "Scan failed"
-msgstr "验证码检测失败."
+msgstr "扫描失败."
#: ejabberd_web_admin:2282
msgid "Script check"
@@ -1582,11 +1573,11 @@ msgstr "九月"
#: mod_irc_connection:648
msgid "Server Connect Failed"
-msgstr ""
+msgstr "服务器连接失败"
#: ejabberd_s2s:369
msgid "Server connections to local subdomains are forbidden"
-msgstr ""
+msgstr "禁止服务器连接到本地子域"
#: mod_irc:842
msgid "Server ~b"
@@ -1700,7 +1691,7 @@ msgstr "订阅"
#: mod_muc_room:3708
msgid "Subscriptions are not allowed"
-msgstr ""
+msgstr "不允许订阅"
#: mod_muc_log:469
msgid "Sunday"
@@ -1724,11 +1715,11 @@ msgstr "验证码检查失败"
#: mod_muc_room:302
msgid "The feature requested is not supported by the conference"
-msgstr ""
+msgstr "会议不支持所请求的特征"
#: mod_register:308 mod_register:366
msgid "The password contains unacceptable characters"
-msgstr ""
+msgstr "密码包含不可接受的字符"
#: mod_register:311 mod_register:370
msgid "The password is too weak"
@@ -1740,17 +1731,17 @@ msgstr "你的Jabber帐户密码已成功更新."
#: mod_register:160 mod_vcard:219
msgid "The query is only allowed from local users"
-msgstr ""
+msgstr "仅本地用户可以查询"
#: mod_roster:203
msgid "The query must not contain <item/> elements"
-msgstr ""
+msgstr "查询不能包含 <item/> 元素"
#: mod_privacy:280
msgid ""
"The stanza MUST contain only one <active/> element, one <default/> element, "
"or one <list/> element"
-msgstr ""
+msgstr "本节必须只含一个 <active/> 元素, <default/> 元素,或 <list/> 元素"
#: mod_register_web:146
msgid "There was an error changing the password: "
@@ -1803,7 +1794,7 @@ msgstr "到"
#: mod_register:215
msgid "To register, visit ~s"
-msgstr ""
+msgstr "要注册,请访问 ~s"
#: mod_configure:709
msgid "To ~s"
@@ -1811,41 +1802,39 @@ msgstr "发送给~s"
#: ejabberd_oauth:439
msgid "Token TTL"
-msgstr ""
+msgstr "TTL令牌"
#: xmpp_stream_in:463
msgid "Too long value of 'xml:lang' attribute"
-msgstr ""
+msgstr "'xml:lang'的值太长"
#: mod_muc_room:2541 mod_muc_room:3081
msgid "Too many <item/> elements"
-msgstr ""
+msgstr "太多 <item/> 元素"
#: mod_privacy:164
msgid "Too many <list/> elements"
-msgstr ""
+msgstr "太多 <list/> 元素"
#: mod_muc_room:1924 mod_register:240
msgid "Too many CAPTCHA requests"
msgstr "验证码请求太多"
#: mod_proxy65_service:223
-#, fuzzy
msgid "Too many active bytestreams"
-msgstr "未被确认的节太多"
+msgstr "活跃的字节流太多"
#: mod_stream_mgmt:205
msgid "Too many unacked stanzas"
msgstr "未被确认的节太多"
#: mod_muc_room:1802
-#, fuzzy
msgid "Too many users in this conference"
-msgstr "该会议的声音请求以被禁用"
+msgstr "该会议的用户太多"
#: mod_register:355
msgid "Too many users registered"
-msgstr ""
+msgstr "注册用户太多"
#: mod_muc_admin:368
msgid "Total rooms"
@@ -1881,7 +1870,7 @@ msgstr "无法生成验证码"
#: ejabberd_service:120
msgid "Unable to register route on existing local domain"
-msgstr ""
+msgstr "在已存在的本地域上无法注册路由"
#: ejabberd_web_admin:209 ejabberd_web_admin:221 ejabberd_web_admin:241
#: ejabberd_web_admin:253
@@ -1890,7 +1879,7 @@ msgstr "未认证的"
#: mod_announce:485 mod_configure:830 mod_configure:1758
msgid "Unexpected action"
-msgstr ""
+msgstr "意外行为"
#: mod_register_web:488
msgid "Unregister"
@@ -1902,11 +1891,11 @@ msgstr "注销Jabber帐户"
#: mod_mam:526
msgid "Unsupported <index/> element"
-msgstr ""
+msgstr "不支持的 <index/> 元素"
#: mod_mix:119
msgid "Unsupported MIX query"
-msgstr ""
+msgstr "不支持的 MIX 查询"
#: ejabberd_web_admin:1872 ejabberd_web_admin:2285
msgid "Update"
@@ -1937,9 +1926,8 @@ msgid "Uptime:"
msgstr "正常运行时间:"
#: xmpp_stream_out:533
-#, fuzzy
msgid "Use of STARTTLS forbidden"
-msgstr "要求使用 STARTTLS"
+msgstr "禁止使用 STARTTLS"
#: xmpp_stream_in:573 xmpp_stream_out:527 xmpp_stream_out:603
msgid "Use of STARTTLS required"
@@ -1952,7 +1940,7 @@ msgstr "用户"
#: ejabberd_oauth:428
msgid "User (jid)"
-msgstr ""
+msgstr "用户 (jid)"
#: mod_configure:308 mod_configure:505
msgid "User Management"
@@ -1960,20 +1948,19 @@ msgstr "用户管理"
#: mod_register:345
msgid "User already exists"
-msgstr ""
+msgstr "用户已存在"
#: mod_echo:138
msgid "User part of JID in 'from' is empty"
-msgstr ""
+msgstr "'from' 中 JID 值的用户部分为空"
#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_sic:106
-#, fuzzy
msgid "User session not found"
-msgstr "没有找到节点"
+msgstr "用户会话未找到"
#: mod_stream_mgmt:561 mod_stream_mgmt:583
msgid "User session terminated"
-msgstr ""
+msgstr "用户会话已终止"
#: ejabberd_web_admin:1700
msgid "User ~s"
@@ -2002,7 +1989,7 @@ msgstr "确认"
#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3662 mod_muc_room:3802
#: mod_pubsub:895 mod_push:249
msgid "Value 'get' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "不允许 'type' 属性的 'get' 值"
#: mod_disco:159 mod_disco:175 mod_disco:279 mod_disco:346 mod_irc:270
#: mod_irc:285 mod_irc:339 mod_last:118 mod_last:140 mod_muc:479 mod_muc:504
@@ -2011,20 +1998,20 @@ msgstr ""
#: mod_pubsub:821 mod_pubsub:839 mod_pubsub:877 mod_sic:81 mod_sic:93
#: mod_stats:55 mod_time:62 mod_vcard:198 mod_vcard:236 mod_version:62
msgid "Value 'set' of 'type' attribute is not allowed"
-msgstr ""
+msgstr "不允许 'type' 属性的 'set' 值"
#: pubsub_subscription:237 pubsub_subscription_sql:202
msgid "Value of '~s' should be boolean"
-msgstr ""
+msgstr "'~s' 的值应为布尔型"
#: pubsub_subscription:215 pubsub_subscription_sql:180
msgid "Value of '~s' should be datetime string"
-msgstr ""
+msgstr "'~s' 的值应为日期时间字符串"
#: pubsub_subscription:209 pubsub_subscription:227 pubsub_subscription_sql:174
#: pubsub_subscription_sql:192
msgid "Value of '~s' should be integer"
-msgstr ""
+msgstr "'~s' 的值应为整数"
#: ejabberd_web_admin:950
msgid "Virtual Hosts"
@@ -2044,7 +2031,7 @@ msgstr "声音请求"
#: mod_muc_room:885
msgid "Voice requests are disabled in this conference"
-msgstr "该会议的声音请求以被禁用"
+msgstr "该会议的声音请求已被禁用"
#: mod_muc_log:465
msgid "Wednesday"
@@ -2060,7 +2047,7 @@ msgstr "您已被禁止进入该房间"
#: mod_muc_room:1811
msgid "You have joined too many conferences"
-msgstr ""
+msgstr "您加入的会议太多"
#: mod_muc:777
msgid "You must fill in field \"Nickname\" in the form"
@@ -2083,9 +2070,8 @@ msgid "You need an x:data capable client to search"
msgstr "您需要一个兼容 x:data 的客户端来搜索"
#: mod_pubsub:1504
-#, fuzzy
msgid "You're not allowed to create nodes"
-msgstr "不可以发送私聊消息"
+msgstr "您不可以创建节点"
#: mod_register_web:111
msgid "Your Jabber account was successfully created."
diff --git a/rebar.config b/rebar.config
index 5806e6ae3..7b03fc8c4 100644
--- a/rebar.config
+++ b/rebar.config
@@ -21,15 +21,16 @@
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager",
{tag, {if_version_above, "17", "3.4.2", "3.2.1"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.10"}}},
- {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.11"}}},
+ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "938610ad3"}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.16"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.10"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.24"}}},
- {xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.15"}}},
+ {xmpp, ".*", {git, "https://github.com/processone/xmpp", "3289a6b4e3f3d82e5be513524d2293c0c2b3e7fd"}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.11"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.2"}}},
{luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "v0.2"}}},
+ {fs, ".*", {git, "https://github.com/synrc/fs.git", {tag, "2.12.0"}}},
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.15"}}}},
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.16"}}}},
{if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
@@ -98,6 +99,7 @@
{if_have_fun, {rand, uniform, 1}, {d, 'RAND_UNIFORM'}},
{if_have_fun, {gb_sets, iterator_from, 2}, {d, 'GB_SETS_ITERATOR_FROM'}},
{if_have_fun, {public_key, short_name_hash, 1}, {d, 'SHORT_NAME_HASH'}},
+ {if_var_true, new_sql_schema, {d, 'NEW_SQL_SCHEMA'}},
{if_var_true, hipe, native},
{src_dirs, [asn1, src,
{if_var_true, tools, tools},
diff --git a/rebar.config.script b/rebar.config.script
index 219514a2f..85f918fff 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -229,13 +229,22 @@ TestConfig = case file:read_file_info(TestConfigFile) of
""
end,
-ResolveDepPath = case IsRebar3 of
- true ->
+ResolveDepPath = case {SystemDeps, IsRebar3} of
+ {true, _} ->
fun("deps/" ++ Rest) ->
Slash = string:str(Rest, "/"),
- Dir = "_build/default/lib/" ++
- string:sub_string(Rest, 1, Slash - 1),
- Dir ++ string:sub_string(Rest, Slash);
+ code:lib_dir(
+ string:sub_string(Rest, 1, Slash -1)) ++
+ string:sub_string(Rest, Slash);
+ (Path) ->
+ Path
+ end;
+ {_, true} ->
+ fun("deps/" ++ Rest) ->
+ Slash = string:str(Rest, "/"),
+ "_build/default/lib/" ++
+ string:sub_string(Rest, 1, Slash - 1) ++
+ string:sub_string(Rest, Slash);
(Path) ->
Path
end;
@@ -326,7 +335,7 @@ Rules = [
AppendList([{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl.git", "master"}}]), []},
{[post_hooks], [cover_enabled], os:getenv("TRAVIS") == "true",
AppendList2(TravisPostHooks), [], false},
- {[overrides], [post_hook_configure], true,
+ {[overrides], [post_hook_configure], SystemDeps == false,
AppendList2(GenDepsConfigure), [], []},
{[ct_extra_params], [eunit_compile_opts], true,
AppendStr2(CtParams), "", []},
diff --git a/sql/lite.sql b/sql/lite.sql
index 1cc0c4dc5..b0c8675f5 100644
--- a/sql/lite.sql
+++ b/sql/lite.sql
@@ -97,7 +97,7 @@ CREATE TABLE archive (
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-CREATE INDEX i_username ON archive(username);
+CREATE INDEX i_username_timestamp ON archive(username, timestamp);
CREATE INDEX i_timestamp ON archive(timestamp);
CREATE INDEX i_peer ON archive(peer);
CREATE INDEX i_bare_peer ON archive(bare_peer);
@@ -290,6 +290,18 @@ CREATE TABLE muc_online_users (
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users (username, server);
+CREATE TABLE muc_room_subscribers (
+ room text NOT NULL,
+ host text NOT NULL,
+ jid text NOT NULL,
+ nick text NOT NULL,
+ nodes text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers(host, jid);
+CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers(host, room, jid);
+
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
@@ -375,3 +387,14 @@ CREATE TABLE proxy65 (
CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 (sid);
CREATE INDEX i_proxy65_jid ON proxy65 (jid_i);
+
+CREATE TABLE push_session (
+ username text NOT NULL,
+ timestamp bigint NOT NULL,
+ service text NOT NULL,
+ node text NOT NULL,
+ xml text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_push_usn ON push_session (username, service, node);
+CREATE UNIQUE INDEX i_push_ut ON push_session (username, timestamp);
diff --git a/sql/mssql.sql b/sql/mssql.sql
index 607acae8f..83b219298 100644
--- a/sql/mssql.sql
+++ b/sql/mssql.sql
@@ -38,7 +38,7 @@ CREATE TABLE [dbo].[archive] (
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
-CREATE INDEX [archive_username] ON [archive] (username)
+CREATE INDEX [archive_username_timestamp] ON [archive] (username, timestamp)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [archive_timestamp] ON [archive] (timestamp)
@@ -149,6 +149,18 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_us] ON [muc_online_users] (username, server);
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+CREATE TABLE [dbo].[muc_room_subscribers] (
+ [room] [varchar] (191) NOT NULL,
+ [host] [varchar] (191) NOT NULL,
+ [jid] [varchar] (191) NOT NULL,
+ [nick] [text] NOT NULL,
+ [nodes] [text] NOT NULL,
+ [created_at] [datetime] NOT NULL DEFAULT GETDATE()
+);
+
+CREATE UNIQUE CLUSTERED INDEX [muc_room_subscribers_host_room_jid] ON [muc_room_subscribers] (host, room, jid);
+CREATE INDEX [muc_room_subscribers_host_jid] ON [muc_room_subscribers] (host, jid);
+
CREATE TABLE [dbo].[privacy_default_list] (
[username] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
@@ -541,3 +553,17 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE INDEX [carboncopy_user] ON [carboncopy] (username)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+
+CREATE TABLE [dbo].[push_session] (
+ [username] [varchar] (255) NOT NULL,
+ [timestamp] [bigint] NOT NULL,
+ [service] [varchar] (255) NOT NULL,
+ [node] [varchar] (255) NOT NULL,
+ [xml] [varchar] (255) NOT NULL
+);
+
+CREATE UNIQUE CLUSTERED INDEX [i_push_usn] ON [push_session] (username, service, node)
+WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+
+CREATE UNIQUE CLUSTERED INDEX [i_push_ut] ON [push_session] (username, timestamp)
+WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
diff --git a/sql/mysql.sql b/sql/mysql.sql
index e2586853b..acf2bfe1a 100644
--- a/sql/mysql.sql
+++ b/sql/mysql.sql
@@ -306,6 +306,18 @@ CREATE TABLE muc_online_users (
CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75));
CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75));
+CREATE TABLE muc_room_subscribers (
+ room varchar(191) NOT NULL,
+ host varchar(191) NOT NULL,
+ jid varchar(191) NOT NULL,
+ nick text NOT NULL,
+ nodes text NOT NULL,
+ created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ UNIQUE KEY i_muc_room_subscribers_host_room_jid (host, room, jid)
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE INDEX i_muc_room_subscribers_host_jid USING BTREE ON muc_room_subscribers(host, jid);
+
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
@@ -391,3 +403,14 @@ CREATE TABLE proxy65 (
CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 (sid(191));
CREATE INDEX i_proxy65_jid ON proxy65 (jid_i(191));
+
+CREATE TABLE push_session (
+ username text NOT NULL,
+ timestamp bigint NOT NULL,
+ service text NOT NULL,
+ node text NOT NULL,
+ xml text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_push_usn ON push_session (username(191), service(191), node(191));
+CREATE UNIQUE INDEX i_push_ut ON push_session (username(191), timestamp);
diff --git a/sql/pg.new.sql b/sql/pg.new.sql
new file mode 100644
index 000000000..b155a4223
--- /dev/null
+++ b/sql/pg.new.sql
@@ -0,0 +1,604 @@
+--
+-- ejabberd, Copyright (C) 2002-2017 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.
+--
+
+-- To update from the old schema, replace <HOST> with the host's domain:
+
+-- ALTER TABLE users ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE users DROP CONSTRAINT users_pkey;
+-- ALTER TABLE users ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE users ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE last ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE last DROP CONSTRAINT last_pkey;
+-- ALTER TABLE last ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE last ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE rosterusers ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_rosteru_user_jid;
+-- DROP INDEX i_rosteru_username;
+-- DROP INDEX i_rosteru_jid;
+-- CREATE UNIQUE INDEX i_rosteru_sh_user_jid ON rosterusers USING btree (server_host, username, jid);
+-- CREATE INDEX i_rosteru_sh_username ON rosterusers USING btree (server_host, username);
+-- CREATE INDEX i_rosteru_sh_jid ON rosterusers USING btree (server_host, jid);
+-- ALTER TABLE rosterusers ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE rostergroups ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX pk_rosterg_user_jid;
+-- CREATE INDEX i_rosterg_sh_user_jid ON rostergroups USING btree (server_host, username, jid);
+-- ALTER TABLE rostergroups ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE sr_group ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE sr_group ADD PRIMARY KEY (server_host, name);
+-- ALTER TABLE sr_group ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE sr_user ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_sr_user_jid_grp;
+-- DROP INDEX i_sr_user_jid;
+-- DROP INDEX i_sr_user_grp;
+-- ALTER TABLE sr_user ADD PRIMARY KEY (server_host, jid, grp);
+-- CREATE INDEX i_sr_user_sh_jid ON sr_user USING btree (server_host, jid);
+-- CREATE INDEX i_sr_user_sh_grp ON sr_user USING btree (server_host, grp);
+-- ALTER TABLE sr_user ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE spool ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_despool;
+-- CREATE INDEX i_spool_sh_username ON spool USING btree (server_host, username);
+-- ALTER TABLE spool ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE archive ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_username;
+-- DROP INDEX i_username_timestamp;
+-- DROP INDEX i_timestamp;
+-- DROP INDEX i_peer;
+-- DROP INDEX i_bare_peer;
+-- CREATE INDEX i_archive_sh_username_timestamp ON archive USING btree (server_host, username, timestamp);
+-- CREATE INDEX i_archive_sh_timestamp ON archive USING btree (server_host, timestamp);
+-- CREATE INDEX i_archive_sh_peer ON archive USING btree (server_host, peer);
+-- CREATE INDEX i_archive_sh_bare_peer ON archive USING btree (server_host, bare_peer);
+-- ALTER TABLE archive ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE archive_prefs ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE archive_prefs DROP CONSTRAINT archive_prefs_pkey;
+-- ALTER TABLE archive_prefs ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE archive_prefs ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE vcard ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE vcard DROP CONSTRAINT vcard_pkey;
+-- ALTER TABLE vcard ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE vcard ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE vcard_search ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE vcard_search DROP CONSTRAINT vcard_search_pkey;
+-- DROP INDEX i_vcard_search_lfn;
+-- DROP INDEX i_vcard_search_lfamily;
+-- DROP INDEX i_vcard_search_lgiven;
+-- DROP INDEX i_vcard_search_lmiddle;
+-- DROP INDEX i_vcard_search_lnickname;
+-- DROP INDEX i_vcard_search_lbday;
+-- DROP INDEX i_vcard_search_lctry;
+-- DROP INDEX i_vcard_search_llocality;
+-- DROP INDEX i_vcard_search_lemail;
+-- DROP INDEX i_vcard_search_lorgname;
+-- DROP INDEX i_vcard_search_lorgunit;
+-- ALTER TABLE vcard_search ADD PRIMARY KEY (server_host, username);
+-- CREATE INDEX i_vcard_search_sh_lfn ON vcard_search(server_host, lfn);
+-- CREATE INDEX i_vcard_search_sh_lfamily ON vcard_search(server_host, lfamily);
+-- CREATE INDEX i_vcard_search_sh_lgiven ON vcard_search(server_host, lgiven);
+-- CREATE INDEX i_vcard_search_sh_lmiddle ON vcard_search(server_host, lmiddle);
+-- CREATE INDEX i_vcard_search_sh_lnickname ON vcard_search(server_host, lnickname);
+-- CREATE INDEX i_vcard_search_sh_lbday ON vcard_search(server_host, lbday);
+-- CREATE INDEX i_vcard_search_sh_lctry ON vcard_search(server_host, lctry);
+-- CREATE INDEX i_vcard_search_sh_llocality ON vcard_search(server_host, llocality);
+-- CREATE INDEX i_vcard_search_sh_lemail ON vcard_search(server_host, lemail);
+-- CREATE INDEX i_vcard_search_sh_lorgname ON vcard_search(server_host, lorgname);
+-- CREATE INDEX i_vcard_search_sh_lorgunit ON vcard_search(server_host, lorgunit);
+-- ALTER TABLE vcard_search ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE privacy_default_list ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE privacy_default_list DROP CONSTRAINT privacy_default_list_pkey;
+-- ALTER TABLE privacy_default_list ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE privacy_default_list ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE privacy_list ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_privacy_list_username;
+-- DROP INDEX i_privacy_list_username_name;
+-- CREATE INDEX i_privacy_list_sh_username ON privacy_list USING btree (server_host, username);
+-- CREATE UNIQUE INDEX i_privacy_list_sh_username_name ON privacy_list USING btree (server_host, username, name);
+-- ALTER TABLE privacy_list ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE private_storage ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_private_storage_username;
+-- DROP INDEX i_private_storage_username_namespace;
+-- ALTER TABLE private_storage ADD PRIMARY KEY (server_host, username, namespace);
+-- CREATE INDEX i_private_storage_sh_username ON private_storage USING btree (server_host, username);
+-- ALTER TABLE private_storage ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE roster_version ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE roster_version DROP CONSTRAINT roster_version_pkey;
+-- ALTER TABLE roster_version ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE roster_version ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE muc_room ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE muc_room ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE muc_registered ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE muc_registered ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE muc_online_room ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE muc_online_room ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE muc_online_users ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE muc_online_users ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE irc_custom ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE irc_custom ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE motd ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- ALTER TABLE motd DROP CONSTRAINT motd_pkey;
+-- ALTER TABLE motd ADD PRIMARY KEY (server_host, username);
+-- ALTER TABLE motd ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE sm ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_sm_sid;
+-- DROP INDEX i_sm_username;
+-- ALTER TABLE sm ADD PRIMARY KEY (usec, pid);
+-- CREATE INDEX i_sm_sh_username ON sm USING btree (server_host, username);
+-- ALTER TABLE sm ALTER COLUMN server_host DROP DEFAULT;
+
+-- ALTER TABLE carboncopy ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
+-- DROP INDEX i_carboncopy_ur;
+-- DROP INDEX i_carboncopy_user;
+-- ALTER TABLE carboncopy ADD PRIMARY KEY (server_host, username, resource);
+-- CREATE INDEX i_carboncopy_sh_user ON carboncopy USING btree (server_host, username);
+-- ALTER TABLE carboncopy ALTER COLUMN server_host DROP DEFAULT;
+
+
+CREATE TABLE users (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ "password" text NOT NULL,
+ serverkey text NOT NULL DEFAULT '',
+ salt text NOT NULL DEFAULT '',
+ iterationcount integer NOT NULL DEFAULT 0,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, username)
+);
+
+-- Add support for SCRAM auth to a database created before ejabberd 16.03:
+-- ALTER TABLE users ADD COLUMN serverkey text NOT NULL DEFAULT '';
+-- ALTER TABLE users ADD COLUMN salt text NOT NULL DEFAULT '';
+-- ALTER TABLE users ADD COLUMN iterationcount integer NOT NULL DEFAULT 0;
+
+CREATE TABLE last (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ seconds text NOT NULL,
+ state text NOT NULL,
+ PRIMARY KEY (server_host, username)
+);
+
+
+CREATE TABLE rosterusers (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ jid text NOT NULL,
+ nick text NOT NULL,
+ subscription character(1) NOT NULL,
+ ask character(1) NOT NULL,
+ askmessage text NOT NULL,
+ server character(1) NOT NULL,
+ subscribe text NOT NULL,
+ "type" text,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE UNIQUE INDEX i_rosteru_sh_user_jid ON rosterusers USING btree (server_host, username, jid);
+CREATE INDEX i_rosteru_sh_username ON rosterusers USING btree (server_host, username);
+CREATE INDEX i_rosteru_sh_jid ON rosterusers USING btree (server_host, jid);
+
+
+CREATE TABLE rostergroups (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ jid text NOT NULL,
+ grp text NOT NULL
+);
+
+CREATE INDEX i_rosterg_sh_user_jid ON rostergroups USING btree (server_host, username, jid);
+
+CREATE TABLE sr_group (
+ name text NOT NULL,
+ server_host text NOT NULL,
+ opts text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, name)
+);
+
+CREATE TABLE sr_user (
+ jid text NOT NULL,
+ server_host text NOT NULL,
+ grp text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, jid, grp)
+);
+
+CREATE INDEX i_sr_user_sh_jid ON sr_user USING btree (server_host, jid);
+CREATE INDEX i_sr_user_sh_grp ON sr_user USING btree (server_host, grp);
+
+CREATE TABLE spool (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ xml text NOT NULL,
+ seq SERIAL,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_spool_sh_username ON spool USING btree (server_host, username);
+
+CREATE TABLE archive (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ timestamp BIGINT NOT NULL,
+ peer text NOT NULL,
+ bare_peer text NOT NULL,
+ xml text NOT NULL,
+ txt text,
+ id SERIAL,
+ kind text,
+ nick text,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_archive_sh_username_timestamp ON archive USING btree (server_host, username, timestamp);
+CREATE INDEX i_archive_sh_timestamp ON archive USING btree (server_host, timestamp);
+CREATE INDEX i_archive_sh_peer ON archive USING btree (server_host, peer);
+CREATE INDEX i_archive_sh_bare_peer ON archive USING btree (server_host, bare_peer);
+
+CREATE TABLE archive_prefs (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ def text NOT NULL,
+ always text NOT NULL,
+ never text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, username)
+);
+
+CREATE TABLE vcard (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ vcard text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, username)
+);
+
+CREATE TABLE vcard_search (
+ username text NOT NULL,
+ lusername text NOT NULL,
+ server_host text NOT NULL,
+ fn text NOT NULL,
+ lfn text NOT NULL,
+ family text NOT NULL,
+ lfamily text NOT NULL,
+ given text NOT NULL,
+ lgiven text NOT NULL,
+ middle text NOT NULL,
+ lmiddle text NOT NULL,
+ nickname text NOT NULL,
+ lnickname text NOT NULL,
+ bday text NOT NULL,
+ lbday text NOT NULL,
+ ctry text NOT NULL,
+ lctry text NOT NULL,
+ locality text NOT NULL,
+ llocality text NOT NULL,
+ email text NOT NULL,
+ lemail text NOT NULL,
+ orgname text NOT NULL,
+ lorgname text NOT NULL,
+ orgunit text NOT NULL,
+ lorgunit text NOT NULL,
+ PRIMARY KEY (server_host, username)
+);
+
+CREATE INDEX i_vcard_search_sh_lfn ON vcard_search(server_host, lfn);
+CREATE INDEX i_vcard_search_sh_lfamily ON vcard_search(server_host, lfamily);
+CREATE INDEX i_vcard_search_sh_lgiven ON vcard_search(server_host, lgiven);
+CREATE INDEX i_vcard_search_sh_lmiddle ON vcard_search(server_host, lmiddle);
+CREATE INDEX i_vcard_search_sh_lnickname ON vcard_search(server_host, lnickname);
+CREATE INDEX i_vcard_search_sh_lbday ON vcard_search(server_host, lbday);
+CREATE INDEX i_vcard_search_sh_lctry ON vcard_search(server_host, lctry);
+CREATE INDEX i_vcard_search_sh_llocality ON vcard_search(server_host, llocality);
+CREATE INDEX i_vcard_search_sh_lemail ON vcard_search(server_host, lemail);
+CREATE INDEX i_vcard_search_sh_lorgname ON vcard_search(server_host, lorgname);
+CREATE INDEX i_vcard_search_sh_lorgunit ON vcard_search(server_host, lorgunit);
+
+CREATE TABLE privacy_default_list (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ name text NOT NULL,
+ PRIMARY KEY (server_host, username)
+);
+
+CREATE TABLE privacy_list (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ name text NOT NULL,
+ id SERIAL UNIQUE,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_privacy_list_sh_username ON privacy_list USING btree (server_host, username);
+CREATE UNIQUE INDEX i_privacy_list_sh_username_name ON privacy_list USING btree (server_host, username, name);
+
+CREATE TABLE privacy_list_data (
+ id bigint REFERENCES privacy_list(id) ON DELETE CASCADE,
+ t character(1) NOT NULL,
+ value text NOT NULL,
+ action character(1) NOT NULL,
+ ord NUMERIC NOT NULL,
+ match_all boolean NOT NULL,
+ match_iq boolean NOT NULL,
+ match_message boolean NOT NULL,
+ match_presence_in boolean NOT NULL,
+ match_presence_out boolean NOT NULL
+);
+
+CREATE INDEX i_privacy_list_data_id ON privacy_list_data USING btree (id);
+
+CREATE TABLE private_storage (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ namespace text NOT NULL,
+ data text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, username, namespace)
+);
+
+CREATE INDEX i_private_storage_sh_username ON private_storage USING btree (server_host, username);
+
+
+CREATE TABLE roster_version (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ version text NOT NULL,
+ PRIMARY KEY (server_host, username)
+);
+
+-- To update from 0.9.8:
+-- CREATE SEQUENCE spool_seq_seq;
+-- ALTER TABLE spool ADD COLUMN seq integer;
+-- ALTER TABLE spool ALTER COLUMN seq SET DEFAULT nextval('spool_seq_seq');
+-- UPDATE spool SET seq = DEFAULT;
+-- ALTER TABLE spool ALTER COLUMN seq SET NOT NULL;
+
+-- To update from 1.x:
+-- ALTER TABLE rosterusers ADD COLUMN askmessage text;
+-- UPDATE rosterusers SET askmessage = '';
+-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
+
+CREATE TABLE pubsub_node (
+ host text NOT NULL,
+ node text NOT NULL,
+ parent text NOT NULL DEFAULT '',
+ "type" text NOT NULL,
+ nodeid SERIAL UNIQUE
+);
+CREATE INDEX i_pubsub_node_parent ON pubsub_node USING btree (parent);
+CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node USING btree (host, node);
+
+CREATE TABLE pubsub_node_option (
+ nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+ name text NOT NULL,
+ val text NOT NULL
+);
+CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option USING btree (nodeid);
+
+CREATE TABLE pubsub_node_owner (
+ nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+ owner text NOT NULL
+);
+CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner USING btree (nodeid);
+
+CREATE TABLE pubsub_state (
+ nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+ jid text NOT NULL,
+ affiliation character(1),
+ subscriptions text NOT NULL DEFAULT '',
+ stateid SERIAL UNIQUE
+);
+CREATE INDEX i_pubsub_state_jid ON pubsub_state USING btree (jid);
+CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state USING btree (nodeid, jid);
+
+CREATE TABLE pubsub_item (
+ nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
+ itemid text NOT NULL,
+ publisher text NOT NULL,
+ creation text NOT NULL,
+ modification text NOT NULL,
+ payload text NOT NULL DEFAULT ''
+);
+CREATE INDEX i_pubsub_item_itemid ON pubsub_item USING btree (itemid);
+CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item USING btree (nodeid, itemid);
+
+CREATE TABLE pubsub_subscription_opt (
+ subid text NOT NULL,
+ opt_name varchar(32),
+ opt_value text NOT NULL
+);
+CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt USING btree (subid, opt_name);
+
+CREATE TABLE muc_room (
+ name text NOT NULL,
+ host text NOT NULL,
+ server_host text NOT NULL,
+ opts text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE UNIQUE INDEX i_muc_room_name_host ON muc_room USING btree (name, host);
+
+CREATE TABLE muc_registered (
+ jid text NOT NULL,
+ host text NOT NULL,
+ server_host text NOT NULL,
+ nick text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_muc_registered_nick ON muc_registered USING btree (nick);
+CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered USING btree (jid, host);
+
+CREATE TABLE muc_online_room (
+ name text NOT NULL,
+ host text NOT NULL,
+ server_host text NOT NULL,
+ node text NOT NULL,
+ pid text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room USING btree (name, host);
+
+CREATE TABLE muc_online_users (
+ username text NOT NULL,
+ server text NOT NULL,
+ resource text NOT NULL,
+ name text NOT NULL,
+ host text NOT NULL,
+ server_host text NOT NULL,
+ node text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
+CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
+
+CREATE TABLE muc_room_subscribers (
+ room text NOT NULL,
+ host text NOT NULL,
+ jid text NOT NULL,
+ nick text NOT NULL,
+ nodes text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
+CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
+
+CREATE TABLE irc_custom (
+ jid text NOT NULL,
+ host text NOT NULL,
+ server_host text NOT NULL,
+ data text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom USING btree (jid, host);
+
+CREATE TABLE motd (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ xml text,
+ created_at TIMESTAMP NOT NULL DEFAULT now(),
+ PRIMARY KEY (server_host, username)
+);
+
+CREATE TABLE caps_features (
+ node text NOT NULL,
+ subnode text NOT NULL,
+ feature text,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_caps_features_node_subnode ON caps_features USING btree (node, subnode);
+
+CREATE TABLE sm (
+ usec bigint NOT NULL,
+ pid text NOT NULL,
+ node text NOT NULL,
+ username text NOT NULL,
+ resource text NOT NULL,
+ priority text NOT NULL,
+ info text NOT NULL,
+ PRIMARY KEY (usec, pid)
+);
+
+CREATE INDEX i_sm_node ON sm USING btree (node);
+CREATE INDEX i_sm_sh_username ON sm USING btree (server_host, username);
+
+CREATE TABLE oauth_token (
+ token text NOT NULL,
+ jid text NOT NULL,
+ scope text NOT NULL,
+ expire bigint NOT NULL
+);
+
+CREATE UNIQUE INDEX i_oauth_token_token ON oauth_token USING btree (token);
+
+CREATE TABLE route (
+ domain text NOT NULL,
+ server_host text NOT NULL,
+ node text NOT NULL,
+ pid text NOT NULL,
+ local_hint text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_route ON route USING btree (domain, server_host, node, pid);
+CREATE INDEX i_route_domain ON route USING btree (domain);
+
+CREATE TABLE bosh (
+ sid text NOT NULL,
+ node text NOT NULL,
+ pid text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_bosh_sid ON bosh USING btree (sid);
+
+CREATE TABLE carboncopy (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ resource text NOT NULL,
+ namespace text NOT NULL,
+ node text NOT NULL,
+ PRIMARY KEY (server_host, username, resource)
+);
+
+CREATE INDEX i_carboncopy_sh_user ON carboncopy USING btree (server_host, username);
+
+CREATE TABLE proxy65 (
+ sid text NOT NULL,
+ pid_t text NOT NULL,
+ pid_i text NOT NULL,
+ node_t text NOT NULL,
+ node_i text NOT NULL,
+ jid_i text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 USING btree (sid);
+CREATE INDEX i_proxy65_jid ON proxy65 USING btree (jid_i);
+
+CREATE TABLE push_session (
+ username text NOT NULL,
+ server_host text NOT NULL,
+ timestamp bigint NOT NULL,
+ service text NOT NULL,
+ node text NOT NULL,
+ xml text NOT NULL,
+ PRIMARY KEY (server_host, username, timestamp)
+);
+
+CREATE UNIQUE INDEX i_push_session_susn ON push_session USING btree (server_host, username, service, node);
diff --git a/sql/pg.sql b/sql/pg.sql
index f761e68da..fd56ba39d 100644
--- a/sql/pg.sql
+++ b/sql/pg.sql
@@ -101,7 +101,7 @@ CREATE TABLE archive (
created_at TIMESTAMP NOT NULL DEFAULT now()
);
-CREATE INDEX i_username ON archive USING btree (username);
+CREATE INDEX i_username_timestamp ON archive USING btree (username, timestamp);
CREATE INDEX i_timestamp ON archive USING btree (timestamp);
CREATE INDEX i_peer ON archive USING btree (peer);
CREATE INDEX i_bare_peer ON archive USING btree (bare_peer);
@@ -308,6 +308,18 @@ CREATE TABLE muc_online_users (
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
+CREATE TABLE muc_room_subscribers (
+ room text NOT NULL,
+ host text NOT NULL,
+ jid text NOT NULL,
+ nick text NOT NULL,
+ nodes text NOT NULL,
+ created_at TIMESTAMP NOT NULL DEFAULT now()
+);
+
+CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
+CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
+
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
@@ -395,3 +407,14 @@ CREATE TABLE proxy65 (
CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 USING btree (sid);
CREATE INDEX i_proxy65_jid ON proxy65 USING btree (jid_i);
+
+CREATE TABLE push_session (
+ username text NOT NULL,
+ timestamp bigint NOT NULL,
+ service text NOT NULL,
+ node text NOT NULL,
+ xml text NOT NULL
+);
+
+CREATE UNIQUE INDEX i_push_usn ON push_session USING btree (username, service, node);
+CREATE UNIQUE INDEX i_push_ut ON push_session USING btree (username, timestamp);
diff --git a/src/ejabberd.erl b/src/ejabberd.erl
index 4edab98f1..7e1a1106c 100644
--- a/src/ejabberd.erl
+++ b/src/ejabberd.erl
@@ -37,7 +37,7 @@
-protocol({xep, 270, '1.0'}).
-export([start/0, stop/0, start_app/1, start_app/2,
- get_pid_file/0, check_app/1]).
+ get_pid_file/0, check_app/1, module_name/1]).
-include("logger.hrl").
@@ -148,3 +148,29 @@ get_module_file(App, Mod) ->
Dir ->
filename:join([Dir, BaseName ++ ".beam"])
end.
+
+module_name([Dir, _, <<H,_/binary>> | _] = Mod) when H >= 65, H =< 90 ->
+ Module = str:join([elixir_name(M) || M<-tl(Mod)], <<>>),
+ Prefix = case elixir_name(Dir) of
+ <<"Ejabberd">> -> <<"Elixir.Ejabberd.">>;
+ Lib -> <<"Elixir.Ejabberd.", Lib/binary, ".">>
+ end,
+ misc:binary_to_atom(<<Prefix/binary, Module/binary>>);
+module_name([<<"ejabberd">> | _] = Mod) ->
+ Module = str:join([erlang_name(M) || M<-Mod], $_),
+ misc:binary_to_atom(Module);
+module_name(Mod) when is_list(Mod) ->
+ Module = str:join([erlang_name(M) || M<-tl(Mod)], $_),
+ misc:binary_to_atom(Module).
+
+elixir_name(Atom) when is_atom(Atom) ->
+ elixir_name(misc:atom_to_binary(Atom));
+elixir_name(<<H,T/binary>>) when H >= 65, H =< 90 ->
+ <<H, T/binary>>;
+elixir_name(<<H,T/binary>>) ->
+ <<(H-32), T/binary>>.
+
+erlang_name(Atom) when is_atom(Atom) ->
+ misc:atom_to_binary(Atom);
+erlang_name(Bin) when is_binary(Bin) ->
+ Bin.
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index b34925ff0..f49bef43b 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -35,7 +35,7 @@
check_password/6, check_password_with_authmodule/4,
check_password_with_authmodule/6, try_register/3,
get_users/0, get_users/1, password_to_scram/1,
- get_users/2, export/1, import_info/0,
+ get_users/2, import_info/0,
count_users/1, import/5, import_start/2,
count_users/2, get_password/2,
get_password_s/2, get_password_with_authmodule/2,
@@ -735,8 +735,8 @@ auth_modules(Server) ->
LServer = jid:nameprep(Server),
Default = ejabberd_config:default_db(LServer, ?MODULE),
Methods = ejabberd_config:get_option({auth_method, LServer}, [Default]),
- [misc:binary_to_atom(<<"ejabberd_auth_",
- (misc:atom_to_binary(M))/binary>>)
+ [ejabberd:module_name([<<"ejabberd">>, <<"auth">>,
+ misc:atom_to_binary(M)])
|| M <- Methods].
-spec match_passwords(password(), password(),
@@ -798,9 +798,6 @@ validate_credentials(User, Server, Password) ->
end
end.
-export(Server) ->
- ejabberd_auth_mnesia:export(Server).
-
import_info() ->
[{<<"users">>, 3}].
diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl
index 690152674..7705f62e1 100644
--- a/src/ejabberd_auth_mnesia.erl
+++ b/src/ejabberd_auth_mnesia.erl
@@ -34,16 +34,13 @@
-export([start/1, stop/1, set_password/3, try_register/3,
get_users/2, init_db/0,
count_users/2, get_password/2,
- remove_user/2, store_type/1, export/1, import/2,
+ remove_user/2, store_type/1, import/2,
plain_password_required/1, use_cache/1]).
-export([need_transform/1, transform/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
--include("ejabberd_sql_pt.hrl").
-
--record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1',
- password = <<"">> :: binary() | scram() | '_'}).
+-include("ejabberd_auth.hrl").
-record(reg_users_counter, {vhost = <<"">> :: binary(),
count = 0 :: integer() | '$1'}).
@@ -272,29 +269,6 @@ transform(#passwd{password = Password} = P)
when is_record(Password, scram) ->
P.
-export(_Server) ->
- [{passwd,
- fun(Host, #passwd{us = {LUser, LServer}, password = Password})
- when LServer == Host,
- is_binary(Password) ->
- [?SQL("delete from users where username=%(LUser)s;"),
- ?SQL("insert into users(username, password) "
- "values (%(LUser)s, %(Password)s);")];
- (Host, #passwd{us = {LUser, LServer}, password = #scram{} = Scram})
- when LServer == Host ->
- StoredKey = Scram#scram.storedkey,
- ServerKey = Scram#scram.serverkey,
- Salt = Scram#scram.salt,
- IterationCount = Scram#scram.iterationcount,
- [?SQL("delete from users where username=%(LUser)s;"),
- ?SQL("insert into users(username, password, serverkey, salt, "
- "iterationcount) "
- "values (%(LUser)s, %(StoredKey)s, %(ServerKey)s,"
- " %(Salt)s, %(IterationCount)d);")];
- (_Host, _R) ->
- []
- end}].
-
import(LServer, [LUser, Password, _TimeStamp]) ->
mnesia:dirty_write(
#passwd{us = {LUser, LServer}, password = Password}).
diff --git a/src/ejabberd_auth_riak.erl b/src/ejabberd_auth_riak.erl
index fccaba102..3cdb74258 100644
--- a/src/ejabberd_auth_riak.erl
+++ b/src/ejabberd_auth_riak.erl
@@ -40,9 +40,7 @@
-include("ejabberd.hrl").
-include("ejabberd_sql_pt.hrl").
-
--record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1',
- password = <<"">> :: binary() | scram() | '_'}).
+-include("ejabberd_auth.hrl").
start(_Host) ->
ok.
@@ -108,9 +106,12 @@ export(_Server) ->
[{passwd,
fun(Host, #passwd{us = {LUser, LServer}, password = Password})
when LServer == Host ->
- [?SQL("delete from users where username=%(LUser)s;"),
- ?SQL("insert into users(username, password) "
- "values (%(LUser)s, %(Password)s);")];
+ [?SQL("delete from users where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "users",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "password=%(Password)s"])];
(_Host, _R) ->
[]
end}].
diff --git a/src/ejabberd_auth_sql.erl b/src/ejabberd_auth_sql.erl
index 0d7c7b375..3f328c4a1 100644
--- a/src/ejabberd_auth_sql.erl
+++ b/src/ejabberd_auth_sql.erl
@@ -35,11 +35,12 @@
-export([start/1, stop/1, set_password/3, try_register/3,
get_users/2, count_users/2, get_password/2,
remove_user/2, store_type/1, plain_password_required/1,
- convert_to_scram/1, opt_type/1]).
+ convert_to_scram/1, opt_type/1, export/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
+-include("ejabberd_auth.hrl").
-define(SALT_LENGTH, 16).
@@ -60,11 +61,11 @@ set_password(User, Server, Password) ->
F = fun() ->
if is_record(Password, scram) ->
set_password_scram_t(
- User,
+ User, Server,
Password#scram.storedkey, Password#scram.serverkey,
Password#scram.salt, Password#scram.iterationcount);
true ->
- set_password_t(User, Password)
+ set_password_t(User, Server, Password)
end
end,
case ejabberd_sql:sql_transaction(Server, F) of
@@ -132,20 +133,22 @@ remove_user(User, Server) ->
-define(BATCH_SIZE, 1000).
-set_password_scram_t(LUser,
+set_password_scram_t(LUser, LServer,
StoredKey, ServerKey, Salt, IterationCount) ->
?SQL_UPSERT_T(
"users",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"password=%(StoredKey)s",
"serverkey=%(ServerKey)s",
"salt=%(Salt)s",
"iterationcount=%(IterationCount)d"]).
-set_password_t(LUser, Password) ->
+set_password_t(LUser, LServer, Password) ->
?SQL_UPSERT_T(
"users",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"password=%(Password)s"]).
get_password_scram(LServer, LUser) ->
@@ -153,32 +156,39 @@ get_password_scram(LServer, LUser) ->
LServer,
?SQL("select @(password)s, @(serverkey)s, @(salt)s, @(iterationcount)d"
" from users"
- " where username=%(LUser)s")).
+ " where username=%(LUser)s and %(LServer)H")).
add_user_scram(LServer, LUser,
StoredKey, ServerKey, Salt, IterationCount) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("insert into users(username, password, serverkey, salt, "
- "iterationcount) "
- "values (%(LUser)s, %(StoredKey)s, %(ServerKey)s,"
- " %(Salt)s, %(IterationCount)d)")).
+ ?SQL_INSERT(
+ "users",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "password=%(StoredKey)s",
+ "serverkey=%(ServerKey)s",
+ "salt=%(Salt)s",
+ "iterationcount=%(IterationCount)d"])).
add_user(LServer, LUser, Password) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("insert into users(username, password) "
- "values (%(LUser)s, %(Password)s)")).
+ ?SQL_INSERT(
+ "users",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "password=%(Password)s"])).
del_user(LServer, LUser) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from users where username=%(LUser)s")).
+ ?SQL("delete from users where username=%(LUser)s and %(LServer)H")).
list_users(LServer, []) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("select @(username)s from users"));
+ ?SQL("select @(username)s from users where %(LServer)H"));
list_users(LServer, [{from, Start}, {to, End}])
when is_integer(Start) and is_integer(End) ->
list_users(LServer,
@@ -195,6 +205,7 @@ list_users(LServer, [{limit, Limit}, {offset, Offset}])
ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users "
+ "where %(LServer)H "
"order by username "
"limit %(Limit)d offset %(Offset)d"));
list_users(LServer,
@@ -206,7 +217,7 @@ list_users(LServer,
ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users "
- "where username like %(SPrefix2)s escape '^' "
+ "where username like %(SPrefix2)s escape '^' and %(LServer)H "
"order by username "
"limit %(Limit)d offset %(Offset)d")).
@@ -223,11 +234,11 @@ users_number(LServer) ->
" where oid = 'users'::regclass::oid"));
_ ->
ejabberd_sql:sql_query_t(
- ?SQL("select @(count(*))d from users"))
+ ?SQL("select @(count(*))d from users where %(LServer)H"))
end;
(_Type, _) ->
ejabberd_sql:sql_query_t(
- ?SQL("select @(count(*))d from users"))
+ ?SQL("select @(count(*))d from users where %(LServer)H"))
end).
users_number(LServer, [{prefix, Prefix}])
@@ -237,7 +248,7 @@ users_number(LServer, [{prefix, Prefix}])
ejabberd_sql:sql_query(
LServer,
?SQL("select @(count(*))d from users "
- "where username like %(SPrefix2)s escape '^'"));
+ "where username like %(SPrefix2)s escape '^' and %(LServer)H"));
users_number(LServer, []) ->
users_number(LServer).
@@ -253,7 +264,7 @@ convert_to_scram(Server) ->
case ejabberd_sql:sql_query_t(
?SQL("select @(username)s, @(password)s"
" from users"
- " where iterationcount=0"
+ " where iterationcount=0 and %(LServer)H"
" limit %(BatchSize)d")) of
{selected, []} ->
ok;
@@ -269,7 +280,7 @@ convert_to_scram(Server) ->
_ ->
Scram = ejabberd_auth:password_to_scram(Password),
set_password_scram_t(
- LUser,
+ LUser, LServer,
Scram#scram.storedkey,
Scram#scram.serverkey,
Scram#scram.salt,
@@ -288,6 +299,36 @@ convert_to_scram(Server) ->
end
end.
+export(_Server) ->
+ [{passwd,
+ fun(Host, #passwd{us = {LUser, LServer}, password = Password})
+ when LServer == Host,
+ is_binary(Password) ->
+ [?SQL("delete from users where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "users",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "password=%(Password)s"])];
+ (Host, #passwd{us = {LUser, LServer}, password = #scram{} = Scram})
+ when LServer == Host ->
+ StoredKey = Scram#scram.storedkey,
+ ServerKey = Scram#scram.serverkey,
+ Salt = Scram#scram.salt,
+ IterationCount = Scram#scram.iterationcount,
+ [?SQL("delete from users where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "users",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "password=%(StoredKey)s",
+ "serverkey=%(ServerKey)s",
+ "salt=%(Salt)s",
+ "iterationcount=%(IterationCount)d"])];
+ (_Host, _R) ->
+ []
+ end}].
+
-spec opt_type(pgsql_users_number_estimate) -> fun((boolean()) -> boolean());
(atom()) -> [atom()].
opt_type(pgsql_users_number_estimate) ->
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index c5af2e031..93bb50836 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -302,10 +302,7 @@ tls_options(#{lserver := LServer, tls_options := DefaultOpts,
TLSOpts1 = case {Encrypted, proplists:get_value(certfile, DefaultOpts)} of
{true, CertFile} when CertFile /= undefined -> DefaultOpts;
{_, _} ->
- case ejabberd_config:get_option(
- {domain_certfile, LServer},
- ejabberd_config:get_option(
- {c2s_certfile, LServer})) of
+ case get_certfile(LServer) of
undefined -> DefaultOpts;
CertFile -> lists:keystore(certfile, 1, DefaultOpts,
{certfile, CertFile})
@@ -928,6 +925,17 @@ format_reason(_, {shutdown, _}) ->
format_reason(_, _) ->
<<"internal server error">>.
+-spec get_certfile(binary()) -> file:filename_all().
+get_certfile(LServer) ->
+ case ejabberd_pkix:get_certfile(LServer) of
+ {ok, CertFile} ->
+ CertFile;
+ error ->
+ ejabberd_config:get_option(
+ {domain_certfile, LServer},
+ ejabberd_config:get_option({c2s_certfile, LServer}))
+ end.
+
transform_listen_option(Opt, Opts) ->
[Opt|Opts].
@@ -941,7 +949,11 @@ transform_listen_option(Opt, Opts) ->
(resource_conflict) -> fun((resource_conflict()) -> resource_conflict());
(disable_sasl_mechanisms) -> fun((binary() | [binary()]) -> [binary()]);
(atom()) -> [atom()].
-opt_type(c2s_certfile) -> fun misc:try_read_file/1;
+opt_type(c2s_certfile = Opt) ->
+ fun(File) ->
+ ?WARNING_MSG("option '~s' is deprecated, use 'certfiles' instead", [Opt]),
+ misc:try_read_file(File)
+ end;
opt_type(c2s_ciphers) -> fun iolist_to_binary/1;
opt_type(c2s_dhfile) -> fun misc:try_read_file/1;
opt_type(c2s_cafile) -> fun misc:try_read_file/1;
@@ -986,8 +998,10 @@ opt_type(_) ->
(atom()) -> [atom()].
listen_opt_type(access) -> fun acl:access_rules_validator/1;
listen_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
-listen_opt_type(certfile) ->
+listen_opt_type(certfile = Opt) ->
fun(S) ->
+ ?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
+ "'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index 5d3bc8680..4b7c15806 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -1417,8 +1417,11 @@ opt_type(cache_life_time) ->
(infinity) -> infinity;
(unlimited) -> infinity
end;
-opt_type(domain_certfile) ->
- fun misc:try_read_file/1;
+opt_type(domain_certfile = Opt) ->
+ fun(File) ->
+ ?WARNING_MSG("option '~s' is deprecated, use 'certfiles' instead", [Opt]),
+ misc:try_read_file(File)
+ end;
opt_type(shared_key) ->
fun iolist_to_binary/1;
opt_type(node_start) ->
diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl
index 43bbb3f04..30cce1952 100644
--- a/src/ejabberd_http.erl
+++ b/src/ejabberd_http.erl
@@ -266,10 +266,11 @@ process_header(State, Data) ->
add_header(Name, Value, State)};
{ok, http_eoh}
when State#state.request_host == undefined ->
- ?WARNING_MSG("An HTTP request without 'Host' HTTP "
- "header was received.",
- []),
- throw(http_request_no_host_header);
+ ?DEBUG("An HTTP request without 'Host' HTTP "
+ "header was received.", []),
+ {State1, Out} = process_request(State),
+ send_text(State1, Out),
+ process_header(State, {ok, {http_error, <<>>}});
{ok, http_eoh} ->
?DEBUG("(~w) http query: ~w ~p~n",
[State#state.socket, State#state.request_method,
@@ -418,6 +419,10 @@ extract_path_query(#state{request_method = Method,
extract_path_query(State) ->
{State, false}.
+process_request(#state{request_host = undefined,
+ custom_headers = CustomHeaders} = State) ->
+ {State, make_text_output(State, 400, CustomHeaders,
+ <<"Missing Host header">>)};
process_request(#state{request_method = Method,
request_auth = Auth,
request_lang = Lang,
diff --git a/src/ejabberd_pkix.erl b/src/ejabberd_pkix.erl
index f9f0472f6..b74b47669 100644
--- a/src/ejabberd_pkix.erl
+++ b/src/ejabberd_pkix.erl
@@ -27,19 +27,22 @@
%% API
-export([start_link/0, add_certfile/1, format_error/1, opt_type/1,
- get_certfile/1, try_certfile/1, route_registered/1]).
+ get_certfile/1, try_certfile/1, route_registered/1,
+ config_reloaded/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include_lib("public_key/include/public_key.hrl").
-include("logger.hrl").
--include("jid.hrl").
-record(state, {validate = true :: boolean(),
- certs = #{}}).
--record(cert_state, {domains = [] :: [binary()]}).
+ notify = false :: boolean(),
+ paths = [] :: [file:filename()],
+ certs = #{} :: map(),
+ keys = [] :: [public_key:private_key()]}).
+-type state() :: #state{}.
-type cert() :: #'OTPCertificate'{}.
-type priv_key() :: public_key:private_key().
-type pub_key() :: #'RSAPublicKey'{} | {integer(), #'Dss-Parms'{}} | #'ECPoint'{}.
@@ -62,8 +65,8 @@ add_certfile(Path) ->
-spec try_certfile(filename:filename()) -> binary().
try_certfile(Path0) ->
Path = prep_path(Path0),
- case mk_cert_state(Path, false) of
- {ok, _} -> Path;
+ case load_certfile(Path) of
+ {ok, _, _} -> Path;
{error, _} -> erlang:error(badarg)
end.
@@ -78,14 +81,14 @@ format_error(not_pem) ->
format_error(not_der) ->
"failed to decode from DER format";
format_error(encrypted) ->
- "encrypted certificate found in the chain";
+ "encrypted certificate";
format_error({bad_cert, cert_expired}) ->
"certificate is no longer valid as its expiration date has passed";
format_error({bad_cert, invalid_issuer}) ->
"certificate issuer name does not match the name of the "
- "issuer certificate in the chain";
+ "issuer certificate";
format_error({bad_cert, invalid_signature}) ->
- "certificate was not signed by its issuer certificate in the chain";
+ "certificate was not signed by its issuer certificate";
format_error({bad_cert, name_not_permitted}) ->
"invalid Subject Alternative Name extension";
format_error({bad_cert, missing_basic_constraint}) ->
@@ -95,7 +98,7 @@ format_error({bad_cert, invalid_key_usage}) ->
"certificate key is used in an invalid way according "
"to the key-usage extension";
format_error({bad_cert, selfsigned_peer}) ->
- "self-signed certificate in the chain";
+ "self-signed certificate";
format_error({bad_cert, unknown_sig_algo}) ->
"certificate is signed using unknown algorithm";
format_error({bad_cert, unknown_ca}) ->
@@ -139,18 +142,27 @@ get_certfile(Domain) ->
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+config_reloaded() ->
+ gen_server:cast(?MODULE, config_reloaded).
+
opt_type(ca_path) ->
fun(Path) -> iolist_to_binary(Path) end;
+opt_type(certfiles) ->
+ fun(CertList) ->
+ [binary_to_list(Path) || Path <- CertList]
+ end;
opt_type(_) ->
- [ca_path].
+ [ca_path, certfiles].
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
init([]) ->
+ Notify = start_fs(),
process_flag(trap_exit, true),
- ets:new(?MODULE, [named_table, public, bag]),
+ ets:new(?MODULE, [named_table, public]),
ejabberd_hooks:add(route_registered, ?MODULE, route_registered, 50),
+ ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 30),
Validate = case os:type() of
{win32, _} -> false;
_ ->
@@ -161,35 +173,79 @@ init([]) ->
if Validate -> check_ca_dir();
true -> ok
end,
- State = #state{validate = Validate},
- {ok, add_certfiles(State)}.
+ State = #state{validate = Validate, notify = Notify},
+ case filelib:ensure_dir(filename:join(certs_dir(), "foo")) of
+ ok ->
+ clean_dir(certs_dir()),
+ case add_certfiles(State) of
+ {ok, State1} ->
+ {ok, State1};
+ {error, Why} ->
+ {stop, Why}
+ end;
+ {error, Why} ->
+ ?CRITICAL_MSG("Failed to create directory ~s: ~s",
+ [certs_dir(), file:format_error(Why)]),
+ {stop, Why}
+ end.
handle_call({add_certfile, Path}, _, State) ->
{Result, NewState} = add_certfile(Path, State),
{reply, Result, NewState};
handle_call({route_registered, Host}, _, State) ->
- NewState = add_certfiles(Host, State),
- case get_certfile(Host) of
- {ok, _} -> ok;
- error ->
- ?WARNING_MSG("No certificate found matching '~s': strictly "
- "configured clients or servers will reject "
- "connections with this host", [Host])
- end,
- {reply, ok, NewState};
+ case add_certfiles(Host, State) of
+ {ok, NewState} ->
+ case get_certfile(Host) of
+ {ok, _} -> ok;
+ error ->
+ ?WARNING_MSG("No certificate found matching '~s': strictly "
+ "configured clients or servers will reject "
+ "connections with this host; obtain "
+ "a certificate for this (sub)domain from any "
+ "trusted CA such as Let's Encrypt "
+ "(www.letsencrypt.org)",
+ [Host])
+ end,
+ {reply, ok, NewState};
+ {error, _} ->
+ {reply, ok, State}
+ end;
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
+handle_cast(config_reloaded, State) ->
+ State1 = State#state{paths = [], certs = #{}, keys = []},
+ case add_certfiles(State1) of
+ {ok, State2} ->
+ {noreply, State2};
+ {error, _} ->
+ {noreply, State}
+ end;
handle_cast(_Msg, State) ->
{noreply, State}.
+handle_info({_, {fs, file_event}, {File, Events}}, State) ->
+ ?DEBUG("got FS events for ~s: ~p", [File, Events]),
+ Path = iolist_to_binary(File),
+ case lists:member(modified, Events) of
+ true ->
+ case lists:member(Path, State#state.paths) of
+ true ->
+ handle_cast(config_reloaded, State);
+ false ->
+ {noreply, State}
+ end;
+ false ->
+ {noreply, State}
+ end;
handle_info(_Info, State) ->
?WARNING_MSG("unexpected info: ~p", [_Info]),
{noreply, State}.
terminate(_Reason, _State) ->
- ejabberd_hooks:delete(route_registered, ?MODULE, route_registered, 50).
+ ejabberd_hooks:delete(route_registered, ?MODULE, route_registered, 50),
+ ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 30).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -197,73 +253,150 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
+-spec certfiles_from_config_options() -> [atom()].
+certfiles_from_config_options() ->
+ [c2s_certfile, s2s_certfile, domain_certfile].
+
+-spec get_certfiles_from_config_options(state()) -> [binary()].
+get_certfiles_from_config_options(State) ->
+ Global = case ejabberd_config:get_option(certfiles) of
+ undefined ->
+ [];
+ Paths ->
+ lists:flatmap(fun filelib:wildcard/1, Paths)
+ end,
+ Local = lists:flatmap(
+ fun(OptHost) ->
+ case ejabberd_config:get_option(OptHost) of
+ undefined -> [];
+ Path -> [Path]
+ end
+ end, [{Opt, Host}
+ || Opt <- certfiles_from_config_options(),
+ Host <- ejabberd_config:get_myhosts()]),
+ [iolist_to_binary(P) || P <- lists:usort(Local ++ Global)].
+
+-spec add_certfiles(state()) -> {ok, state()} | {error, bad_cert()}.
add_certfiles(State) ->
- lists:foldl(
- fun(Host, AccState) ->
- add_certfiles(Host, AccState)
- end, State, ejabberd_config:get_myhosts()).
+ Paths = get_certfiles_from_config_options(State),
+ State1 = lists:foldl(
+ fun(Path, Acc) ->
+ {_, NewAcc} = add_certfile(Path, Acc),
+ NewAcc
+ end, State, Paths),
+ case build_chain_and_check(State1) of
+ ok -> {ok, State1};
+ {error, _} = Err -> Err
+ end.
+-spec add_certfiles(binary(), state()) -> {ok, state()} | {error, bad_cert()}.
add_certfiles(Host, State) ->
- lists:foldl(
- fun(Opt, AccState) ->
- case ejabberd_config:get_option({Opt, Host}) of
- undefined -> AccState;
- Path ->
- {_, NewAccState} = add_certfile(Path, AccState),
- NewAccState
- end
- end, State, [c2s_certfile, s2s_certfile, domain_certfile]).
+ State1 = lists:foldl(
+ fun(Opt, AccState) ->
+ case ejabberd_config:get_option({Opt, Host}) of
+ undefined -> AccState;
+ Path ->
+ {_, NewAccState} = add_certfile(Path, AccState),
+ NewAccState
+ end
+ end, State, certfiles_from_config_options()),
+ if State /= State1 ->
+ case build_chain_and_check(State1) of
+ ok -> {ok, State1};
+ {error, _} = Err -> Err
+ end;
+ true ->
+ {ok, State}
+ end.
+-spec add_certfile(file:filename_all(), state()) -> {ok, state()} |
+ {{error, cert_error()}, state()}.
add_certfile(Path, State) ->
- case maps:get(Path, State#state.certs, undefined) of
- #cert_state{} ->
+ case lists:member(Path, State#state.paths) of
+ true ->
{ok, State};
- undefined ->
- case mk_cert_state(Path, State#state.validate) of
- {error, Reason} ->
- {{error, Reason}, State};
- {ok, CertState} ->
- NewCerts = maps:put(Path, CertState, State#state.certs),
- lists:foreach(
- fun(Domain) ->
- ets:insert(?MODULE, {Domain, Path})
- end, CertState#cert_state.domains),
- {ok, State#state{certs = NewCerts}}
+ false ->
+ case load_certfile(Path) of
+ {ok, Certs, Keys} ->
+ NewCerts = lists:foldl(
+ fun(Cert, Acc) ->
+ maps:put(Cert, Path, Acc)
+ end, State#state.certs, Certs),
+ {ok, State#state{paths = [Path|State#state.paths],
+ certs = NewCerts,
+ keys = Keys ++ State#state.keys}};
+ {error, Why} = Err ->
+ ?ERROR_MSG("failed to read certificate from ~s: ~s",
+ [Path, format_error(Why)]),
+ {Err, State}
end
end.
-mk_cert_state(Path, Validate) ->
- case check_certfile(Path, Validate) of
- {ok, Ds} ->
- {ok, #cert_state{domains = Ds}};
- {invalid, Ds, {bad_cert, _} = Why} ->
- ?WARNING_MSG("certificate from ~s is invalid: ~s",
- [Path, format_error(Why)]),
- {ok, #cert_state{domains = Ds}};
- {error, Why} = Err ->
- ?ERROR_MSG("failed to read certificate from ~s: ~s",
+-spec build_chain_and_check(state()) -> ok | {error, bad_cert()}.
+build_chain_and_check(State) ->
+ ?DEBUG("Rebuilding certificate chains from ~s",
+ [str:join(State#state.paths, <<", ">>)]),
+ CertPaths = get_cert_paths(maps:keys(State#state.certs)),
+ case match_cert_keys(CertPaths, State#state.keys) of
+ {ok, Chains} ->
+ CertFilesWithDomains = store_certs(Chains, []),
+ ets:delete_all_objects(?MODULE),
+ lists:foreach(
+ fun({Path, Domain}) ->
+ ets:insert(?MODULE, {Domain, Path})
+ end, CertFilesWithDomains),
+ Errors = validate(CertPaths, State#state.validate),
+ subscribe(State),
+ lists:foreach(
+ fun({Cert, Why}) ->
+ Path = maps:get(Cert, State#state.certs),
+ ?WARNING_MSG("Failed to validate certificate from ~s: ~s",
+ [Path, format_error(Why)])
+ end, Errors);
+ {error, Cert, Why} ->
+ Path = maps:get(Cert, State#state.certs),
+ ?ERROR_MSG("Failed to build certificate chain for ~s: ~s",
[Path, format_error(Why)]),
- Err
+ {error, Why}
end.
--spec check_certfile(filename:filename(), boolean())
- -> {ok, [binary()]} | {invalid, [binary()], bad_cert()} |
- {error, cert_error() | file:posix()}.
-check_certfile(Path, Validate) ->
+-spec store_certs([{[cert()], priv_key()}],
+ [{binary(), binary()}]) -> [{binary(), binary()}].
+store_certs([{Certs, Key}|Chains], Acc) ->
+ CertPEMs = public_key:pem_encode(
+ lists:map(
+ fun(Cert) ->
+ Type = element(1, Cert),
+ DER = public_key:pkix_encode(Type, Cert, otp),
+ {'Certificate', DER, not_encrypted}
+ end, Certs)),
+ KeyPEM = public_key:pem_encode(
+ [{element(1, Key),
+ public_key:der_encode(element(1, Key), Key),
+ not_encrypted}]),
+ PEMs = <<CertPEMs/binary, KeyPEM/binary>>,
+ Cert = hd(Certs),
+ Domains = xmpp_stream_pkix:get_cert_domains(Cert),
+ FileName = filename:join(certs_dir(), str:sha(PEMs)),
+ case file:write_file(FileName, PEMs) of
+ ok ->
+ file:change_mode(FileName, 8#600),
+ NewAcc = [{FileName, Domain} || Domain <- Domains] ++ Acc,
+ store_certs(Chains, NewAcc);
+ {error, Why} ->
+ ?ERROR_MSG("Failed to write to ~s: ~s",
+ [FileName, file:format_error(Why)]),
+ store_certs(Chains, [])
+ end;
+store_certs([], Acc) ->
+ Acc.
+
+-spec load_certfile(file:filename_all()) -> {ok, [cert()], [priv_key()]} |
+ {error, cert_error() | file:posix()}.
+load_certfile(Path) ->
try
{ok, Data} = file:read_file(Path),
- {ok, Certs, PrivKeys} = pem_decode(Data),
- CertPaths = get_cert_paths(Certs),
- Domains = get_domains(CertPaths),
- case match_cert_keys(CertPaths, PrivKeys) of
- {ok, _} ->
- case validate(CertPaths, Validate) of
- ok -> {ok, Domains};
- {error, Why} -> {invalid, Domains, Why}
- end;
- {error, Why} ->
- {invalid, Domains, Why}
- end
+ pem_decode(Data)
catch _:{badmatch, {error, _} = Err} ->
Err
end.
@@ -281,7 +414,7 @@ pem_decode(Data) ->
fun(#'OTPCertificate'{}) -> true;
(_) -> false
end, Objects) of
- {[], _} ->
+ {[], []} ->
{error, not_cert};
{Certs, PrivKeys} ->
{ok, Certs, PrivKeys}
@@ -331,41 +464,44 @@ decode_certs(PemEntries) ->
{error, not_der}
end.
--spec validate([{path, [cert()]}], boolean()) -> ok | {error, bad_cert()}.
-validate([{path, Path}|Paths], true) ->
- case validate_path(Path) of
- ok ->
- validate(Paths, true);
- Err ->
- Err
- end;
+-spec validate([{path, [cert()]}], boolean()) -> [{cert(), bad_cert()}].
+validate(Paths, true) ->
+ lists:flatmap(
+ fun({path, Path}) ->
+ case validate_path(Path) of
+ ok ->
+ [];
+ {error, Cert, Reason} ->
+ [{Cert, Reason}]
+ end
+ end, Paths);
validate(_, _) ->
- ok.
+ [].
--spec validate_path([cert()]) -> ok | {error, bad_cert()}.
+-spec validate_path([cert()]) -> ok | {error, cert(), bad_cert()}.
validate_path([Cert|_] = Certs) ->
case find_local_issuer(Cert) of
{ok, IssuerCert} ->
try public_key:pkix_path_validation(IssuerCert, Certs, []) of
{ok, _} ->
ok;
- Err ->
- Err
+ {error, Reason} ->
+ {error, Cert, Reason}
catch error:function_clause ->
case erlang:get_stacktrace() of
[{public_key, pkix_sign_types, _, _}|_] ->
- {error, {bad_cert, unknown_sig_algo}};
+ {error, Cert, {bad_cert, unknown_sig_algo}};
ST ->
%% Bug in public_key application
erlang:raise(error, function_clause, ST)
end
end;
- {error, _} = Err ->
+ {error, Reason} ->
case public_key:pkix_is_self_signed(Cert) of
true ->
- {error, {bad_cert, selfsigned_peer}};
+ {error, Cert, {bad_cert, selfsigned_peer}};
false ->
- Err
+ {error, Cert, Reason}
end
end.
@@ -373,6 +509,25 @@ validate_path([Cert|_] = Certs) ->
ca_dir() ->
ejabberd_config:get_option(ca_path, "/etc/ssl/certs").
+-spec certs_dir() -> string().
+certs_dir() ->
+ MnesiaDir = mnesia:system_info(directory),
+ filename:join(MnesiaDir, "certs").
+
+-spec clean_dir(file:filename_all()) -> ok.
+clean_dir(Dir) ->
+ ?DEBUG("Cleaning directory ~s", [Dir]),
+ Files = filelib:wildcard(filename:join(Dir, "*")),
+ lists:foreach(
+ fun(Path) ->
+ case filelib:is_file(Path) of
+ true ->
+ file:delete(Path);
+ false ->
+ ok
+ end
+ end, Files).
+
-spec check_ca_dir() -> ok.
check_ca_dir() ->
case filelib:wildcard(filename:join(ca_dir(), "*.0")) of
@@ -424,13 +579,13 @@ match_cert_keys(CertPaths, PrivKeys) ->
-spec match_cert_keys([{path, [cert()]}], [{pub_key(), priv_key()}],
[{cert(), priv_key()}])
- -> {ok, [{cert(), priv_key()}]} | {error, {bad_cert, missing_priv_key}}.
+ -> {ok, [{[cert()], priv_key()}]} | {error, cert(), {bad_cert, missing_priv_key}}.
match_cert_keys([{path, Certs}|CertPaths], KeyPairs, Result) ->
[Cert|_] = RevCerts = lists:reverse(Certs),
PubKey = pubkey_from_cert(Cert),
case lists:keyfind(PubKey, 1, KeyPairs) of
false ->
- {error, {bad_cert, missing_priv_key}};
+ {error, Cert, {bad_cert, missing_priv_key}};
{_, PrivKey} ->
match_cert_keys(CertPaths, KeyPairs, [{RevCerts, PrivKey}|Result])
end;
@@ -465,15 +620,6 @@ pubkey_from_privkey(#'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) ->
pubkey_from_privkey(#'ECPrivateKey'{publicKey = Key}) ->
#'ECPoint'{point = Key}.
--spec get_domains([{path, [cert()]}]) -> [binary()].
-get_domains(CertPaths) ->
- lists:usort(
- lists:flatmap(
- fun({path, Certs}) ->
- Cert = lists:last(Certs),
- xmpp_stream_pkix:get_cert_domains(Cert)
- end, CertPaths)).
-
-spec get_cert_paths([cert()]) -> [{path, [cert()]}].
get_cert_paths(Certs) ->
G = digraph:new([acyclic]),
@@ -533,3 +679,37 @@ short_name_hash(IssuerID) ->
short_name_hash(_) ->
"".
-endif.
+
+-spec subscribe(state()) -> ok.
+subscribe(#state{notify = true} = State) ->
+ lists:foreach(
+ fun(Path) ->
+ Dir = filename:dirname(Path),
+ Name = list_to_atom(integer_to_list(erlang:phash2(Dir))),
+ case fs:start_link(Name, Dir) of
+ {ok, _} ->
+ ?DEBUG("Subscribed to FS events from ~s", [Dir]),
+ fs:subscribe(Name);
+ {error, _} ->
+ ok
+ end
+ end, State#state.paths);
+subscribe(_) ->
+ ok.
+
+-spec start_fs() -> boolean().
+start_fs() ->
+ application:load(fs),
+ application:set_env(fs, backwards_compatible, false),
+ case application:ensure_all_started(fs) of
+ {ok, _} -> true;
+ {error, {already_loaded, _}} -> true;
+ {error, Reason} ->
+ ?ERROR_MSG("Failed to load 'fs' Erlang application: ~p; "
+ "certificates change detection will be disabled. "
+ "You should now manually run `ejabberdctl "
+ "reload_config` whenever certificates are changed "
+ "on disc",
+ [Reason]),
+ false
+ end.
diff --git a/src/ejabberd_redis.erl b/src/ejabberd_redis.erl
index 56948ec83..76ae10ace 100644
--- a/src/ejabberd_redis.erl
+++ b/src/ejabberd_redis.erl
@@ -45,7 +45,7 @@
-define(SERVER, ?MODULE).
-define(PROCNAME, 'ejabberd_redis_client').
-define(TR_STACK, redis_transaction_stack).
--define(DEFAULT_MAX_QUEUE, 5000).
+-define(DEFAULT_MAX_QUEUE, 10000).
-define(MAX_RETRIES, 1).
-define(CALL_TIMEOUT, 60*1000). %% 60 seconds
diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl
index 7dd82b804..0626d62fb 100644
--- a/src/ejabberd_s2s.erl
+++ b/src/ejabberd_s2s.erl
@@ -198,13 +198,11 @@ dirty_get_connections() ->
-spec tls_options(binary(), [proplists:property()]) -> [proplists:property()].
tls_options(LServer, DefaultOpts) ->
- TLSOpts1 = case ejabberd_config:get_option(
- {domain_certfile, LServer},
- ejabberd_config:get_option(
- {s2s_certfile, LServer})) of
+ TLSOpts1 = case get_certfile(LServer) of
undefined -> DefaultOpts;
- CertFile -> lists:keystore(certfile, 1, DefaultOpts,
- {certfile, CertFile})
+ CertFile ->
+ lists:keystore(certfile, 1, DefaultOpts,
+ {certfile, CertFile})
end,
TLSOpts2 = case ejabberd_config:get_option(
{s2s_ciphers, LServer}) of
@@ -269,6 +267,17 @@ queue_type(LServer) ->
{s2s_queue_type, LServer},
ejabberd_config:default_queue_type(LServer)).
+-spec get_certfile(binary()) -> file:filename_all().
+get_certfile(LServer) ->
+ case ejabberd_pkix:get_certfile(LServer) of
+ {ok, CertFile} ->
+ CertFile;
+ error ->
+ ejabberd_config:get_option(
+ {domain_certfile, LServer},
+ ejabberd_config:get_option({s2s_certfile, LServer}))
+ end.
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
@@ -711,7 +720,11 @@ opt_type(route_subdomains) ->
end;
opt_type(s2s_access) ->
fun acl:access_rules_validator/1;
-opt_type(s2s_certfile) -> fun misc:try_read_file/1;
+opt_type(s2s_certfile = Opt) ->
+ fun(File) ->
+ ?WARNING_MSG("option '~s' is deprecated, use 'certfiles' instead", [Opt]),
+ misc:try_read_file(File)
+ end;
opt_type(s2s_ciphers) -> fun iolist_to_binary/1;
opt_type(s2s_dhfile) -> fun misc:try_read_file/1;
opt_type(s2s_cafile) -> fun misc:try_read_file/1;
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index 48a650a4e..a949e83d6 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -359,8 +359,10 @@ change_shaper(#{shaper := ShaperName, server_host := ServerHost} = State,
(max_fsm_queue) -> fun((pos_integer()) -> pos_integer());
(atom()) -> [atom()].
listen_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
-listen_opt_type(certfile) ->
+listen_opt_type(certfile = Opt) ->
fun(S) ->
+ ?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
+ "'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
diff --git a/src/ejabberd_sm_sql.erl b/src/ejabberd_sm_sql.erl
index 2b94064ef..55e21040b 100644
--- a/src/ejabberd_sm_sql.erl
+++ b/src/ejabberd_sm_sql.erl
@@ -74,6 +74,7 @@ set_session(#session{sid = {Now, Pid}, usr = {U, LServer, R},
"!pid=%(PidS)s",
"node=%(Node)s",
"username=%(U)s",
+ "server_host=%(LServer)s",
"resource=%(R)s",
"priority=%(PrioS)s",
"info=%(InfoS)s"]) of
@@ -107,7 +108,8 @@ get_sessions(LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(usec)d, @(pid)s, @(node)s, @(username)s,"
- " @(resource)s, @(priority)s, @(info)s from sm")) of
+ " @(resource)s, @(priority)s, @(info)s from sm"
+ " where %(LServer)H")) of
{selected, Rows} ->
lists:flatmap(
fun(Row) ->
@@ -125,7 +127,7 @@ get_sessions(LUser, LServer) ->
LServer,
?SQL("select @(usec)d, @(pid)s, @(node)s, @(username)s,"
" @(resource)s, @(priority)s, @(info)s from sm"
- " where username=%(LUser)s")) of
+ " where username=%(LUser)s and %(LServer)H")) of
{selected, Rows} ->
{ok, lists:flatmap(
fun(Row) ->
diff --git a/src/ejabberd_sql_pt.erl b/src/ejabberd_sql_pt.erl
index e90947a5f..a32039436 100644
--- a/src/ejabberd_sql_pt.erl
+++ b/src/ejabberd_sql_pt.erl
@@ -26,7 +26,7 @@
-module(ejabberd_sql_pt).
%% API
--export([parse_transform/2]).
+-export([parse_transform/2, format_error/1]).
-export([parse/2]).
@@ -39,7 +39,8 @@
args = [],
res = [],
res_vars = [],
- res_pos = 0}).
+ res_pos = 0,
+ server_host_used = false}).
-define(QUERY_RECORD, "sql_query").
@@ -48,6 +49,12 @@
-define(MOD, sql__module_).
+-ifdef(NEW_SQL_SCHEMA).
+-define(USE_NEW_SCHEMA, true).
+-else.
+-define(USE_NEW_SCHEMA, false).
+-endif.
+
%%====================================================================
%% API
%%====================================================================
@@ -57,11 +64,14 @@
%%--------------------------------------------------------------------
parse_transform(AST, _Options) ->
%io:format("PT: ~p~nOpts: ~p~n", [AST, Options]),
+ put(warnings, []),
NewAST = top_transform(AST),
%io:format("NewPT: ~p~n", [NewAST]),
- NewAST.
+ NewAST ++ get(warnings).
+format_error(no_server_host) ->
+ "server_host field is not used".
%%====================================================================
%% Internal functions
@@ -80,6 +90,12 @@ transform(Form) ->
S = erl_syntax:string_value(Arg),
Pos = erl_syntax:get_pos(Arg),
ParseRes = parse(S, Pos),
+ if
+ ParseRes#state.server_host_used ->
+ ok;
+ true ->
+ add_warning(Pos, no_server_host)
+ end,
set_pos(make_sql_query(ParseRes), Pos);
_ ->
throw({error, erl_syntax:get_pos(Form),
@@ -101,8 +117,17 @@ transform(Form) ->
parse_upsert(
erl_syntax:list_elements(FieldsArg)),
Pos = erl_syntax:get_pos(Form),
+ case lists:keymember(
+ "server_host", 1, ParseRes) of
+ true ->
+ ok;
+ false ->
+ add_warning(Pos, no_server_host)
+ end,
+ ParseRes2 =
+ filter_upsert_sh(Table, ParseRes),
set_pos(
- make_sql_upsert(Table, ParseRes, Pos),
+ make_sql_upsert(Table, ParseRes2, Pos),
Pos);
_ ->
throw({error, erl_syntax:get_pos(Form),
@@ -113,6 +138,38 @@ transform(Form) ->
throw({error, erl_syntax:get_pos(Form),
"wrong number of ?SQL_UPSERT args"})
end;
+ {?SQL_INSERT_MARK, 2} ->
+ case erl_syntax:application_arguments(Form) of
+ [TableArg, FieldsArg] ->
+ case {erl_syntax:type(TableArg),
+ erl_syntax:is_proper_list(FieldsArg)}of
+ {string, true} ->
+ Table = erl_syntax:string_value(TableArg),
+ ParseRes =
+ parse_insert(
+ erl_syntax:list_elements(FieldsArg)),
+ Pos = erl_syntax:get_pos(Form),
+ case lists:keymember(
+ "server_host", 1, ParseRes) of
+ true ->
+ ok;
+ false ->
+ add_warning(Pos, no_server_host)
+ end,
+ ParseRes2 =
+ filter_upsert_sh(Table, ParseRes),
+ set_pos(
+ make_sql_insert(Table, ParseRes2),
+ Pos);
+ _ ->
+ throw({error, erl_syntax:get_pos(Form),
+ "?SQL_INSERT arguments must be "
+ "a constant string and a list"})
+ end;
+ _ ->
+ throw({error, erl_syntax:get_pos(Form),
+ "wrong number of ?SQL_INSERT args"})
+ end;
_ ->
Form
end;
@@ -168,7 +225,7 @@ parse1([], Acc, State) ->
};
parse1([$@, $( | S], Acc, State) ->
State1 = append_string(lists:reverse(Acc), State),
- {Name, Type, S1, State2} = parse_name(S, State1),
+ {Name, Type, S1, State2} = parse_name(S, false, State1),
Var = "__V" ++ integer_to_list(State2#state.res_pos),
EVar = erl_syntax:variable(Var),
Convert =
@@ -192,21 +249,43 @@ parse1([$@, $( | S], Acc, State) ->
parse1(S1, [], State4);
parse1([$%, $( | S], Acc, State) ->
State1 = append_string(lists:reverse(Acc), State),
- {Name, Type, S1, State2} = parse_name(S, State1),
+ {Name, Type, S1, State2} = parse_name(S, true, State1),
Var = State2#state.param_pos,
- Convert =
- erl_syntax:application(
- erl_syntax:record_access(
- erl_syntax:variable(?ESCAPE_VAR),
- erl_syntax:atom(?ESCAPE_RECORD),
- erl_syntax:atom(Type)),
- [erl_syntax:variable(Name)]),
- State3 = State2,
State4 =
- State3#state{'query' = [{var, Var} | State3#state.'query'],
- args = [Convert | State3#state.args],
- params = [Var | State3#state.params],
- param_pos = State3#state.param_pos + 1},
+ case Type of
+ host ->
+ State3 = State2#state{server_host_used = true},
+ case ?USE_NEW_SCHEMA of
+ true ->
+ Convert =
+ erl_syntax:application(
+ erl_syntax:record_access(
+ erl_syntax:variable(?ESCAPE_VAR),
+ erl_syntax:atom(?ESCAPE_RECORD),
+ erl_syntax:atom(string)),
+ [erl_syntax:variable(Name)]),
+ State3#state{'query' = [{var, Var},
+ {str, "server_host="} |
+ State3#state.'query'],
+ args = [Convert | State3#state.args],
+ params = [Var | State3#state.params],
+ param_pos = State3#state.param_pos + 1};
+ false ->
+ append_string("0=0", State3)
+ end;
+ _ ->
+ Convert =
+ erl_syntax:application(
+ erl_syntax:record_access(
+ erl_syntax:variable(?ESCAPE_VAR),
+ erl_syntax:atom(?ESCAPE_RECORD),
+ erl_syntax:atom(Type)),
+ [erl_syntax:variable(Name)]),
+ State2#state{'query' = [{var, Var} | State2#state.'query'],
+ args = [Convert | State2#state.args],
+ params = [Var | State2#state.params],
+ param_pos = State2#state.param_pos + 1}
+ end,
parse1(S1, [], State4);
parse1([C | S], Acc, State) ->
parse1(S, [C | Acc], State).
@@ -216,32 +295,33 @@ append_string([], State) ->
append_string(S, State) ->
State#state{query = [{str, S} | State#state.query]}.
-parse_name(S, State) ->
- parse_name(S, [], 0, State).
+parse_name(S, IsArg, State) ->
+ parse_name(S, [], 0, IsArg, State).
-parse_name([], _Acc, _Depth, State) ->
+parse_name([], _Acc, _Depth, _IsArg, State) ->
throw({error, State#state.loc,
"expected ')', found end of string"});
-parse_name([$), T | S], Acc, 0, State) ->
+parse_name([$), T | S], Acc, 0, IsArg, State) ->
Type =
case T of
$d -> integer;
$s -> string;
$b -> boolean;
+ $H when IsArg -> host;
_ ->
throw({error, State#state.loc,
["unknown type specifier '", T, "'"]})
end,
{lists:reverse(Acc), Type, S, State};
-parse_name([$)], _Acc, 0, State) ->
+parse_name([$)], _Acc, 0, _IsArg, State) ->
throw({error, State#state.loc,
"expected type specifier, found end of string"});
-parse_name([$( = C | S], Acc, Depth, State) ->
- parse_name(S, [C | Acc], Depth + 1, State);
-parse_name([$) = C | S], Acc, Depth, State) ->
- parse_name(S, [C | Acc], Depth - 1, State);
-parse_name([C | S], Acc, Depth, State) ->
- parse_name(S, [C | Acc], Depth, State).
+parse_name([$( = C | S], Acc, Depth, IsArg, State) ->
+ parse_name(S, [C | Acc], Depth + 1, IsArg, State);
+parse_name([$) = C | S], Acc, Depth, IsArg, State) ->
+ parse_name(S, [C | Acc], Depth - 1, IsArg, State);
+parse_name([C | S], Acc, Depth, IsArg, State) ->
+ parse_name(S, [C | Acc], Depth, IsArg, State).
make_var(V) ->
@@ -444,7 +524,7 @@ make_sql_upsert_insert(Table, ParseRes) ->
join_states(Fields, ", "),
#state{'query' = [{str, ") VALUES ("}]},
join_states(Vals, ", "),
- #state{'query' = [{str, ")"}]}
+ #state{'query' = [{str, ");"}]}
]),
State.
@@ -498,6 +578,49 @@ check_upsert(ParseRes, Pos) ->
ok.
+parse_insert(Fields) ->
+ {Fs, _} =
+ lists:foldr(
+ fun(F, {Acc, Param}) ->
+ case erl_syntax:type(F) of
+ string ->
+ V = erl_syntax:string_value(F),
+ {_, _, State} = Res =
+ parse_insert_field(
+ V, Param, erl_syntax:get_pos(F)),
+ {[Res | Acc], State#state.param_pos};
+ _ ->
+ throw({error, erl_syntax:get_pos(F),
+ "?SQL_INSERT field must be "
+ "a constant string"})
+ end
+ end, {[], 0}, Fields),
+ Fs.
+
+parse_insert_field([$! | _S], _ParamPos, Loc) ->
+ throw({error, Loc,
+ "?SQL_INSERT fields must not start with \"!\""});
+parse_insert_field([$- | _S], _ParamPos, Loc) ->
+ throw({error, Loc,
+ "?SQL_INSERT fields must not start with \"-\""});
+parse_insert_field(S, ParamPos, Loc) ->
+ {Name, ParseState} = parse_insert_field1(S, [], ParamPos, Loc),
+ {Name, {true}, ParseState}.
+
+parse_insert_field1([], _Acc, _ParamPos, Loc) ->
+ throw({error, Loc,
+ "?SQL_INSERT fields must have the "
+ "following form: \"name=value\""});
+parse_insert_field1([$= | S], Acc, ParamPos, Loc) ->
+ {lists:reverse(Acc), parse(S, ParamPos, Loc)};
+parse_insert_field1([C | S], Acc, ParamPos, Loc) ->
+ parse_insert_field1(S, [C | Acc], ParamPos, Loc).
+
+
+make_sql_insert(Table, ParseRes) ->
+ make_sql_query(make_sql_upsert_insert(Table, ParseRes)).
+
+
concat_states(States) ->
lists:foldr(
fun(ST11, ST2) ->
@@ -566,3 +689,29 @@ set_pos(Tree, Pos) ->
_ -> Node
end
end, Tree).
+
+filter_upsert_sh(Table, ParseRes) ->
+ case ?USE_NEW_SCHEMA of
+ true ->
+ ParseRes;
+ false ->
+ lists:filter(
+ fun({Field, _Match, _ST}) ->
+ Field /= "server_host" orelse Table == "route"
+ end, ParseRes)
+ end.
+
+-ifdef(ENABLE_PT_WARNINGS).
+
+add_warning(Pos, Warning) ->
+ Marker = erl_syntax:revert(
+ erl_syntax:warning_marker({Pos, ?MODULE, Warning})),
+ put(warnings, [Marker | get(warnings)]),
+ ok.
+
+-else.
+
+add_warning(_Pos, _Warning) ->
+ ok.
+
+-endif.
diff --git a/src/ejd2sql.erl b/src/ejd2sql.erl
index c801eb973..79533421e 100644
--- a/src/ejd2sql.erl
+++ b/src/ejd2sql.erl
@@ -59,6 +59,7 @@ modules() ->
mod_privacy,
mod_private,
mod_pubsub,
+ mod_push,
mod_roster,
mod_shared_roster,
mod_vcard].
@@ -73,18 +74,28 @@ export(Server, Output) ->
end, Modules),
close_output(Output, IO).
-export(Server, Output, Module) ->
+export(Server, Output, Module1) ->
+ Module = case Module1 of
+ mod_pubsub -> pubsub_db;
+ _ -> Module1
+ end,
+ SQLMod = gen_mod:db_mod(sql, Module),
LServer = jid:nameprep(iolist_to_binary(Server)),
IO = prepare_output(Output),
lists:foreach(
fun({Table, ConvertFun}) ->
case export(LServer, Table, IO, ConvertFun) of
{atomic, ok} -> ok;
+ {aborted, {no_exists, _}} ->
+ ?WARNING_MSG("Ignoring export for module ~s: "
+ "Mnesia table ~s doesn't exist (most likely "
+ "because the module is unused)",
+ [Module1, Table]);
{aborted, Reason} ->
?ERROR_MSG("Failed export for module ~p and table ~p: ~p",
[Module, Table, Reason])
end
- end, Module:export(Server)),
+ end, SQLMod:export(Server)),
close_output(Output, IO).
delete(Server) ->
diff --git a/src/mod_admin_update_sql.erl b/src/mod_admin_update_sql.erl
new file mode 100644
index 000000000..2f105d97d
--- /dev/null
+++ b/src/mod_admin_update_sql.erl
@@ -0,0 +1,365 @@
+%%%-------------------------------------------------------------------
+%%% File : mod_admin_update_sql.erl
+%%% Author : Alexey Shchepin <alexey@process-one.net>
+%%% Purpose : Convert SQL DB to the new format
+%%% Created : 9 Aug 2017 by Alexey Shchepin <alexey@process-one.net>
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2017 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_admin_update_sql).
+-author('alexey@process-one.net').
+
+-behaviour(gen_mod).
+
+-export([start/2, stop/1, reload/3, mod_opt_type/1,
+ get_commands_spec/0, depends/2]).
+
+% Commands API
+-export([update_sql/0]).
+
+
+-include("logger.hrl").
+-include("ejabberd.hrl").
+-include("ejabberd_commands.hrl").
+-include("xmpp.hrl").
+-include("ejabberd_sql_pt.hrl").
+
+%%%
+%%% gen_mod
+%%%
+
+start(_Host, _Opts) ->
+ ejabberd_commands:register_commands(get_commands_spec()).
+
+stop(_Host) ->
+ ejabberd_commands:unregister_commands(get_commands_spec()).
+
+reload(_Host, _NewOpts, _OldOpts) ->
+ ok.
+
+depends(_Host, _Opts) ->
+ [].
+
+%%%
+%%% Register commands
+%%%
+
+get_commands_spec() ->
+ [#ejabberd_commands{name = update_sql, tags = [sql],
+ desc = "Convert SQL DB to the new format",
+ module = ?MODULE, function = update_sql,
+ args = [],
+ args_example = [],
+ args_desc = [],
+ result = {res, rescode},
+ result_example = ok,
+ result_desc = "Status code: 0 on success, 1 otherwise"}
+ ].
+
+update_sql() ->
+ lists:foreach(
+ fun(Host) ->
+ case ejabberd_sql_sup:get_pids(Host) of
+ [] ->
+ ok;
+ _ ->
+ update_sql(Host)
+ end
+ end, ?MYHOSTS),
+ ok.
+
+-record(state, {host :: binary(),
+ dbtype :: mysql | pgsql | sqlite | mssql | odbc,
+ escape}).
+
+update_sql(Host) ->
+ LHost = jid:nameprep(Host),
+ DBType = ejabberd_config:get_option({sql_type, LHost}, undefined),
+ IsSupported =
+ case DBType of
+ pgsql -> true;
+ _ -> false
+ end,
+ if
+ not IsSupported ->
+ io:format("Converting ~p DB is not supported~n", [DBType]),
+ error;
+ true ->
+ Escape =
+ case DBType of
+ mssql -> fun ejabberd_sql:standard_escape/1;
+ sqlite -> fun ejabberd_sql:standard_escape/1;
+ _ -> fun ejabberd_sql:escape/1
+ end,
+ State = #state{host = LHost,
+ dbtype = DBType,
+ escape = Escape},
+ update_tables(State)
+ end.
+
+update_tables(State) ->
+ add_sh_column(State, "users"),
+ drop_pkey(State, "users"),
+ add_pkey(State, "users", ["server_host", "username"]),
+ drop_sh_default(State, "users"),
+
+ add_sh_column(State, "last"),
+ drop_pkey(State, "last"),
+ add_pkey(State, "last", ["server_host", "username"]),
+ drop_sh_default(State, "last"),
+
+ add_sh_column(State, "rosterusers"),
+ drop_index(State, "i_rosteru_user_jid"),
+ drop_index(State, "i_rosteru_username"),
+ drop_index(State, "i_rosteru_jid"),
+ create_unique_index(State, "rosterusers", "i_rosteru_sh_user_jid", ["server_host", "username", "jid"]),
+ create_index(State, "rosterusers", "i_rosteru_sh_username", ["server_host", "username"]),
+ create_index(State, "rosterusers", "i_rosteru_sh_jid", ["server_host", "jid"]),
+ drop_sh_default(State, "rosterusers"),
+
+ add_sh_column(State, "rostergroups"),
+ drop_index(State, "pk_rosterg_user_jid"),
+ create_index(State, "rostergroups", "i_rosterg_sh_user_jid", ["server_host", "username", "jid"]),
+ drop_sh_default(State, "rostergroups"),
+
+ add_sh_column(State, "sr_group"),
+ add_pkey(State, "sr_group", ["server_host", "name"]),
+ drop_sh_default(State, "sr_group"),
+
+ add_sh_column(State, "sr_user"),
+ drop_index(State, "i_sr_user_jid_grp"),
+ drop_index(State, "i_sr_user_jid"),
+ drop_index(State, "i_sr_user_grp"),
+ add_pkey(State, "sr_user", ["server_host", "jid", "grp"]),
+ create_index(State, "sr_user", "i_sr_user_sh_jid", ["server_host", "jid"]),
+ create_index(State, "sr_user", "i_sr_user_sh_grp", ["server_host", "grp"]),
+ drop_sh_default(State, "sr_user"),
+
+ add_sh_column(State, "spool"),
+ drop_index(State, "i_despool"),
+ create_index(State, "spool", "i_spool_sh_username", ["server_host", "username"]),
+ drop_sh_default(State, "spool"),
+
+ add_sh_column(State, "archive"),
+ drop_index(State, "i_username"),
+ drop_index(State, "i_username_timestamp"),
+ drop_index(State, "i_timestamp"),
+ drop_index(State, "i_peer"),
+ drop_index(State, "i_bare_peer"),
+ create_index(State, "archive", "i_archive_sh_username_timestamp", ["server_host", "username", "timestamp"]),
+ create_index(State, "archive", "i_archive_sh_timestamp", ["server_host", "timestamp"]),
+ create_index(State, "archive", "i_archive_sh_peer", ["server_host", "peer"]),
+ create_index(State, "archive", "i_archive_sh_bare_peer", ["server_host", "bare_peer"]),
+ drop_sh_default(State, "archive"),
+
+ add_sh_column(State, "archive_prefs"),
+ drop_pkey(State, "archive_prefs"),
+ add_pkey(State, "archive_prefs", ["server_host", "username"]),
+ drop_sh_default(State, "archive_prefs"),
+
+ add_sh_column(State, "vcard"),
+ drop_pkey(State, "vcard"),
+ add_pkey(State, "vcard", ["server_host", "username"]),
+ drop_sh_default(State, "vcard"),
+
+ add_sh_column(State, "vcard_search"),
+ drop_pkey(State, "vcard_search"),
+ drop_index(State, "i_vcard_search_lfn"),
+ drop_index(State, "i_vcard_search_lfamily"),
+ drop_index(State, "i_vcard_search_lgiven"),
+ drop_index(State, "i_vcard_search_lmiddle"),
+ drop_index(State, "i_vcard_search_lnickname"),
+ drop_index(State, "i_vcard_search_lbday"),
+ drop_index(State, "i_vcard_search_lctry"),
+ drop_index(State, "i_vcard_search_llocality"),
+ drop_index(State, "i_vcard_search_lemail"),
+ drop_index(State, "i_vcard_search_lorgname"),
+ drop_index(State, "i_vcard_search_lorgunit"),
+ add_pkey(State, "vcard_search", ["server_host", "username"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lfn", ["server_host", "lfn"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lfamily", ["server_host", "lfamily"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lgiven", ["server_host", "lgiven"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lmiddle", ["server_host", "lmiddle"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lnickname", ["server_host", "lnickname"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lbday", ["server_host", "lbday"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lctry", ["server_host", "lctry"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_llocality", ["server_host", "llocality"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lemail", ["server_host", "lemail"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lorgname", ["server_host", "lorgname"]),
+ create_index(State, "vcard_search", "i_vcard_search_sh_lorgunit", ["server_host", "lorgunit"]),
+ drop_sh_default(State, "vcard_search"),
+
+ add_sh_column(State, "privacy_default_list"),
+ drop_pkey(State, "privacy_default_list"),
+ add_pkey(State, "privacy_default_list", ["server_host", "username"]),
+ drop_sh_default(State, "privacy_default_list"),
+
+ add_sh_column(State, "privacy_list"),
+ drop_index(State, "i_privacy_list_username"),
+ drop_index(State, "i_privacy_list_username_name"),
+ create_index(State, "privacy_list", "i_privacy_list_sh_username", ["server_host", "username"]),
+ create_unique_index(State, "privacy_list", "i_privacy_list_sh_username_name", ["server_host", "username", "name"]),
+ drop_sh_default(State, "privacy_list"),
+
+ add_sh_column(State, "private_storage"),
+ drop_index(State, "i_private_storage_username"),
+ drop_index(State, "i_private_storage_username_namespace"),
+ add_pkey(State, "private_storage", ["server_host", "username", "namespace"]),
+ create_index(State, "private_storage", "i_private_storage_sh_username", ["server_host", "username"]),
+ drop_sh_default(State, "private_storage"),
+
+ add_sh_column(State, "roster_version"),
+ drop_pkey(State, "roster_version"),
+ add_pkey(State, "roster_version", ["server_host", "username"]),
+ drop_sh_default(State, "roster_version"),
+
+ add_sh_column(State, "muc_room"),
+ drop_sh_default(State, "muc_room"),
+
+ add_sh_column(State, "muc_registered"),
+ drop_sh_default(State, "muc_registered"),
+
+ add_sh_column(State, "muc_online_room"),
+ drop_sh_default(State, "muc_online_room"),
+
+ add_sh_column(State, "muc_online_users"),
+ drop_sh_default(State, "muc_online_users"),
+
+ add_sh_column(State, "irc_custom"),
+ drop_sh_default(State, "irc_custom"),
+
+ add_sh_column(State, "motd"),
+ drop_pkey(State, "motd"),
+ add_pkey(State, "motd", ["server_host", "username"]),
+ drop_sh_default(State, "motd"),
+
+ add_sh_column(State, "sm"),
+ drop_index(State, "i_sm_sid"),
+ drop_index(State, "i_sm_username"),
+ add_pkey(State, "sm", ["usec", "pid"]),
+ create_index(State, "sm", "i_sm_sh_username", ["server_host", "username"]),
+ drop_sh_default(State, "sm"),
+
+ add_sh_column(State, "carboncopy"),
+ drop_index(State, "i_carboncopy_ur"),
+ drop_index(State, "i_carboncopy_user"),
+ add_pkey(State, "carboncopy", ["server_host", "username", "resource"]),
+ create_index(State, "carboncopy", "i_carboncopy_sh_user", ["server_host", "username"]),
+ drop_sh_default(State, "carboncopy"),
+
+ add_sh_column(State, "push_session"),
+ drop_index(State, "i_push_usn"),
+ drop_index(State, "i_push_ut"),
+ add_pkey(State, "push_session", ["server_host", "username", "timestamp"]),
+ create_index(State, "push_session", "i_push_session_susn", ["server_host", "username", "service", "node"]),
+ drop_sh_default(State, "push_session"),
+
+ ok.
+
+add_sh_column(#state{dbtype = pgsql} = State, Table) ->
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " ADD COLUMN server_host text NOT NULL DEFAULT '",
+ (State#state.escape)(State#state.host),
+ "';"]);
+add_sh_column(#state{dbtype = mysql} = State, Table) ->
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " ADD COLUMN server_host text NOT NULL DEFAULT '",
+ (State#state.escape)(State#state.host),
+ "';"]).
+
+drop_pkey(#state{dbtype = pgsql} = State, Table) ->
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " DROP CONSTRAINT ", Table, "_pkey;"]);
+drop_pkey(#state{dbtype = mysql} = State, Table) ->
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " DROP PRIMARY KEY;"]).
+
+add_pkey(#state{dbtype = pgsql} = State, Table, Cols) ->
+ SCols = string:join(Cols, ", "),
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " ADD PRIMARY KEY (", SCols, ");"]);
+add_pkey(#state{dbtype = mysql} = State, Table, Cols) ->
+ SCols = string:join(Cols, ", "),
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " ADD PRIMARY KEY (", SCols, ");"]).
+
+drop_sh_default(#state{dbtype = pgsql} = State, Table) ->
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " ALTER COLUMN server_host DROP DEFAULT;"]);
+drop_sh_default(#state{dbtype = mysql} = State, Table) ->
+ sql_query(
+ State#state.host,
+ ["ALTER TABLE ", Table, " ALTER COLUMN server_host DROP DEFAULT;"]).
+
+drop_index(#state{dbtype = pgsql} = State, Index) ->
+ sql_query(
+ State#state.host,
+ ["DROP INDEX ", Index, ";"]);
+drop_index(#state{dbtype = mysql} = State, Index) ->
+ sql_query(
+ State#state.host,
+ ["DROP INDEX ", Index, ";"]).
+
+create_unique_index(#state{dbtype = pgsql} = State, Table, Index, Cols) ->
+ SCols = string:join(Cols, ", "),
+ sql_query(
+ State#state.host,
+ ["CREATE UNIQUE INDEX ", Index, " ON ", Table, " USING btree (",
+ SCols, ");"]);
+create_unique_index(#state{dbtype = mysql} = State, Table, Index, Cols) ->
+ Cols2 = [C ++ "(75)" || C <- Cols],
+ SCols = string:join(Cols2, ", "),
+ sql_query(
+ State#state.host,
+ ["CREATE UNIQUE INDEX ", Index, " ON ", Table, "(",
+ SCols, ");"]).
+
+create_index(#state{dbtype = pgsql} = State, Table, Index, Cols) ->
+ SCols = string:join(Cols, ", "),
+ sql_query(
+ State#state.host,
+ ["CREATE INDEX ", Index, " ON ", Table, " USING btree (",
+ SCols, ");"]);
+create_index(#state{dbtype = mysql} = State, Table, Index, Cols) ->
+ Cols2 = [C ++ "(75)" || C <- Cols],
+ SCols = string:join(Cols2, ", "),
+ sql_query(
+ State#state.host,
+ ["CREATE INDEX ", Index, " ON ", Table, "(",
+ SCols, ");"]).
+
+sql_query(Host, Query) ->
+ io:format("executing \"~s\" on ~s~n", [Query, Host]),
+ case ejabberd_sql:sql_query(Host, Query) of
+ {error, Error} ->
+ io:format("error: ~p~n", [Error]),
+ ok;
+ _ ->
+ ok
+ end.
+
+mod_opt_type(_) -> [].
diff --git a/src/mod_announce_sql.erl b/src/mod_announce_sql.erl
index 1dea0ba75..c5c9eb58f 100644
--- a/src/mod_announce_sql.erl
+++ b/src/mod_announce_sql.erl
@@ -51,6 +51,7 @@ set_motd_users(LServer, USRs) ->
?SQL_UPSERT_T(
"motd",
["!username=%(U)s",
+ "!server_host=%(LServer)s",
"xml=''"])
end, USRs)
end,
@@ -62,20 +63,23 @@ set_motd(LServer, Packet) ->
?SQL_UPSERT_T(
"motd",
["!username=''",
+ "!server_host=%(LServer)s",
"xml=%(XML)s"])
end,
transaction(LServer, F).
delete_motd(LServer) ->
F = fun() ->
- ejabberd_sql:sql_query_t(?SQL("delete from motd"))
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from motd where %(LServer)H"))
end,
transaction(LServer, F).
get_motd(LServer) ->
case catch ejabberd_sql:sql_query(
LServer,
- ?SQL("select @(xml)s from motd where username=''")) of
+ ?SQL("select @(xml)s from motd"
+ " where username='' and %(LServer)H")) of
{selected, [{XML}]} ->
parse_element(XML);
{selected, []} ->
@@ -88,7 +92,7 @@ is_motd_user(LUser, LServer) ->
case catch ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from motd"
- " where username=%(LUser)s")) of
+ " where username=%(LUser)s and %(LServer)H")) of
{selected, [_|_]} ->
{ok, true};
{selected, []} ->
@@ -102,6 +106,7 @@ set_motd_user(LUser, LServer) ->
?SQL_UPSERT_T(
"motd",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"xml=''"])
end,
transaction(LServer, F).
@@ -111,16 +116,24 @@ export(_Server) ->
fun(Host, #motd{server = LServer, packet = El})
when LServer == Host ->
XML = fxml:element_to_binary(El),
- [?SQL("delete from motd where username='';"),
- ?SQL("insert into motd(username, xml) values ('', %(XML)s);")];
+ [?SQL("delete from motd where username='' and %(LServer)H;"),
+ ?SQL_INSERT(
+ "motd",
+ ["username=''",
+ "server_host=%(LServer)s",
+ "xml=%(XML)s"])];
(_Host, _R) ->
[]
end},
{motd_users,
fun(Host, #motd_users{us = {LUser, LServer}})
when LServer == Host, LUser /= <<"">> ->
- [?SQL("delete from motd where username=%(LUser)s;"),
- ?SQL("insert into motd(username, xml) values (%(LUser)s, '');")];
+ [?SQL("delete from motd where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "motd",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "xml=''"])];
(_Host, _R) ->
[]
end}].
diff --git a/src/mod_carboncopy_sql.erl b/src/mod_carboncopy_sql.erl
index 3271d8a1c..1b8e1e111 100644
--- a/src/mod_carboncopy_sql.erl
+++ b/src/mod_carboncopy_sql.erl
@@ -42,6 +42,7 @@ enable(LUser, LServer, LResource, NS) ->
NodeS = erlang:atom_to_binary(node(), latin1),
case ?SQL_UPSERT(LServer, "carboncopy",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"!resource=%(LResource)s",
"namespace=%(NS)s",
"node=%(NodeS)s"]) of
@@ -56,7 +57,7 @@ disable(LUser, LServer, LResource) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("delete from carboncopy where username=%(LUser)s "
- "and resource=%(LResource)s")) of
+ "and %(LServer)H and resource=%(LResource)s")) of
{updated, _} ->
ok;
Err ->
@@ -68,7 +69,7 @@ list(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(resource)s, @(namespace)s, @(node)s from carboncopy "
- "where username=%(LUser)s")) of
+ "where username=%(LUser)s and %(LServer)H")) of
{selected, Rows} ->
{ok, [{Resource, NS, binary_to_atom(Node, latin1)}
|| {Resource, NS, Node} <- Rows]};
diff --git a/src/mod_irc_sql.erl b/src/mod_irc_sql.erl
index f9a7d716f..1f8d7d16a 100644
--- a/src/mod_irc_sql.erl
+++ b/src/mod_irc_sql.erl
@@ -46,7 +46,7 @@ get_data(LServer, Host, From) ->
case catch ejabberd_sql:sql_query(
LServer,
?SQL("select @(data)s from irc_custom"
- " where jid=%(SJID)s and host=%(Host)s")) of
+ " where jid=%(SJID)s and host=%(Host)s and %(LServer)H")) of
{selected, [{SData}]} ->
mod_irc:data_to_binary(From, ejabberd_sql:decode_term(SData));
{'EXIT', _} -> error;
@@ -61,6 +61,7 @@ set_data(LServer, Host, From, Data) ->
"irc_custom",
["!jid=%(SJID)s",
"!host=%(Host)s",
+ "server_host=%(LServer)s",
"data=%(SData)s"]),
ok
end,
@@ -73,11 +74,16 @@ export(_Server) ->
case str:suffix(Host, IRCHost) of
true ->
SJID = jid:encode(jid:make(U, S)),
+ LServer = ejabberd_router:host_of_route(IRCHost),
SData = misc:term_to_expr(Data),
[?SQL("delete from irc_custom"
- " where jid=%(SJID)s and host=%(IRCHost)s;"),
- ?SQL("insert into irc_custom(jid, host, data)"
- " values (%(SJID)s, %(IRCHost)s, %(SData)s);")];
+ " where jid=%(SJID)s and host=%(IRCHost)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "irc_custom",
+ ["jid=%(SJID)s",
+ "host=%(Host)s",
+ "server_host=%(LServer)s",
+ "data=%(SData)s"])];
false ->
[]
end
diff --git a/src/mod_last_sql.erl b/src/mod_last_sql.erl
index b777ba30d..f0889e4ec 100644
--- a/src/mod_last_sql.erl
+++ b/src/mod_last_sql.erl
@@ -46,7 +46,7 @@ get_last(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(seconds)d, @(state)s from last"
- " where username=%(LUser)s")) of
+ " where username=%(LUser)s and %(LServer)H")) of
{selected, []} ->
error;
{selected, [{TimeStamp, Status}]} ->
@@ -60,6 +60,7 @@ get_last(LUser, LServer) ->
store_last_info(LUser, LServer, TimeStamp, Status) ->
case ?SQL_UPSERT(LServer, "last",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"seconds=%(TimeStamp)d",
"state=%(Status)s"]) of
ok ->
@@ -73,16 +74,19 @@ store_last_info(LUser, LServer, TimeStamp, Status) ->
remove_user(LUser, LServer) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from last where username=%(LUser)s")).
+ ?SQL("delete from last where username=%(LUser)s and %(LServer)H")).
export(_Server) ->
[{last_activity,
fun(Host, #last_activity{us = {LUser, LServer},
timestamp = TimeStamp, status = Status})
when LServer == Host ->
- [?SQL("delete from last where username=%(LUser)s;"),
- ?SQL("insert into last(username, seconds, state)"
- " values (%(LUser)s, %(TimeStamp)d, %(Status)s);")];
+ [?SQL("delete from last where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT("last",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "seconds=%(TimeStamp)d",
+ "state=%(Status)s"])];
(_Host, _R) ->
[]
end}].
diff --git a/src/mod_mam_mnesia.erl b/src/mod_mam_mnesia.erl
index f498bc3c7..b672b4107 100644
--- a/src/mod_mam_mnesia.erl
+++ b/src/mod_mam_mnesia.erl
@@ -91,10 +91,10 @@ delete_old_user_messages(User, TimeStamp, Type) ->
ok
end
end,
+ NextRecord = mnesia:dirty_next(archive_msg, User),
case mnesia:transaction(F) of
{atomic, ok} ->
- delete_old_user_messages(mnesia:dirty_next(archive_msg, User),
- TimeStamp, Type);
+ delete_old_user_messages(NextRecord, TimeStamp, Type);
{aborted, Err} ->
?ERROR_MSG("Cannot delete old MAM messages: ~s", [Err]),
Err
diff --git a/src/mod_mam_sql.erl b/src/mod_mam_sql.erl
index 7e02b5791..53ccd94a4 100644
--- a/src/mod_mam_sql.erl
+++ b/src/mod_mam_sql.erl
@@ -38,6 +38,12 @@
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
+-ifdef(NEW_SQL_SCHEMA).
+-define(USE_NEW_SCHEMA, true).
+-else.
+-define(USE_NEW_SCHEMA, false).
+-endif.
+
%%%===================================================================
%%% API
%%%===================================================================
@@ -47,23 +53,32 @@ init(_Host, _Opts) ->
remove_user(LUser, LServer) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from archive where username=%(LUser)s")),
+ ?SQL("delete from archive where username=%(LUser)s and %(LServer)H")),
ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from archive_prefs where username=%(LUser)s")).
+ ?SQL("delete from archive_prefs where username=%(LUser)s and %(LServer)H")).
remove_room(LServer, LName, LHost) ->
LUser = jid:encode({LName, LHost, <<>>}),
remove_user(LUser, LServer).
delete_old_messages(ServerHost, TimeStamp, Type) ->
- TypeClause = if Type == all -> <<"">>;
- true -> [<<" and kind='">>, misc:atom_to_binary(Type), <<"'">>]
- end,
- TS = integer_to_binary(now_to_usec(TimeStamp)),
- ejabberd_sql:sql_query(
- ServerHost, [<<"delete from archive where timestamp<">>,
- TS, TypeClause, <<";">>]),
+ TS = now_to_usec(TimeStamp),
+ case Type of
+ all ->
+ ejabberd_sql:sql_query(
+ ServerHost,
+ ?SQL("delete from archive"
+ " where timestamp < %(TS)d and %(ServerHost)H"));
+ _ ->
+ SType = misc:atom_to_binary(Type),
+ ejabberd_sql:sql_query(
+ ServerHost,
+ ?SQL("delete from archive"
+ " where timestamp < %(TS)d"
+ " and kind=%(SType)s"
+ " and %(ServerHost)H"))
+ end,
ok.
extended_fields() ->
@@ -86,16 +101,17 @@ store(Pkt, LServer, {LUser, LHost}, Type, Peer, Nick, _Dir) ->
SType = misc:atom_to_binary(Type),
case ejabberd_sql:sql_query(
LServer,
- ?SQL("insert into archive (username, timestamp,"
- " peer, bare_peer, xml, txt, kind, nick) values ("
- "%(SUser)s, "
- "%(TSinteger)d, "
- "%(LPeer)s, "
- "%(BarePeer)s, "
- "%(XML)s, "
- "%(Body)s, "
- "%(SType)s, "
- "%(Nick)s)")) of
+ ?SQL_INSERT(
+ "archive",
+ ["username=%(SUser)s",
+ "server_host=%(LServer)s",
+ "timestamp=%(TSinteger)d",
+ "peer=%(LPeer)s",
+ "bare_peer=%(BarePeer)s",
+ "xml=%(XML)s",
+ "txt=%(Body)s",
+ "kind=%(SType)s",
+ "nick=%(Nick)s"])) of
{updated, _} ->
{ok, ID};
Err ->
@@ -113,6 +129,7 @@ write_prefs(LUser, _LServer, #archive_prefs{default = Default,
ServerHost,
"archive_prefs",
["!username=%(LUser)s",
+ "!server_host=%(ServerHost)s",
"def=%(SDefault)s",
"always=%(SAlways)s",
"never=%(SNever)s"]) of
@@ -126,7 +143,7 @@ get_prefs(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(def)s, @(always)s, @(never)s from archive_prefs"
- " where username=%(LUser)s")) of
+ " where username=%(LUser)s and %(LServer)H")) of
{selected, [{SDefault, SAlways, SNever}]} ->
Default = erlang:binary_to_existing_atom(SDefault, utf8),
Always = ejabberd_sql:decode_term(SAlways),
@@ -192,8 +209,13 @@ export(_Server) ->
SDefault = erlang:atom_to_binary(Default, utf8),
SAlways = misc:term_to_expr(Always),
SNever = misc:term_to_expr(Never),
- [?SQL("insert into archive_prefs (username, def, always, never) values"
- "(%(LUser)s, %(SDefault)s, %(SAlways)s, %(SNever)s);")];
+ [?SQL_INSERT(
+ "archive_prefs",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "def=%(SDefault)s",
+ "always=%(SAlways)s",
+ "never=%(SNever)s"])];
(_Host, _R) ->
[]
end},
@@ -212,11 +234,17 @@ export(_Server) ->
XML = fxml:element_to_binary(Pkt),
Body = fxml:get_subtag_cdata(Pkt, <<"body">>),
SType = misc:atom_to_binary(Type),
- [?SQL("insert into archive (username, timestamp, "
- "peer, bare_peer, xml, txt, kind, nick) "
- "values (%(SUser)s, %(TStmp)d, %(LPeer)s, "
- "%(BarePeer)s, %(XML)s, %(Body)s, %(SType)s, "
- "%(Nick)s);")];
+ [?SQL_INSERT(
+ "archive",
+ ["username=%(SUser)s",
+ "server_host=%(LServer)s",
+ "timestamp=%(TStmp)d",
+ "peer=%(LPeer)s",
+ "bare_peer=%(BarePeer)s",
+ "xml=%(XML)s",
+ "txt=%(Body)s",
+ "kind=%(SType)s",
+ "nick=%(Nick)s"])];
(_Host, _R) ->
[]
end}].
@@ -303,11 +331,24 @@ make_sql_query(User, LServer, MAMQuery, RSM) ->
[]
end,
SUser = Escape(User),
+ SServer = Escape(LServer),
- Query = [<<"SELECT ">>, TopClause, <<" timestamp, xml, peer, kind, nick"
- " FROM archive WHERE username='">>,
- SUser, <<"'">>, WithClause, WithTextClause, StartClause, EndClause,
- PageClause],
+ Query =
+ case ?USE_NEW_SCHEMA of
+ true ->
+ [<<"SELECT ">>, TopClause,
+ <<" timestamp, xml, peer, kind, nick"
+ " FROM archive WHERE username='">>,
+ SUser, <<"' and server_host='">>,
+ SServer, <<"'">>, WithClause, WithTextClause,
+ StartClause, EndClause, PageClause];
+ false ->
+ [<<"SELECT ">>, TopClause,
+ <<" timestamp, xml, peer, kind, nick"
+ " FROM archive WHERE username='">>,
+ SUser, <<"'">>, WithClause, WithTextClause,
+ StartClause, EndClause, PageClause]
+ end,
QueryPage =
case Direction of
@@ -322,9 +363,19 @@ make_sql_query(User, LServer, MAMQuery, RSM) ->
[Query, <<" ORDER BY timestamp ASC ">>,
LimitClause, <<";">>]
end,
- {QueryPage,
- [<<"SELECT COUNT(*) FROM archive WHERE username='">>,
- SUser, <<"'">>, WithClause, WithTextClause, StartClause, EndClause, <<";">>]}.
+ case ?USE_NEW_SCHEMA of
+ true ->
+ {QueryPage,
+ [<<"SELECT COUNT(*) FROM archive WHERE username='">>,
+ SUser, <<"' and server_host='">>,
+ SServer, <<"'">>, WithClause, WithTextClause,
+ StartClause, EndClause, <<";">>]};
+ false ->
+ {QueryPage,
+ [<<"SELECT COUNT(*) FROM archive WHERE username='">>,
+ SUser, <<"'">>, WithClause, WithTextClause,
+ StartClause, EndClause, <<";">>]}
+ end.
-spec get_max_direction_id(rsm_set() | undefined) ->
{integer() | undefined,
diff --git a/src/mod_muc.erl b/src/mod_muc.erl
index 1aa48291c..c79cff19b 100644
--- a/src/mod_muc.erl
+++ b/src/mod_muc.erl
@@ -39,6 +39,7 @@
reload/3,
room_destroyed/4,
store_room/4,
+ store_room/5,
restore_room/3,
forget_room/3,
create_room/5,
@@ -88,7 +89,7 @@
-type muc_room_opts() :: [{atom(), any()}].
-callback init(binary(), gen_mod:opts()) -> any().
-callback import(binary(), binary(), [binary()]) -> ok.
--callback store_room(binary(), binary(), binary(), list()) -> {atomic, any()}.
+-callback store_room(binary(), binary(), binary(), list(), list()|undefined) -> {atomic, any()}.
-callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error.
-callback forget_room(binary(), binary(), binary()) -> {atomic, any()}.
-callback can_use_nick(binary(), binary(), jid(), binary()) -> boolean().
@@ -105,6 +106,8 @@
-callback unregister_online_user(binary(), ljid(), binary(), binary()) -> any().
-callback count_online_rooms_by_user(binary(), binary(), binary()) -> non_neg_integer().
-callback get_online_rooms_by_user(binary(), binary(), binary()) -> [{binary(), binary()}].
+-callback get_subscribed_rooms(binary(), binary(), jid()) ->
+ {ok, [{ljid(), binary(), [binary()]}]} | {error, any()}.
%%====================================================================
%% API
@@ -157,9 +160,12 @@ create_room(Host, Name, From, Nick, Opts) ->
gen_server:call(Proc, {create, Name, Host, From, Nick, Opts}).
store_room(ServerHost, Host, Name, Opts) ->
+ store_room(ServerHost, Host, Name, Opts, undefined).
+
+store_room(ServerHost, Host, Name, Opts, ChangesHints) ->
LServer = jid:nameprep(ServerHost),
Mod = gen_mod:db_mod(LServer, ?MODULE),
- Mod:store_room(LServer, Host, Name, Opts).
+ Mod:store_room(LServer, Host, Name, Opts, ChangesHints).
restore_room(ServerHost, Host, Name) ->
LServer = jid:nameprep(ServerHost),
@@ -696,17 +702,24 @@ get_room_disco_item({Name, Host, Pid}, Query) ->
end.
get_subscribed_rooms(ServerHost, Host, From) ->
- Rooms = get_online_rooms(ServerHost, Host),
+ LServer = jid:nameprep(ServerHost),
+ Mod = gen_mod:db_mod(LServer, ?MODULE),
BareFrom = jid:remove_resource(From),
- lists:flatmap(
- fun({Name, _, Pid}) ->
- case p1_fsm:sync_send_all_state_event(Pid, {is_subscribed, BareFrom}) of
- true -> [jid:make(Name, Host)];
- false -> []
- end;
- (_) ->
- []
- end, Rooms).
+ case Mod:get_subscribed_rooms(LServer, Host, BareFrom) of
+ not_implemented ->
+ Rooms = get_online_rooms(ServerHost, Host),
+ lists:flatmap(
+ fun({Name, _, Pid}) ->
+ case p1_fsm:sync_send_all_state_event(Pid, {is_subscribed, BareFrom}) of
+ true -> [jid:make(Name, Host)];
+ false -> []
+ end;
+ (_) ->
+ []
+ end, Rooms);
+ V ->
+ V
+ end.
get_nick(ServerHost, Host, From) ->
LServer = jid:nameprep(ServerHost),
diff --git a/src/mod_muc_mnesia.erl b/src/mod_muc_mnesia.erl
index 015c5ec43..aa59038c9 100644
--- a/src/mod_muc_mnesia.erl
+++ b/src/mod_muc_mnesia.erl
@@ -28,12 +28,13 @@
-behaviour(mod_muc_room).
%% API
--export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
+-export([init/2, import/3, store_room/5, restore_room/3, forget_room/3,
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
register_online_user/4, unregister_online_user/4,
- count_online_rooms_by_user/3, get_online_rooms_by_user/3]).
+ count_online_rooms_by_user/3, get_online_rooms_by_user/3,
+ get_subscribed_rooms/3]).
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
get_affiliations/3, search_affiliation/4]).
%% gen_server callbacks
@@ -63,7 +64,7 @@ start_link(Host, Opts) ->
Name = gen_mod:get_module_proc(Host, ?MODULE),
gen_server:start_link({local, Name}, ?MODULE, [Host, Opts], []).
-store_room(_LServer, Host, Name, Opts) ->
+store_room(_LServer, Host, Name, Opts, _) ->
F = fun () ->
mnesia:write(#muc_room{name_host = {Name, Host},
opts = Opts})
@@ -397,3 +398,6 @@ transform(#muc_registered{us_host = {{U, S}, H}, nick = Nick} = R) ->
R#muc_registered{us_host = {{iolist_to_binary(U), iolist_to_binary(S)},
iolist_to_binary(H)},
nick = iolist_to_binary(Nick)}.
+
+get_subscribed_rooms(_, _, _) ->
+ not_implemented.
diff --git a/src/mod_muc_riak.erl b/src/mod_muc_riak.erl
index 42e644fdd..57d9666bf 100644
--- a/src/mod_muc_riak.erl
+++ b/src/mod_muc_riak.erl
@@ -28,12 +28,13 @@
-behaviour(mod_muc_room).
%% API
--export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
+-export([init/2, import/3, store_room/5, restore_room/3, forget_room/3,
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
register_online_user/4, unregister_online_user/4,
- count_online_rooms_by_user/3, get_online_rooms_by_user/3]).
+ count_online_rooms_by_user/3, get_online_rooms_by_user/3,
+ get_subscribed_rooms/3]).
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
get_affiliations/3, search_affiliation/4]).
@@ -46,7 +47,7 @@
init(_Host, _Opts) ->
ok.
-store_room(_LServer, Host, Name, Opts) ->
+store_room(_LServer, Host, Name, Opts, _) ->
{atomic, ejabberd_riak:put(#muc_room{name_host = {Name, Host},
opts = Opts},
muc_room_schema())}.
@@ -183,6 +184,9 @@ import(_LServer, <<"muc_registered">>,
ejabberd_riak:put(R, muc_registered_schema(),
[{'2i', [{<<"nick_host">>, {Nick, RoomHost}}]}]).
+get_subscribed_rooms(_, _, _) ->
+ not_implemented.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index e06c20683..7e71c6904 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -1241,7 +1241,7 @@ get_error_condition(undefined) ->
-spec get_error_text(stanza_error()) -> binary().
get_error_text(#stanza_error{text = Txt}) ->
- xmpp:get_text([Txt]).
+ xmpp:get_text(Txt).
-spec make_reason(stanza(), jid(), state(), binary()) -> binary().
make_reason(Packet, From, StateData, Reason1) ->
@@ -1260,8 +1260,16 @@ expulse_participant(Packet, From, StateData, Reason1) ->
LJID = jid:tolower(From),
{ok, #user{nick = Nick}} = (?DICT):find(LJID, StateData#state.users),
case (?DICT):find(Nick, StateData#state.nicks) of
- {ok, [_, _ | _]} -> ok;
- _ -> send_new_presence(From, NewState, StateData)
+ {ok, [_, _ | _]} ->
+ Aff = get_affiliation(From, StateData),
+ Item = #muc_item{affiliation = Aff, role = none, jid = From},
+ Pres = xmpp:set_subtag(
+ Packet, #muc_user{items = [Item],
+ status_codes = [110]}),
+ send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
+ From, Pres, ?NS_MUCSUB_NODES_PRESENCE, StateData);
+ _ ->
+ send_new_presence(From, NewState, StateData)
end,
remove_online_user(From, NewState).
@@ -1616,7 +1624,13 @@ set_subscriber(JID, Nick, Nodes, StateData) ->
Nicks = ?DICT:store(Nick, [LBareJID], StateData#state.subscriber_nicks),
NewStateData = StateData#state{subscribers = Subscribers,
subscriber_nicks = Nicks},
- store_room(NewStateData),
+ store_room(NewStateData, [{add_subscription, BareJID, Nick, Nodes}]),
+ case not ?DICT:is_key(LBareJID, StateData#state.subscribers) of
+ true ->
+ send_subscriptions_change_notifications(BareJID, Nick, subscribe, NewStateData);
+ _ ->
+ ok
+ end,
NewStateData.
-spec add_online_user(jid(), binary(), role(), state()) -> state().
@@ -2716,7 +2730,7 @@ find_changed_items(UJID, UAffiliation, URole,
[#muc_item{jid = J, nick = Nick, reason = Reason,
role = Role, affiliation = Affiliation}|Items],
Lang, StateData, Res) ->
- [JID | _] = JIDs =
+ [JID | _] = JIDs =
if J /= undefined ->
[J];
Nick /= <<"">> ->
@@ -3321,8 +3335,7 @@ change_config(Config, StateData) ->
Config#config.persistent}
of
{_, true} ->
- mod_muc:store_room(NSD#state.server_host,
- NSD#state.host, NSD#state.room, make_opts(NSD));
+ store_room(NSD);
{true, false} ->
mod_muc:forget_room(NSD#state.server_host,
NSD#state.host, NSD#state.room);
@@ -3786,7 +3799,8 @@ process_iq_mucsub(From, #iq{type = set, sub_els = [#muc_unsubscribe{}]},
Subscribers = ?DICT:erase(LBareJID, StateData#state.subscribers),
NewStateData = StateData#state{subscribers = Subscribers,
subscriber_nicks = Nicks},
- store_room(NewStateData),
+ store_room(NewStateData, [{del_subscription, LBareJID}]),
+ send_subscriptions_change_notifications(LBareJID, Nick, unsubscribe, StateData),
NewStateData2 = case close_room_if_temporary_and_empty(NewStateData) of
{stop, normal, _} -> stop;
{next_state, normal_state, SD} -> SD
@@ -3831,7 +3845,8 @@ get_subscription_nodes(#iq{sub_els = [#muc_subscribe{events = Nodes}]}) ->
?NS_MUCSUB_NODES_AFFILIATIONS,
?NS_MUCSUB_NODES_SUBJECT,
?NS_MUCSUB_NODES_CONFIG,
- ?NS_MUCSUB_NODES_PARTICIPANTS])
+ ?NS_MUCSUB_NODES_PARTICIPANTS,
+ ?NS_MUCSUB_NODES_SUBSCRIBERS])
end, Nodes);
get_subscription_nodes(_) ->
[].
@@ -4052,14 +4067,51 @@ element_size(El) ->
-spec store_room(state()) -> ok.
store_room(StateData) ->
+ store_room(StateData, []).
+store_room(StateData, ChangesHints) ->
if (StateData#state.config)#config.persistent ->
mod_muc:store_room(StateData#state.server_host,
StateData#state.host, StateData#state.room,
- make_opts(StateData));
+ make_opts(StateData),
+ ChangesHints);
true ->
ok
end.
+-spec send_subscriptions_change_notifications(jid(), binary(), subscribe|unsubscribe, state()) -> ok.
+send_subscriptions_change_notifications(From, Nick, Type, State) ->
+ ?DICT:fold(fun(_, #subscriber{nodes = Nodes, jid = JID}, _) ->
+ case lists:member(?NS_MUCSUB_NODES_SUBSCRIBERS, Nodes) of
+ true ->
+ ShowJid = case (State#state.config)#config.anonymous == false orelse
+ get_role(JID, State) == moderator orelse
+ get_default_role(get_affiliation(JID, State), State) == moderator of
+ true -> true;
+ _ -> false
+ end,
+ Payload = case {Type, ShowJid} of
+ {subscribe, true} ->
+ #muc_subscribe{jid = From, nick = Nick};
+ {subscribe, _} ->
+ #muc_subscribe{nick = Nick};
+ {unsubscribe, true} ->
+ #muc_unsubscribe{jid = From, nick = Nick};
+ {unsubscribe, _} ->
+ #muc_unsubscribe{nick = Nick}
+ end,
+ Packet = #message{
+ sub_els = [#ps_event{
+ items = #ps_items{
+ node = ?NS_MUCSUB_NODES_SUBSCRIBERS,
+ items = [#ps_item{
+ id = randoms:get_string(),
+ xml_els = [xmpp:encode(Payload)]}]}}]},
+ ejabberd_router:route(xmpp:set_from_to(Packet, From, JID));
+ false ->
+ ok
+ end
+ end, ok, State#state.subscribers).
+
-spec send_wrapped(jid(), jid(), stanza(), binary(), state()) -> ok.
send_wrapped(From, To, Packet, Node, State) ->
LTo = jid:tolower(To),
diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl
index 94d5706b8..41ad92bf9 100644
--- a/src/mod_muc_sql.erl
+++ b/src/mod_muc_sql.erl
@@ -30,13 +30,14 @@
-behaviour(mod_muc_room).
%% API
--export([init/2, store_room/4, restore_room/3, forget_room/3,
+-export([init/2, store_room/5, restore_room/3, forget_room/3,
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
import/3, export/1]).
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
register_online_user/4, unregister_online_user/4,
- count_online_rooms_by_user/3, get_online_rooms_by_user/3]).
+ count_online_rooms_by_user/3, get_online_rooms_by_user/3,
+ get_subscribed_rooms/3]).
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
get_affiliations/3, search_affiliation/4]).
@@ -56,24 +57,79 @@ init(Host, Opts) ->
ok
end.
-store_room(LServer, Host, Name, Opts) ->
- SOpts = misc:term_to_expr(Opts),
+store_room(LServer, Host, Name, Opts, ChangesHints) ->
+ {Subs, Opts2} = case lists:keytake(subscribers, 1, Opts) of
+ {value, {subscribers, S}, OptN} -> {S, OptN};
+ _ -> {[], Opts}
+ end,
+ SOpts = misc:term_to_expr(Opts2),
F = fun () ->
?SQL_UPSERT_T(
"muc_room",
["!name=%(Name)s",
"!host=%(Host)s",
- "opts=%(SOpts)s"])
+ "server_host=%(LServer)s",
+ "opts=%(SOpts)s"]),
+ case ChangesHints of
+ Changes when is_list(Changes) ->
+ [change_room(Host, Name, Change) || Change <- Changes];
+ _ ->
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from muc_room_subscribers where "
+ "room=%(Name)s and host=%(Host)s")),
+ [change_room(Host, Name, {add_subscription, JID, Nick, Nodes})
+ || {JID, Nick, Nodes} <- Subs]
+ end
end,
ejabberd_sql:sql_transaction(LServer, F).
+change_room(Host, Room, {add_subscription, JID, Nick, Nodes}) ->
+ SJID = jid:encode(JID),
+ SNodes = misc:term_to_expr(Nodes),
+ ?SQL_UPSERT_T(
+ "muc_room_subscribers",
+ ["!jid=%(SJID)s",
+ "!host=%(Host)s",
+ "!room=%(Room)s",
+ "nick=%(Nick)s",
+ "nodes=%(SNodes)s"]);
+change_room(Host, Room, {del_subscription, JID}) ->
+ SJID = jid:encode(JID),
+ ejabberd_sql:sql_query_t(?SQL("delete from muc_room_subscribers where "
+ "room=%(Room)s and host=%(Host)s and jid=%(SJID)s"));
+change_room(Host, Room, Change) ->
+ ?ERROR_MSG("Unsupported change on room ~s@~s: ~p", [Room, Host, Change]).
+
restore_room(LServer, Host, Name) ->
case catch ejabberd_sql:sql_query(
LServer,
?SQL("select @(opts)s from muc_room where name=%(Name)s"
" and host=%(Host)s")) of
{selected, [{Opts}]} ->
- mod_muc:opts_to_binary(ejabberd_sql:decode_term(Opts));
+ OptsD = ejabberd_sql:decode_term(Opts),
+ case catch ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(jid)s, @(nick)s, @(nodes)s from muc_room_subscribers where name=%(Name)s"
+ " and host=%(Host)s")) of
+ {selected, []} ->
+ OptsR = mod_muc:opts_to_binary(OptsD),
+ case lists:keymember(subscribers, 1, OptsD) of
+ true ->
+ store_room(LServer, Host, Name, OptsR, undefined);
+ _ ->
+ ok
+ end,
+ OptsR;
+ {selected, Subs} ->
+ SubData = lists:map(
+ fun({Jid, Nick, Nodes}) ->
+ {jid:decode(Jid), Nick, ejabberd_sql:decode_term(Nodes)}
+ end, Subs),
+ Opts2 = lists:keystore(subscribers, 1, OptsD, {subscribers, SubData}),
+ mod_muc:opts_to_binary(Opts2);
+ _ ->
+ error
+ end;
_ ->
error
end.
@@ -82,6 +138,9 @@ forget_room(LServer, Host, Name) ->
F = fun () ->
ejabberd_sql:sql_query_t(
?SQL("delete from muc_room where name=%(Name)s"
+ " and host=%(Host)s")),
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from muc_room_subscribers where room=%(Name)s"
" and host=%(Host)s"))
end,
ejabberd_sql:sql_transaction(LServer, F).
@@ -103,13 +162,36 @@ get_rooms(LServer, Host) ->
?SQL("select @(name)s, @(opts)s from muc_room"
" where host=%(Host)s")) of
{selected, RoomOpts} ->
+ case catch ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(room)s, @(jid)s, @(nick)s, @(nodes)s from muc_room_subscribers"
+ " where host=%(Host)s")) of
+ {selected, Subs} ->
+ SubsD = lists:foldl(
+ fun({Room, Jid, Nick, Nodes}, Dict) ->
+ dict:append(Room, {jid:decode(Jid),
+ Nick, ejabberd_sql:decode_term(Nodes)}, Dict)
+ end, dict:new(), Subs),
lists:map(
fun({Room, Opts}) ->
+ OptsD = ejabberd_sql:decode_term(Opts),
+ OptsD2 = case {dict:find(Room, SubsD), lists:keymember(subscribers, 1, OptsD)} of
+ {_, true} ->
+ store_room(LServer, Host, Room, mod_muc:opts_to_binary(OptsD), undefined),
+ OptsD;
+ {{ok, SubsI}, false} ->
+ lists:keystore(subscribers, 1, OptsD, {subscribers, SubsI});
+ _ ->
+ OptsD
+ end,
#muc_room{name_host = {Room, Host},
- opts = mod_muc:opts_to_binary(
- ejabberd_sql:decode_term(Opts))}
+ opts = mod_muc:opts_to_binary(OptsD2)}
end, RoomOpts);
Err ->
+ ?ERROR_MSG("failed to get rooms subscribers: ~p", [Err]),
+ []
+ end;
+ Err ->
?ERROR_MSG("failed to get rooms: ~p", [Err]),
[]
end.
@@ -146,6 +228,7 @@ set_nick(LServer, Host, From, Nick) ->
"muc_registered",
["!jid=%(JID)s",
"!host=%(Host)s",
+ "server_host=%(LServer)s",
"nick=%(Nick)s"]),
ok;
true ->
@@ -177,6 +260,7 @@ register_online_room(ServerHost, Room, Host, Pid) ->
"muc_online_room",
["!name=%(Room)s",
"!host=%(Host)s",
+ "server_host=%(ServerHost)s",
"node=%(NodeS)s",
"pid=%(PidS)s"]) of
ok ->
@@ -251,6 +335,7 @@ register_online_user(ServerHost, {U, S, R}, Room, Host) ->
"!resource=%(R)s",
"!name=%(Room)s",
"!host=%(Host)s",
+ "server_host=%(ServerHost)s",
"node=%(NodeS)s"]) of
ok ->
ok;
@@ -299,9 +384,12 @@ export(_Server) ->
SOpts = misc:term_to_expr(Opts),
[?SQL("delete from muc_room where name=%(Name)s"
" and host=%(RoomHost)s;"),
- ?SQL("insert into muc_room(name, host, opts) "
- "values ("
- "%(Name)s, %(RoomHost)s, %(SOpts)s);")];
+ ?SQL_INSERT(
+ "muc_room",
+ ["name=%(Name)s",
+ "host=%(Host)s",
+ "server_host=%(Host)s",
+ "opts=%(SOpts)s"])];
false ->
[]
end
@@ -314,9 +402,12 @@ export(_Server) ->
SJID = jid:encode(jid:make(U, S)),
[?SQL("delete from muc_registered where"
" jid=%(SJID)s and host=%(RoomHost)s;"),
- ?SQL("insert into muc_registered(jid, host, "
- "nick) values ("
- "%(SJID)s, %(RoomHost)s, %(Nick)s);")];
+ ?SQL_INSERT(
+ "muc_registered",
+ ["jid=%(SJID)s",
+ "host=%(Host)s",
+ "server_host=%(Host)s",
+ "nick=%(Nick)s"])];
false ->
[]
end
@@ -325,6 +416,19 @@ export(_Server) ->
import(_, _, _) ->
ok.
+get_subscribed_rooms(LServer, Host, Jid) ->
+ JidS = jid:encode(Jid),
+ case catch ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(room)s from muc_room_subscribers where jid=%(JidS)s"
+ " and host=%(Host)s")) of
+ {selected, Subs} ->
+ [jid:make(Room, Host, <<>>) || {Room} <- Subs];
+ Error ->
+ ?ERROR_MSG("Error when fetching subscribed rooms ~p", [Error]),
+ []
+ end.
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
diff --git a/src/mod_offline_sql.erl b/src/mod_offline_sql.erl
index f43f4c929..53a0d3451 100644
--- a/src/mod_offline_sql.erl
+++ b/src/mod_offline_sql.erl
@@ -56,8 +56,11 @@ store_message(#offline_msg{us = {LUser, LServer}} = M) ->
xmpp:encode(NewPacket)),
case ejabberd_sql:sql_query(
LServer,
- ?SQL("insert into spool(username, xml) values "
- "(%(LUser)s, %(XML)s)")) of
+ ?SQL_INSERT(
+ "spool",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "xml=%(XML)s"])) of
{updated, _} ->
ok;
_ ->
@@ -87,10 +90,8 @@ remove_expired_messages(_LServer) ->
remove_old_messages(Days, LServer) ->
case ejabberd_sql:sql_query(
LServer,
- [<<"DELETE FROM spool"
- " WHERE created_at < "
- "NOW() - INTERVAL '">>,
- integer_to_list(Days), <<"' DAY;">>]) of
+ ?SQL("DELETE FROM spool"
+ " WHERE created_at < NOW() - INTERVAL %(Days)d DAY")) of
{updated, N} ->
?INFO_MSG("~p message(s) deleted from offline spool", [N]);
_Error ->
@@ -101,13 +102,13 @@ remove_old_messages(Days, LServer) ->
remove_user(LUser, LServer) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from spool where username=%(LUser)s")).
+ ?SQL("delete from spool where username=%(LUser)s and %(LServer)H")).
read_message_headers(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(xml)s, @(seq)d from spool"
- " where username=%(LUser)s order by seq")) of
+ " where username=%(LUser)s and %(LServer)H order by seq")) of
{selected, Rows} ->
lists:flatmap(
fun({XML, Seq}) ->
@@ -129,6 +130,7 @@ read_message(LUser, LServer, Seq) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(xml)s from spool where username=%(LUser)s"
+ " and %(LServer)H"
" and seq=%(Seq)d")) of
{selected, [{RawXML}|_]} ->
case xml_to_offline_msg(RawXML) of
@@ -144,7 +146,7 @@ read_message(LUser, LServer, Seq) ->
remove_message(LUser, LServer, Seq) ->
ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from spool where username=%(LUser)s"
+ ?SQL("delete from spool where username=%(LUser)s and %(LServer)H"
" and seq=%(Seq)d")),
ok.
@@ -152,7 +154,7 @@ read_all_messages(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(xml)s from spool where "
- "username=%(LUser)s order by seq")) of
+ "username=%(LUser)s and %(LServer)H order by seq")) of
{selected, Rs} ->
lists:flatmap(
fun({XML}) ->
@@ -173,7 +175,7 @@ count_messages(LUser, LServer) ->
case catch ejabberd_sql:sql_query(
LServer,
?SQL("select @(count(*))d from spool "
- "where username=%(LUser)s")) of
+ "where username=%(LUser)s and %(LServer)H")) of
{selected, [{Res}]} ->
Res;
_ -> 0
@@ -183,7 +185,8 @@ export(_Server) ->
[{offline_msg,
fun(Host, #offline_msg{us = {LUser, LServer}})
when LServer == Host ->
- [?SQL("delete from spool where username=%(LUser)s;")];
+ [?SQL("delete from spool where username=%(LUser)s"
+ " and %(LServer)H;")];
(_Host, _R) ->
[]
end},
@@ -199,8 +202,11 @@ export(_Server) ->
Packet1, jid:make(LServer),
TimeStamp, <<"Offline Storage">>),
XML = fxml:element_to_binary(xmpp:encode(Packet2)),
- [?SQL("insert into spool(username, xml) values ("
- "%(LUser)s, %(XML)s);")]
+ [?SQL_INSERT(
+ "spool",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "xml=%(XML)s"])]
catch _:{xmpp_codec, Why} ->
?ERROR_MSG("failed to decode packet ~p of user ~s@~s: ~s",
[El, LUser, LServer, xmpp:format_error(Why)]),
@@ -249,9 +255,10 @@ get_and_del_spool_msg_t(LServer, LUser) ->
Result =
ejabberd_sql:sql_query_t(
?SQL("select @(username)s, @(xml)s from spool where "
- "username=%(LUser)s order by seq;")),
+ "username=%(LUser)s and %(LServer)H order by seq;")),
ejabberd_sql:sql_query_t(
- ?SQL("delete from spool where username=%(LUser)s;")),
+ ?SQL("delete from spool where"
+ " username=%(LUser)s and %(LServer)H;")),
Result
end,
ejabberd_sql:sql_transaction(LServer, F).
diff --git a/src/mod_privacy_sql.erl b/src/mod_privacy_sql.erl
index b19c95fe5..7939cbb26 100644
--- a/src/mod_privacy_sql.erl
+++ b/src/mod_privacy_sql.erl
@@ -56,13 +56,13 @@ unset_default(LUser, LServer) ->
set_default(LUser, LServer, Name) ->
F = fun () ->
- case get_privacy_list_names_t(LUser) of
+ case get_privacy_list_names_t(LUser, LServer) of
{selected, []} ->
{error, notfound};
{selected, Names} ->
case lists:member({Name}, Names) of
true ->
- set_default_privacy_list(LUser, Name);
+ set_default_privacy_list(LUser, LServer, Name);
false ->
{error, notfound}
end
@@ -72,14 +72,14 @@ set_default(LUser, LServer, Name) ->
remove_list(LUser, LServer, Name) ->
F = fun () ->
- case get_default_privacy_list_t(LUser) of
+ case get_default_privacy_list_t(LUser, LServer) of
{selected, []} ->
- remove_privacy_list_t(LUser, Name);
+ remove_privacy_list_t(LUser, LServer, Name);
{selected, [{Default}]} ->
if Name == Default ->
{error, conflict};
true ->
- remove_privacy_list_t(LUser, Name)
+ remove_privacy_list_t(LUser, LServer, Name)
end
end
end,
@@ -91,13 +91,14 @@ set_lists(#privacy{us = {LUser, LServer},
F = fun() ->
lists:foreach(
fun({Name, List}) ->
- add_privacy_list(LUser, Name),
+ add_privacy_list(LUser, LServer, Name),
{selected, [<<"id">>], [[I]]} =
- get_privacy_list_id_t(LUser, Name),
+ get_privacy_list_id_t(LUser, LServer, Name),
RItems = lists:map(fun item_to_raw/1, List),
set_privacy_list(I, RItems),
if is_binary(Default) ->
- set_default_privacy_list(LUser, Default);
+ set_default_privacy_list(
+ LUser, LServer, Default);
true ->
ok
end
@@ -108,11 +109,11 @@ set_lists(#privacy{us = {LUser, LServer},
set_list(LUser, LServer, Name, List) ->
RItems = lists:map(fun item_to_raw/1, List),
F = fun () ->
- ID = case get_privacy_list_id_t(LUser, Name) of
+ ID = case get_privacy_list_id_t(LUser, LServer, Name) of
{selected, []} ->
- add_privacy_list(LUser, Name),
+ add_privacy_list(LUser, LServer, Name),
{selected, [{I}]} =
- get_privacy_list_id_t(LUser, Name),
+ get_privacy_list_id_t(LUser, LServer, Name),
I;
{selected, [{I}]} -> I
end,
@@ -199,9 +200,12 @@ export(Server) ->
when LServer == Host ->
if Default /= none ->
[?SQL("delete from privacy_default_list where"
- " username=%(LUser)s;"),
- ?SQL("insert into privacy_default_list(username, name) "
- "values (%(LUser)s, %(Default)s);")];
+ " username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "privacy_default_list",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "name=%(Default)s"])];
true ->
[]
end ++
@@ -210,11 +214,14 @@ export(Server) ->
RItems = lists:map(fun item_to_raw/1, List),
ID = get_id(),
[?SQL("delete from privacy_list where"
- " username=%(LUser)s and"
+ " username=%(LUser)s and %(LServer)H and"
" name=%(Name)s;"),
- ?SQL("insert into privacy_list(username, "
- "name, id) values ("
- "%(LUser)s, %(Name)s, %(ID)d);"),
+ ?SQL_INSERT(
+ "privacy_list",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "name=%(Name)s",
+ "id=%(ID)d"]),
?SQL("delete from privacy_list_data where"
" id=%(ID)d;")] ++
[?SQL("insert into privacy_list_data(id, t, "
@@ -312,28 +319,28 @@ get_default_privacy_list(LUser, LServer) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(name)s from privacy_default_list "
- "where username=%(LUser)s")).
+ "where username=%(LUser)s and %(LServer)H")).
-get_default_privacy_list_t(LUser) ->
+get_default_privacy_list_t(LUser, LServer) ->
ejabberd_sql:sql_query_t(
?SQL("select @(name)s from privacy_default_list "
- "where username=%(LUser)s")).
+ "where username=%(LUser)s and %(LServer)H")).
get_privacy_list_names(LUser, LServer) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(name)s from privacy_list"
- " where username=%(LUser)s")).
+ " where username=%(LUser)s and %(LServer)H")).
-get_privacy_list_names_t(LUser) ->
+get_privacy_list_names_t(LUser, LServer) ->
ejabberd_sql:sql_query_t(
?SQL("select @(name)s from privacy_list"
- " where username=%(LUser)s")).
+ " where username=%(LUser)s and %(LServer)H")).
-get_privacy_list_id_t(LUser, Name) ->
+get_privacy_list_id_t(LUser, LServer, Name) ->
ejabberd_sql:sql_query_t(
?SQL("select @(id)d from privacy_list"
- " where username=%(LUser)s and name=%(Name)s")).
+ " where username=%(LUser)s and %(LServer)H and name=%(Name)s")).
get_privacy_list_data(LUser, LServer, Name) ->
ejabberd_sql:sql_query(
@@ -343,37 +350,41 @@ get_privacy_list_data(LUser, LServer, Name) ->
"@(match_presence_out)b from privacy_list_data "
"where id ="
" (select id from privacy_list"
- " where username=%(LUser)s and name=%(Name)s) "
+ " where username=%(LUser)s and %(LServer)H and name=%(Name)s) "
"order by ord")).
-set_default_privacy_list(LUser, Name) ->
+set_default_privacy_list(LUser, LServer, Name) ->
?SQL_UPSERT_T(
"privacy_default_list",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"name=%(Name)s"]).
unset_default_privacy_list(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("delete from privacy_default_list"
- " where username=%(LUser)s")) of
+ " where username=%(LUser)s and %(LServer)H")) of
{updated, _} -> ok;
Err -> Err
end.
-remove_privacy_list_t(LUser, Name) ->
+remove_privacy_list_t(LUser, LServer, Name) ->
case ejabberd_sql:sql_query_t(
?SQL("delete from privacy_list where"
- " username=%(LUser)s and name=%(Name)s")) of
+ " username=%(LUser)s and %(LServer)H and name=%(Name)s")) of
{updated, 0} -> {error, notfound};
{updated, _} -> ok;
Err -> Err
end.
-add_privacy_list(LUser, Name) ->
+add_privacy_list(LUser, LServer, Name) ->
ejabberd_sql:sql_query_t(
- ?SQL("insert into privacy_list(username, name) "
- "values (%(LUser)s, %(Name)s)")).
+ ?SQL_INSERT(
+ "privacy_list",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "name=%(Name)s"])).
set_privacy_list(ID, RItems) ->
ejabberd_sql:sql_query_t(
@@ -395,12 +406,12 @@ set_privacy_list(ID, RItems) ->
del_privacy_lists(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from privacy_list where username=%(LUser)s")) of
+ ?SQL("delete from privacy_list where username=%(LUser)s and %(LServer)H")) of
{updated, _} ->
case ejabberd_sql:sql_query(
LServer,
?SQL("delete from privacy_default_list "
- "where username=%(LUser)s")) of
+ "where username=%(LUser)s and %(LServer)H")) of
{updated, _} -> ok;
Err -> Err
end;
diff --git a/src/mod_private_sql.erl b/src/mod_private_sql.erl
index 907eeaf3a..5ed584c30 100644
--- a/src/mod_private_sql.erl
+++ b/src/mod_private_sql.erl
@@ -49,6 +49,7 @@ set_data(LUser, LServer, Data) ->
?SQL_UPSERT_T(
"private_storage",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"!namespace=%(XMLNS)s",
"data=%(SData)s"])
end, Data)
@@ -64,7 +65,8 @@ get_data(LUser, LServer, XMLNS) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(data)s from private_storage"
- " where username=%(LUser)s and namespace=%(XMLNS)s")) of
+ " where username=%(LUser)s and %(LServer)H"
+ " and namespace=%(XMLNS)s")) of
{selected, [{SData}]} ->
parse_element(LUser, LServer, SData);
{selected, []} ->
@@ -77,7 +79,7 @@ get_all_data(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(namespace)s, @(data)s from private_storage"
- " where username=%(LUser)s")) of
+ " where username=%(LUser)s and %(LServer)H")) of
{selected, []} ->
error;
{selected, Res} ->
@@ -95,7 +97,8 @@ get_all_data(LUser, LServer) ->
del_data(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
- ?SQL("delete from private_storage where username=%(LUser)s")) of
+ ?SQL("delete from private_storage"
+ " where username=%(LUser)s and %(LServer)H")) of
{updated, _} ->
ok;
_ ->
@@ -109,10 +112,13 @@ export(_Server) ->
when LServer == Host ->
SData = fxml:element_to_binary(Data),
[?SQL("delete from private_storage where"
- " username=%(LUser)s and namespace=%(XMLNS)s;"),
- ?SQL("insert into private_storage(username, "
- "namespace, data) values ("
- "%(LUser)s, %(XMLNS)s, %(SData)s);")];
+ " username=%(LUser)s and %(LServer)H and namespace=%(XMLNS)s;"),
+ ?SQL_INSERT(
+ "private_storage",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "namespace=%(XMLNS)s",
+ "data=%(SData)s"])];
(_Host, _R) ->
[]
end}].
diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl
index 0f344cc18..e065bdaae 100644
--- a/src/mod_pubsub.erl
+++ b/src/mod_pubsub.erl
@@ -89,7 +89,7 @@
%% API and gen_server callbacks
-export([start/2, stop/1, init/1,
handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3, depends/2, export/1, mod_opt_type/1]).
+ terminate/2, code_change/3, depends/2, mod_opt_type/1]).
%%====================================================================
%% API
@@ -447,10 +447,7 @@ disco_identity(Host, Node, From) ->
{result, _} ->
{result, [#identity{category = <<"pubsub">>, type = <<"pep">>},
#identity{category = <<"pubsub">>, type = <<"leaf">>,
- name = case get_option(Options, title) of
- false -> <<>>;
- Title -> Title
- end}]};
+ name = get_option(Options, title, <<>>)}]};
_ ->
{result, []}
end
@@ -514,10 +511,7 @@ disco_items(Host, <<>>, From) ->
{result, _} ->
[#disco_item{node = Node,
jid = jid:make(Host),
- name = case get_option(Options, title) of
- false -> <<>>;
- Title -> Title
- end} | Acc];
+ name = get_option(Options, title, <<>>)} | Acc];
_ ->
Acc
end
@@ -829,7 +823,8 @@ process_disco_info(#iq{from = From, to = To, lang = Lang, type = get,
[ServerHost, ?MODULE, <<>>, <<>>]),
case iq_disco_info(Host, Node, From, Lang) of
{result, IQRes} ->
- xmpp:make_iq_result(IQ, IQRes#disco_info{node = Node, xdata = Info});
+ XData = IQRes#disco_info.xdata ++ Info,
+ xmpp:make_iq_result(IQ, IQRes#disco_info{node = Node, xdata = XData});
{error, Error} ->
xmpp:make_error(IQ, Error)
end.
@@ -938,14 +933,25 @@ node_disco_info(Host, Node, From) ->
{result, disco_info()} | {error, stanza_error()}.
node_disco_info(Host, Node, _From, _Identity, _Features) ->
Action =
- fun(#pubsub_node{type = Type, options = Options}) ->
+ fun(#pubsub_node{id = Nidx, type = Type, options = Options}) ->
NodeType = case get_option(Options, node_type) of
collection -> <<"collection">>;
_ -> <<"leaf">>
end,
+ Affs = case node_call(Host, Type, get_node_affiliations, [Nidx]) of
+ {result, Result} -> Result;
+ _ -> []
+ end,
+ Meta = [{title, get_option(Options, title, <<>>)},
+ {description, get_option(Options, description, <<>>)},
+ {owner, [jid:make(LJID) || {LJID, Aff} <- Affs, Aff =:= owner]},
+ {publisher, [jid:make(LJID) || {LJID, Aff} <- Affs, Aff =:= publisher]},
+ {num_subscribers, length([LJID || {LJID, Aff} <- Affs, Aff =:= subscriber])}],
+ XData = #xdata{type = result,
+ fields = pubsub_meta_data:encode(Meta)},
Is = [#identity{category = <<"pubsub">>, type = NodeType}],
Fs = [?NS_PUBSUB | [feature(F) || F <- plugin_features(Host, Type)]],
- {result, #disco_info{identities = Is, features = Fs}}
+ {result, #disco_info{identities = Is, features = Fs, xdata = [XData]}}
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> {result, Result};
@@ -1562,6 +1568,7 @@ delete_node(Host, Node, Owner) ->
RNidx = RNode#pubsub_node.id,
RType = RNode#pubsub_node.type,
ROptions = RNode#pubsub_node.options,
+ unset_cached_item(RH, RNidx),
broadcast_removed_node(RH, RN, RNidx, RType, ROptions, SubsByDepth),
ejabberd_hooks:run(pubsub_delete_node,
ServerHost,
@@ -1576,6 +1583,7 @@ delete_node(Host, Node, Owner) ->
lists:foreach(fun ({RNode, _RSubs}) ->
{RH, RN} = RNode#pubsub_node.nodeid,
RNidx = RNode#pubsub_node.id,
+ unset_cached_item(RH, RNidx),
ejabberd_hooks:run(pubsub_delete_node,
ServerHost,
[ServerHost, RH, RN, RNidx])
@@ -1587,6 +1595,7 @@ delete_node(Host, Node, Owner) ->
end;
{result, {TNode, {_, Result}}} ->
Nidx = TNode#pubsub_node.id,
+ unset_cached_item(Host, Nidx),
ejabberd_hooks:run(pubsub_delete_node, ServerHost,
[ServerHost, Host, Node, Nidx]),
case Result of
@@ -3371,11 +3380,11 @@ tree(Host) ->
tree(_Host, <<"virtual">>) ->
nodetree_virtual; % special case, virtual does not use any backend
tree(Host, Name) ->
- submodule(Host, <<"nodetree_", Name/binary>>).
+ submodule(Host, <<"nodetree">>, Name).
-spec plugin(host(), binary()) -> atom().
plugin(Host, Name) ->
- submodule(Host, <<"node_", Name/binary>>).
+ submodule(Host, <<"node">>, Name).
-spec plugins(host()) -> [binary()].
plugins(Host) ->
@@ -3387,14 +3396,13 @@ plugins(Host) ->
-spec subscription_plugin(host()) -> atom().
subscription_plugin(Host) ->
- submodule(Host, <<"pubsub_subscription">>).
+ submodule(Host, <<"pubsub">>, <<"subscription">>).
--spec submodule(host(), binary()) -> atom().
-submodule(Host, Name) ->
+-spec submodule(host(), binary(), binary()) -> atom().
+submodule(Host, Type, Name) ->
case gen_mod:db_type(serverhost(Host), ?MODULE) of
- mnesia -> misc:binary_to_atom(Name);
- Type -> misc:binary_to_atom(<<Name/binary, "_",
- (misc:atom_to_binary(Type))/binary>>)
+ mnesia -> ejabberd:module_name([<<"pubsub">>, Type, Name]);
+ Db -> ejabberd:module_name([<<"pubsub">>, Type, Name, misc:atom_to_binary(Db)])
end.
-spec config(binary(), any()) -> any().
@@ -3789,7 +3797,7 @@ purge_offline(Host, LJID, Node) ->
Nidx = Node#pubsub_node.id,
Type = Node#pubsub_node.type,
Options = Node#pubsub_node.options,
- case node_action(Host, Type, get_items, [Nidx, service_jid(Host), none]) of
+ case node_action(Host, Type, get_items, [Nidx, service_jid(Host), undefined]) of
{result, {[], _}} ->
ok;
{result, {Items, _}} ->
@@ -3819,9 +3827,6 @@ purge_offline(Host, LJID, Node) ->
Error
end.
-export(Server) ->
- pubsub_db_sql:export(Server).
-
mod_opt_type(access_createnode) -> fun acl:access_rules_validator/1;
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
mod_opt_type(host) -> fun iolist_to_binary/1;
diff --git a/src/mod_push.erl b/src/mod_push.erl
index 2ca0bf525..2fa62cacd 100644
--- a/src/mod_push.erl
+++ b/src/mod_push.erl
@@ -56,26 +56,27 @@
-type c2s_state() :: ejabberd_c2s:state().
-type timestamp() :: erlang:timestamp().
-type push_session() :: {timestamp(), ljid(), binary(), xdata()}.
+-type err_reason() :: notfound | db_failure.
-callback init(binary(), gen_mod:opts())
-> any().
-callback store_session(binary(), binary(), timestamp(), jid(), binary(),
xdata())
- -> {ok, push_session()} | error.
+ -> {ok, push_session()} | {error, err_reason()}.
-callback lookup_session(binary(), binary(), jid(), binary())
- -> {ok, push_session()} | error.
+ -> {ok, push_session()} | {error, err_reason()}.
-callback lookup_session(binary(), binary(), timestamp())
- -> {ok, push_session()} | error.
+ -> {ok, push_session()} | {error, err_reason()}.
-callback lookup_sessions(binary(), binary(), jid())
- -> {ok, [push_session()]} | error.
+ -> {ok, [push_session()]} | {error, err_reason()}.
-callback lookup_sessions(binary(), binary())
- -> {ok, [push_session()]} | error.
+ -> {ok, [push_session()]} | {error, err_reason()}.
-callback lookup_sessions(binary())
- -> {ok, [push_session()]} | error.
+ -> {ok, [push_session()]} | {error, err_reason()}.
-callback delete_session(binary(), binary(), timestamp())
- -> ok | error.
+ -> ok | {error, err_reason()}.
-callback delete_old_sessions(binary() | global, erlang:timestamp())
- -> any().
+ -> ok | {error, err_reason()}.
-callback use_cache(binary())
-> boolean().
-callback cache_nodes(binary())
@@ -253,29 +254,39 @@ process_iq(#iq{lang = Lang, sub_els = [#push_enable{node = <<>>}]} = IQ) ->
xmpp:make_error(IQ, xmpp:err_feature_not_implemented(Txt, Lang));
process_iq(#iq{from = #jid{lserver = LServer} = JID,
to = #jid{lserver = LServer},
+ lang = Lang,
sub_els = [#push_enable{jid = PushJID,
node = Node,
xdata = XData}]} = IQ) ->
case enable(JID, PushJID, Node, XData) of
ok ->
xmpp:make_iq_result(IQ);
- error ->
- xmpp:make_error(IQ, xmpp:err_internal_server_error())
+ {error, db_failure} ->
+ Txt = <<"Database failure">>,
+ xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang));
+ {error, notfound} ->
+ Txt = <<"User session not found">>,
+ xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
end;
process_iq(#iq{from = #jid{lserver = LServer} = JID,
to = #jid{lserver = LServer},
+ lang = Lang,
sub_els = [#push_disable{jid = PushJID,
node = Node}]} = IQ) ->
case disable(JID, PushJID, Node) of
ok ->
xmpp:make_iq_result(IQ);
- error ->
- xmpp:make_error(IQ, xmpp:err_item_not_found())
+ {error, db_failure} ->
+ Txt = <<"Database failure">>,
+ xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang));
+ {error, notfound} ->
+ Txt = <<"Push record not found">>,
+ xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
end;
process_iq(IQ) ->
xmpp:make_error(IQ, xmpp:err_not_allowed()).
--spec enable(jid(), jid(), binary(), xdata()) -> ok | error.
+-spec enable(jid(), jid(), binary(), xdata()) -> ok | {error, err_reason()}.
enable(#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID,
PushJID, Node, XData) ->
case ejabberd_sm:get_session_sid(LUser, LServer, LResource) of
@@ -285,18 +296,18 @@ enable(#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID,
?INFO_MSG("Enabling push notifications for ~s",
[jid:encode(JID)]),
ejabberd_c2s:cast(PID, push_enable);
- error ->
+ {error, _} = Err ->
?ERROR_MSG("Cannot enable push for ~s: database error",
[jid:encode(JID)]),
- error
+ Err
end;
none ->
?WARNING_MSG("Cannot enable push for ~s: session not found",
[jid:encode(JID)]),
- error
+ {error, notfound}
end.
--spec disable(jid(), jid(), binary() | undefined) -> ok | error.
+-spec disable(jid(), jid(), binary() | undefined) -> ok | {error, err_reason()}.
disable(#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID,
PushJID, Node) ->
case ejabberd_sm:get_session_sid(LUser, LServer, LResource) of
@@ -308,7 +319,7 @@ disable(#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID,
?WARNING_MSG("Session not found while disabling push for ~s",
[jid:encode(JID)])
end,
- if Node /= undefined ->
+ if Node /= <<>> ->
delete_session(LUser, LServer, PushJID, Node);
true ->
delete_sessions(LUser, LServer, PushJID)
@@ -388,7 +399,7 @@ c2s_handle_cast(State, push_disable) ->
c2s_handle_cast(State, _Msg) ->
State.
--spec remove_user(binary(), binary()) -> ok | error.
+-spec remove_user(binary(), binary()) -> ok | {error, err_reason()}.
remove_user(LUser, LServer) ->
?INFO_MSG("Removing any push sessions of ~s@~s", [LUser, LServer]),
Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -403,7 +414,7 @@ notify(#{jid := #jid{luser = LUser, lserver = LServer}, sid := {TS, _}}) ->
case lookup_session(LUser, LServer, TS) of
{ok, Client} ->
notify(LUser, LServer, [Client]);
- error ->
+ _Err ->
ok
end.
@@ -440,7 +451,7 @@ notify(LServer, PushLJID, Node, XData, HandleResponse) ->
%% Internal functions.
%%--------------------------------------------------------------------
-spec store_session(binary(), binary(), timestamp(), jid(), binary(), xdata())
- -> {ok, push_session()} | error.
+ -> {ok, push_session()} | {error, err_reason()}.
store_session(LUser, LServer, TS, PushJID, Node, XData) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
delete_session(LUser, LServer, PushJID, Node),
@@ -460,7 +471,7 @@ store_session(LUser, LServer, TS, PushJID, Node, XData) ->
end.
-spec lookup_session(binary(), binary(), timestamp())
- -> {ok, push_session()} | error.
+ -> {ok, push_session()} | error | {error, err_reason()}.
lookup_session(LUser, LServer, TS) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
case use_cache(Mod, LServer) of
@@ -472,7 +483,7 @@ lookup_session(LUser, LServer, TS) ->
Mod:lookup_session(LUser, LServer, TS)
end.
--spec lookup_sessions(binary(), binary()) -> {ok, [push_session()]} | error.
+-spec lookup_sessions(binary(), binary()) -> {ok, [push_session()]} | {error, err_reason()}.
lookup_sessions(LUser, LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
case use_cache(Mod, LServer) of
@@ -484,40 +495,48 @@ lookup_sessions(LUser, LServer) ->
Mod:lookup_sessions(LUser, LServer)
end.
--spec delete_session(binary(), binary(), timestamp()) -> ok | error.
+-spec delete_session(binary(), binary(), timestamp()) -> ok | {error, db_failure}.
delete_session(LUser, LServer, TS) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
- ok = Mod:delete_session(LUser, LServer, TS),
- case use_cache(Mod, LServer) of
- true ->
- ets_cache:delete(?PUSH_CACHE, {LUser, LServer},
- cache_nodes(Mod, LServer)),
- ets_cache:delete(?PUSH_CACHE, {LUser, LServer, TS},
- cache_nodes(Mod, LServer));
- false ->
- ok
+ case Mod:delete_session(LUser, LServer, TS) of
+ ok ->
+ case use_cache(Mod, LServer) of
+ true ->
+ ets_cache:delete(?PUSH_CACHE, {LUser, LServer},
+ cache_nodes(Mod, LServer)),
+ ets_cache:delete(?PUSH_CACHE, {LUser, LServer, TS},
+ cache_nodes(Mod, LServer));
+ false ->
+ ok
+ end;
+ {error, _} = Err ->
+ Err
end.
--spec delete_session(binary(), binary(), jid(), binary()) -> ok | error.
+-spec delete_session(binary(), binary(), jid(), binary()) -> ok | {error, err_reason()}.
delete_session(LUser, LServer, PushJID, Node) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
case Mod:lookup_session(LUser, LServer, PushJID, Node) of
{ok, {TS, _, _, _}} ->
delete_session(LUser, LServer, TS);
error ->
- error
+ {error, notfound};
+ {error, _} = Err ->
+ Err
end.
--spec delete_sessions(binary(), binary(), jid()) -> ok | error.
+-spec delete_sessions(binary(), binary(), jid()) -> ok | {error, err_reason()}.
delete_sessions(LUser, LServer, PushJID) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
LookupFun = fun() -> Mod:lookup_sessions(LUser, LServer, PushJID) end,
delete_sessions(LUser, LServer, LookupFun, Mod).
--spec delete_sessions(binary(), binary(), fun(() -> ok | error), module())
- -> ok | error.
+-spec delete_sessions(binary(), binary(), fun(() -> any()), module())
+ -> ok | {error, err_reason()}.
delete_sessions(LUser, LServer, LookupFun, Mod) ->
case LookupFun() of
+ {ok, []} ->
+ {error, notfound};
{ok, Clients} ->
case use_cache(Mod, LServer) of
true ->
@@ -538,8 +557,8 @@ delete_sessions(LUser, LServer, LookupFun, Mod) ->
ok
end
end, Clients);
- error ->
- error
+ {error, _} = Err ->
+ Err
end.
-spec drop_online_sessions(binary(), binary(), [push_session()])
diff --git a/src/mod_push_mnesia.erl b/src/mod_push_mnesia.erl
index 309ff80e3..ff12150f2 100644
--- a/src/mod_push_mnesia.erl
+++ b/src/mod_push_mnesia.erl
@@ -31,18 +31,12 @@
%% API
-export([init/2, store_session/6, lookup_session/4, lookup_session/3,
lookup_sessions/3, lookup_sessions/2, lookup_sessions/1,
- delete_session/3, delete_old_sessions/2]).
+ delete_session/3, delete_old_sessions/2, transform/1]).
-include_lib("stdlib/include/ms_transform.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-
--record(push_session,
- {us = {<<"">>, <<"">>} :: {binary(), binary()},
- timestamp = p1_time_compat:timestamp() :: erlang:timestamp(),
- service = {<<"">>, <<"">>, <<"">>} :: ljid(),
- node = <<"">> :: binary(),
- xdata = #xdata{} :: xdata()}).
+-include("mod_push.hrl").
%%%-------------------------------------------------------------------
%%% API
@@ -67,7 +61,7 @@ store_session(LUser, LServer, TS, PushJID, Node, XData) ->
timestamp = TS,
service = PushLJID,
node = Node,
- xdata = XData})
+ xml = encode_xdata(XData)})
end,
case mnesia:transaction(F) of
{atomic, ok} ->
@@ -75,7 +69,7 @@ store_session(LUser, LServer, TS, PushJID, Node, XData) ->
{aborted, E} ->
?ERROR_MSG("Cannot store push session for ~s@~s: ~p",
[LUser, LServer, E]),
- error
+ {error, db_failure}
end.
lookup_session(LUser, LServer, PushJID, Node) ->
@@ -89,12 +83,12 @@ lookup_session(LUser, LServer, PushJID, Node) ->
Rec
end),
case mnesia:dirty_select(push_session, MatchSpec) of
- [#push_session{timestamp = TS, xdata = XData}] ->
- {ok, {TS, PushLJID, Node, XData}};
- _ ->
+ [#push_session{timestamp = TS, xml = El}] ->
+ {ok, {TS, PushLJID, Node, decode_xdata(El)}};
+ [] ->
?DEBUG("No push session found for ~s@~s (~p, ~s)",
[LUser, LServer, PushJID, Node]),
- error
+ {error, notfound}
end.
lookup_session(LUser, LServer, TS) ->
@@ -106,33 +100,31 @@ lookup_session(LUser, LServer, TS) ->
Rec
end),
case mnesia:dirty_select(push_session, MatchSpec) of
- [#push_session{service = PushLJID, node = Node, xdata = XData}] ->
- {ok, {TS, PushLJID, Node, XData}};
- _ ->
+ [#push_session{service = PushLJID, node = Node, xml = El}] ->
+ {ok, {TS, PushLJID, Node, decode_xdata(El)}};
+ [] ->
?DEBUG("No push session found for ~s@~s (~p)",
[LUser, LServer, TS]),
- error
+ {error, notfound}
end.
lookup_sessions(LUser, LServer, PushJID) ->
PushLJID = jid:tolower(PushJID),
MatchSpec = ets:fun2ms(
- fun(#push_session{us = {U, S}, service = P, node = N} = Rec)
+ fun(#push_session{us = {U, S}, service = P,
+ node = Node, timestamp = TS,
+ xml = El} = Rec)
when U == LUser,
S == LServer,
P == PushLJID ->
Rec
end),
- {ok, mnesia:dirty_select(push_session, MatchSpec)}.
+ Records = mnesia:dirty_select(push_session, MatchSpec),
+ {ok, records_to_sessions(Records)}.
lookup_sessions(LUser, LServer) ->
Records = mnesia:dirty_read(push_session, {LUser, LServer}),
- Clients = [{TS, PushLJID, Node, XData}
- || #push_session{timestamp = TS,
- service = PushLJID,
- node = Node,
- xdata = XData} <- Records],
- {ok, Clients}.
+ {ok, records_to_sessions(Records)}.
lookup_sessions(LServer) ->
MatchSpec = ets:fun2ms(
@@ -140,11 +132,12 @@ lookup_sessions(LServer) ->
timestamp = TS,
service = PushLJID,
node = Node,
- xdata = XData})
+ xml = El})
when S == LServer ->
- {TS, PushLJID, Node, XData}
+ {TS, PushLJID, Node, El}
end),
- {ok, mnesia:dirty_select(push_session, MatchSpec)}.
+ Records = mnesia:dirty_select(push_session, MatchSpec),
+ {ok, records_to_sessions(Records)}.
delete_session(LUser, LServer, TS) ->
MatchSpec = ets:fun2ms(
@@ -164,7 +157,7 @@ delete_session(LUser, LServer, TS) ->
{aborted, E} ->
?ERROR_MSG("Cannot delete push session of ~s@~s: ~p",
[LUser, LServer, E]),
- error
+ {error, db_failure}
end.
delete_old_sessions(_LServer, Time) ->
@@ -181,9 +174,14 @@ delete_old_sessions(_LServer, Time) ->
ok;
{aborted, E} ->
?ERROR_MSG("Cannot delete old push sessions: ~p", [E]),
- error
+ {error, db_failure}
end.
+transform({push_session, US, TS, Service, Node, XData}) ->
+ ?INFO_MSG("Transforming push_session Mnesia table", []),
+ #push_session{us = US, timestamp = TS, service = Service,
+ node = Node, xml = encode_xdata(XData)}.
+
%%--------------------------------------------------------------------
%% Internal functions.
%%--------------------------------------------------------------------
@@ -202,3 +200,20 @@ enforce_max_sessions({U, S} = US, Max) ->
true ->
ok
end.
+
+decode_xdata(undefined) ->
+ undefined;
+decode_xdata(El) ->
+ xmpp:decode(El).
+
+encode_xdata(undefined) ->
+ undefined;
+encode_xdata(XData) ->
+ xmpp:encode(XData).
+
+records_to_sessions(Records) ->
+ [{TS, PushLJID, Node, decode_xdata(El)}
+ || #push_session{timestamp = TS,
+ service = PushLJID,
+ node = Node,
+ xml = El} <- Records].
diff --git a/src/mod_push_sql.erl b/src/mod_push_sql.erl
new file mode 100644
index 000000000..a94b686fc
--- /dev/null
+++ b/src/mod_push_sql.erl
@@ -0,0 +1,233 @@
+%%%----------------------------------------------------------------------
+%%% ejabberd, Copyright (C) 2017 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_push_sql).
+-behaviour(mod_push).
+-compile([{parse_transform, ejabberd_sql_pt}]).
+
+%% API
+-export([init/2, store_session/6, lookup_session/4, lookup_session/3,
+ lookup_sessions/3, lookup_sessions/2, lookup_sessions/1,
+ delete_session/3, delete_old_sessions/2, export/1]).
+
+-include("xmpp.hrl").
+-include("logger.hrl").
+-include("ejabberd_sql_pt.hrl").
+-include("mod_push.hrl").
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+init(_Host, _Opts) ->
+ ok.
+
+store_session(LUser, LServer, NowTS, PushJID, Node, XData) ->
+ XML = encode_xdata(XData),
+ TS = misc:now_to_usec(NowTS),
+ PushLJID = jid:tolower(PushJID),
+ Service = jid:encode(PushLJID),
+ case ?SQL_UPSERT(LServer, "push_session",
+ ["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
+ "!timestamp=%(TS)d",
+ "!service=%(Service)s",
+ "!node=%(Node)s",
+ "xml=%(XML)s"]) of
+ ok ->
+ {ok, {NowTS, PushLJID, Node, XData}};
+ Err ->
+ ?ERROR_MSG("Failed to update 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+lookup_session(LUser, LServer, PushJID, Node) ->
+ PushLJID = jid:tolower(PushJID),
+ Service = jid:encode(PushLJID),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(timestamp)d, @(xml)s from push_session "
+ "where username=%(LUser)s and %(LServer)H "
+ "and service=%(Service)s "
+ "and node=%(Node)s")) of
+ {selected, [{TS, XML}]} ->
+ NowTS = misc:usec_to_now(TS),
+ XData = decode_xdata(XML, LUser, LServer),
+ {ok, {NowTS, PushLJID, Node, XData}};
+ {selected, []} ->
+ {error, notfound};
+ Err ->
+ ?ERROR_MSG("Failed to select from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+lookup_session(LUser, LServer, NowTS) ->
+ TS = misc:now_to_usec(NowTS),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(service)s, @(node)s, @(xml)s "
+ "from push_session where username=%(LUser)s and %(LServer)H "
+ "and timestamp=%(TS)d")) of
+ {selected, [{Service, Node, XML}]} ->
+ PushLJID = jid:tolower(jid:decode(Service)),
+ XData = decode_xdata(XML, LUser, LServer),
+ {ok, {NowTS, PushLJID, Node, XData}};
+ {selected, []} ->
+ {error, notfound};
+ Err ->
+ ?ERROR_MSG("Failed to select from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+lookup_sessions(LUser, LServer, PushJID) ->
+ PushLJID = jid:tolower(PushJID),
+ Service = jid:encode(PushLJID),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(timestamp)d, @(xml)s, @(node)s from push_session "
+ "where username=%(LUser)s and %(LServer)H "
+ "and service=%(Service)s")) of
+ {selected, Rows} ->
+ {ok, lists:map(
+ fun({TS, XML, Node}) ->
+ NowTS = misc:usec_to_now(TS),
+ XData = decode_xdata(XML, LUser, LServer),
+ {NowTS, PushLJID, Node, XData}
+ end, Rows)};
+ Err ->
+ ?ERROR_MSG("Failed to select from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+lookup_sessions(LUser, LServer) ->
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(timestamp)d, @(xml)s, @(node)s, @(service)s "
+ "from push_session "
+ "where username=%(LUser)s and %(LServer)H")) of
+ {selected, Rows} ->
+ {ok, lists:map(
+ fun({TS, XML, Node, Service}) ->
+ NowTS = misc:usec_to_now(TS),
+ XData = decode_xdata(XML, LUser, LServer),
+ PushLJID = jid:tolower(jid:decode(Service)),
+ {NowTS, PushLJID,Node, XData}
+ end, Rows)};
+ Err ->
+ ?ERROR_MSG("Failed to select from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+lookup_sessions(LServer) ->
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(username)s, @(timestamp)d, @(xml)s, "
+ "@(node)s, @(service)s from push_session "
+ "where %(LServer)H")) of
+ {selected, Rows} ->
+ {ok, lists:map(
+ fun({LUser, TS, XML, Node, Service}) ->
+ NowTS = misc:usec_to_now(TS),
+ XData = decode_xdata(XML, LUser, LServer),
+ PushLJID = jid:tolower(jid:decode(Service)),
+ {NowTS, PushLJID, Node, XData}
+ end, Rows)};
+ Err ->
+ ?ERROR_MSG("Failed to select from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+delete_session(LUser, LServer, NowTS) ->
+ TS = misc:now_to_usec(NowTS),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("delete from push_session where "
+ "username=%(LUser)s and %(LServer)H and timestamp=%(TS)d")) of
+ {updated, _} ->
+ ok;
+ Err ->
+ ?ERROR_MSG("failed to delete from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+delete_old_sessions(LServer, Time) ->
+ TS = misc:now_to_usec(Time),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("delete from push_session where timestamp<%(TS)d "
+ "and %(LServer)H")) of
+ {updated, _} ->
+ ok;
+ Err ->
+ ?ERROR_MSG("failed to delete from 'push_session' table: ~p", [Err]),
+ {error, db_failure}
+ end.
+
+export(_Server) ->
+ [{push_session,
+ fun(Host, #push_session{us = {LUser, LServer},
+ timestamp = NowTS,
+ service = PushLJID,
+ node = Node,
+ xml = XData})
+ when LServer == Host ->
+ TS = misc:now_to_usec(NowTS),
+ Service = jid:encode(PushLJID),
+ XML = encode_xdata(XData),
+ [?SQL("delete from push_session where "
+ "username=%(LUser)s and %(LServer)H and "
+ "timestamp=%(TS)d and "
+ "service=%(Service)s and node=%(Node)s and "
+ "xml=%(XML)s;"),
+ ?SQL_INSERT(
+ "push_session",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "timestamp=%(TS)d",
+ "service=%(Service)s",
+ "node=%(Node)s",
+ "xml=%(XML)s"])];
+ (_Host, _R) ->
+ []
+ end}].
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+decode_xdata(<<>>, _LUser, _LServer) ->
+ undefined;
+decode_xdata(XML, LUser, LServer) ->
+ case fxml_stream:parse_element(XML) of
+ #xmlel{} = El ->
+ try xmpp:decode(El)
+ catch _:{xmpp_codec, Why} ->
+ ?ERROR_MSG("Failed to decode ~s for user ~s@~s "
+ "from table 'push_session': ~s",
+ [XML, LUser, LServer, xmpp:format_error(Why)]),
+ undefined
+ end;
+ Err ->
+ ?ERROR_MSG("Failed to decode ~s for user ~s@~s from "
+ "table 'push_session': ~p",
+ [XML, LUser, LServer, Err]),
+ undefined
+ end.
+
+encode_xdata(undefined) ->
+ <<>>;
+encode_xdata(XData) ->
+ fxml:element_to_binary(xmpp:encode(XData)).
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index c03ea1154..a86b50d98 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -1180,12 +1180,18 @@ import_stop(_LServer, _DBType) ->
ets:delete(rostergroups_tmp),
ok.
+-ifdef(NEW_SQL_SCHEMA).
+-define(ROW_LENGTH, 10).
+-else.
+-define(ROW_LENGTH, 9).
+-endif.
+
import(LServer, {sql, _}, _DBType, <<"rostergroups">>, [LUser, SJID, Group]) ->
LJID = jid:tolower(jid:decode(SJID)),
ets:insert(rostergroups_tmp, {{LUser, LServer, LJID}, Group}),
ok;
import(LServer, {sql, _}, DBType, <<"rosterusers">>, Row) ->
- I = mod_roster_sql:raw_to_record(LServer, lists:sublist(Row, 9)),
+ I = mod_roster_sql:raw_to_record(LServer, lists:sublist(Row, ?ROW_LENGTH)),
Groups = [G || {_, G} <- ets:lookup(rostergroups_tmp, I#roster.usj)],
RosterItem = I#roster{groups = Groups},
Mod = gen_mod:db_mod(DBType, ?MODULE),
diff --git a/src/mod_roster_sql.erl b/src/mod_roster_sql.erl
index 77899624a..82a3c4951 100644
--- a/src/mod_roster_sql.erl
+++ b/src/mod_roster_sql.erl
@@ -49,7 +49,7 @@ read_roster_version(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
?SQL("select @(version)s from roster_version"
- " where username = %(LUser)s")) of
+ " where username = %(LUser)s and %(LServer)H")) of
{selected, [{Version}]} -> {ok, Version};
{selected, []} -> error;
_ -> {error, db_failure}
@@ -57,11 +57,11 @@ read_roster_version(LUser, LServer) ->
write_roster_version(LUser, LServer, InTransaction, Ver) ->
if InTransaction ->
- set_roster_version(LUser, Ver);
+ set_roster_version(LUser, LServer, Ver);
true ->
transaction(
LServer,
- fun () -> set_roster_version(LUser, Ver) end)
+ fun () -> set_roster_version(LUser, LServer, Ver) end)
end.
get_roster(LUser, LServer) ->
@@ -69,7 +69,8 @@ get_roster(LUser, LServer) ->
LServer,
?SQL("select @(username)s, @(jid)s, @(nick)s, @(subscription)s, "
"@(ask)s, @(askmessage)s, @(server)s, @(subscribe)s, "
- "@(type)s from rosterusers where username=%(LUser)s")) of
+ "@(type)s from rosterusers "
+ "where username=%(LUser)s and %(LServer)H")) of
{selected, Items} when is_list(Items) ->
JIDGroups = case get_roster_jid_groups(LServer, LUser) of
{selected, JGrps} when is_list(JGrps) ->
@@ -130,36 +131,42 @@ remove_user(LUser, LServer) ->
LServer,
fun () ->
ejabberd_sql:sql_query_t(
- ?SQL("delete from rosterusers where username=%(LUser)s")),
+ ?SQL("delete from rosterusers"
+ " where username=%(LUser)s and %(LServer)H")),
ejabberd_sql:sql_query_t(
- ?SQL("delete from rostergroups where username=%(LUser)s"))
+ ?SQL("delete from rostergroups"
+ " where username=%(LUser)s and %(LServer)H"))
end),
ok.
-update_roster(LUser, _LServer, LJID, Item) ->
+update_roster(LUser, LServer, LJID, Item) ->
SJID = jid:encode(LJID),
ItemVals = record_to_row(Item),
ItemGroups = Item#roster.groups,
roster_subscribe(ItemVals),
ejabberd_sql:sql_query_t(
?SQL("delete from rostergroups"
- " where username=%(LUser)s and jid=%(SJID)s")),
+ " where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")),
lists:foreach(
fun(ItemGroup) ->
ejabberd_sql:sql_query_t(
- ?SQL("insert into rostergroups(username, jid, grp) "
- "values (%(LUser)s, %(SJID)s, %(ItemGroup)s)"))
+ ?SQL_INSERT(
+ "rostergroups",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "jid=%(SJID)s",
+ "grp=%(ItemGroup)s"]))
end,
ItemGroups).
-del_roster(LUser, _LServer, LJID) ->
+del_roster(LUser, LServer, LJID) ->
SJID = jid:encode(LJID),
ejabberd_sql:sql_query_t(
?SQL("delete from rosterusers"
- " where username=%(LUser)s and jid=%(SJID)s")),
+ " where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")),
ejabberd_sql:sql_query_t(
?SQL("delete from rostergroups"
- " where username=%(LUser)s and jid=%(SJID)s")).
+ " where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")).
read_subscription_and_groups(LUser, LServer, LJID) ->
SJID = jid:encode(LJID),
@@ -200,9 +207,13 @@ export(_Server) ->
{roster_version,
fun(Host, #roster_version{us = {LUser, LServer}, version = Ver})
when LServer == Host ->
- [?SQL("delete from roster_version where username=%(LUser)s;"),
- ?SQL("insert into roster_version(username, version) values("
- " %(LUser)s, %(Ver)s);")];
+ [?SQL("delete from roster_version"
+ " where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT(
+ "roster_version",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "version=%(Ver)s"])];
(_Host, _R) ->
[]
end}].
@@ -213,27 +224,29 @@ import(_, _, _) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
-set_roster_version(LUser, Version) ->
+set_roster_version(LUser, LServer, Version) ->
?SQL_UPSERT_T(
"roster_version",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"version=%(Version)s"]).
get_roster_jid_groups(LServer, LUser) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(jid)s, @(grp)s from rostergroups where "
- "username=%(LUser)s")).
+ "username=%(LUser)s and %(LServer)H")).
-get_roster_groups(_LServer, LUser, SJID) ->
+get_roster_groups(LServer, LUser, SJID) ->
ejabberd_sql:sql_query_t(
?SQL("select @(grp)s from rostergroups"
- " where username=%(LUser)s and jid=%(SJID)s")).
+ " where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")).
-roster_subscribe({LUser, SJID, Name, SSubscription, SAsk, AskMessage}) ->
+roster_subscribe({LUser, LServer, SJID, Name, SSubscription, SAsk, AskMessage}) ->
?SQL_UPSERT_T(
"rosterusers",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"!jid=%(SJID)s",
"nick=%(Name)s",
"subscription=%(SSubscription)s",
@@ -243,57 +256,67 @@ roster_subscribe({LUser, SJID, Name, SSubscription, SAsk, AskMessage}) ->
"subscribe=''",
"type='item'"]).
-get_roster_by_jid(_LServer, LUser, SJID) ->
+get_roster_by_jid(LServer, LUser, SJID) ->
ejabberd_sql:sql_query_t(
?SQL("select @(username)s, @(jid)s, @(nick)s, @(subscription)s,"
" @(ask)s, @(askmessage)s, @(server)s, @(subscribe)s,"
" @(type)s from rosterusers"
- " where username=%(LUser)s and jid=%(SJID)s")).
+ " where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")).
get_rostergroup_by_jid(LServer, LUser, SJID) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(grp)s from rostergroups"
- " where username=%(LUser)s and jid=%(SJID)s")).
+ " where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")).
get_subscription(LServer, LUser, SJID) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(subscription)s from rosterusers "
- "where username=%(LUser)s and jid=%(SJID)s")).
+ "where username=%(LUser)s and %(LServer)H and jid=%(SJID)s")).
-update_roster_sql({LUser, SJID, Name, SSubscription, SAsk, AskMessage},
+update_roster_sql({LUser, LServer, SJID, Name, SSubscription, SAsk, AskMessage},
ItemGroups) ->
[?SQL("delete from rosterusers where"
- " username=%(LUser)s and jid=%(SJID)s;"),
- ?SQL("insert into rosterusers("
- " username, jid, nick,"
- " subscription, ask, askmessage,"
- " server, subscribe, type) "
- "values ("
- "%(LUser)s, "
- "%(SJID)s, "
- "%(Name)s, "
- "%(SSubscription)s, "
- "%(SAsk)s, "
- "%(AskMessage)s, "
- "'N', '', 'item');"),
+ " username=%(LUser)s and %(LServer)H and jid=%(SJID)s;"),
+ ?SQL_INSERT(
+ "rosterusers",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "jid=%(SJID)s",
+ "nick=%(Name)s",
+ "subscription=%(SSubscription)s",
+ "ask=%(SAsk)s",
+ "askmessage=%(AskMessage)s",
+ "server='N'",
+ "subscribe=''",
+ "type='item'"]),
?SQL("delete from rostergroups where"
- " username=%(LUser)s and jid=%(SJID)s;")]
+ " username=%(LUser)s and %(LServer)H and jid=%(SJID)s;")]
++
- [?SQL("insert into rostergroups(username, jid, grp) "
- "values (%(LUser)s, %(SJID)s, %(ItemGroup)s);")
+ [?SQL_INSERT(
+ "rostergroups",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "jid=%(SJID)s",
+ "grp=%(ItemGroup)s"])
|| ItemGroup <- ItemGroups].
raw_to_record(LServer,
- [User, SJID, Nick, SSubscription, SAsk, SAskMessage,
+ [User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType]) ->
raw_to_record(LServer,
- {User, SJID, Nick, SSubscription, SAsk, SAskMessage,
+ {User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType});
raw_to_record(LServer,
{User, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType}) ->
+ raw_to_record(LServer,
+ {User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
+ _SServer, _SSubscribe, _SType});
+raw_to_record(LServer,
+ {User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
+ _SServer, _SSubscribe, _SType}) ->
try jid:decode(SJID) of
JID ->
LJID = jid:tolower(JID),
@@ -331,7 +354,7 @@ raw_to_record(LServer,
end.
record_to_row(
- #roster{us = {LUser, _LServer},
+ #roster{us = {LUser, LServer},
jid = JID, name = Name, subscription = Subscription,
ask = Ask, askmessage = AskMessage}) ->
SJID = jid:encode(jid:tolower(JID)),
@@ -349,7 +372,7 @@ record_to_row(
in -> <<"I">>;
none -> <<"N">>
end,
- {LUser, SJID, Name, SSubscription, SAsk, AskMessage}.
+ {LUser, LServer, SJID, Name, SSubscription, SAsk, AskMessage}.
format_row_error(User, Server, Why) ->
[case Why of
diff --git a/src/mod_s2s_dialback.erl b/src/mod_s2s_dialback.erl
index 403ac9cce..b4c2ed9df 100644
--- a/src/mod_s2s_dialback.erl
+++ b/src/mod_s2s_dialback.erl
@@ -353,9 +353,9 @@ format_stanza_error(#stanza_error{reason = Reason, text = Txt}) ->
#redirect{} -> <<"redirect">>;
_ -> erlang:atom_to_binary(Reason, latin1)
end,
- case Txt of
- undefined -> Slogan;
- #text{data = <<"">>} -> Slogan;
- #text{data = Data} ->
+ case xmpp:get_text(Txt) of
+ <<"">> ->
+ Slogan;
+ Data ->
<<Data/binary, " (", Slogan/binary, ")">>
end.
diff --git a/src/mod_shared_roster_sql.erl b/src/mod_shared_roster_sql.erl
index 51b332455..488e0ec76 100644
--- a/src/mod_shared_roster_sql.erl
+++ b/src/mod_shared_roster_sql.erl
@@ -50,7 +50,7 @@ init(_Host, _Opts) ->
list_groups(Host) ->
case ejabberd_sql:sql_query(
Host,
- ?SQL("select @(name)s from sr_group")) of
+ ?SQL("select @(name)s from sr_group where %(Host)H")) of
{selected, Rs} -> [G || {G} <- Rs];
_ -> []
end.
@@ -58,7 +58,7 @@ list_groups(Host) ->
groups_with_opts(Host) ->
case ejabberd_sql:sql_query(
Host,
- ?SQL("select @(name)s, @(opts)s from sr_group"))
+ ?SQL("select @(name)s, @(opts)s from sr_group where %(Host)H"))
of
{selected, Rs} ->
[{G, mod_shared_roster:opts_to_binary(ejabberd_sql:decode_term(Opts))}
@@ -72,6 +72,7 @@ create_group(Host, Group, Opts) ->
?SQL_UPSERT_T(
"sr_group",
["!name=%(Group)s",
+ "!server_host=%(Host)s",
"opts=%(SOpts)s"])
end,
ejabberd_sql:sql_transaction(Host, F).
@@ -79,9 +80,9 @@ create_group(Host, Group, Opts) ->
delete_group(Host, Group) ->
F = fun () ->
ejabberd_sql:sql_query_t(
- ?SQL("delete from sr_group where name=%(Group)s")),
+ ?SQL("delete from sr_group where name=%(Group)s and %(Host)H")),
ejabberd_sql:sql_query_t(
- ?SQL("delete from sr_user where grp=%(Group)s"))
+ ?SQL("delete from sr_user where grp=%(Group)s and %(Host)H"))
end,
case ejabberd_sql:sql_transaction(Host, F) of
{atomic,{updated,_}} -> {atomic, ok};
@@ -91,7 +92,8 @@ delete_group(Host, Group) ->
get_group_opts(Host, Group) ->
case catch ejabberd_sql:sql_query(
Host,
- ?SQL("select @(opts)s from sr_group where name=%(Group)s")) of
+ ?SQL("select @(opts)s from sr_group"
+ " where name=%(Group)s and %(Host)H")) of
{selected, [{SOpts}]} ->
mod_shared_roster:opts_to_binary(ejabberd_sql:decode_term(SOpts));
_ -> error
@@ -103,6 +105,7 @@ set_group_opts(Host, Group, Opts) ->
?SQL_UPSERT_T(
"sr_group",
["!name=%(Group)s",
+ "!server_host=%(Host)s",
"opts=%(SOpts)s"])
end,
ejabberd_sql:sql_transaction(Host, F).
@@ -111,7 +114,8 @@ get_user_groups(US, Host) ->
SJID = make_jid_s(US),
case catch ejabberd_sql:sql_query(
Host,
- ?SQL("select @(grp)s from sr_user where jid=%(SJID)s")) of
+ ?SQL("select @(grp)s from sr_user"
+ " where jid=%(SJID)s and %(Host)H")) of
{selected, Rs} -> [G || {G} <- Rs];
_ -> []
end.
@@ -119,7 +123,8 @@ get_user_groups(US, Host) ->
get_group_explicit_users(Host, Group) ->
case catch ejabberd_sql:sql_query(
Host,
- ?SQL("select @(jid)s from sr_user where grp=%(Group)s")) of
+ ?SQL("select @(jid)s from sr_user"
+ " where grp=%(Group)s and %(Host)H")) of
{selected, Rs} ->
lists:map(
fun({JID}) ->
@@ -134,7 +139,8 @@ get_user_displayed_groups(LUser, LServer, GroupsOpts) ->
SJID = make_jid_s(LUser, LServer),
case catch ejabberd_sql:sql_query(
LServer,
- ?SQL("select @(grp)s from sr_user where jid=%(SJID)s")) of
+ ?SQL("select @(grp)s from sr_user"
+ " where jid=%(SJID)s and %(LServer)H")) of
{selected, Rs} ->
[{Group, proplists:get_value(Group, GroupsOpts, [])}
|| {Group} <- Rs];
@@ -146,7 +152,7 @@ is_user_in_group(US, Group, Host) ->
case catch ejabberd_sql:sql_query(
Host,
?SQL("select @(jid)s from sr_user where jid=%(SJID)s"
- " and grp=%(Group)s")) of
+ " and %(Host)H and grp=%(Group)s")) of
{selected, []} -> false;
_ -> true
end.
@@ -155,15 +161,18 @@ add_user_to_group(Host, US, Group) ->
SJID = make_jid_s(US),
ejabberd_sql:sql_query(
Host,
- ?SQL("insert into sr_user(jid, grp) values ("
- "%(SJID)s, %(Group)s)")).
+ ?SQL_INSERT(
+ "sr_user",
+ ["jid=%(SJID)s",
+ "server_host=%(Host)s",
+ "grp=%(Group)s"])).
remove_user_from_group(Host, US, Group) ->
SJID = make_jid_s(US),
F = fun () ->
ejabberd_sql:sql_query_t(
- ?SQL("delete from sr_user where jid=%(SJID)s and"
- " grp=%(Group)s")),
+ ?SQL("delete from sr_user where jid=%(SJID)s and %(Host)H"
+ " and grp=%(Group)s")),
ok
end,
ejabberd_sql:sql_transaction(Host, F).
@@ -173,9 +182,12 @@ export(_Server) ->
fun(Host, #sr_group{group_host = {Group, LServer}, opts = Opts})
when LServer == Host ->
SOpts = misc:term_to_expr(Opts),
- [?SQL("delete from sr_group where name=%(Group)s;"),
- ?SQL("insert into sr_group(name, opts) values ("
- "%(Group)s, %(SOpts)s);")];
+ [?SQL("delete from sr_group where name=%(Group)s and %(Host)H;"),
+ ?SQL_INSERT(
+ "sr_group",
+ ["name=%(Group)s",
+ "server_host=%(Host)s",
+ "opts=%(SOpts)s"])];
(_Host, _R) ->
[]
end},
@@ -184,9 +196,12 @@ export(_Server) ->
when LServer == Host ->
SJID = make_jid_s(U, S),
[?SQL("select @(jid)s from sr_user where jid=%(SJID)s"
- " and grp=%(Group)s;"),
- ?SQL("insert into sr_user(jid, grp) values ("
- "%(SJID)s, %(Group)s);")];
+ " and %(Host)H and grp=%(Group)s;"),
+ ?SQL_INSERT(
+ "sr_user",
+ ["jid=%(SJID)s",
+ "server_host=%(Host)s",
+ "grp=%(Group)s"])];
(_Host, _R) ->
[]
end}].
diff --git a/src/mod_stream_mgmt.erl b/src/mod_stream_mgmt.erl
index 2f6b0fc71..2bf151a04 100644
--- a/src/mod_stream_mgmt.erl
+++ b/src/mod_stream_mgmt.erl
@@ -709,7 +709,7 @@ bounce_message_queue() ->
%%%===================================================================
get_max_ack_queue(Host, Opts) ->
gen_mod:get_module_opt(Host, ?MODULE, max_ack_queue,
- gen_mod:get_opt(max_ack_queue, Opts, 1000)).
+ gen_mod:get_opt(max_ack_queue, Opts, 5000)).
get_resume_timeout(Host, Opts) ->
gen_mod:get_module_opt(Host, ?MODULE, resume_timeout,
diff --git a/src/mod_vcard_sql.erl b/src/mod_vcard_sql.erl
index 6092c3500..07d90b69e 100644
--- a/src/mod_vcard_sql.erl
+++ b/src/mod_vcard_sql.erl
@@ -39,6 +39,12 @@
-include("ejabberd_sql_pt.hrl").
-include("translate.hrl").
+-ifdef(NEW_SQL_SCHEMA).
+-define(USE_NEW_SCHEMA, true).
+-else.
+-define(USE_NEW_SCHEMA, false).
+-endif.
+
%%%===================================================================
%%% API
%%%===================================================================
@@ -54,7 +60,8 @@ is_search_supported(_LServer) ->
get_vcard(LUser, LServer) ->
case ejabberd_sql:sql_query(
LServer,
- ?SQL("select @(vcard)s from vcard where username=%(LUser)s")) of
+ ?SQL("select @(vcard)s from vcard"
+ " where username=%(LUser)s and %(LServer)H")) of
{selected, [{SVCARD}]} ->
case fxml_stream:parse_element(SVCARD) of
{error, _Reason} -> error;
@@ -94,10 +101,12 @@ set_vcard(LUser, LServer, VCARD,
fun() ->
?SQL_UPSERT(LServer, "vcard",
["!username=%(LUser)s",
+ "!server_host=%(LServer)s",
"vcard=%(SVCARD)s"]),
?SQL_UPSERT(LServer, "vcard_search",
["username=%(User)s",
"!lusername=%(LUser)s",
+ "!server_host=%(LServer)s",
"fn=%(FN)s",
"lfn=%(LFN)s",
"family=%(Family)s",
@@ -183,9 +192,11 @@ remove_user(LUser, LServer) ->
LServer,
fun() ->
ejabberd_sql:sql_query_t(
- ?SQL("delete from vcard where username=%(LUser)s")),
+ ?SQL("delete from vcard"
+ " where username=%(LUser)s and %(LServer)H")),
ejabberd_sql:sql_query_t(
- ?SQL("delete from vcard_search where lusername=%(LUser)s"))
+ ?SQL("delete from vcard_search"
+ " where lusername=%(LUser)s and %(LServer)H"))
end).
export(_Server) ->
@@ -193,9 +204,12 @@ export(_Server) ->
fun(Host, #vcard{us = {LUser, LServer}, vcard = VCARD})
when LServer == Host ->
SVCARD = fxml:element_to_binary(VCARD),
- [?SQL("delete from vcard where username=%(LUser)s;"),
- ?SQL("insert into vcard(username, vcard) values ("
- "%(LUser)s, %(SVCARD)s);")];
+ [?SQL("delete from vcard"
+ " where username=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT("vcard",
+ ["username=%(LUser)s",
+ "server_host=%(LServer)s",
+ "vcard=%(SVCARD)s"])];
(_Host, _R) ->
[]
end},
@@ -212,26 +226,34 @@ export(_Server) ->
orgname = OrgName, lorgname = LOrgName,
orgunit = OrgUnit, lorgunit = LOrgUnit})
when LServer == Host ->
- [?SQL("delete from vcard_search where lusername=%(LUser)s;"),
- ?SQL("insert into vcard_search(username,"
- " lusername, fn, lfn, family, lfamily,"
- " given, lgiven, middle, lmiddle,"
- " nickname, lnickname, bday, lbday,"
- " ctry, lctry, locality, llocality,"
- " email, lemail, orgname, lorgname,"
- " orgunit, lorgunit) values ("
- " %(LUser)s, %(User)s,"
- " %(FN)s, %(LFN)s,"
- " %(Family)s, %(LFamily)s,"
- " %(Given)s, %(LGiven)s,"
- " %(Middle)s, %(LMiddle)s,"
- " %(Nickname)s, %(LNickname)s,"
- " %(BDay)s, %(LBDay)s,"
- " %(CTRY)s, %(LCTRY)s,"
- " %(Locality)s, %(LLocality)s,"
- " %(EMail)s, %(LEMail)s,"
- " %(OrgName)s, %(LOrgName)s,"
- " %(OrgUnit)s, %(LOrgUnit)s);")];
+ [?SQL("delete from vcard_search"
+ " where lusername=%(LUser)s and %(LServer)H;"),
+ ?SQL_INSERT("vcard_search",
+ ["username=%(User)s",
+ "lusername=%(LUser)s",
+ "server_host=%(LServer)s",
+ "fn=%(FN)s",
+ "lfn=%(LFN)s",
+ "family=%(Family)s",
+ "lfamily=%(LFamily)s",
+ "given=%(Given)s",
+ "lgiven=%(LGiven)s",
+ "middle=%(Middle)s",
+ "lmiddle=%(LMiddle)s",
+ "nickname=%(Nickname)s",
+ "lnickname=%(LNickname)s",
+ "bday=%(BDay)s",
+ "lbday=%(LBDay)s",
+ "ctry=%(CTRY)s",
+ "lctry=%(LCTRY)s",
+ "locality=%(Locality)s",
+ "llocality=%(LLocality)s",
+ "email=%(EMail)s",
+ "lemail=%(LEMail)s",
+ "orgname=%(OrgName)s",
+ "lorgname=%(LOrgName)s",
+ "orgunit=%(OrgUnit)s",
+ "lorgunit=%(LOrgUnit)s"])];
(_Host, _R) ->
[]
end}].
@@ -245,10 +267,19 @@ import(_, _, _) ->
make_matchspec(LServer, Data) ->
filter_fields(Data, <<"">>, LServer).
-filter_fields([], Match, _LServer) ->
- case Match of
- <<"">> -> <<"">>;
- _ -> [<<" where ">>, Match]
+filter_fields([], Match, LServer) ->
+ case ?USE_NEW_SCHEMA of
+ true ->
+ SServer = ejabberd_sql:escape(LServer),
+ case Match of
+ <<"">> -> [<<"where server_host='">>, SServer, <<"'">>];
+ _ -> [<<" where server_host='">>, SServer, <<"' and ">>, Match]
+ end;
+ false ->
+ case Match of
+ <<"">> -> <<"">>;
+ _ -> [<<" where ">>, Match]
+ end
end;
filter_fields([{SVar, [Val]} | Ds], Match, LServer)
when is_binary(Val) and (Val /= <<"">>) ->
diff --git a/src/node_flat.erl b/src/node_flat.erl
index 2c11edde7..18d4f4745 100644
--- a/src/node_flat.erl
+++ b/src/node_flat.erl
@@ -88,7 +88,6 @@ options() ->
{max_payload_size, ?MAX_PAYLOAD_SIZE},
{send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
- {title, <<>>},
{presence_based_delivery, false},
{itemreply, none}].
@@ -446,21 +445,30 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) ->
case Affiliation of
owner ->
{result, States} = get_states(Nidx),
+ Records = States ++ mnesia:read({pubsub_orphan, Nidx}),
lists:foldl(fun
- (#pubsub_state{items = PI} = S, Res) ->
- case lists:member(ItemId, PI) of
+ (#pubsub_state{items = RI} = S, Res) ->
+ case lists:member(ItemId, RI) of
true ->
- Nitems = lists:delete(ItemId, PI),
+ NI = lists:delete(ItemId, RI),
del_item(Nidx, ItemId),
- set_state(S#pubsub_state{items = Nitems}),
+ mnesia:write(S#pubsub_state{items = NI}),
{result, {default, broadcast}};
false ->
Res
end;
- (_, Res) ->
- Res
+ (#pubsub_orphan{items = RI} = S, Res) ->
+ case lists:member(ItemId, RI) of
+ true ->
+ NI = lists:delete(ItemId, RI),
+ del_item(Nidx, ItemId),
+ mnesia:write(S#pubsub_orphan{items = NI}),
+ {result, {default, broadcast}};
+ false ->
+ Res
+ end
end,
- {error, xmpp:err_item_not_found()}, States);
+ {error, xmpp:err_item_not_found()}, Records);
_ ->
{error, xmpp:err_forbidden()}
end
diff --git a/src/nodetree_tree_sql.erl b/src/nodetree_tree_sql.erl
index 3af035f6c..0b05a885e 100644
--- a/src/nodetree_tree_sql.erl
+++ b/src/nodetree_tree_sql.erl
@@ -287,7 +287,7 @@ raw_to_node(Host, {Node, Parent, Type, Nidx}) ->
Module = misc:binary_to_atom(<<"node_", Type/binary, "_sql">>),
StdOpts = Module:options(),
lists:foldl(fun ({Key, Value}, Acc) ->
- lists:keyreplace(Key, 1, Acc, {Key, Value})
+ lists:keystore(Key, 1, Acc, {Key, Value})
end,
StdOpts, DbOpts);
_ ->
diff --git a/src/xmpp_stream_in.erl b/src/xmpp_stream_in.erl
index d9be3d4f7..329ebad61 100644
--- a/src/xmpp_stream_in.erl
+++ b/src/xmpp_stream_in.erl
@@ -1117,17 +1117,17 @@ format_inet_error(Reason) ->
Txt -> Txt
end.
--spec format_stream_error(atom() | 'see-other-host'(), undefined | text()) -> string().
+-spec format_stream_error(atom() | 'see-other-host'(), [text()]) -> string().
format_stream_error(Reason, Txt) ->
Slogan = case Reason of
undefined -> "no reason";
#'see-other-host'{} -> "see-other-host";
_ -> atom_to_list(Reason)
end,
- case Txt of
- undefined -> Slogan;
- #text{data = <<"">>} -> Slogan;
- #text{data = Data} ->
+ case xmpp:get_text(Txt) of
+ <<"">> ->
+ Slogan;
+ Data ->
binary_to_list(Data) ++ " (" ++ Slogan ++ ")"
end.
diff --git a/src/xmpp_stream_out.erl b/src/xmpp_stream_out.erl
index 982be4dee..7ddc183bf 100644
--- a/src/xmpp_stream_out.erl
+++ b/src/xmpp_stream_out.erl
@@ -25,6 +25,7 @@
-protocol({rfc, 6120}).
-protocol({xep, 114, '1.6'}).
+-protocol({xep, 368, '1.0.0'}).
%% API
-export([start/3, start_link/3, call/3, cast/2, reply/2, connect/1,
@@ -48,8 +49,9 @@
-type state() :: map().
-type noreply() :: {noreply, state(), timeout()}.
--type host_port() :: {inet:hostname(), inet:port_number()}.
--type ip_port() :: {inet:ip_address(), inet:port_number()}.
+-type host_port() :: {inet:hostname(), inet:port_number(), boolean()}.
+-type ip_port() :: {inet:ip_address(), inet:port_number(), boolean()}.
+-type h_addr_list() :: {{integer(), integer(), inet:port_number(), string()}, boolean()}.
-type network_error() :: {error, inet:posix() | inet_res:res_error()}.
-type tls_error_reason() :: inet:posix() | atom() | binary().
-type socket_error_reason() :: inet:posix() | atom().
@@ -278,11 +280,11 @@ handle_cast(connect, #{remote_server := RemoteServer,
process_stream_end({idna, bad_string}, State);
ASCIIName ->
case resolve(binary_to_list(ASCIIName), State) of
- {{ok, AddrPorts}, Encrypted} ->
- case connect(AddrPorts, State, Encrypted) of
- {ok, Socket, AddrPort} ->
+ {ok, AddrPorts} ->
+ case connect(AddrPorts, State) of
+ {ok, Socket, {Addr, Port, Encrypted}} ->
SocketMonitor = SockMod:monitor(Socket),
- State1 = State#{ip => AddrPort,
+ State1 = State#{ip => {Addr, Port},
socket => Socket,
stream_encrypted => Encrypted,
socket_monitor => SocketMonitor},
@@ -291,7 +293,7 @@ handle_cast(connect, #{remote_server := RemoteServer,
{error, {Class, Why}} ->
process_stream_end({Class, Why}, State)
end;
- {{error, Why}, _} ->
+ {error, Why} ->
process_stream_end({dns, Why}, State)
end
end);
@@ -796,17 +798,17 @@ format_inet_error(Reason) ->
Txt -> Txt
end.
--spec format_stream_error(atom() | 'see-other-host'(), undefined | text()) -> string().
+-spec format_stream_error(atom() | 'see-other-host'(), [text()]) -> string().
format_stream_error(Reason, Txt) ->
Slogan = case Reason of
undefined -> "no reason";
#'see-other-host'{} -> "see-other-host";
_ -> atom_to_list(Reason)
end,
- case Txt of
- undefined -> Slogan;
- #text{data = <<"">>} -> Slogan;
- #text{data = Data} ->
+ case xmpp:get_text(Txt) of
+ <<"">> ->
+ Slogan;
+ Data ->
binary_to_list(Data) ++ " (" ++ Slogan ++ ")"
end.
@@ -854,79 +856,92 @@ idna_to_ascii(Host) ->
{error, _} -> ejabberd_idna:domain_utf8_to_ascii(Host)
end.
--spec resolve(string(), state()) -> {{ok, [ip_port()]} | network_error(), boolean()}.
+-spec resolve(string(), state()) -> {ok, [ip_port()]} | network_error().
resolve(Host, State) ->
case srv_lookup(Host, State) of
- {{error, _Reason}, _} ->
+ {error, _Reason} ->
DefaultPort = get_default_port(State),
- {a_lookup([{Host, DefaultPort}], State), false};
- {{ok, HostPorts}, TLS} ->
- {a_lookup(HostPorts, State), TLS}
+ a_lookup([{Host, DefaultPort, false}], State);
+ {ok, HostPorts} ->
+ a_lookup(HostPorts, State)
end.
--spec srv_lookup(string(), state()) -> {{ok, [host_port()]} | network_error(), boolean()}.
+-spec srv_lookup(string(), state()) -> {ok, [host_port()]} | network_error().
srv_lookup(_Host, #{xmlns := ?NS_COMPONENT}) ->
%% Do not attempt to lookup SRV for component connections
- {{error, nxdomain}, false};
+ {error, nxdomain};
srv_lookup(Host, State) ->
%% Only perform SRV lookups for FQDN names
case string:chr(Host, $.) of
0 ->
- {{error, nxdomain}, false};
+ {error, nxdomain};
_ ->
case inet:parse_address(Host) of
{ok, _} ->
- {{error, nxdomain}, false};
+ {error, nxdomain};
{error, _} ->
Timeout = get_dns_timeout(State),
Retries = get_dns_retries(State),
- case is_starttls_available(State) of
- true ->
- case srv_lookup("_xmpps-server._tcp." ++ Host,
- Timeout, Retries) of
- {error, _} ->
- {srv_lookup("_xmpp-server._tcp." ++ Host,
- Timeout, Retries),
- false};
- {ok, Res} ->
- {{ok, Res}, true}
- end;
- false ->
- {srv_lookup("_xmpp-server._tcp." ++ Host,
- Timeout, Retries),
- false}
+ case srv_lookup(Host, State, Timeout, Retries) of
+ {ok, AddrList} ->
+ h_addr_list_to_host_ports(AddrList);
+ {error, _} = Err ->
+ Err
end
end
end.
+srv_lookup(Host, State, Timeout, Retries) ->
+ TLSAddrs = case is_starttls_available(State) of
+ true ->
+ case srv_lookup("_xmpps-server._tcp." ++ Host,
+ Timeout, Retries) of
+ {ok, HostEnt} ->
+ [{A, true} || A <- HostEnt#hostent.h_addr_list];
+ {error, _} ->
+ []
+ end;
+ false ->
+ []
+ end,
+ case srv_lookup("_xmpp-server._tcp." ++ Host, Timeout, Retries) of
+ {ok, HostEntry} ->
+ Addrs = [{A, false} || A <- HostEntry#hostent.h_addr_list],
+ {ok, TLSAddrs ++ Addrs};
+ {error, _} when TLSAddrs /= [] ->
+ {ok, TLSAddrs};
+ {error, _} = Err ->
+ Err
+ end.
+
-spec srv_lookup(string(), timeout(), integer()) ->
- {ok, [host_port()]} | network_error().
+ {ok, inet:hostent()} | network_error().
srv_lookup(_SRVName, _Timeout, Retries) when Retries < 1 ->
{error, timeout};
srv_lookup(SRVName, Timeout, Retries) ->
case inet_res:getbyname(SRVName, srv, Timeout) of
{ok, HostEntry} ->
- host_entry_to_host_ports(HostEntry);
+ {ok, HostEntry};
{error, timeout} ->
srv_lookup(SRVName, Timeout, Retries - 1);
{error, _} = Err ->
Err
end.
--spec a_lookup([{inet:hostname(), inet:port_number()}], state()) ->
+-spec a_lookup([host_port()], state()) ->
{ok, [ip_port()]} | network_error().
a_lookup(HostPorts, State) ->
- HostPortFamilies = [{Host, Port, Family}
- || {Host, Port} <- HostPorts,
+ HostPortFamilies = [{Host, Port, TLS, Family}
+ || {Host, Port, TLS} <- HostPorts,
Family <- get_address_families(State)],
a_lookup(HostPortFamilies, State, [], {error, nxdomain}).
--spec a_lookup([{inet:hostname(), inet:port_number(), inet:address_family()}],
+-spec a_lookup([{inet:hostname(), inet:port_number(), boolean(), inet:address_family()}],
state(), [ip_port()], network_error()) -> {ok, [ip_port()]} | network_error().
-a_lookup([{Host, Port, Family}|HostPortFamilies], State, Acc, Err) ->
+a_lookup([{Host, Port, TLS, Family}|HostPortFamilies], State, Acc, Err) ->
Timeout = get_dns_timeout(State),
Retries = get_dns_retries(State),
- case a_lookup(Host, Port, Family, Timeout, Retries) of
+ case a_lookup(Host, Port, TLS, Family, Timeout, Retries) of
{error, Reason} ->
a_lookup(HostPortFamilies, State, Acc, {error, Reason});
{ok, AddrPorts} ->
@@ -937,11 +952,11 @@ a_lookup([], _State, [], Err) ->
a_lookup([], _State, Acc, _) ->
{ok, Acc}.
--spec a_lookup(inet:hostname(), inet:port_number(), inet:address_family(),
+-spec a_lookup(inet:hostname(), inet:port_number(), boolean(), inet:address_family(),
timeout(), integer()) -> {ok, [ip_port()]} | network_error().
-a_lookup(_Host, _Port, _Family, _Timeout, Retries) when Retries < 1 ->
+a_lookup(_Host, _Port, _TLS, _Family, _Timeout, Retries) when Retries < 1 ->
{error, timeout};
-a_lookup(Host, Port, Family, Timeout, Retries) ->
+a_lookup(Host, Port, TLS, Family, Timeout, Retries) ->
Start = p1_time_compat:monotonic_time(milli_seconds),
case inet:gethostbyname(Host, Family, Timeout) of
{error, nxdomain} = Err ->
@@ -952,43 +967,43 @@ a_lookup(Host, Port, Family, Timeout, Retries) ->
%% it ignores DNS configuration settings (/etc/hosts, etc)
End = p1_time_compat:monotonic_time(milli_seconds),
if (End - Start) >= Timeout ->
- a_lookup(Host, Port, Family, Timeout, Retries - 1);
+ a_lookup(Host, Port, TLS, Family, Timeout, Retries - 1);
true ->
Err
end;
{error, _} = Err ->
Err;
{ok, HostEntry} ->
- host_entry_to_addr_ports(HostEntry, Port)
+ host_entry_to_addr_ports(HostEntry, Port, TLS)
end.
--spec host_entry_to_host_ports(inet:hostent()) -> {ok, [host_port()]} |
+-spec h_addr_list_to_host_ports(h_addr_list()) -> {ok, [host_port()]} |
{error, nxdomain}.
-host_entry_to_host_ports(#hostent{h_addr_list = AddrList}) ->
+h_addr_list_to_host_ports(AddrList) ->
PrioHostPorts = lists:flatmap(
- fun({Priority, Weight, Port, Host}) ->
+ fun({{Priority, Weight, Port, Host}, TLS}) ->
N = case Weight of
0 -> 0;
_ -> (Weight + 1) * randoms:uniform()
end,
- [{Priority * 65536 - N, Host, Port}];
+ [{Priority * 65536 - N, Host, Port, TLS}];
(_) ->
[]
end, AddrList),
- HostPorts = [{Host, Port}
- || {_Priority, Host, Port} <- lists:usort(PrioHostPorts)],
+ HostPorts = [{Host, Port, TLS}
+ || {_Priority, Host, Port, TLS} <- lists:usort(PrioHostPorts)],
case HostPorts of
[] -> {error, nxdomain};
_ -> {ok, HostPorts}
end.
--spec host_entry_to_addr_ports(inet:hostent(), inet:port_number()) ->
+-spec host_entry_to_addr_ports(inet:hostent(), inet:port_number(), boolean()) ->
{ok, [ip_port()]} | {error, nxdomain}.
-host_entry_to_addr_ports(#hostent{h_addr_list = AddrList}, Port) ->
+host_entry_to_addr_ports(#hostent{h_addr_list = AddrList}, Port, TLS) ->
AddrPorts = lists:flatmap(
fun(Addr) ->
try get_addr_type(Addr) of
- _ -> [{Addr, Port}]
+ _ -> [{Addr, Port, TLS}]
catch _:_ ->
[]
end
@@ -998,26 +1013,26 @@ host_entry_to_addr_ports(#hostent{h_addr_list = AddrList}, Port) ->
_ -> {ok, AddrPorts}
end.
--spec connect([ip_port()], state(), boolean()) -> {ok, term(), ip_port()} |
- {error, {socket, socket_error_reason()}} |
- {error, {tls, tls_error_reason()}}.
-connect(AddrPorts, #{sockmod := SockMod} = State, TLS) ->
+-spec connect([ip_port()], state()) -> {ok, term(), ip_port()} |
+ {error, {socket, socket_error_reason()}} |
+ {error, {tls, tls_error_reason()}}.
+connect(AddrPorts, #{sockmod := SockMod} = State) ->
Timeout = get_connect_timeout(State),
case connect(AddrPorts, SockMod, Timeout, {error, nxdomain}) of
- {ok, Socket, AddrPort} when TLS ->
+ {ok, Socket, {Addr, Port, TLS = true}} ->
case starttls(Socket, State) of
- {ok, TLSSocket} -> {ok, TLSSocket, AddrPort};
+ {ok, TLSSocket} -> {ok, TLSSocket, {Addr, Port, TLS}};
{error, Why} -> {error, {tls, Why}}
end;
- {ok, _Socket, _AddrPort} = OK ->
- OK;
+ {ok, Socket, {Addr, Port, TLS = false}} ->
+ {ok, Socket, {Addr, Port, TLS}};
{error, Why} ->
{error, {socket, Why}}
end.
-spec connect([ip_port()], module(), timeout(), network_error()) ->
{ok, term(), ip_port()} | network_error().
-connect([{Addr, Port}|AddrPorts], SockMod, Timeout, _) ->
+connect([{Addr, Port, TLS}|AddrPorts], SockMod, Timeout, _) ->
Type = get_addr_type(Addr),
try SockMod:connect(Addr, Port,
[binary, {packet, 0},
@@ -1026,7 +1041,7 @@ connect([{Addr, Port}|AddrPorts], SockMod, Timeout, _) ->
{active, false}, Type],
Timeout) of
{ok, Socket} ->
- {ok, Socket, {Addr, Port}};
+ {ok, Socket, {Addr, Port, TLS}};
Err ->
connect(AddrPorts, SockMod, Timeout, Err)
catch _:badarg ->
diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl
index 97c56159a..0479c593f 100644
--- a/test/ejabberd_SUITE.erl
+++ b/test/ejabberd_SUITE.erl
@@ -460,6 +460,7 @@ db_tests(_) ->
muc_tests:single_cases(),
offline_tests:single_cases(),
mam_tests:single_cases(),
+ push_tests:single_cases(),
test_unregister]},
muc_tests:master_slave_cases(),
privacy_tests:master_slave_cases(),
@@ -469,7 +470,8 @@ db_tests(_) ->
mam_tests:master_slave_cases(),
vcard_tests:master_slave_cases(),
announce_tests:master_slave_cases(),
- carbons_tests:master_slave_cases()].
+ carbons_tests:master_slave_cases(),
+ push_tests:master_slave_cases()].
ldap_tests() ->
[{ldap_tests, [sequence],
diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml
index a648cb422..b73d6a67f 100644
--- a/test/ejabberd_SUITE_data/ejabberd.yml
+++ b/test/ejabberd_SUITE_data/ejabberd.yml
@@ -52,7 +52,12 @@ host_config:
mod_disco: []
mod_ping: []
mod_proxy65: []
+ mod_push:
+ db_type: sql
+ mod_push_keepalive: []
mod_s2s_dialback: []
+ mod_stream_mgmt:
+ resume_timeout: 3
mod_legacy_auth: []
mod_register:
welcome_message:
@@ -110,7 +115,12 @@ Welcome to this XMPP server."
mod_disco: []
mod_ping: []
mod_proxy65: []
+ mod_push:
+ db_type: sql
+ mod_push_keepalive: []
mod_s2s_dialback: []
+ mod_stream_mgmt:
+ resume_timeout: 3
mod_legacy_auth: []
mod_register:
welcome_message:
@@ -173,7 +183,12 @@ Welcome to this XMPP server."
mod_disco: []
mod_ping: []
mod_proxy65: []
+ mod_push:
+ db_type: sql
+ mod_push_keepalive: []
mod_s2s_dialback: []
+ mod_stream_mgmt:
+ resume_timeout: 3
mod_legacy_auth: []
mod_register:
welcome_message:
diff --git a/test/pubsub_tests.erl b/test/pubsub_tests.erl
index 9cdbd1586..92423c9d9 100644
--- a/test/pubsub_tests.erl
+++ b/test/pubsub_tests.erl
@@ -108,7 +108,7 @@ test_configure(Config) ->
[{title, NodeTitle}]),
set_node_config(Config, Node, MyNodeConfig),
NewNodeConfig = get_node_config(Config, Node),
- NodeTitle = proplists:get_value(title, NewNodeConfig),
+ NodeTitle = proplists:get_value(title, NewNodeConfig, <<>>),
disconnect(Config).
test_default(Config) ->
@@ -122,7 +122,7 @@ test_create_configure(Config) ->
[{title, NodeTitle}]),
Node = create_node(Config, <<>>, CustomNodeConfig),
NodeConfig = get_node_config(Config, Node),
- NodeTitle = proplists:get_value(title, NodeConfig),
+ NodeTitle = proplists:get_value(title, NodeConfig, <<>>),
delete_node(Config, Node),
disconnect(Config).
diff --git a/vars.config.in b/vars.config.in
index 47fc5dd44..ff549242d 100644
--- a/vars.config.in
+++ b/vars.config.in
@@ -25,6 +25,7 @@
{debug, @debug@}.
{hipe, @hipe@}.
{erlang_deprecated_types, @erlang_deprecated_types@}.
+{new_sql_schema, @new_sql_schema@}.
%% Ad-hoc directories with source files
{tools, @tools@}.