diff options
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()}). @@ -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@}. |
