mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-28 16:34:13 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d364eab74b
@ -3,6 +3,7 @@ language: erlang
|
||||
otp_release:
|
||||
- 17.5
|
||||
- 18.3
|
||||
- 19.1
|
||||
|
||||
services:
|
||||
- riak
|
||||
|
10
Makefile.in
10
Makefile.in
@ -108,14 +108,6 @@ edoc:
|
||||
$(ERL) -noinput +B -eval \
|
||||
'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.'
|
||||
|
||||
spec:
|
||||
$(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \
|
||||
'case fxml_gen:compile("specs/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.'
|
||||
|
||||
xdata:
|
||||
$(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \
|
||||
'case xdata_codec:compile("specs", [{erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.'
|
||||
|
||||
JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1))
|
||||
|
||||
VERSIONED_DEP=$(if $(DEP_$(1)_VERSION),$(DEP_$(1)_VERSION),$(1))
|
||||
@ -347,5 +339,5 @@ quicktest:
|
||||
$(REBAR) skip_deps=true ct suites=elixir
|
||||
|
||||
.PHONY: src edoc dialyzer Makefile TAGS clean clean-rel distclean rel \
|
||||
install uninstall uninstall-binary uninstall-all translations deps test spec \
|
||||
install uninstall uninstall-binary uninstall-all translations deps test \
|
||||
quicktest erlang_plt deps_plt ejabberd_plt
|
||||
|
51
include/bosh.hrl
Normal file
51
include/bosh.hrl
Normal file
@ -0,0 +1,51 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2016 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.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(CT_XML,
|
||||
{<<"Content-Type">>, <<"text/xml; charset=utf-8">>}).
|
||||
|
||||
-define(CT_PLAIN,
|
||||
{<<"Content-Type">>, <<"text/plain">>}).
|
||||
|
||||
-define(CT_JSON,
|
||||
{<<"Content-Type">>, <<"application/json">>}).
|
||||
|
||||
-define(AC_ALLOW_ORIGIN,
|
||||
{<<"Access-Control-Allow-Origin">>, <<"*">>}).
|
||||
|
||||
-define(AC_ALLOW_METHODS,
|
||||
{<<"Access-Control-Allow-Methods">>,
|
||||
<<"GET, POST, OPTIONS">>}).
|
||||
|
||||
-define(AC_ALLOW_HEADERS,
|
||||
{<<"Access-Control-Allow-Headers">>,
|
||||
<<"Content-Type">>}).
|
||||
|
||||
-define(AC_MAX_AGE,
|
||||
{<<"Access-Control-Max-Age">>, <<"86400">>}).
|
||||
|
||||
-define(OPTIONS_HEADER,
|
||||
[?CT_PLAIN, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_METHODS,
|
||||
?AC_ALLOW_HEADERS, ?AC_MAX_AGE]).
|
||||
|
||||
-define(HEADER(CType),
|
||||
[CType, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_bosh).
|
@ -1,10 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: flex_offline.xdata
|
||||
%% Form type: http://jabber.org/protocol/offline
|
||||
%% Document: XEP-0013
|
||||
|
||||
|
||||
-type property() :: {'number_of_messages', non_neg_integer()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type form() :: [property() | xdata_field()].
|
@ -1,17 +0,0 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% @copyright (C) 2016, Evgeny Khramtsov
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 10 Jul 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%-------------------------------------------------------------------
|
||||
-record(jid, {user = <<"">> :: binary(),
|
||||
server = <<"">> :: binary(),
|
||||
resource = <<"">> :: binary(),
|
||||
luser = <<"">> :: binary(),
|
||||
lserver = <<"">> :: binary(),
|
||||
lresource = <<"">> :: binary()}).
|
||||
|
||||
-type(jid() :: #jid{}).
|
||||
-type(ljid() :: {binary(), binary(), binary()}).
|
@ -1,13 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: mam_query.xdata
|
||||
%% Form type: urn:xmpp:mam:1
|
||||
%% Document: XEP-0313
|
||||
|
||||
|
||||
-type property() :: {'with', jid:jid()} |
|
||||
{'start', erlang:timestamp()} |
|
||||
{'end', erlang:timestamp()} |
|
||||
{'withtext', binary()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type form() :: [property() | xdata_field()].
|
@ -1,7 +1,7 @@
|
||||
-record(offline_msg,
|
||||
{us = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||
timestamp = now() :: erlang:timestamp() | '_',
|
||||
expire = now() :: erlang:timestamp() | never | '_',
|
||||
timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_',
|
||||
expire = p1_time_compat:timestamp() :: erlang:timestamp() | never | '_',
|
||||
from = #jid{} :: jid() | '_',
|
||||
to = #jid{} :: jid() | '_',
|
||||
packet = #xmlel{} :: xmlel() | '_'}).
|
||||
|
@ -1,16 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: muc_register.xdata
|
||||
%% Form type: http://jabber.org/protocol/muc#register
|
||||
%% Document: XEP-0045
|
||||
|
||||
|
||||
-type property() :: {'allow', boolean()} |
|
||||
{'email', binary()} |
|
||||
{'faqentry', [binary()]} |
|
||||
{'first', binary()} |
|
||||
{'last', binary()} |
|
||||
{'roomnick', binary()} |
|
||||
{'url', binary()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type form() :: [property() | xdata_field()].
|
@ -1,16 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: muc_request.xdata
|
||||
%% Form type: http://jabber.org/protocol/muc#request
|
||||
%% Document: XEP-0045
|
||||
|
||||
|
||||
-type property() :: {'role', participant} |
|
||||
{'jid', jid:jid()} |
|
||||
{'roomnick', binary()} |
|
||||
{'request_allow', boolean()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type options(T) :: [{binary(), T}].
|
||||
-type property_with_options() ::
|
||||
{'role', participant, options(participant)}.
|
||||
-type form() :: [property() | property_with_options() | xdata_field()].
|
@ -1,55 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: muc_roomconfig.xdata
|
||||
%% Form type: http://jabber.org/protocol/muc#roomconfig
|
||||
%% Document: XEP-0045
|
||||
|
||||
-type 'allow_private_messages_from_visitors'() :: nobody | moderators | anyone.
|
||||
-type 'maxusers'() :: none | non_neg_integer().
|
||||
-type 'presencebroadcast'() :: moderator | participant | visitor.
|
||||
-type 'whois'() :: moderators | anyone.
|
||||
|
||||
-type property() :: {'maxhistoryfetch', binary()} |
|
||||
{'allowpm', binary()} |
|
||||
{'allow_private_messages', boolean()} |
|
||||
{'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'()} |
|
||||
{'allow_visitor_status', boolean()} |
|
||||
{'allow_visitor_nickchange', boolean()} |
|
||||
{'allow_voice_requests', boolean()} |
|
||||
{'allow_subscription', boolean()} |
|
||||
{'voice_request_min_interval', non_neg_integer()} |
|
||||
{'captcha_protected', boolean()} |
|
||||
{'captcha_whitelist', [jid:jid()]} |
|
||||
{'allow_query_users', boolean()} |
|
||||
{'allowinvites', boolean()} |
|
||||
{'changesubject', boolean()} |
|
||||
{'enablelogging', boolean()} |
|
||||
{'getmemberlist', [binary()]} |
|
||||
{'lang', binary()} |
|
||||
{'pubsub', binary()} |
|
||||
{'maxusers', 'maxusers'()} |
|
||||
{'membersonly', boolean()} |
|
||||
{'moderatedroom', boolean()} |
|
||||
{'members_by_default', boolean()} |
|
||||
{'passwordprotectedroom', boolean()} |
|
||||
{'persistentroom', boolean()} |
|
||||
{'presencebroadcast', ['presencebroadcast'()]} |
|
||||
{'publicroom', boolean()} |
|
||||
{'public_list', boolean()} |
|
||||
{'roomadmins', [jid:jid()]} |
|
||||
{'roomdesc', binary()} |
|
||||
{'roomname', binary()} |
|
||||
{'roomowners', [jid:jid()]} |
|
||||
{'roomsecret', binary()} |
|
||||
{'whois', 'whois'()} |
|
||||
{'mam', boolean()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type options(T) :: [{binary(), T}].
|
||||
-type property_with_options() ::
|
||||
{'allowpm', binary(), options(binary())} |
|
||||
{'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'(), options('allow_private_messages_from_visitors'())} |
|
||||
{'getmemberlist', [binary()], options(binary())} |
|
||||
{'maxusers', 'maxusers'(), options('maxusers'())} |
|
||||
{'presencebroadcast', ['presencebroadcast'()], options('presencebroadcast'())} |
|
||||
{'whois', 'whois'(), options('whois'())}.
|
||||
-type form() :: [property() | property_with_options() | xdata_field()].
|
@ -1,18 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: muc_roominfo.xdata
|
||||
%% Form type: http://jabber.org/protocol/muc#roominfo
|
||||
%% Document: XEP-0045
|
||||
|
||||
|
||||
-type property() :: {'maxhistoryfetch', non_neg_integer()} |
|
||||
{'contactjid', [jid:jid()]} |
|
||||
{'description', binary()} |
|
||||
{'lang', binary()} |
|
||||
{'ldapgroup', binary()} |
|
||||
{'logs', binary()} |
|
||||
{'occupants', non_neg_integer()} |
|
||||
{'subject', binary()} |
|
||||
{'subjectmod', boolean()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type form() :: [property() | xdata_field()].
|
182
include/ns.hrl
182
include/ns.hrl
@ -1,182 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2016 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.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-define(NS_COMPONENT, <<"jabber:component:accept">>).
|
||||
-define(NS_SERVER, <<"jabber:server">>).
|
||||
-define(NS_SERVER_DIALBACK, <<"jabber:server:dialback">>).
|
||||
-define(NS_CLIENT, <<"jabber:client">>).
|
||||
-define(NS_DISCO_ITEMS,
|
||||
<<"http://jabber.org/protocol/disco#items">>).
|
||||
-define(NS_DISCO_INFO,
|
||||
<<"http://jabber.org/protocol/disco#info">>).
|
||||
-define(NS_VCARD, <<"vcard-temp">>).
|
||||
-define(NS_VCARD_UPDATE, <<"vcard-temp:x:update">>).
|
||||
-define(NS_AUTH, <<"jabber:iq:auth">>).
|
||||
-define(NS_AUTH_ERROR, <<"jabber:iq:auth:error">>).
|
||||
-define(NS_REGISTER, <<"jabber:iq:register">>).
|
||||
-define(NS_SEARCH, <<"jabber:iq:search">>).
|
||||
-define(NS_ROSTER, <<"jabber:iq:roster">>).
|
||||
-define(NS_ROSTER_VER,
|
||||
<<"urn:xmpp:features:rosterver">>).
|
||||
-define(NS_PRIVACY, <<"jabber:iq:privacy">>).
|
||||
-define(NS_BLOCKING, <<"urn:xmpp:blocking">>).
|
||||
-define(NS_PRIVATE, <<"jabber:iq:private">>).
|
||||
-define(NS_VERSION, <<"jabber:iq:version">>).
|
||||
-define(NS_TIME, <<"urn:xmpp:time">>).
|
||||
-define(NS_LAST, <<"jabber:iq:last">>).
|
||||
-define(NS_XDATA, <<"jabber:x:data">>).
|
||||
-define(NS_IQDATA, <<"jabber:iq:data">>).
|
||||
-define(NS_DELAY, <<"urn:xmpp:delay">>).
|
||||
-define(NS_HINTS, <<"urn:xmpp:hints">>).
|
||||
-define(NS_EXPIRE, <<"jabber:x:expire">>).
|
||||
-define(NS_EVENT, <<"jabber:x:event">>).
|
||||
-define(NS_CHATSTATES,
|
||||
<<"http://jabber.org/protocol/chatstates">>).
|
||||
-define(NS_XCONFERENCE, <<"jabber:x:conference">>).
|
||||
-define(NS_STATS,
|
||||
<<"http://jabber.org/protocol/stats">>).
|
||||
-define(NS_MUC, <<"http://jabber.org/protocol/muc">>).
|
||||
-define(NS_MUC_USER,
|
||||
<<"http://jabber.org/protocol/muc#user">>).
|
||||
-define(NS_MUC_ADMIN,
|
||||
<<"http://jabber.org/protocol/muc#admin">>).
|
||||
-define(NS_MUC_OWNER,
|
||||
<<"http://jabber.org/protocol/muc#owner">>).
|
||||
-define(NS_MUC_UNIQUE,
|
||||
<<"http://jabber.org/protocol/muc#unique">>).
|
||||
-define(NS_PUBSUB,
|
||||
<<"http://jabber.org/protocol/pubsub">>).
|
||||
-define(NS_PUBSUB_EVENT,
|
||||
<<"http://jabber.org/protocol/pubsub#event">>).
|
||||
-define(NS_PUBSUB_META_DATA,
|
||||
<<"http://jabber.org/protocol/pubsub#meta-data">>).
|
||||
-define(NS_PUBSUB_OWNER,
|
||||
<<"http://jabber.org/protocol/pubsub#owner">>).
|
||||
-define(NS_PUBSUB_NMI,
|
||||
<<"http://jabber.org/protocol/pubsub#node-meta-info">>).
|
||||
-define(NS_PUBSUB_ERRORS,
|
||||
<<"http://jabber.org/protocol/pubsub#errors">>).
|
||||
-define(NS_PUBSUB_NODE_CONFIG,
|
||||
<<"http://jabber.org/protocol/pubsub#node_config">>).
|
||||
-define(NS_PUBSUB_SUB_OPTIONS,
|
||||
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
|
||||
-define(NS_PUBSUB_SUBSCRIBE_OPTIONS,
|
||||
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
|
||||
-define(NS_PUBSUB_PUBLISH_OPTIONS,
|
||||
<<"http://jabber.org/protocol/pubsub#publish_options">>).
|
||||
-define(NS_PUBSUB_SUB_AUTH,
|
||||
<<"http://jabber.org/protocol/pubsub#subscribe_authorization">>).
|
||||
-define(NS_PUBSUB_GET_PENDING,
|
||||
<<"http://jabber.org/protocol/pubsub#get-pending">>).
|
||||
-define(NS_COMMANDS,
|
||||
<<"http://jabber.org/protocol/commands">>).
|
||||
-define(NS_BYTESTREAMS,
|
||||
<<"http://jabber.org/protocol/bytestreams">>).
|
||||
-define(NS_ADMIN,
|
||||
<<"http://jabber.org/protocol/admin">>).
|
||||
-define(NS_ADMIN_ANNOUNCE,
|
||||
<<"http://jabber.org/protocol/admin#announce">>).
|
||||
-define(NS_ADMIN_ANNOUNCE_ALL,
|
||||
<<"http://jabber.org/protocol/admin#announce-all">>).
|
||||
-define(NS_ADMIN_SET_MOTD,
|
||||
<<"http://jabber.org/protocol/admin#set-motd">>).
|
||||
-define(NS_ADMIN_EDIT_MOTD,
|
||||
<<"http://jabber.org/protocol/admin#edit-motd">>).
|
||||
-define(NS_ADMIN_DELETE_MOTD,
|
||||
<<"http://jabber.org/protocol/admin#delete-motd">>).
|
||||
-define(NS_ADMIN_ANNOUNCE_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#announce-allhosts">>).
|
||||
-define(NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#announce-all-allhosts">>).
|
||||
-define(NS_ADMIN_SET_MOTD_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#set-motd-allhosts">>).
|
||||
-define(NS_ADMIN_EDIT_MOTD_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#edit-motd-allhosts">>).
|
||||
-define(NS_ADMIN_DELETE_MOTD_ALLHOSTS,
|
||||
<<"http://jabber.org/protocol/admin#delete-motd-allhosts">>).
|
||||
-define(NS_SERVERINFO,
|
||||
<<"http://jabber.org/network/serverinfo">>).
|
||||
-define(NS_RSM, <<"http://jabber.org/protocol/rsm">>).
|
||||
-define(NS_EJABBERD_CONFIG, <<"ejabberd:config">>).
|
||||
-define(NS_STREAM,
|
||||
<<"http://etherx.jabber.org/streams">>).
|
||||
-define(NS_STANZAS,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-stanzas">>).
|
||||
-define(NS_STREAMS,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-streams">>).
|
||||
-define(NS_TLS, <<"urn:ietf:params:xml:ns:xmpp-tls">>).
|
||||
-define(NS_SASL,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-sasl">>).
|
||||
-define(NS_SESSION,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-session">>).
|
||||
-define(NS_BIND,
|
||||
<<"urn:ietf:params:xml:ns:xmpp-bind">>).
|
||||
-define(NS_FEATURE_IQAUTH,
|
||||
<<"http://jabber.org/features/iq-auth">>).
|
||||
-define(NS_FEATURE_IQREGISTER,
|
||||
<<"http://jabber.org/features/iq-register">>).
|
||||
-define(NS_FEATURE_COMPRESS,
|
||||
<<"http://jabber.org/features/compress">>).
|
||||
-define(NS_FEATURE_MSGOFFLINE, <<"msgoffline">>).
|
||||
-define(NS_FLEX_OFFLINE, <<"http://jabber.org/protocol/offline">>).
|
||||
-define(NS_COMPRESS,
|
||||
<<"http://jabber.org/protocol/compress">>).
|
||||
-define(NS_CAPS, <<"http://jabber.org/protocol/caps">>).
|
||||
-define(NS_SHIM, <<"http://jabber.org/protocol/shim">>).
|
||||
-define(NS_ADDRESS,
|
||||
<<"http://jabber.org/protocol/address">>).
|
||||
-define(NS_OOB, <<"jabber:x:oob">>).
|
||||
-define(NS_CAPTCHA, <<"urn:xmpp:captcha">>).
|
||||
-define(NS_MEDIA, <<"urn:xmpp:media-element">>).
|
||||
-define(NS_BOB, <<"urn:xmpp:bob">>).
|
||||
-define(NS_MAM_TMP, <<"urn:xmpp:mam:tmp">>).
|
||||
-define(NS_MAM_0, <<"urn:xmpp:mam:0">>).
|
||||
-define(NS_MAM_1, <<"urn:xmpp:mam:1">>).
|
||||
-define(NS_SID_0, <<"urn:xmpp:sid:0">>).
|
||||
-define(NS_PING, <<"urn:xmpp:ping">>).
|
||||
-define(NS_CARBONS_2, <<"urn:xmpp:carbons:2">>).
|
||||
-define(NS_CARBONS_1, <<"urn:xmpp:carbons:1">>).
|
||||
-define(NS_FORWARD, <<"urn:xmpp:forward:0">>).
|
||||
-define(NS_CLIENT_STATE, <<"urn:xmpp:csi:0">>).
|
||||
-define(NS_STREAM_MGMT_2, <<"urn:xmpp:sm:2">>).
|
||||
-define(NS_STREAM_MGMT_3, <<"urn:xmpp:sm:3">>).
|
||||
-define(NS_HTTP_UPLOAD, <<"urn:xmpp:http:upload">>).
|
||||
-define(NS_HTTP_UPLOAD_OLD, <<"eu:siacs:conversations:http:upload">>).
|
||||
-define(NS_THUMBS_1, <<"urn:xmpp:thumbs:1">>).
|
||||
-define(NS_NICK, <<"http://jabber.org/protocol/nick">>).
|
||||
-define(NS_SIC_0, <<"urn:xmpp:sic:0">>).
|
||||
-define(NS_SIC_1, <<"urn:xmpp:sic:1">>).
|
||||
-define(NS_MIX_0, <<"urn:xmpp:mix:0">>).
|
||||
-define(NS_MIX_SERVICEINFO_0, <<"urn:xmpp:mix:0#serviceinfo">>).
|
||||
-define(NS_MIX_NODES_MESSAGES, <<"urn:xmpp:mix:nodes:messages">>).
|
||||
-define(NS_MIX_NODES_PRESENCE, <<"urn:xmpp:mix:nodes:presence">>).
|
||||
-define(NS_MIX_NODES_PARTICIPANTS, <<"urn:xmpp:mix:nodes:participants">>).
|
||||
-define(NS_MIX_NODES_SUBJECT, <<"urn:xmpp:mix:nodes:subject">>).
|
||||
-define(NS_MIX_NODES_CONFIG, <<"urn:xmpp:mix:nodes:config">>).
|
||||
-define(NS_PRIVILEGE, <<"urn:xmpp:privilege:1">>).
|
||||
-define(NS_DELEGATION, <<"urn:xmpp:delegation:1">>).
|
||||
-define(NS_MUCSUB, <<"urn:xmpp:mucsub:0">>).
|
||||
-define(NS_MUCSUB_NODES_PRESENCE, <<"urn:xmpp:mucsub:nodes:presence">>).
|
||||
-define(NS_MUCSUB_NODES_MESSAGES, <<"urn:xmpp:mucsub:nodes:messages">>).
|
||||
-define(NS_MUCSUB_NODES_PARTICIPANTS, <<"urn:xmpp:mucsub:nodes:participants">>).
|
||||
-define(NS_MUCSUB_NODES_AFFILIATIONS, <<"urn:xmpp:mucsub:nodes:affiliations">>).
|
||||
-define(NS_MUCSUB_NODES_SUBJECT, <<"urn:xmpp:mucsub:nodes:subject">>).
|
||||
-define(NS_MUCSUB_NODES_CONFIG, <<"urn:xmpp:mucsub:nodes:config">>).
|
||||
-define(NS_MUCSUB_NODES_SYSTEM, <<"urn:xmpp:mucsub:nodes:system">>).
|
@ -1,13 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: pubsub_get_pending.xdata
|
||||
%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization
|
||||
%% Document: XEP-0060
|
||||
|
||||
|
||||
-type property() :: {'node', binary()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type options(T) :: [{binary(), T}].
|
||||
-type property_with_options() ::
|
||||
{'node', binary(), options(binary())}.
|
||||
-type form() :: [property() | property_with_options() | xdata_field()].
|
@ -1,60 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: pubsub_node_config.xdata
|
||||
%% Form type: http://jabber.org/protocol/pubsub#node_config
|
||||
%% Document: XEP-0060
|
||||
|
||||
-type 'access_model'() :: authorize | open | presence | roster | whitelist.
|
||||
-type 'children_association_policy'() :: all | owners | whitelist.
|
||||
-type 'itemreply'() :: owner | publisher | none.
|
||||
-type 'node_type'() :: leaf | collection.
|
||||
-type 'notification_type'() :: normal | headline.
|
||||
-type 'publish_model'() :: publishers | subscribers | open.
|
||||
-type 'send_last_published_item'() :: never | on_sub | on_sub_and_presence.
|
||||
|
||||
-type property() :: {'access_model', 'access_model'()} |
|
||||
{'body_xslt', binary()} |
|
||||
{'children_association_policy', 'children_association_policy'()} |
|
||||
{'children_association_whitelist', [jid:jid()]} |
|
||||
{'children', [binary()]} |
|
||||
{'children_max', binary()} |
|
||||
{'collection', [binary()]} |
|
||||
{'contact', [jid:jid()]} |
|
||||
{'dataform_xslt', binary()} |
|
||||
{'deliver_notifications', boolean()} |
|
||||
{'deliver_payloads', boolean()} |
|
||||
{'description', binary()} |
|
||||
{'item_expire', binary()} |
|
||||
{'itemreply', 'itemreply'()} |
|
||||
{'language', binary()} |
|
||||
{'max_items', non_neg_integer()} |
|
||||
{'max_payload_size', non_neg_integer()} |
|
||||
{'node_type', 'node_type'()} |
|
||||
{'notification_type', 'notification_type'()} |
|
||||
{'notify_config', boolean()} |
|
||||
{'notify_delete', boolean()} |
|
||||
{'notify_retract', boolean()} |
|
||||
{'notify_sub', boolean()} |
|
||||
{'persist_items', boolean()} |
|
||||
{'presence_based_delivery', boolean()} |
|
||||
{'publish_model', 'publish_model'()} |
|
||||
{'purge_offline', boolean()} |
|
||||
{'roster_groups_allowed', [binary()]} |
|
||||
{'send_last_published_item', 'send_last_published_item'()} |
|
||||
{'tempsub', boolean()} |
|
||||
{'subscribe', boolean()} |
|
||||
{'title', binary()} |
|
||||
{'type', binary()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type options(T) :: [{binary(), T}].
|
||||
-type property_with_options() ::
|
||||
{'access_model', 'access_model'(), options('access_model'())} |
|
||||
{'children_association_policy', 'children_association_policy'(), options('children_association_policy'())} |
|
||||
{'itemreply', 'itemreply'(), options('itemreply'())} |
|
||||
{'language', binary(), options(binary())} |
|
||||
{'node_type', 'node_type'(), options('node_type'())} |
|
||||
{'notification_type', 'notification_type'(), options('notification_type'())} |
|
||||
{'publish_model', 'publish_model'(), options('publish_model'())} |
|
||||
{'roster_groups_allowed', [binary()], options(binary())} |
|
||||
{'send_last_published_item', 'send_last_published_item'(), options('send_last_published_item'())}.
|
||||
-type form() :: [property() | property_with_options() | xdata_field()].
|
@ -1,14 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: pubsub_publish_options.xdata
|
||||
%% Form type: http://jabber.org/protocol/pubsub#publish-options
|
||||
%% Document: XEP-0060
|
||||
|
||||
-type 'access_model'() :: authorize | open | presence | roster | whitelist.
|
||||
|
||||
-type property() :: {'access_model', 'access_model'()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type options(T) :: [{binary(), T}].
|
||||
-type property_with_options() ::
|
||||
{'access_model', 'access_model'(), options('access_model'())}.
|
||||
-type form() :: [property() | property_with_options() | xdata_field()].
|
@ -1,13 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: pubsub_subscribe_authorization.xdata
|
||||
%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization
|
||||
%% Document: XEP-0060
|
||||
|
||||
|
||||
-type property() :: {'allow', boolean()} |
|
||||
{'node', binary()} |
|
||||
{'subscriber_jid', jid:jid()} |
|
||||
{'subid', binary()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type form() :: [property() | xdata_field()].
|
@ -1,25 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: pubsub_subscribe_options.xdata
|
||||
%% Form type: http://jabber.org/protocol/pubsub#subscribe_options
|
||||
%% Document: XEP-0060
|
||||
|
||||
-type 'show-values'() :: away | chat | dnd | online | xa.
|
||||
-type 'subscription_type'() :: items | nodes.
|
||||
-type 'subscription_depth'() :: 1 | all.
|
||||
|
||||
-type property() :: {'deliver', boolean()} |
|
||||
{'digest', boolean()} |
|
||||
{'digest_frequency', binary()} |
|
||||
{'expire', binary()} |
|
||||
{'include_body', boolean()} |
|
||||
{'show-values', ['show-values'()]} |
|
||||
{'subscription_type', 'subscription_type'()} |
|
||||
{'subscription_depth', 'subscription_depth'()}.
|
||||
-type result() :: [property()].
|
||||
|
||||
-type options(T) :: [{binary(), T}].
|
||||
-type property_with_options() ::
|
||||
{'show-values', ['show-values'()], options('show-values'())} |
|
||||
{'subscription_type', 'subscription_type'(), options('subscription_type'())} |
|
||||
{'subscription_depth', 'subscription_depth'(), options('subscription_depth'())}.
|
||||
-type form() :: [property() | property_with_options() | xdata_field()].
|
@ -1,25 +0,0 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% @copyright (C) 2015, Evgeny Khramtsov
|
||||
%%% @doc
|
||||
%%%
|
||||
%%% @end
|
||||
%%% Created : 10 Dec 2015 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%-------------------------------------------------------------------
|
||||
-include("ns.hrl").
|
||||
-include("jid.hrl").
|
||||
-include("xmpp_codec.hrl").
|
||||
-include("fxml.hrl").
|
||||
|
||||
-type iq_type() :: get | set | result | error.
|
||||
-type message_type() :: chat | error | groupchat | headline | normal.
|
||||
-type presence_type() :: available | error | probe | subscribe |
|
||||
subscribed | unavailable | unsubscribe |
|
||||
unsubscribed.
|
||||
|
||||
-type stanza() :: iq() | presence() | message().
|
||||
|
||||
-define(is_stanza(Pkt),
|
||||
(is_record(Pkt, iq) or
|
||||
is_record(Pkt, message) or
|
||||
is_record(Pkt, presence))).
|
File diff suppressed because it is too large
Load Diff
9
mix.exs
9
mix.exs
@ -27,14 +27,14 @@ defmodule Ejabberd.Mixfile do
|
||||
[mod: {:ejabberd_app, []},
|
||||
applications: [:ssl],
|
||||
included_applications: [:lager, :mnesia, :p1_utils, :cache_tab,
|
||||
:fast_tls, :stringprep, :fast_xml,
|
||||
:fast_tls, :stringprep, :fast_xml, :xmpp,
|
||||
:stun, :fast_yaml, :esip, :jiffy, :p1_oauth2]
|
||||
++ cond_apps]
|
||||
end
|
||||
|
||||
defp erlc_options do
|
||||
# Use our own includes + includes from all dependencies
|
||||
includes = ["include"] ++ Path.wildcard(Path.join("..", "/*/include"))
|
||||
includes = ["include"] ++ Path.wildcard("deps/*/include")
|
||||
[:debug_info] ++ Enum.map(includes, fn(path) -> {:i, path} end)
|
||||
end
|
||||
|
||||
@ -42,10 +42,11 @@ defmodule Ejabberd.Mixfile do
|
||||
[{:lager, "~> 3.2"},
|
||||
{:p1_utils, "~> 1.0"},
|
||||
{:cache_tab, "~> 1.0"},
|
||||
{:stringprep, "~> 1.0"},
|
||||
{:stringprep, "~> 1.0", override: true}, # override cause of :xmpp
|
||||
{:fast_yaml, "~> 1.0"},
|
||||
{:fast_tls, "~> 1.0"},
|
||||
{:fast_xml, "~> 1.1"},
|
||||
{:fast_xml, "~> 1.1", override: true}, # override cause of :xmpp
|
||||
{:xmpp, github: "processone/xmpp", tag: "1.0.3"},
|
||||
{:stun, "~> 1.0"},
|
||||
{:esip, "~> 1.0"},
|
||||
{:jiffy, "~> 0.14.7"},
|
||||
|
7
mix.lock
7
mix.lock
@ -1,7 +1,7 @@
|
||||
%{"bbmustache": {:hex, :bbmustache, "1.0.4", "7ba94f971c5afd7b6617918a4bb74705e36cab36eb84b19b6a1b7ee06427aa38", [:rebar], []},
|
||||
"cache_tab": {:hex, :cache_tab, "1.0.4", "3fd2b1ab40c36e7830a4e09e836c6b0fa89191cd4e5fd471873e4eb42f5cd37c", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
|
||||
"cf": {:hex, :cf, "0.2.1", "69d0b1349fd4d7d4dc55b7f407d29d7a840bf9a1ef5af529f1ebe0ce153fc2ab", [:rebar3], []},
|
||||
"earmark": {:hex, :earmark, "1.0.2", "a0b0904d74ecc14da8bd2e6e0248e1a409a2bc91aade75fcf428125603de3853", [:mix], []},
|
||||
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []},
|
||||
"erlware_commons": {:hex, :erlware_commons, "0.21.0", "a04433071ad7d112edefc75ac77719dd3e6753e697ac09428fc83d7564b80b15", [:rebar3], [{:cf, "0.2.1", [hex: :cf, optional: false]}]},
|
||||
"esip": {:hex, :esip, "1.0.8", "69885a6c07964aabc6c077fe1372aa810a848bd3d9a415b160dabdce9c7a79b5", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}, {:stun, "1.0.7", [hex: :stun, optional: false]}]},
|
||||
"ex_doc": {:hex, :ex_doc, "0.14.3", "e61cec6cf9731d7d23d254266ab06ac1decbb7651c3d1568402ec535d387b6f7", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
|
||||
@ -13,11 +13,12 @@
|
||||
"getopt": {:hex, :getopt, "0.8.2", "b17556db683000ba50370b16c0619df1337e7af7ecbf7d64fbf8d1d6bce3109b", [:rebar], []},
|
||||
"goldrush": {:hex, :goldrush, "0.1.8", "2024ba375ceea47e27ea70e14d2c483b2d8610101b4e852ef7f89163cdb6e649", [:rebar3], []},
|
||||
"iconv": {:hex, :iconv, "1.0.2", "a0792f06ab4b5ea1b5bb49789405739f1281a91c44cf3879cb70e4d777666217", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
|
||||
"jiffy": {:hex, :jiffy, "0.14.7", "9f33b893edd6041ceae03bc1e50b412e858cc80b46f3d7535a7a9940a79a1c37", [:rebar, :make], []},
|
||||
"jiffy": {:hex, :jiffy, "0.14.7", "9f33b893edd6041ceae03bc1e50b412e858cc80b46f3d7535a7a9940a79a1c37", [:make, :rebar], []},
|
||||
"lager": {:hex, :lager, "3.2.1", "eef4e18b39e4195d37606d9088ea05bf1b745986cf8ec84f01d332456fe88d17", [:rebar3], [{:goldrush, "0.1.8", [hex: :goldrush, optional: false]}]},
|
||||
"p1_oauth2": {:hex, :p1_oauth2, "0.6.1", "4e021250cc198c538b097393671a41e7cebf463c248980320e038fe0316eb56b", [:rebar3], []},
|
||||
"p1_utils": {:hex, :p1_utils, "1.0.5", "3e698354fdc1fea5491d991457b0cb986c0a00a47d224feb841dc3ec82b9f721", [:rebar3], []},
|
||||
"providers": {:hex, :providers, "1.6.0", "db0e2f9043ae60c0155205fcd238d68516331d0e5146155e33d1e79dc452964a", [:rebar3], [{:getopt, "0.8.2", [hex: :getopt, optional: false]}]},
|
||||
"relx": {:hex, :relx, "3.21.1", "f989dc520730efd9075e9f4debcb8ba1d7d1e86b018b0bcf45a2eb80270b4ad6", [:rebar3], [{:bbmustache, "1.0.4", [hex: :bbmustache, optional: false]}, {:cf, "0.2.1", [hex: :cf, optional: false]}, {:erlware_commons, "0.21.0", [hex: :erlware_commons, optional: false]}, {:getopt, "0.8.2", [hex: :getopt, optional: false]}, {:providers, "1.6.0", [hex: :providers, optional: false]}]},
|
||||
"stringprep": {:hex, :stringprep, "1.0.6", "1cf1c439eb038aa590da5456e019f86afbfbfeb5a2d37b6e5f873041624c6701", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
|
||||
"stun": {:hex, :stun, "1.0.7", "904dc6f26a3c30c54881c4c3003699f2a4968067ee6b3aecdf9895aad02df75e", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]}}
|
||||
"stun": {:hex, :stun, "1.0.7", "904dc6f26a3c30c54881c4c3003699f2a4968067ee6b3aecdf9895aad02df75e", [:rebar3], [{:fast_tls, "1.0.7", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
|
||||
"xmpp": {:git, "https://github.com/processone/xmpp.git", "e4630667bc63de7ad2d236387f4631a0656a9355", [tag: "1.0.3"]}}
|
||||
|
12
rebar.config
12
rebar.config
@ -13,6 +13,7 @@
|
||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}},
|
||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}},
|
||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}},
|
||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.3"}}},
|
||||
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}},
|
||||
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}},
|
||||
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}},
|
||||
@ -55,6 +56,7 @@
|
||||
luerl,
|
||||
stun,
|
||||
fast_yaml,
|
||||
xmpp,
|
||||
p1_utils,
|
||||
p1_mysql,
|
||||
p1_pgsql,
|
||||
@ -65,7 +67,9 @@
|
||||
{erl_first_files, ["src/ejabberd_config.erl", "src/gen_mod.erl"]}.
|
||||
|
||||
{erl_opts, [nowarn_deprecated_function,
|
||||
{i, "include"}, {i, "deps/fast_xml/include"},
|
||||
{i, "include"},
|
||||
{i, "deps/fast_xml/include"},
|
||||
{i, "deps/xmpp/include"},
|
||||
{if_var_false, debug, no_debug_info},
|
||||
{if_var_true, debug, debug_info},
|
||||
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
|
||||
@ -113,8 +117,10 @@
|
||||
{if_var_false, elixir, "(\"Elixir.*\":_/_)"},
|
||||
{if_var_false, redis, "(\"eredis\":_/_)"}]}.
|
||||
|
||||
{eunit_compile_opts, [{i, "tools"}, {i, "include"},
|
||||
{i, "deps/fast_xml/include"}]}.
|
||||
{eunit_compile_opts, [{i, "tools"},
|
||||
{i, "include"},
|
||||
{i, "deps/fast_xml/include"},
|
||||
{i, "deps/xmpp/include"}]}.
|
||||
|
||||
{if_version_above, "17", {cover_enabled, true}}.
|
||||
{cover_export_enabled, true}.
|
||||
|
@ -1 +0,0 @@
|
||||
[{decode, [{<<"number_of_messages">>, {dec_int, [0, infinity]}}]}].
|
@ -1,12 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/offline</name>
|
||||
<doc>XEP-0013</doc>
|
||||
<desc>
|
||||
Service Discovery extension for number of messages
|
||||
in an offline message queue.
|
||||
</desc>
|
||||
<field
|
||||
var='number_of_messages'
|
||||
type='text-single'
|
||||
label='Number of Offline Messages'/>
|
||||
</form_type>
|
@ -1,9 +0,0 @@
|
||||
[{decode, [{<<"start">>, {xmpp_util, decode_timestamp, []}},
|
||||
{<<"end">>, {xmpp_util, decode_timestamp, []}}]},
|
||||
{specs, [{<<"start">>, "erlang:timestamp()"},
|
||||
{<<"end">>, "erlang:timestamp()"}]}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,23 +0,0 @@
|
||||
<form_type>
|
||||
<name>urn:xmpp:mam:1</name>
|
||||
<doc>XEP-0313</doc>
|
||||
<desc>Form to query message archives</desc>
|
||||
<field var='with'
|
||||
type='jid-single'
|
||||
label='User JID'/>
|
||||
<field var='start'
|
||||
type='text-single'
|
||||
label='Search from the date'/>
|
||||
<field var='end'
|
||||
type='text-single'
|
||||
label='Search until the date'/>
|
||||
<field var='withtext'
|
||||
type='text-single'
|
||||
label='Search the text'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,2 +0,0 @@
|
||||
[{prefix, <<"muc#register_">>},
|
||||
{required, [<<"muc#register_roomnick">>]}].
|
@ -1,37 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/muc#register</name>
|
||||
<doc>XEP-0045</doc>
|
||||
<desc>
|
||||
Forms enabling user registration with a
|
||||
Multi-User Chat (MUC) room or admin approval
|
||||
of user registration requests.
|
||||
</desc>
|
||||
<field
|
||||
var='muc#register_allow'
|
||||
type='boolean'
|
||||
label='Allow this person to register with the room?'/>
|
||||
<field
|
||||
var='muc#register_email'
|
||||
type='text-single'
|
||||
label='Email Address'/>
|
||||
<field
|
||||
var='muc#register_faqentry'
|
||||
type='text-multi'
|
||||
label='FAQ Entry'/>
|
||||
<field
|
||||
var='muc#register_first'
|
||||
type='text-single'
|
||||
label='Given Name'/>
|
||||
<field
|
||||
var='muc#register_last'
|
||||
type='text-single'
|
||||
label='Family Name'/>
|
||||
<field
|
||||
var='muc#register_roomnick'
|
||||
type='text-single'
|
||||
label='Nickname'/>
|
||||
<field
|
||||
var='muc#register_url'
|
||||
type='text-single'
|
||||
label='A Web Page'/>
|
||||
</form_type>
|
@ -1,2 +0,0 @@
|
||||
[{prefix, <<"muc#">>},
|
||||
{required, [<<"muc#role">>]}].
|
@ -1,31 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/muc#request</name>
|
||||
<doc>XEP-0045</doc>
|
||||
<desc>
|
||||
Forms enabling voice requests in a
|
||||
Multi-User Chat (MUC) room or admin
|
||||
approval of such requests.
|
||||
</desc>
|
||||
<field var='muc#role'
|
||||
type='list-single'
|
||||
label='Requested role'>
|
||||
<option label='Participant'>
|
||||
<value>participant</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='muc#jid'
|
||||
type='jid-single'
|
||||
label='User JID'/>
|
||||
<field var='muc#roomnick'
|
||||
type='text-single'
|
||||
label='Nickname'/>
|
||||
<field var='muc#request_allow'
|
||||
type='boolean'
|
||||
label='Grant voice to this person?'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,11 +0,0 @@
|
||||
[{prefix, <<"muc#roomconfig_">>},
|
||||
{prefix, <<"muc#">>},
|
||||
{decode, [{<<"muc#roomconfig_maxusers">>,
|
||||
{dec_enum_int, [[none], 0, infinity]}},
|
||||
{<<"voice_request_min_interval">>,
|
||||
{dec_int, [0, infinity]}}]}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,192 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/muc#roomconfig</name>
|
||||
<doc>XEP-0045</doc>
|
||||
<desc>
|
||||
Forms enabling creation and configuration of
|
||||
a Multi-User Chat (MUC) room.
|
||||
</desc>
|
||||
<field
|
||||
var='muc#maxhistoryfetch'
|
||||
type='text-single'
|
||||
label='Maximum Number of History Messages Returned by Room'/>
|
||||
<field
|
||||
var='muc#roomconfig_allowpm'
|
||||
type='list-single'
|
||||
label='Roles that May Send Private Messages'/>
|
||||
<field
|
||||
var='allow_private_messages'
|
||||
type='boolean'
|
||||
label='Allow users to send private messages'/>
|
||||
<field
|
||||
var='allow_private_messages_from_visitors'
|
||||
type='list-single'
|
||||
label='Allow visitors to send private messages to'>
|
||||
<option label='nobody'>
|
||||
<value>nobody</value>
|
||||
</option>
|
||||
<option label='moderators only'>
|
||||
<value>moderators</value>
|
||||
</option>
|
||||
<option label='anyone'>
|
||||
<value>anyone</value>
|
||||
</option>
|
||||
</field>
|
||||
<field
|
||||
var='allow_visitor_status'
|
||||
type='boolean'
|
||||
label='Allow visitors to send status text in presence updates'/>
|
||||
<field
|
||||
var='allow_visitor_nickchange'
|
||||
type='boolean'
|
||||
label='Allow visitors to change nickname'/>
|
||||
<field
|
||||
var='allow_voice_requests'
|
||||
type='boolean'
|
||||
label='Allow visitors to send voice requests'/>
|
||||
<field
|
||||
var='allow_subscription'
|
||||
type='boolean'
|
||||
label='Allow subscription'/>
|
||||
<field
|
||||
var='voice_request_min_interval'
|
||||
type='text-single'
|
||||
label='Minimum interval between voice requests (in seconds)'/>
|
||||
<field
|
||||
var='captcha_protected'
|
||||
type='boolean'
|
||||
label='Make room CAPTCHA protected'/>
|
||||
<field
|
||||
var='captcha_whitelist'
|
||||
type='jid-multi'
|
||||
label='Exclude Jabber IDs from CAPTCHA challenge'/>
|
||||
<field
|
||||
var='allow_query_users'
|
||||
type='boolean'
|
||||
label='Allow users to query other users'/>
|
||||
<field
|
||||
var='muc#roomconfig_allowinvites'
|
||||
type='boolean'
|
||||
label='Allow users to send invites'/>
|
||||
<field
|
||||
var='muc#roomconfig_changesubject'
|
||||
type='boolean'
|
||||
label='Allow users to change the subject'/>
|
||||
<field
|
||||
var='muc#roomconfig_enablelogging'
|
||||
type='boolean'
|
||||
label='Enable logging'/>
|
||||
<field
|
||||
var='muc#roomconfig_getmemberlist'
|
||||
type='list-multi'
|
||||
label='Roles and Affiliations that May Retrieve Member List'/>
|
||||
<field
|
||||
var='muc#roomconfig_lang'
|
||||
type='text-single'
|
||||
label='Natural Language for Room Discussions'/>
|
||||
<field
|
||||
var='muc#roomconfig_pubsub'
|
||||
type='text-single'
|
||||
label='XMPP URI of Associated Publish-Subscribe Node'/>
|
||||
<field
|
||||
var='muc#roomconfig_maxusers'
|
||||
type='list-single'
|
||||
label='Maximum Number of Occupants'>
|
||||
<option label='No limit'>
|
||||
<value>none</value>
|
||||
</option>
|
||||
<option><value>5</value></option>
|
||||
<option><value>10</value></option>
|
||||
<option><value>20</value></option>
|
||||
<option><value>30</value></option>
|
||||
<option><value>50</value></option>
|
||||
<option><value>100</value></option>
|
||||
<option><value>200</value></option>
|
||||
<option><value>500</value></option>
|
||||
<option><value>1000</value></option>
|
||||
<option><value>2000</value></option>
|
||||
<option><value>5000</value></option>
|
||||
</field>
|
||||
<field
|
||||
var='muc#roomconfig_membersonly'
|
||||
type='boolean'
|
||||
label='Make room members-only'/>
|
||||
<field
|
||||
var='muc#roomconfig_moderatedroom'
|
||||
type='boolean'
|
||||
label='Make room moderated'/>
|
||||
<field
|
||||
var='members_by_default'
|
||||
type='boolean'
|
||||
label='Default users as participants'/>
|
||||
<field
|
||||
var='muc#roomconfig_passwordprotectedroom'
|
||||
type='boolean'
|
||||
label='Make room password protected'/>
|
||||
<field
|
||||
var='muc#roomconfig_persistentroom'
|
||||
type='boolean'
|
||||
label='Make room persistent'/>
|
||||
<field
|
||||
var='muc#roomconfig_presencebroadcast'
|
||||
type='list-multi'
|
||||
label='Roles for which Presence is Broadcasted'>
|
||||
<option label='Moderator'>
|
||||
<value>moderator</value>
|
||||
</option>
|
||||
<option label='Participant'>
|
||||
<value>participant</value>
|
||||
</option>
|
||||
<option label='Visitor'>
|
||||
<value>visitor</value>
|
||||
</option>
|
||||
</field>
|
||||
<field
|
||||
var='muc#roomconfig_publicroom'
|
||||
type='boolean'
|
||||
label='Make room public searchable'/>
|
||||
<field
|
||||
var='public_list'
|
||||
type='boolean'
|
||||
label='Make participants list public'/>
|
||||
<field
|
||||
var='muc#roomconfig_roomadmins'
|
||||
type='jid-multi'
|
||||
label='Full List of Room Admins'/>
|
||||
<field
|
||||
var='muc#roomconfig_roomdesc'
|
||||
type='text-single'
|
||||
label='Room description'/>
|
||||
<field
|
||||
var='muc#roomconfig_roomname'
|
||||
type='text-single'
|
||||
label='Room title'/>
|
||||
<field
|
||||
var='muc#roomconfig_roomowners'
|
||||
type='jid-multi'
|
||||
label='Full List of Room Owners'/>
|
||||
<field
|
||||
var='muc#roomconfig_roomsecret'
|
||||
type='text-private'
|
||||
label='Password'/>
|
||||
<field
|
||||
var='muc#roomconfig_whois'
|
||||
type='list-single'
|
||||
label='Present real Jabber IDs to'>
|
||||
<option label='moderators only'>
|
||||
<value>moderators</value>
|
||||
</option>
|
||||
<option label='anyone'>
|
||||
<value>anyone</value>
|
||||
</option>
|
||||
</field>
|
||||
<field
|
||||
var='mam'
|
||||
type='boolean'
|
||||
label='Enable message archiving'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,11 +0,0 @@
|
||||
[{prefix, <<"muc#roominfo_">>},
|
||||
{prefix, <<"muc#">>},
|
||||
{decode, [{<<"muc#maxhistoryfetch">>,
|
||||
{dec_int, [0, infinity]}},
|
||||
{<<"muc#roominfo_occupants">>,
|
||||
{dec_int, [0, infinity]}}]}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,55 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/muc#roominfo</name>
|
||||
<doc>XEP-0045</doc>
|
||||
<desc>
|
||||
Forms enabling the communication of extended service discovery
|
||||
information about a Multi-User Chat (MUC) room.
|
||||
</desc>
|
||||
<field
|
||||
var='muc#maxhistoryfetch'
|
||||
type='text-single'
|
||||
label='Maximum Number of History Messages Returned by Room'/>
|
||||
<field
|
||||
var='muc#roominfo_contactjid'
|
||||
type='jid-multi'
|
||||
label='Contact Addresses (normally, room owner or owners)'/>
|
||||
<field
|
||||
var='muc#roominfo_description'
|
||||
type='text-single'
|
||||
label='Room description'/>
|
||||
<field
|
||||
var='muc#roominfo_lang'
|
||||
type='text-single'
|
||||
label='Natural Language for Room Discussions'/>
|
||||
<field
|
||||
var='muc#roominfo_ldapgroup'
|
||||
type='text-single'
|
||||
label='An associated LDAP group that defines
|
||||
room membership; this should be an LDAP
|
||||
Distinguished Name according to an
|
||||
implementation-specific or
|
||||
deployment-specific definition of a
|
||||
group.'/>
|
||||
<field
|
||||
var='muc#roominfo_logs'
|
||||
type='text-single'
|
||||
label='URL for Archived Discussion Logs'/>
|
||||
<field
|
||||
var='muc#roominfo_occupants'
|
||||
type='text-single'
|
||||
label='Number of occupants'/>
|
||||
<field
|
||||
var='muc#roominfo_subject'
|
||||
type='text-single'
|
||||
label='Current Discussion Topic'/>
|
||||
<field
|
||||
var='muc#roominfo_subjectmod'
|
||||
type='boolean'
|
||||
label='The room subject can be modified by participants'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,7 +0,0 @@
|
||||
[{prefix, <<"pubsub#">>},
|
||||
{required, [<<"pubsub#node">>]}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,15 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/pubsub#subscribe_authorization</name>
|
||||
<doc>XEP-0060</doc>
|
||||
<desc>Forms enabling authorization of subscriptions to pubsub nodes</desc>
|
||||
<field
|
||||
var='pubsub#node'
|
||||
type='list-single'
|
||||
label='The NodeID of the relevant node'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,8 +0,0 @@
|
||||
[{prefix, <<"pubsub#">>},
|
||||
{decode, [{<<"pubsub#max_items">>, {dec_int, [0,infinity]}},
|
||||
{<<"pubsub#max_payload_size">>, {dec_int, [0,infinity]}}]}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,189 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/pubsub#node_config</name>
|
||||
<doc>XEP-0060</doc>
|
||||
<desc>Forms enabling configuration of pubsub nodes</desc>
|
||||
<field var='pubsub#access_model'
|
||||
type='list-single'
|
||||
label='Specify the access model'>
|
||||
<option label='Subscription requests must be approved and only subscribers may retrieve items'>
|
||||
<value>authorize</value>
|
||||
</option>
|
||||
<option label='Anyone may subscribe and retrieve items'>
|
||||
<value>open</value>
|
||||
</option>
|
||||
<option label='Anyone with a presence subscription of both or from may subscribe and retrieve items'>
|
||||
<value>presence</value>
|
||||
</option>
|
||||
<option label='Anyone in the specified roster group(s) may subscribe and retrieve items'>
|
||||
<value>roster</value>
|
||||
</option>
|
||||
<option label='Only those on a whitelist may subscribe and retrieve items'>
|
||||
<value>whitelist</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#body_xslt'
|
||||
type='text-single'
|
||||
label='The URL of an XSL transformation which can be
|
||||
applied to payloads in order to generate an
|
||||
appropriate message body element.'/>
|
||||
<field var='pubsub#children_association_policy'
|
||||
type='list-single'
|
||||
label='Who may associate leaf nodes with a collection'>
|
||||
<option label='Anyone may associate leaf nodes with the collection'>
|
||||
<value>all</value>
|
||||
</option>
|
||||
<option label='Only collection node owners may associate leaf nodes with the collection'>
|
||||
<value>owners</value>
|
||||
</option>
|
||||
<option label='Only those on a whitelist may associate leaf nodes with the collection'>
|
||||
<value>whitelist</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#children_association_whitelist'
|
||||
type='jid-multi'
|
||||
label='The list of JIDs that may associate leaf nodes with a collection'/>
|
||||
<field var='pubsub#children'
|
||||
type='text-multi'
|
||||
label='The child nodes (leaf or collection) associated with a collection'/>
|
||||
<field var='pubsub#children_max'
|
||||
type='text-single'
|
||||
label='The maximum number of child nodes that can be associated with a collection'/>
|
||||
<field var='pubsub#collection'
|
||||
type='text-multi'
|
||||
label='The collections with which a node is affiliated'/>
|
||||
<field var='pubsub#contact'
|
||||
type='jid-multi'
|
||||
label='The JIDs of those to contact with questions'/>
|
||||
<field var='pubsub#dataform_xslt'
|
||||
type='text-single'
|
||||
label='The URL of an XSL transformation which can be
|
||||
applied to the payload format in order to generate
|
||||
a valid Data Forms result that the client could
|
||||
display using a generic Data Forms rendering
|
||||
engine'/>
|
||||
<field var='pubsub#deliver_notifications' type='boolean'
|
||||
label='Deliver event notifications'>
|
||||
<value>true</value>
|
||||
</field>
|
||||
<field var='pubsub#deliver_payloads'
|
||||
type='boolean'
|
||||
label='Deliver payloads with event notifications'/>
|
||||
<field var='pubsub#description'
|
||||
type='text-single'
|
||||
label='A description of the node'/>
|
||||
<field var='pubsub#item_expire'
|
||||
type='text-single'
|
||||
label='Number of seconds after which to automatically purge items'/>
|
||||
<field var='pubsub#itemreply'
|
||||
type='list-single'
|
||||
label='Whether owners or publisher should receive replies to items'>
|
||||
<option label='Statically specify a replyto of the node owner(s)'>
|
||||
<value>owner</value>
|
||||
</option>
|
||||
<option label='Dynamically specify a replyto of the item publisher'>
|
||||
<value>publisher</value>
|
||||
</option>
|
||||
<option>
|
||||
<value>none</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#language'
|
||||
type='list-single'
|
||||
label='The default language of the node'/>
|
||||
<field var='pubsub#max_items'
|
||||
type='text-single'
|
||||
label='Max # of items to persist'>
|
||||
</field>
|
||||
<field var='pubsub#max_payload_size'
|
||||
type='text-single'
|
||||
label='Max payload size in bytes'/>
|
||||
<field var='pubsub#node_type'
|
||||
type='list-single'
|
||||
label='Whether the node is a leaf (default) or a collection'>
|
||||
<option label='The node is a leaf node (default)'>
|
||||
<value>leaf</value>
|
||||
</option>
|
||||
<option label='The node is a collection node'>
|
||||
<value>collection</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#notification_type' type='list-single'
|
||||
label='Specify the event message type'>
|
||||
<option label='Messages of type normal'>
|
||||
<value>normal</value>
|
||||
</option>
|
||||
<option label='Messages of type headline'>
|
||||
<value>headline</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#notify_config'
|
||||
type='boolean'
|
||||
label='Notify subscribers when the node configuration changes'/>
|
||||
<field var='pubsub#notify_delete'
|
||||
type='boolean'
|
||||
label='Notify subscribers when the node is deleted'/>
|
||||
<field var='pubsub#notify_retract'
|
||||
type='boolean'
|
||||
label='Notify subscribers when items are removed from the node'/>
|
||||
<field var='pubsub#notify_sub'
|
||||
type='boolean'
|
||||
label='Whether to notify owners about new subscribers and unsubscribes'/>
|
||||
<field var='pubsub#persist_items'
|
||||
type='boolean'
|
||||
label='Persist items to storage'/>
|
||||
<field var='pubsub#presence_based_delivery'
|
||||
type='boolean'
|
||||
label='Only deliver notifications to available users'/>
|
||||
<field var='pubsub#publish_model'
|
||||
type='list-single'
|
||||
label='Specify the publisher model'>
|
||||
<option label='Only publishers may publish'>
|
||||
<value>publishers</value>
|
||||
</option>
|
||||
<option label='Subscribers may publish'>
|
||||
<value>subscribers</value>
|
||||
</option>
|
||||
<option label='Anyone may publish'>
|
||||
<value>open</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#purge_offline'
|
||||
type='boolean'
|
||||
label='Purge all items when the relevant publisher goes offline'/>
|
||||
<field var='pubsub#roster_groups_allowed'
|
||||
type='list-multi'
|
||||
label='Roster groups allowed to subscribe'/>
|
||||
<field var='pubsub#send_last_published_item'
|
||||
type='list-single'
|
||||
label='When to send the last published item'>
|
||||
<option label='Never'>
|
||||
<value>never</value>
|
||||
</option>
|
||||
<option label='When a new subscription is processed'>
|
||||
<value>on_sub</value>
|
||||
</option>
|
||||
<option label='When a new subscription is processed and whenever a subscriber comes online'>
|
||||
<value>on_sub_and_presence</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#tempsub'
|
||||
type='boolean'
|
||||
label='Whether to make all subscriptions temporary, based on subscriber presence'/>
|
||||
<field var='pubsub#subscribe' type='boolean'
|
||||
label='Whether to allow subscriptions'>
|
||||
<value>1</value>
|
||||
</field>
|
||||
<field var='pubsub#title'
|
||||
type='text-single'
|
||||
label='A friendly name for the node'/>
|
||||
<field var='pubsub#type'
|
||||
type='text-single'
|
||||
label='The type of node data, usually specified by
|
||||
the namespace of the payload (if any)'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,6 +0,0 @@
|
||||
[{prefix, <<"pubsub#">>}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,34 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/pubsub#publish-options</name>
|
||||
<doc>XEP-0060</doc>
|
||||
<desc>
|
||||
Forms enabling publication with options; each field must specify whether it
|
||||
defines METADATA to be attached to the item, a per-item OVERRIDE of the node
|
||||
configuration, or a PRECONDITION to be checked against the node configuration.
|
||||
</desc>
|
||||
<field var='pubsub#access_model'
|
||||
type='list-single'
|
||||
label='Specify the access model'>
|
||||
<option label='Access model of authorize'>
|
||||
<value>authorize</value>
|
||||
</option>
|
||||
<option label='Access model of open'>
|
||||
<value>open</value>
|
||||
</option>
|
||||
<option label='Access model of presence'>
|
||||
<value>presence</value>
|
||||
</option>
|
||||
<option label='Access model of roster'>
|
||||
<value>roster</value>
|
||||
</option>
|
||||
<option label='Access model of whitelist'>
|
||||
<value>whitelist</value>
|
||||
</option>
|
||||
</field>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1,7 +0,0 @@
|
||||
[{prefix, <<"pubsub#">>},
|
||||
{required, [<<"pubsub#node">>, <<"pubsub#subscriber_jid">>, <<"pubsub#allow">>]}].
|
||||
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
%% vim: set filetype=erlang tabstop=8:
|
@ -1,27 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/pubsub#subscribe_authorization</name>
|
||||
<doc>XEP-0060</doc>
|
||||
<desc>Forms enabling authorization of subscriptions to pubsub nodes</desc>
|
||||
<field
|
||||
var='pubsub#allow'
|
||||
type='boolean'
|
||||
label='Allow this Jabber ID to subscribe to this pubsub node?'/>
|
||||
<field
|
||||
var='pubsub#node'
|
||||
type='text-single'
|
||||
label='Node ID'/>
|
||||
<field
|
||||
var='pubsub#subscriber_jid'
|
||||
type='jid-single'
|
||||
label='Subscriber Address'/>
|
||||
<field
|
||||
var='pubsub#subid'
|
||||
type='text-single'
|
||||
label='The subscription identifier associated with the subscription request'/>
|
||||
</form_type>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
End:
|
||||
-->
|
@ -1 +0,0 @@
|
||||
[{prefix, <<"pubsub#">>}].
|
@ -1,70 +0,0 @@
|
||||
<form_type>
|
||||
<name>http://jabber.org/protocol/pubsub#subscribe_options</name>
|
||||
<doc>XEP-0060</doc>
|
||||
<desc>Forms enabling configuration of subscription options for pubsub nodes</desc>
|
||||
<field
|
||||
var='pubsub#deliver'
|
||||
type='boolean'
|
||||
label='Whether an entity wants to receive
|
||||
or disable notifications'/>
|
||||
<field
|
||||
var='pubsub#digest'
|
||||
type='boolean'
|
||||
label='Whether an entity wants to receive digests
|
||||
(aggregations) of notifications or all
|
||||
notifications individually'/>
|
||||
<field var='pubsub#digest_frequency'
|
||||
type='text-single'
|
||||
label='The minimum number of milliseconds between
|
||||
sending any two notification digests'/>
|
||||
<field
|
||||
var='pubsub#expire'
|
||||
type='text-single'
|
||||
label='The DateTime at which a leased subscription
|
||||
will end or has ended'/>
|
||||
<field
|
||||
var='pubsub#include_body'
|
||||
type='boolean'
|
||||
label='Whether an entity wants to receive an XMPP
|
||||
message body in addition to the payload
|
||||
format'/>
|
||||
<field
|
||||
var='pubsub#show-values'
|
||||
type='list-multi'
|
||||
label='The presence states for which an entity
|
||||
wants to receive notifications'>
|
||||
<option label='XMPP Show Value of Away'>
|
||||
<value>away</value>
|
||||
</option>
|
||||
<option label='XMPP Show Value of Chat'>
|
||||
<value>chat</value>
|
||||
</option>
|
||||
<option label='XMPP Show Value of DND (Do Not Disturb)'>
|
||||
<value>dnd</value>
|
||||
</option>
|
||||
<option label='Mere Availability in XMPP (No Show Value)'>
|
||||
<value>online</value>
|
||||
</option>
|
||||
<option label='XMPP Show Value of XA (Extended Away)'>
|
||||
<value>xa</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#subscription_type'
|
||||
type='list-single'>
|
||||
<option label='Receive notification of new items only'>
|
||||
<value>items</value>
|
||||
</option>
|
||||
<option label='Receive notification of new nodes only'>
|
||||
<value>nodes</value>
|
||||
</option>
|
||||
</field>
|
||||
<field var='pubsub#subscription_depth'
|
||||
type='list-single'>
|
||||
<option label='Receive notification from direct child nodes only'>
|
||||
<value>1</value>
|
||||
</option>
|
||||
<option label='Receive notification from all descendent nodes'>
|
||||
<value>all</value>
|
||||
</option>
|
||||
</field>
|
||||
</form_type>
|
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,6 @@
|
||||
start(normal, _Args) ->
|
||||
ejabberd_logger:start(),
|
||||
write_pid_file(),
|
||||
jid:start(),
|
||||
start_apps(),
|
||||
start_elixir_application(),
|
||||
ejabberd:check_app(ejabberd),
|
||||
@ -223,8 +222,7 @@ start_apps() ->
|
||||
ejabberd:start_app(ssl),
|
||||
ejabberd:start_app(fast_yaml),
|
||||
ejabberd:start_app(fast_tls),
|
||||
ejabberd:start_app(fast_xml),
|
||||
ejabberd:start_app(stringprep),
|
||||
ejabberd:start_app(xmpp),
|
||||
ejabberd:start_app(cache_tab).
|
||||
|
||||
opt_type(net_ticktime) ->
|
||||
|
@ -36,8 +36,8 @@
|
||||
check_password/6, check_password_with_authmodule/4,
|
||||
check_password_with_authmodule/6, try_register/3,
|
||||
dirty_get_registered_users/0, get_vh_registered_users/1,
|
||||
get_vh_registered_users/2, export/1, import/1,
|
||||
get_vh_registered_users_number/1, import/3,
|
||||
get_vh_registered_users/2, export/1, import_info/0,
|
||||
get_vh_registered_users_number/1, import/5, import_start/2,
|
||||
get_vh_registered_users_number/2, get_password/2,
|
||||
get_password_s/2, get_password_with_authmodule/2,
|
||||
is_user_exists/2, is_user_exists_in_other_modules/3,
|
||||
@ -438,15 +438,20 @@ auth_modules(Server) ->
|
||||
export(Server) ->
|
||||
ejabberd_auth_mnesia:export(Server).
|
||||
|
||||
import(Server) ->
|
||||
ejabberd_auth_mnesia:import(Server).
|
||||
import_info() ->
|
||||
[{<<"users">>, 3}].
|
||||
|
||||
import(Server, mnesia, Passwd) ->
|
||||
ejabberd_auth_mnesia:import(Server, mnesia, Passwd);
|
||||
import(Server, riak, Passwd) ->
|
||||
ejabberd_auth_riak:import(Server, riak, Passwd);
|
||||
import(_, _, _) ->
|
||||
pass.
|
||||
import_start(_LServer, mnesia) ->
|
||||
ejabberd_auth_mnesia:init_db();
|
||||
import_start(_LServer, _) ->
|
||||
ok.
|
||||
|
||||
import(Server, {sql, _}, mnesia, <<"users">>, Fields) ->
|
||||
ejabberd_auth_mnesia:import(Server, Fields);
|
||||
import(Server, {sql, _}, riak, <<"users">>, Fields) ->
|
||||
ejabberd_auth_riak:import(Server, Fields);
|
||||
import(_LServer, {sql, _}, sql, <<"users">>, _) ->
|
||||
ok.
|
||||
|
||||
opt_type(auth_method) ->
|
||||
fun (V) when is_list(V) ->
|
||||
|
@ -36,12 +36,12 @@
|
||||
-export([start/1, set_password/3, check_password/4,
|
||||
check_password/6, try_register/3,
|
||||
dirty_get_registered_users/0, get_vh_registered_users/1,
|
||||
get_vh_registered_users/2,
|
||||
get_vh_registered_users/2, init_db/0,
|
||||
get_vh_registered_users_number/1,
|
||||
get_vh_registered_users_number/2, get_password/2,
|
||||
get_password_s/2, is_user_exists/2, remove_user/2,
|
||||
remove_user/3, store_type/0, export/1, import/1,
|
||||
import/3, plain_password_required/0, opt_type/1]).
|
||||
remove_user/3, store_type/0, export/1, import/2,
|
||||
plain_password_required/0, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -59,16 +59,19 @@
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(Host) ->
|
||||
init_db(),
|
||||
update_table(),
|
||||
update_reg_users_counter_table(Host),
|
||||
maybe_alert_password_scrammed_without_option(),
|
||||
ok.
|
||||
|
||||
init_db() ->
|
||||
mnesia:create_table(passwd,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, passwd)}]),
|
||||
mnesia:create_table(reg_users_counter,
|
||||
[{ram_copies, [node()]},
|
||||
{attributes, record_info(fields, reg_users_counter)}]),
|
||||
update_table(),
|
||||
update_reg_users_counter_table(Host),
|
||||
maybe_alert_password_scrammed_without_option(),
|
||||
ok.
|
||||
{attributes, record_info(fields, reg_users_counter)}]).
|
||||
|
||||
update_reg_users_counter_table(Server) ->
|
||||
Set = get_vh_registered_users(Server),
|
||||
@ -493,16 +496,9 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select username, password from users;">>,
|
||||
fun([LUser, Password]) ->
|
||||
#passwd{us = {LUser, LServer}, password = Password}
|
||||
end}].
|
||||
|
||||
import(_LServer, mnesia, #passwd{} = P) ->
|
||||
mnesia:dirty_write(P);
|
||||
import(_, _, _) ->
|
||||
pass.
|
||||
import(LServer, [LUser, Password, _TimeStamp]) ->
|
||||
mnesia:dirty_write(
|
||||
#passwd{us = {LUser, LServer}, password = Password}).
|
||||
|
||||
opt_type(auth_password_format) -> fun (V) -> V end;
|
||||
opt_type(_) -> [auth_password_format].
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
-compile([{parse_transform, ejabberd_sql_pt}]).
|
||||
|
||||
-behaviour(ejabberd_config).
|
||||
|
||||
-author('alexey@process-one.net').
|
||||
|
||||
-behaviour(ejabberd_auth).
|
||||
@ -39,8 +41,8 @@
|
||||
get_vh_registered_users_number/1,
|
||||
get_vh_registered_users_number/2, get_password/2,
|
||||
get_password_s/2, is_user_exists/2, remove_user/2,
|
||||
remove_user/3, store_type/0, export/1, import/3,
|
||||
plain_password_required/0]).
|
||||
remove_user/3, store_type/0, export/1, import/2,
|
||||
plain_password_required/0, opt_type/1]).
|
||||
-export([passwd_schema/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
@ -301,7 +303,9 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer, riak, #passwd{} = Passwd) ->
|
||||
ejabberd_riak:put(Passwd, passwd_schema(), [{'2i', [{<<"host">>, LServer}]}]);
|
||||
import(_, _, _) ->
|
||||
pass.
|
||||
import(LServer, [LUser, Password, _TimeStamp]) ->
|
||||
Passwd = #passwd{us = {LUser, LServer}, password = Password},
|
||||
ejabberd_riak:put(Passwd, passwd_schema(), [{'2i', [{<<"host">>, LServer}]}]).
|
||||
|
||||
opt_type(auth_password_format) -> fun (V) -> V end;
|
||||
opt_type(_) -> [auth_password_format].
|
||||
|
1095
src/ejabberd_bosh.erl
Normal file
1095
src/ejabberd_bosh.erl
Normal file
File diff suppressed because it is too large
Load Diff
@ -277,6 +277,10 @@ get_commands_spec() ->
|
||||
args_example = ["/home/me/docs/api.html", "mod_admin", "java,json"],
|
||||
result_example = ok}].
|
||||
init() ->
|
||||
try mnesia:transform_table(ejabberd_commands, ignore,
|
||||
record_info(fields, ejabberd_commands))
|
||||
catch exit:{aborted, {no_exists, _}} -> ok
|
||||
end,
|
||||
mnesia:create_table(ejabberd_commands,
|
||||
[{ram_copies, [node()]},
|
||||
{local_content, true},
|
||||
|
@ -231,10 +231,10 @@ open_socket(init, StateData) ->
|
||||
send_header(NewStateData, Version),
|
||||
{next_state, wait_for_stream, NewStateData,
|
||||
?FSMTIMEOUT};
|
||||
{error, _Reason} ->
|
||||
{error, Reason} ->
|
||||
?INFO_MSG("s2s connection: ~s -> ~s (remote server "
|
||||
"not found)",
|
||||
[StateData#state.myname, StateData#state.server]),
|
||||
"not found: ~p)",
|
||||
[StateData#state.myname, StateData#state.server, Reason]),
|
||||
case ejabberd_hooks:run_fold(find_s2s_bridge, undefined,
|
||||
[StateData#state.myname,
|
||||
StateData#state.server])
|
||||
|
@ -52,12 +52,14 @@
|
||||
-include("logger.hrl").
|
||||
|
||||
-type sockmod() :: ejabberd_http_bind |
|
||||
ejabberd_bosh |
|
||||
ejabberd_http_ws |
|
||||
gen_tcp | fast_tls | ezlib.
|
||||
-type receiver() :: pid () | atom().
|
||||
-type socket() :: pid() | inet:socket() |
|
||||
fast_tls:tls_socket() |
|
||||
ezlib:zlib_socket() |
|
||||
ezlib:zlib_socket() |
|
||||
ejabberd_bosh:bind_socket() |
|
||||
ejabberd_http_bind:bind_socket().
|
||||
|
||||
-record(socket_state, {sockmod = gen_tcp :: sockmod(),
|
||||
@ -228,6 +230,7 @@ get_transport(#socket_state{sockmod = SockMod,
|
||||
tcp -> tcp_zlib;
|
||||
tls -> tls_zlib
|
||||
end;
|
||||
ejabberd_bosh -> http_bind;
|
||||
ejabberd_http_bind -> http_bind;
|
||||
ejabberd_http_ws -> websocket
|
||||
end.
|
||||
@ -254,4 +257,3 @@ peername(#socket_state{sockmod = SockMod,
|
||||
gen_tcp -> inet:peername(Socket);
|
||||
_ -> SockMod:peername(Socket)
|
||||
end.
|
||||
|
||||
|
@ -61,10 +61,6 @@ start_link(Host) ->
|
||||
?MODULE, [Host]).
|
||||
|
||||
init([Host]) ->
|
||||
PoolSize = ejabberd_config:get_option(
|
||||
{sql_pool_size, Host},
|
||||
fun(I) when is_integer(I), I>0 -> I end,
|
||||
?DEFAULT_POOL_SIZE),
|
||||
StartInterval = ejabberd_config:get_option(
|
||||
{sql_start_interval, Host},
|
||||
fun(I) when is_integer(I), I>0 -> I end,
|
||||
@ -76,6 +72,7 @@ init([Host]) ->
|
||||
(mssql) -> mssql;
|
||||
(odbc) -> odbc
|
||||
end, odbc),
|
||||
PoolSize = get_pool_size(Type, Host),
|
||||
case Type of
|
||||
sqlite ->
|
||||
check_sqlite_db(Host);
|
||||
@ -117,6 +114,23 @@ remove_pid(Host, Pid) ->
|
||||
end,
|
||||
mnesia:ets(F).
|
||||
|
||||
-spec get_pool_size(atom(), binary()) -> pos_integer().
|
||||
get_pool_size(SQLType, Host) ->
|
||||
PoolSize = ejabberd_config:get_option(
|
||||
{sql_pool_size, Host},
|
||||
fun(I) when is_integer(I), I>0 -> I end,
|
||||
case SQLType of
|
||||
sqlite -> 1;
|
||||
_ -> ?DEFAULT_POOL_SIZE
|
||||
end),
|
||||
if PoolSize > 1 andalso SQLType == sqlite ->
|
||||
?WARNING_MSG("it's not recommended to set sql_pool_size > 1 for "
|
||||
"sqlite, because it may cause race conditions", []);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
PoolSize.
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
|
294
src/ejd2sql.erl
294
src/ejd2sql.erl
@ -30,12 +30,12 @@
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
|
||||
-export([export/2, export/3, import_file/2, import/2,
|
||||
import/3, delete/1]).
|
||||
-export([export/2, export/3, import/3, import/4, delete/1, import_info/1]).
|
||||
|
||||
|
||||
-define(MAX_RECORDS_PER_TRANSACTION, 100).
|
||||
|
||||
-record(dump, {fd, cont = start}).
|
||||
-record(sql_dump, {fd, type}).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
@ -50,13 +50,14 @@
|
||||
modules() ->
|
||||
[ejabberd_auth,
|
||||
mod_announce,
|
||||
mod_caps,
|
||||
mod_irc,
|
||||
mod_last,
|
||||
mod_muc,
|
||||
mod_offline,
|
||||
mod_privacy,
|
||||
mod_private,
|
||||
%% mod_pubsub,
|
||||
mod_pubsub,
|
||||
mod_roster,
|
||||
mod_shared_roster,
|
||||
mod_vcard,
|
||||
@ -100,49 +101,44 @@ delete(Server, Module) ->
|
||||
delete(LServer, Table, ConvertFun)
|
||||
end, Module:export(Server)).
|
||||
|
||||
import_file(Server, FileName) when is_binary(FileName) ->
|
||||
import(Server, binary_to_list(FileName));
|
||||
import_file(Server, FileName) ->
|
||||
case disk_log:open([{name, make_ref()},
|
||||
{file, FileName},
|
||||
{mode, read_only}]) of
|
||||
{ok, Fd} ->
|
||||
LServer = jid:nameprep(Server),
|
||||
Mods = [{Mod, gen_mod:db_type(LServer, Mod)}
|
||||
|| Mod <- modules(), gen_mod:is_loaded(LServer, Mod)],
|
||||
AuthMods = case lists:member(ejabberd_auth_mnesia,
|
||||
ejabberd_auth:auth_modules(LServer)) of
|
||||
true ->
|
||||
[{ejabberd_auth, mnesia}];
|
||||
false ->
|
||||
[]
|
||||
end,
|
||||
import_dump(LServer, AuthMods ++ Mods, #dump{fd = Fd});
|
||||
Err ->
|
||||
exit(Err)
|
||||
end.
|
||||
|
||||
import(Server, Output) ->
|
||||
import(Server, Output, [{fast, true}]).
|
||||
|
||||
import(Server, Output, Opts) ->
|
||||
LServer = jid:nameprep(iolist_to_binary(Server)),
|
||||
Modules = modules(),
|
||||
IO = prepare_output(Output, disk_log),
|
||||
import(Server, Dir, ToType) ->
|
||||
lists:foreach(
|
||||
fun(Module) ->
|
||||
import(LServer, IO, Opts, Module)
|
||||
end, Modules),
|
||||
close_output(Output, IO).
|
||||
fun(Mod) ->
|
||||
?INFO_MSG("importing ~p...", [Mod]),
|
||||
import(Mod, Server, Dir, ToType)
|
||||
end, modules()).
|
||||
|
||||
import(Server, Output, Opts, Module) ->
|
||||
import(Mod, Server, Dir, ToType) ->
|
||||
LServer = jid:nameprep(iolist_to_binary(Server)),
|
||||
IO = prepare_output(Output, disk_log),
|
||||
try Mod:import_start(LServer, ToType)
|
||||
catch error:undef -> ok end,
|
||||
lists:foreach(
|
||||
fun({SelectQuery, ConvertFun}) ->
|
||||
import(LServer, SelectQuery, IO, ConvertFun, Opts)
|
||||
end, Module:import(Server)),
|
||||
close_output(Output, IO).
|
||||
fun({File, Tab, _Mod, FieldsNumber}) ->
|
||||
FileName = filename:join([Dir, File]),
|
||||
case open_sql_dump(FileName) of
|
||||
{ok, #sql_dump{type = FromType} = Dump} ->
|
||||
import_rows(LServer, {sql, FromType}, ToType,
|
||||
Tab, Mod, Dump, FieldsNumber),
|
||||
close_sql_dump(Dump);
|
||||
{error, enoent} ->
|
||||
ok;
|
||||
eof ->
|
||||
?INFO_MSG("It seems like SQL dump ~s is empty", [FileName]);
|
||||
Err ->
|
||||
?ERROR_MSG("Failed to open SQL dump ~s: ~s",
|
||||
[FileName, format_error(Err)])
|
||||
end
|
||||
end, import_info(Mod)),
|
||||
try Mod:import_stop(LServer, ToType)
|
||||
catch error:undef -> ok end.
|
||||
|
||||
import_info(Mod) ->
|
||||
Info = Mod:import_info(),
|
||||
lists:map(
|
||||
fun({Tab, FieldsNum}) ->
|
||||
FileName = <<Tab/binary, ".txt">>,
|
||||
{FileName, Tab, Mod, FieldsNum}
|
||||
end, Info).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
@ -200,79 +196,6 @@ delete(LServer, Table, ConvertFun) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(LServer, SelectQuery, IO, ConvertFun, Opts) ->
|
||||
F = case proplists:get_bool(fast, Opts) of
|
||||
true ->
|
||||
fun() ->
|
||||
case ejabberd_sql:sql_query_t(SelectQuery) of
|
||||
{selected, _, Rows} ->
|
||||
lists:foldl(fun process_sql_row/2,
|
||||
{IO, ConvertFun, undefined}, Rows);
|
||||
Err ->
|
||||
erlang:error(Err)
|
||||
end
|
||||
end;
|
||||
false ->
|
||||
fun() ->
|
||||
ejabberd_sql:sql_query_t(
|
||||
[iolist_to_binary(
|
||||
[<<"declare c cursor for ">>, SelectQuery])]),
|
||||
fetch(IO, ConvertFun, undefined)
|
||||
end
|
||||
end,
|
||||
ejabberd_sql:sql_transaction(LServer, F).
|
||||
|
||||
fetch(IO, ConvertFun, PrevRow) ->
|
||||
case ejabberd_sql:sql_query_t([<<"fetch c;">>]) of
|
||||
{selected, _, [Row]} ->
|
||||
process_sql_row(Row, {IO, ConvertFun, PrevRow}),
|
||||
fetch(IO, ConvertFun, Row);
|
||||
{selected, _, []} ->
|
||||
ok;
|
||||
Err ->
|
||||
erlang:error(Err)
|
||||
end.
|
||||
|
||||
process_sql_row(Row, {IO, ConvertFun, PrevRow}) when Row == PrevRow ->
|
||||
%% Avoid calling ConvertFun with the same input
|
||||
{IO, ConvertFun, Row};
|
||||
process_sql_row(Row, {IO, ConvertFun, _PrevRow}) ->
|
||||
case catch ConvertFun(Row) of
|
||||
{'EXIT', _} = Err ->
|
||||
?ERROR_MSG("failed to convert ~p: ~p", [Row, Err]);
|
||||
Term ->
|
||||
ok = disk_log:log(IO#dump.fd, Term)
|
||||
end,
|
||||
{IO, ConvertFun, Row}.
|
||||
|
||||
import_dump(LServer, Mods, #dump{fd = Fd, cont = Cont}) ->
|
||||
case disk_log:chunk(Fd, Cont) of
|
||||
{NewCont, Terms} ->
|
||||
import_terms(LServer, Mods, Terms),
|
||||
import_dump(LServer, Mods, #dump{fd = Fd, cont = NewCont});
|
||||
eof ->
|
||||
ok;
|
||||
Err ->
|
||||
exit(Err)
|
||||
end.
|
||||
|
||||
import_terms(LServer, Mods, [Term|Terms]) ->
|
||||
import_term(LServer, Mods, Term),
|
||||
import_terms(LServer, Mods, Terms);
|
||||
import_terms(_LServer, _Mods, []) ->
|
||||
ok.
|
||||
|
||||
import_term(LServer, [{Mod, DBType}|Mods], Term) ->
|
||||
case catch Mod:import(LServer, DBType, Term) of
|
||||
pass -> import_term(LServer, Mods, Term);
|
||||
ok -> ok;
|
||||
Err ->
|
||||
?ERROR_MSG("failed to import ~p for module ~p: ~p",
|
||||
[Term, Mod, Err])
|
||||
end;
|
||||
import_term(_LServer, [], _Term) ->
|
||||
ok.
|
||||
|
||||
prepare_output(FileName) ->
|
||||
prepare_output(FileName, normal).
|
||||
|
||||
@ -285,25 +208,11 @@ prepare_output(FileName, normal) when is_list(FileName) ->
|
||||
Err ->
|
||||
exit(Err)
|
||||
end;
|
||||
prepare_output(FileName, disk_log) when is_list(FileName) ->
|
||||
case disk_log:open([{name, make_ref()},
|
||||
{repair, truncate},
|
||||
{file, FileName}]) of
|
||||
{ok, Fd} ->
|
||||
#dump{fd = Fd};
|
||||
Err ->
|
||||
exit(Err)
|
||||
end;
|
||||
prepare_output(Output, _Type) ->
|
||||
Output.
|
||||
|
||||
close_output(FileName, Fd) when FileName /= Fd ->
|
||||
case Fd of
|
||||
#dump{} ->
|
||||
disk_log:close(Fd#dump.fd);
|
||||
_ ->
|
||||
file:close(Fd)
|
||||
end,
|
||||
file:close(Fd),
|
||||
ok;
|
||||
close_output(_, _) ->
|
||||
ok.
|
||||
@ -321,6 +230,129 @@ flatten1([H|T], Acc) ->
|
||||
flatten1([], Acc) ->
|
||||
Acc.
|
||||
|
||||
import_rows(LServer, FromType, ToType, Tab, Mod, Dump, FieldsNumber) ->
|
||||
case read_row_from_sql_dump(Dump, FieldsNumber) of
|
||||
{ok, Fields} ->
|
||||
case catch Mod:import(LServer, FromType, ToType, Tab, Fields) of
|
||||
ok ->
|
||||
ok;
|
||||
Err ->
|
||||
?ERROR_MSG("Failed to import fields ~p for tab ~p: ~p",
|
||||
[Fields, Tab, Err])
|
||||
end,
|
||||
import_rows(LServer, FromType, ToType,
|
||||
Tab, Mod, Dump, FieldsNumber);
|
||||
eof ->
|
||||
ok;
|
||||
Err ->
|
||||
?ERROR_MSG("Failed to read row from SQL dump: ~s",
|
||||
[format_error(Err)])
|
||||
end.
|
||||
|
||||
open_sql_dump(FileName) ->
|
||||
case file:open(FileName, [raw, read, binary, read_ahead]) of
|
||||
{ok, Fd} ->
|
||||
case file:read(Fd, 11) of
|
||||
{ok, <<"PGCOPY\n", 16#ff, "\r\n", 0>>} ->
|
||||
case skip_pgcopy_header(Fd) of
|
||||
ok ->
|
||||
{ok, #sql_dump{fd = Fd, type = pgsql}};
|
||||
Err ->
|
||||
Err
|
||||
end;
|
||||
{ok, _} ->
|
||||
file:position(Fd, 0),
|
||||
{ok, #sql_dump{fd = Fd, type = mysql}};
|
||||
Err ->
|
||||
Err
|
||||
end;
|
||||
Err ->
|
||||
Err
|
||||
end.
|
||||
|
||||
close_sql_dump(#sql_dump{fd = Fd}) ->
|
||||
file:close(Fd).
|
||||
|
||||
read_row_from_sql_dump(#sql_dump{fd = Fd, type = pgsql}, _) ->
|
||||
case file:read(Fd, 2) of
|
||||
{ok, <<(-1):16/signed>>} ->
|
||||
eof;
|
||||
{ok, <<FieldsNum:16>>} ->
|
||||
read_fields(Fd, FieldsNum, []);
|
||||
{ok, _} ->
|
||||
{error, eof};
|
||||
eof ->
|
||||
{error, eof};
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end;
|
||||
read_row_from_sql_dump(#sql_dump{fd = Fd, type = mysql}, FieldsNum) ->
|
||||
read_lines(Fd, FieldsNum, <<"">>, []).
|
||||
|
||||
skip_pgcopy_header(Fd) ->
|
||||
try
|
||||
{ok, <<_:4/binary, ExtSize:32>>} = file:read(Fd, 8),
|
||||
{ok, <<_:ExtSize/binary>>} = file:read(Fd, ExtSize),
|
||||
ok
|
||||
catch error:{badmatch, {error, _} = Err} ->
|
||||
Err;
|
||||
error:{badmatch, _} ->
|
||||
{error, eof}
|
||||
end.
|
||||
|
||||
read_fields(_Fd, 0, Acc) ->
|
||||
{ok, lists:reverse(Acc)};
|
||||
read_fields(Fd, N, Acc) ->
|
||||
case file:read(Fd, 4) of
|
||||
{ok, <<(-1):32/signed>>} ->
|
||||
read_fields(Fd, N-1, [null|Acc]);
|
||||
{ok, <<ValSize:32>>} ->
|
||||
case file:read(Fd, ValSize) of
|
||||
{ok, <<Val:ValSize/binary>>} ->
|
||||
read_fields(Fd, N-1, [Val|Acc]);
|
||||
{ok, _} ->
|
||||
{error, eof};
|
||||
Err ->
|
||||
Err
|
||||
end;
|
||||
{ok, _} ->
|
||||
{error, eof};
|
||||
eof ->
|
||||
{error, eof};
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end.
|
||||
|
||||
read_lines(_Fd, 0, <<"">>, Acc) ->
|
||||
{ok, lists:reverse(Acc)};
|
||||
read_lines(Fd, N, Buf, Acc) ->
|
||||
case file:read_line(Fd) of
|
||||
{ok, Data} when size(Data) >= 2 ->
|
||||
Size = size(Data) - 2,
|
||||
case Data of
|
||||
<<Val:Size/binary, 0, $\n>> ->
|
||||
NewBuf = <<Buf/binary, Val/binary>>,
|
||||
read_lines(Fd, N-1, <<"">>, [NewBuf|Acc]);
|
||||
_ ->
|
||||
NewBuf = <<Buf/binary, Data/binary>>,
|
||||
read_lines(Fd, N, NewBuf, Acc)
|
||||
end;
|
||||
{ok, Data} ->
|
||||
NewBuf = <<Buf/binary, Data/binary>>,
|
||||
read_lines(Fd, N, NewBuf, Acc);
|
||||
eof when Buf == <<"">>, Acc == [] ->
|
||||
eof;
|
||||
eof ->
|
||||
{error, eof};
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end.
|
||||
|
||||
format_error({error, eof}) ->
|
||||
"unexpected end of file";
|
||||
format_error({error, Posix}) ->
|
||||
file:format_error(Posix).
|
||||
|
||||
format_queries(SQLs) ->
|
||||
lists:map(
|
||||
fun(#sql_query{} = SQL) ->
|
||||
|
@ -1,128 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: flex_offline.xdata
|
||||
%% Form type: http://jabber.org/protocol/offline
|
||||
%% Document: XEP-0013
|
||||
|
||||
-module(flex_offline).
|
||||
|
||||
-export([decode/1, decode/2, encode/1, encode/2,
|
||||
format_error/1]).
|
||||
|
||||
-include("xmpp_codec.hrl").
|
||||
|
||||
-include("flex_offline.hrl").
|
||||
|
||||
-export_type([property/0, result/0, form/0]).
|
||||
|
||||
dec_int(Val, Min, Max) ->
|
||||
case list_to_integer(binary_to_list(Val)) of
|
||||
Int when Int =< Max, Min == infinity -> Int;
|
||||
Int when Int =< Max, Int >= Min -> Int
|
||||
end.
|
||||
|
||||
enc_int(Int) -> integer_to_binary(Int).
|
||||
|
||||
format_error({form_type_mismatch, Type}) ->
|
||||
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
|
||||
format_error({bad_var_value, Var, Type}) ->
|
||||
<<"Bad value of field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>;
|
||||
format_error({missing_value, Var, Type}) ->
|
||||
<<"Missing value of field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>;
|
||||
format_error({too_many_values, Var, Type}) ->
|
||||
<<"Too many values for field '", Var/binary,
|
||||
"' of type '", Type/binary, "'">>;
|
||||
format_error({unknown_var, Var, Type}) ->
|
||||
<<"Unknown field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>;
|
||||
format_error({missing_required_var, Var, Type}) ->
|
||||
<<"Missing required field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>.
|
||||
|
||||
decode(Fs) -> decode(Fs, []).
|
||||
|
||||
decode(Fs, Acc) ->
|
||||
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
|
||||
Fs)
|
||||
of
|
||||
false -> decode(Fs, Acc, []);
|
||||
#xdata_field{values =
|
||||
[<<"http://jabber.org/protocol/offline">>]} ->
|
||||
decode(Fs, Acc, []);
|
||||
_ ->
|
||||
erlang:error({?MODULE,
|
||||
{form_type_mismatch,
|
||||
<<"http://jabber.org/protocol/offline">>}})
|
||||
end.
|
||||
|
||||
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
|
||||
|
||||
encode(List, Translate) when is_list(List) ->
|
||||
Fs = [case Opt of
|
||||
{number_of_messages, Val} ->
|
||||
[encode_number_of_messages(Val, Translate)];
|
||||
{number_of_messages, _, _} ->
|
||||
erlang:error({badarg, Opt});
|
||||
#xdata_field{} -> [Opt];
|
||||
_ -> []
|
||||
end
|
||||
|| Opt <- List],
|
||||
FormType = #xdata_field{var = <<"FORM_TYPE">>,
|
||||
type = hidden,
|
||||
values =
|
||||
[<<"http://jabber.org/protocol/offline">>]},
|
||||
[FormType | lists:flatten(Fs)].
|
||||
|
||||
decode([#xdata_field{var = <<"number_of_messages">>,
|
||||
values = [Value]}
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
try dec_int(Value, 0, infinity) of
|
||||
Result ->
|
||||
decode(Fs, [{number_of_messages, Result} | Acc],
|
||||
lists:delete(<<"number_of_messages">>, Required))
|
||||
catch
|
||||
_:_ ->
|
||||
erlang:error({?MODULE,
|
||||
{bad_var_value, <<"number_of_messages">>,
|
||||
<<"http://jabber.org/protocol/offline">>}})
|
||||
end;
|
||||
decode([#xdata_field{var = <<"number_of_messages">>,
|
||||
values = []} =
|
||||
F
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
decode([F#xdata_field{var = <<"number_of_messages">>,
|
||||
values = [<<>>]}
|
||||
| Fs],
|
||||
Acc, Required);
|
||||
decode([#xdata_field{var = <<"number_of_messages">>}
|
||||
| _],
|
||||
_, _) ->
|
||||
erlang:error({?MODULE,
|
||||
{too_many_values, <<"number_of_messages">>,
|
||||
<<"http://jabber.org/protocol/offline">>}});
|
||||
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
|
||||
if Var /= <<"FORM_TYPE">> ->
|
||||
erlang:error({?MODULE,
|
||||
{unknown_var, Var,
|
||||
<<"http://jabber.org/protocol/offline">>}});
|
||||
true -> decode(Fs, Acc, Required)
|
||||
end;
|
||||
decode([], _, [Var | _]) ->
|
||||
erlang:error({?MODULE,
|
||||
{missing_required_var, Var,
|
||||
<<"http://jabber.org/protocol/offline">>}});
|
||||
decode([], Acc, []) -> Acc.
|
||||
|
||||
encode_number_of_messages(Value, Translate) ->
|
||||
Values = case Value of
|
||||
undefined -> [];
|
||||
Value -> [enc_int(Value)]
|
||||
end,
|
||||
Opts = [],
|
||||
#xdata_field{var = <<"number_of_messages">>,
|
||||
values = Values, required = false, type = 'text-single',
|
||||
options = Opts, desc = <<>>,
|
||||
label = Translate(<<"Number of Offline Messages">>)}.
|
266
src/jid.erl
266
src/jid.erl
@ -1,266 +0,0 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% @doc
|
||||
%%% JID processing library
|
||||
%%% @end
|
||||
%%% Created : 24 Nov 2015 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2016 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(jid).
|
||||
|
||||
%% API
|
||||
-export([start/0,
|
||||
make/1,
|
||||
make/2,
|
||||
make/3,
|
||||
split/1,
|
||||
from_string/1,
|
||||
to_string/1,
|
||||
is_nodename/1,
|
||||
nodeprep/1,
|
||||
nameprep/1,
|
||||
resourceprep/1,
|
||||
tolower/1,
|
||||
remove_resource/1,
|
||||
replace_resource/2]).
|
||||
|
||||
-include("jid.hrl").
|
||||
|
||||
-export_type([jid/0]).
|
||||
-export_type([ljid/0]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
-spec start() -> ok.
|
||||
|
||||
start() ->
|
||||
{ok, Owner} = ets_owner(),
|
||||
SplitPattern = binary:compile_pattern([<<"@">>, <<"/">>]),
|
||||
%% Table is public to allow ETS insert to fix / update the table even if table already exist
|
||||
%% with another owner.
|
||||
catch ets:new(jlib, [named_table, public, set, {keypos, 1}, {heir, Owner, undefined}]),
|
||||
ets:insert(jlib, {string_to_jid_pattern, SplitPattern}),
|
||||
ok.
|
||||
|
||||
ets_owner() ->
|
||||
case whereis(jlib_ets) of
|
||||
undefined ->
|
||||
Pid = spawn(fun() -> ets_keepalive() end),
|
||||
case catch register(jlib_ets, Pid) of
|
||||
true ->
|
||||
{ok, Pid};
|
||||
Error -> Error
|
||||
end;
|
||||
Pid ->
|
||||
{ok,Pid}
|
||||
end.
|
||||
|
||||
%% Process used to keep jlib ETS table alive in case the original owner dies.
|
||||
%% The table need to be public, otherwise subsequent inserts would fail.
|
||||
ets_keepalive() ->
|
||||
receive
|
||||
_ ->
|
||||
ets_keepalive()
|
||||
end.
|
||||
|
||||
-spec make(binary(), binary(), binary()) -> jid() | error.
|
||||
|
||||
make(User, Server, Resource) ->
|
||||
case nodeprep(User) of
|
||||
error -> error;
|
||||
LUser ->
|
||||
case nameprep(Server) of
|
||||
error -> error;
|
||||
LServer ->
|
||||
case resourceprep(Resource) of
|
||||
error -> error;
|
||||
LResource ->
|
||||
#jid{user = User, server = Server, resource = Resource,
|
||||
luser = LUser, lserver = LServer,
|
||||
lresource = LResource}
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
-spec make(binary(), binary()) -> jid() | error.
|
||||
make(User, Server) ->
|
||||
make(User, Server, <<"">>).
|
||||
|
||||
-spec make({binary(), binary(), binary()} | binary()) -> jid() | error.
|
||||
|
||||
make({User, Server, Resource}) ->
|
||||
make(User, Server, Resource);
|
||||
make(Server) ->
|
||||
make(<<"">>, Server, <<"">>).
|
||||
|
||||
%% This is the reverse of make_jid/1
|
||||
-spec split(jid()) -> {binary(), binary(), binary()} | error.
|
||||
|
||||
split(#jid{user = U, server = S, resource = R}) ->
|
||||
{U, S, R};
|
||||
split(_) ->
|
||||
error.
|
||||
|
||||
-spec from_string(binary() | string()) -> jid() | error.
|
||||
from_string(S) when is_list(S) ->
|
||||
%% We do not accept list because we want to enforce good practice of
|
||||
%% using binaries for string. However, we do not let it crash to avoid
|
||||
%% losing associated ets table.
|
||||
{error, need_jid_as_binary};
|
||||
from_string(<<>>) ->
|
||||
error;
|
||||
from_string(S) when is_binary(S) ->
|
||||
SplitPattern = ets:lookup_element(jlib, string_to_jid_pattern, 2),
|
||||
Size = size(S),
|
||||
End = Size-1,
|
||||
case binary:match(S, SplitPattern) of
|
||||
{0, _} ->
|
||||
error;
|
||||
{End, _} ->
|
||||
error;
|
||||
{Pos1, _} ->
|
||||
case binary:at(S, Pos1) of
|
||||
$/ ->
|
||||
make(<<>>,
|
||||
binary:part(S, 0, Pos1),
|
||||
binary:part(S, Pos1+1, Size-Pos1-1));
|
||||
_ ->
|
||||
Pos1N = Pos1+1,
|
||||
case binary:match(S, SplitPattern, [{scope, {Pos1+1, Size-Pos1-1}}]) of
|
||||
{End, _} ->
|
||||
error;
|
||||
{Pos1N, _} ->
|
||||
error;
|
||||
{Pos2, _} ->
|
||||
case binary:at(S, Pos2) of
|
||||
$/ ->
|
||||
make(binary:part(S, 0, Pos1),
|
||||
binary:part(S, Pos1+1, Pos2-Pos1-1),
|
||||
binary:part(S, Pos2+1, Size-Pos2-1));
|
||||
_ -> error
|
||||
end;
|
||||
_ ->
|
||||
make(binary:part(S, 0, Pos1),
|
||||
binary:part(S, Pos1+1, Size-Pos1-1),
|
||||
<<>>)
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
make(<<>>, S, <<>>)
|
||||
end.
|
||||
|
||||
-spec to_string(jid() | ljid()) -> binary().
|
||||
|
||||
to_string(#jid{user = User, server = Server,
|
||||
resource = Resource}) ->
|
||||
to_string({User, Server, Resource});
|
||||
to_string({N, S, R}) ->
|
||||
Node = iolist_to_binary(N),
|
||||
Server = iolist_to_binary(S),
|
||||
Resource = iolist_to_binary(R),
|
||||
S1 = case Node of
|
||||
<<"">> -> <<"">>;
|
||||
_ -> <<Node/binary, "@">>
|
||||
end,
|
||||
S2 = <<S1/binary, Server/binary>>,
|
||||
S3 = case Resource of
|
||||
<<"">> -> S2;
|
||||
_ -> <<S2/binary, "/", Resource/binary>>
|
||||
end,
|
||||
S3.
|
||||
|
||||
-spec is_nodename(binary()) -> boolean().
|
||||
|
||||
is_nodename(Node) ->
|
||||
N = nodeprep(Node),
|
||||
(N /= error) and (N /= <<>>).
|
||||
|
||||
-define(LOWER(Char),
|
||||
if Char >= $A, Char =< $Z -> Char + 32;
|
||||
true -> Char
|
||||
end).
|
||||
|
||||
-spec nodeprep(binary()) -> binary() | error.
|
||||
|
||||
nodeprep("") -> <<>>;
|
||||
nodeprep(S) when byte_size(S) < 1024 ->
|
||||
R = stringprep:nodeprep(S),
|
||||
if byte_size(R) < 1024 -> R;
|
||||
true -> error
|
||||
end;
|
||||
nodeprep(_) -> error.
|
||||
|
||||
-spec nameprep(binary()) -> binary() | error.
|
||||
|
||||
nameprep(S) when byte_size(S) < 1024 ->
|
||||
R = stringprep:nameprep(S),
|
||||
if byte_size(R) < 1024 -> R;
|
||||
true -> error
|
||||
end;
|
||||
nameprep(_) -> error.
|
||||
|
||||
-spec resourceprep(binary()) -> binary() | error.
|
||||
|
||||
resourceprep(S) when byte_size(S) < 1024 ->
|
||||
R = stringprep:resourceprep(S),
|
||||
if byte_size(R) < 1024 -> R;
|
||||
true -> error
|
||||
end;
|
||||
resourceprep(_) -> error.
|
||||
|
||||
-spec tolower(jid() | ljid()) -> error | ljid().
|
||||
|
||||
tolower(#jid{luser = U, lserver = S,
|
||||
lresource = R}) ->
|
||||
{U, S, R};
|
||||
tolower({U, S, R}) ->
|
||||
case nodeprep(U) of
|
||||
error -> error;
|
||||
LUser ->
|
||||
case nameprep(S) of
|
||||
error -> error;
|
||||
LServer ->
|
||||
case resourceprep(R) of
|
||||
error -> error;
|
||||
LResource -> {LUser, LServer, LResource}
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
-spec remove_resource(jid()) -> jid();
|
||||
(ljid()) -> ljid().
|
||||
|
||||
remove_resource(#jid{} = JID) ->
|
||||
JID#jid{resource = <<"">>, lresource = <<"">>};
|
||||
remove_resource({U, S, _R}) -> {U, S, <<"">>}.
|
||||
|
||||
-spec replace_resource(jid(), binary()) -> error | jid().
|
||||
|
||||
replace_resource(JID, Resource) ->
|
||||
case resourceprep(Resource) of
|
||||
error -> error;
|
||||
LResource ->
|
||||
JID#jid{resource = Resource, lresource = LResource}
|
||||
end.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
@ -1,220 +0,0 @@
|
||||
%% Created automatically by xdata generator (xdata_codec.erl)
|
||||
%% Source: mam_query.xdata
|
||||
%% Form type: urn:xmpp:mam:1
|
||||
%% Document: XEP-0313
|
||||
|
||||
-module(mam_query).
|
||||
|
||||
-export([decode/1, decode/2, encode/1, encode/2,
|
||||
format_error/1]).
|
||||
|
||||
-include("xmpp_codec.hrl").
|
||||
|
||||
-include("mam_query.hrl").
|
||||
|
||||
-export_type([property/0, result/0, form/0]).
|
||||
|
||||
enc_jid(J) -> jid:to_string(J).
|
||||
|
||||
dec_jid(Val) ->
|
||||
case jid:from_string(Val) of
|
||||
error -> erlang:error(badarg);
|
||||
J -> J
|
||||
end.
|
||||
|
||||
format_error({form_type_mismatch, Type}) ->
|
||||
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
|
||||
format_error({bad_var_value, Var, Type}) ->
|
||||
<<"Bad value of field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>;
|
||||
format_error({missing_value, Var, Type}) ->
|
||||
<<"Missing value of field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>;
|
||||
format_error({too_many_values, Var, Type}) ->
|
||||
<<"Too many values for field '", Var/binary,
|
||||
"' of type '", Type/binary, "'">>;
|
||||
format_error({unknown_var, Var, Type}) ->
|
||||
<<"Unknown field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>;
|
||||
format_error({missing_required_var, Var, Type}) ->
|
||||
<<"Missing required field '", Var/binary, "' of type '",
|
||||
Type/binary, "'">>.
|
||||
|
||||
decode(Fs) -> decode(Fs, []).
|
||||
|
||||
decode(Fs, Acc) ->
|
||||
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
|
||||
Fs)
|
||||
of
|
||||
false -> decode(Fs, Acc, []);
|
||||
#xdata_field{values = [<<"urn:xmpp:mam:1">>]} ->
|
||||
decode(Fs, Acc, []);
|
||||
_ ->
|
||||
erlang:error({?MODULE,
|
||||
{form_type_mismatch, <<"urn:xmpp:mam:1">>}})
|
||||
end.
|
||||
|
||||
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
|
||||
|
||||
encode(List, Translate) when is_list(List) ->
|
||||
Fs = [case Opt of
|
||||
{with, Val} -> [encode_with(Val, Translate)];
|
||||
{with, _, _} -> erlang:error({badarg, Opt});
|
||||
{start, Val} -> [encode_start(Val, Translate)];
|
||||
{start, _, _} -> erlang:error({badarg, Opt});
|
||||
{'end', Val} -> [encode_end(Val, Translate)];
|
||||
{'end', _, _} -> erlang:error({badarg, Opt});
|
||||
{withtext, Val} -> [encode_withtext(Val, Translate)];
|
||||
{withtext, _, _} -> erlang:error({badarg, Opt});
|
||||
#xdata_field{} -> [Opt];
|
||||
_ -> []
|
||||
end
|
||||
|| Opt <- List],
|
||||
FormType = #xdata_field{var = <<"FORM_TYPE">>,
|
||||
type = hidden, values = [<<"urn:xmpp:mam:1">>]},
|
||||
[FormType | lists:flatten(Fs)].
|
||||
|
||||
decode([#xdata_field{var = <<"with">>, values = [Value]}
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
try dec_jid(Value) of
|
||||
Result ->
|
||||
decode(Fs, [{with, Result} | Acc],
|
||||
lists:delete(<<"with">>, Required))
|
||||
catch
|
||||
_:_ ->
|
||||
erlang:error({?MODULE,
|
||||
{bad_var_value, <<"with">>, <<"urn:xmpp:mam:1">>}})
|
||||
end;
|
||||
decode([#xdata_field{var = <<"with">>, values = []} = F
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
decode([F#xdata_field{var = <<"with">>, values = [<<>>]}
|
||||
| Fs],
|
||||
Acc, Required);
|
||||
decode([#xdata_field{var = <<"with">>} | _], _, _) ->
|
||||
erlang:error({?MODULE,
|
||||
{too_many_values, <<"with">>, <<"urn:xmpp:mam:1">>}});
|
||||
decode([#xdata_field{var = <<"start">>,
|
||||
values = [Value]}
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
try xmpp_util:decode_timestamp(Value) of
|
||||
Result ->
|
||||
decode(Fs, [{start, Result} | Acc],
|
||||
lists:delete(<<"start">>, Required))
|
||||
catch
|
||||
_:_ ->
|
||||
erlang:error({?MODULE,
|
||||
{bad_var_value, <<"start">>, <<"urn:xmpp:mam:1">>}})
|
||||
end;
|
||||
decode([#xdata_field{var = <<"start">>, values = []} = F
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
decode([F#xdata_field{var = <<"start">>,
|
||||
values = [<<>>]}
|
||||
| Fs],
|
||||
Acc, Required);
|
||||
decode([#xdata_field{var = <<"start">>} | _], _, _) ->
|
||||
erlang:error({?MODULE,
|
||||
{too_many_values, <<"start">>, <<"urn:xmpp:mam:1">>}});
|
||||
decode([#xdata_field{var = <<"end">>, values = [Value]}
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
try xmpp_util:decode_timestamp(Value) of
|
||||
Result ->
|
||||
decode(Fs, [{'end', Result} | Acc],
|
||||
lists:delete(<<"end">>, Required))
|
||||
catch
|
||||
_:_ ->
|
||||
erlang:error({?MODULE,
|
||||
{bad_var_value, <<"end">>, <<"urn:xmpp:mam:1">>}})
|
||||
end;
|
||||
decode([#xdata_field{var = <<"end">>, values = []} = F
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
decode([F#xdata_field{var = <<"end">>, values = [<<>>]}
|
||||
| Fs],
|
||||
Acc, Required);
|
||||
decode([#xdata_field{var = <<"end">>} | _], _, _) ->
|
||||
erlang:error({?MODULE,
|
||||
{too_many_values, <<"end">>, <<"urn:xmpp:mam:1">>}});
|
||||
decode([#xdata_field{var = <<"withtext">>,
|
||||
values = [Value]}
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
try Value of
|
||||
Result ->
|
||||
decode(Fs, [{withtext, Result} | Acc],
|
||||
lists:delete(<<"withtext">>, Required))
|
||||
catch
|
||||
_:_ ->
|
||||
erlang:error({?MODULE,
|
||||
{bad_var_value, <<"withtext">>, <<"urn:xmpp:mam:1">>}})
|
||||
end;
|
||||
decode([#xdata_field{var = <<"withtext">>,
|
||||
values = []} =
|
||||
F
|
||||
| Fs],
|
||||
Acc, Required) ->
|
||||
decode([F#xdata_field{var = <<"withtext">>,
|
||||
values = [<<>>]}
|
||||
| Fs],
|
||||
Acc, Required);
|
||||
decode([#xdata_field{var = <<"withtext">>} | _], _,
|
||||
_) ->
|
||||
erlang:error({?MODULE,
|
||||
{too_many_values, <<"withtext">>,
|
||||
<<"urn:xmpp:mam:1">>}});
|
||||
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
|
||||
if Var /= <<"FORM_TYPE">> ->
|
||||
erlang:error({?MODULE,
|
||||
{unknown_var, Var, <<"urn:xmpp:mam:1">>}});
|
||||
true -> decode(Fs, Acc, Required)
|
||||
end;
|
||||
decode([], _, [Var | _]) ->
|
||||
erlang:error({?MODULE,
|
||||
{missing_required_var, Var, <<"urn:xmpp:mam:1">>}});
|
||||
decode([], Acc, []) -> Acc.
|
||||
|
||||
encode_with(Value, Translate) ->
|
||||
Values = case Value of
|
||||
undefined -> [];
|
||||
Value -> [enc_jid(Value)]
|
||||
end,
|
||||
Opts = [],
|
||||
#xdata_field{var = <<"with">>, values = Values,
|
||||
required = false, type = 'jid-single', options = Opts,
|
||||
desc = <<>>, label = Translate(<<"User JID">>)}.
|
||||
|
||||
encode_start(Value, Translate) ->
|
||||
Values = case Value of
|
||||
undefined -> [];
|
||||
Value -> [Value]
|
||||
end,
|
||||
Opts = [],
|
||||
#xdata_field{var = <<"start">>, values = Values,
|
||||
required = false, type = 'text-single', options = Opts,
|
||||
desc = <<>>,
|
||||
label = Translate(<<"Search from the date">>)}.
|
||||
|
||||
encode_end(Value, Translate) ->
|
||||
Values = case Value of
|
||||
undefined -> [];
|
||||
Value -> [Value]
|
||||
end,
|
||||
Opts = [],
|
||||
#xdata_field{var = <<"end">>, values = Values,
|
||||
required = false, type = 'text-single', options = Opts,
|
||||
desc = <<>>,
|
||||
label = Translate(<<"Search until the date">>)}.
|
||||
|
||||
encode_withtext(Value, Translate) ->
|
||||
Values = case Value of
|
||||
<<>> -> [];
|
||||
Value -> [Value]
|
||||
end,
|
||||
Opts = [],
|
||||
#xdata_field{var = <<"withtext">>, values = Values,
|
||||
required = false, type = 'text-single', options = Opts,
|
||||
desc = <<>>, label = Translate(<<"Search the text">>)}.
|
@ -31,8 +31,8 @@
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, init/0, stop/1, export/1, import/1,
|
||||
import/3, announce/3, send_motd/1, disco_identity/5,
|
||||
-export([start/2, init/0, stop/1, export/1, import_info/0,
|
||||
import_start/2, import/5, announce/3, send_motd/1, disco_identity/5,
|
||||
disco_features/5, disco_items/5, depends/2,
|
||||
send_announcement_to_all/3, announce_commands/4,
|
||||
announce_items/4, mod_opt_type/1]).
|
||||
@ -43,7 +43,7 @@
|
||||
-include("mod_announce.hrl").
|
||||
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #motd{} | #motd_users{}) -> ok | pass.
|
||||
-callback import(binary(), binary(), [binary()]) -> ok.
|
||||
-callback set_motd_users(binary(), [{binary(), binary(), binary()}]) -> {atomic, any()}.
|
||||
-callback set_motd(binary(), xmlel()) -> {atomic, any()}.
|
||||
-callback delete_motd(binary()) -> {atomic, any()}.
|
||||
@ -832,15 +832,17 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
import_info() ->
|
||||
[{<<"motd">>, 3}].
|
||||
|
||||
import(LServer, DBType, LA) ->
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, LA).
|
||||
Mod:init(LServer, []).
|
||||
|
||||
mod_opt_type(access) ->
|
||||
fun acl:access_rules_validator/1;
|
||||
import(LServer, {sql, _}, DBType, Tab, List) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Tab, List).
|
||||
|
||||
mod_opt_type(access) -> fun acl:access_rules_validator/1;
|
||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||
mod_opt_type(_) -> [access, db_type].
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1,
|
||||
get_motd/1, is_motd_user/2, set_motd_user/2, import/2]).
|
||||
get_motd/1, is_motd_user/2, set_motd_user/2, import/3]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_announce.hrl").
|
||||
@ -81,10 +81,11 @@ set_motd_user(LUser, LServer) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #motd{} = Motd) ->
|
||||
mnesia:dirty_write(Motd);
|
||||
import(_LServer, #motd_users{} = Users) ->
|
||||
mnesia:dirty_write(Users).
|
||||
import(LServer, <<"motd">>, [<<>>, XML, _TimeStamp]) ->
|
||||
El = fxml_stream:parse_element(XML),
|
||||
mnesia:dirty_write(#motd{server = LServer, packet = El});
|
||||
import(LServer, <<"motd">>, [LUser, <<>>, _TimeStamp]) ->
|
||||
mnesia:dirty_write(#motd_users{us = {LUser, LServer}}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1,
|
||||
get_motd/1, is_motd_user/2, set_motd_user/2, import/2]).
|
||||
get_motd/1, is_motd_user/2, set_motd_user/2, import/3]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_announce.hrl").
|
||||
@ -71,11 +71,13 @@ set_motd_user(LUser, LServer) ->
|
||||
#motd_users{us = {LUser, LServer}}, motd_users_schema(),
|
||||
[{'2i', [{<<"server">>, LServer}]}])}.
|
||||
|
||||
import(_LServer, #motd{} = Motd) ->
|
||||
ejabberd_riak:put(Motd, motd_schema());
|
||||
import(_LServer, #motd_users{us = {_, S}} = Users) ->
|
||||
import(LServer, <<"motd">>, [<<>>, XML, _TimeStamp]) ->
|
||||
El = fxml_stream:parse_element(XML),
|
||||
ejabberd_riak:put(#motd{server = LServer, packet = El}, motd_schema());
|
||||
import(LServer, <<"motd">>, [LUser, <<>>, _TimeStamp]) ->
|
||||
Users = #motd_users{us = {LUser, LServer}},
|
||||
ejabberd_riak:put(Users, motd_users_schema(),
|
||||
[{'2i', [{<<"server">>, S}]}]).
|
||||
[{'2i', [{<<"server">>, LServer}]}]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1,
|
||||
get_motd/1, is_motd_user/2, set_motd_user/2, import/1,
|
||||
import/2, export/1]).
|
||||
get_motd/1, is_motd_user/2, set_motd_user/2, import/3,
|
||||
export/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_announce.hrl").
|
||||
@ -108,19 +108,8 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select xml from motd where username='';">>,
|
||||
fun([XML]) ->
|
||||
El = fxml_stream:parse_element(XML),
|
||||
#motd{server = LServer, packet = El}
|
||||
end},
|
||||
{<<"select username from motd where xml='';">>,
|
||||
fun([LUser]) ->
|
||||
#motd_users{us = {LUser, LServer}}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_, _, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
296
src/mod_bosh.erl
Normal file
296
src/mod_bosh.erl
Normal file
@ -0,0 +1,296 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% File : mod_bosh.erl
|
||||
%%% Author : Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||
%%% Purpose : This module acts as a bridge to ejabberd_bosh which implements
|
||||
%%% the real stuff, this is to handle the new pluggable architecture
|
||||
%%% for extending ejabberd's http service.
|
||||
%%% Created : 20 Jul 2011 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2016 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_bosh).
|
||||
|
||||
-author('steve@zeank.in-berlin.de').
|
||||
|
||||
%%-define(ejabberd_debug, true).
|
||||
|
||||
-behaviour(gen_server).
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start_link/0]).
|
||||
-export([start/2, stop/1, process/2, open_session/2,
|
||||
close_session/1, find_session/1]).
|
||||
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
handle_info/2, terminate/2, code_change/3,
|
||||
depends/2, mod_opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
-include("bosh.hrl").
|
||||
|
||||
-record(bosh, {sid = <<"">> :: binary() | '_',
|
||||
timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_',
|
||||
pid = self() :: pid() | '$1'}).
|
||||
|
||||
-record(state, {}).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||
|
||||
process([], #request{method = 'POST', data = <<>>}) ->
|
||||
?DEBUG("Bad Request: no data", []),
|
||||
{400, ?HEADER(?CT_XML),
|
||||
#xmlel{name = <<"h1">>, attrs = [],
|
||||
children = [{xmlcdata, <<"400 Bad Request">>}]}};
|
||||
process([],
|
||||
#request{method = 'POST', data = Data, ip = IP, headers = Hdrs}) ->
|
||||
?DEBUG("Incoming data: ~p", [Data]),
|
||||
Type = get_type(Hdrs),
|
||||
ejabberd_bosh:process_request(Data, IP, Type);
|
||||
process([], #request{method = 'GET', data = <<>>}) ->
|
||||
{200, ?HEADER(?CT_XML), get_human_html_xmlel()};
|
||||
process([], #request{method = 'OPTIONS', data = <<>>}) ->
|
||||
{200, ?OPTIONS_HEADER, []};
|
||||
process(_Path, _Request) ->
|
||||
?DEBUG("Bad Request: ~p", [_Request]),
|
||||
{400, ?HEADER(?CT_XML),
|
||||
#xmlel{name = <<"h1">>, attrs = [],
|
||||
children = [{xmlcdata, <<"400 Bad Request">>}]}}.
|
||||
|
||||
get_human_html_xmlel() ->
|
||||
Heading = <<"ejabberd ", (jlib:atom_to_binary(?MODULE))/binary>>,
|
||||
#xmlel{name = <<"html">>,
|
||||
attrs =
|
||||
[{<<"xmlns">>, <<"http://www.w3.org/1999/xhtml">>}],
|
||||
children =
|
||||
[#xmlel{name = <<"head">>, attrs = [],
|
||||
children =
|
||||
[#xmlel{name = <<"title">>, attrs = [],
|
||||
children = [{xmlcdata, Heading}]}]},
|
||||
#xmlel{name = <<"body">>, attrs = [],
|
||||
children =
|
||||
[#xmlel{name = <<"h1">>, attrs = [],
|
||||
children = [{xmlcdata, Heading}]},
|
||||
#xmlel{name = <<"p">>, attrs = [],
|
||||
children =
|
||||
[{xmlcdata, <<"An implementation of ">>},
|
||||
#xmlel{name = <<"a">>,
|
||||
attrs =
|
||||
[{<<"href">>,
|
||||
<<"http://xmpp.org/extensions/xep-0206.html">>}],
|
||||
children =
|
||||
[{xmlcdata,
|
||||
<<"XMPP over BOSH (XEP-0206)">>}]}]},
|
||||
#xmlel{name = <<"p">>, attrs = [],
|
||||
children =
|
||||
[{xmlcdata,
|
||||
<<"This web page is only informative. To "
|
||||
"use HTTP-Bind you need a Jabber/XMPP "
|
||||
"client that supports it.">>}]}]}]}.
|
||||
|
||||
open_session(SID, Pid) ->
|
||||
Session = #bosh{sid = SID, timestamp = p1_time_compat:timestamp(), pid = Pid},
|
||||
lists:foreach(
|
||||
fun(Node) when Node == node() ->
|
||||
gen_server:call(?MODULE, {write, Session});
|
||||
(Node) ->
|
||||
cluster_send({?MODULE, Node}, {write, Session})
|
||||
end, ejabberd_cluster:get_nodes()).
|
||||
|
||||
close_session(SID) ->
|
||||
case mnesia:dirty_read(bosh, SID) of
|
||||
[Session] ->
|
||||
lists:foreach(
|
||||
fun(Node) when Node == node() ->
|
||||
gen_server:call(?MODULE, {delete, Session});
|
||||
(Node) ->
|
||||
cluster_send({?MODULE, Node}, {delete, Session})
|
||||
end, ejabberd_cluster:get_nodes());
|
||||
[] ->
|
||||
ok
|
||||
end.
|
||||
|
||||
write_session(#bosh{pid = Pid1, sid = SID, timestamp = T1} = S1) ->
|
||||
case mnesia:dirty_read(bosh, SID) of
|
||||
[#bosh{pid = Pid2, timestamp = T2} = S2] ->
|
||||
if Pid1 == Pid2 ->
|
||||
mnesia:dirty_write(S1);
|
||||
T1 < T2 ->
|
||||
cluster_send(Pid2, replaced),
|
||||
mnesia:dirty_write(S1);
|
||||
true ->
|
||||
cluster_send(Pid1, replaced),
|
||||
mnesia:dirty_write(S2)
|
||||
end;
|
||||
[] ->
|
||||
mnesia:dirty_write(S1)
|
||||
end.
|
||||
|
||||
delete_session(#bosh{sid = SID, pid = Pid1}) ->
|
||||
case mnesia:dirty_read(bosh, SID) of
|
||||
[#bosh{pid = Pid2}] ->
|
||||
if Pid1 == Pid2 ->
|
||||
mnesia:dirty_delete(bosh, SID);
|
||||
true ->
|
||||
ok
|
||||
end;
|
||||
[] ->
|
||||
ok
|
||||
end.
|
||||
|
||||
find_session(SID) ->
|
||||
case mnesia:dirty_read(bosh, SID) of
|
||||
[#bosh{pid = Pid}] ->
|
||||
{ok, Pid};
|
||||
[] ->
|
||||
error
|
||||
end.
|
||||
|
||||
start(Host, Opts) ->
|
||||
setup_database(),
|
||||
start_jiffy(Opts),
|
||||
TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
TmpSupSpec = {TmpSup,
|
||||
{ejabberd_tmp_sup, start_link, [TmpSup, ejabberd_bosh]},
|
||||
permanent, infinity, supervisor, [ejabberd_tmp_sup]},
|
||||
ProcSpec = {?MODULE,
|
||||
{?MODULE, start_link, []},
|
||||
transient, 2000, worker, [?MODULE]},
|
||||
case supervisor:start_child(ejabberd_sup, ProcSpec) of
|
||||
{ok, _} ->
|
||||
supervisor:start_child(ejabberd_sup, TmpSupSpec);
|
||||
{error, {already_started, _}} ->
|
||||
supervisor:start_child(ejabberd_sup, TmpSupSpec);
|
||||
Err ->
|
||||
Err
|
||||
end.
|
||||
|
||||
stop(Host) ->
|
||||
TmpSup = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
supervisor:terminate_child(ejabberd_sup, TmpSup),
|
||||
supervisor:delete_child(ejabberd_sup, TmpSup).
|
||||
|
||||
%%%===================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%===================================================================
|
||||
init([]) ->
|
||||
{ok, #state{}}.
|
||||
|
||||
handle_call({write, Session}, _From, State) ->
|
||||
Res = write_session(Session),
|
||||
{reply, Res, State};
|
||||
handle_call({delete, Session}, _From, State) ->
|
||||
Res = delete_session(Session),
|
||||
{reply, Res, State};
|
||||
handle_call(_Request, _From, State) ->
|
||||
Reply = ok,
|
||||
{reply, Reply, State}.
|
||||
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({write, Session}, State) ->
|
||||
write_session(Session),
|
||||
{noreply, State};
|
||||
handle_info({delete, Session}, State) ->
|
||||
delete_session(Session),
|
||||
{noreply, State};
|
||||
handle_info(_Info, State) ->
|
||||
?ERROR_MSG("got unexpected info: ~p", [_Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
setup_database() ->
|
||||
case catch mnesia:table_info(bosh, attributes) of
|
||||
[sid, pid] ->
|
||||
mnesia:delete_table(bosh);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
mnesia:create_table(bosh,
|
||||
[{ram_copies, [node()]}, {local_content, true},
|
||||
{attributes, record_info(fields, bosh)}]),
|
||||
mnesia:add_table_copy(bosh, node(), ram_copies).
|
||||
|
||||
start_jiffy(Opts) ->
|
||||
case gen_mod:get_opt(json, Opts,
|
||||
fun(false) -> false;
|
||||
(true) -> true
|
||||
end, false) of
|
||||
false ->
|
||||
ok;
|
||||
true ->
|
||||
case catch ejabberd:start_app(jiffy) of
|
||||
ok ->
|
||||
ok;
|
||||
Err ->
|
||||
?WARNING_MSG("Failed to start JSON codec (jiffy): ~p. "
|
||||
"JSON support will be disabled", [Err])
|
||||
end
|
||||
end.
|
||||
|
||||
get_type(Hdrs) ->
|
||||
try
|
||||
{_, S} = lists:keyfind('Content-Type', 1, Hdrs),
|
||||
[T|_] = str:tokens(S, <<";">>),
|
||||
[_, <<"json">>] = str:tokens(T, <<"/">>),
|
||||
json
|
||||
catch _:_ ->
|
||||
xml
|
||||
end.
|
||||
|
||||
cluster_send(NodePid, Msg) ->
|
||||
erlang:send(NodePid, Msg, [noconnect, nosuspend]).
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
mod_opt_type(json) ->
|
||||
fun (false) -> false;
|
||||
(true) -> true
|
||||
end;
|
||||
mod_opt_type(max_concat) ->
|
||||
fun (unlimited) -> unlimited;
|
||||
(N) when is_integer(N), N > 0 -> N
|
||||
end;
|
||||
mod_opt_type(max_inactivity) ->
|
||||
fun (I) when is_integer(I), I > 0 -> I end;
|
||||
mod_opt_type(max_pause) ->
|
||||
fun (I) when is_integer(I), I > 0 -> I end;
|
||||
mod_opt_type(prebind) ->
|
||||
fun (B) when is_boolean(B) -> B end;
|
||||
mod_opt_type(_) ->
|
||||
[json, max_concat, max_inactivity, max_pause, prebind].
|
@ -55,20 +55,16 @@
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_caps.hrl").
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_caps).
|
||||
|
||||
-define(BAD_HASH_LIFETIME, 600).
|
||||
|
||||
-record(caps_features,
|
||||
{
|
||||
node_pair = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||
features = [] :: [binary()] | pos_integer()
|
||||
}).
|
||||
|
||||
-record(state, {host = <<"">> :: binary()}).
|
||||
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), {binary(), binary()}, [binary() | pos_integer()]) -> ok.
|
||||
-callback caps_read(binary(), {binary(), binary()}) ->
|
||||
{ok, non_neg_integer() | [binary()]} | error.
|
||||
-callback caps_write(binary(), {binary(), binary()},
|
||||
@ -525,9 +521,6 @@ is_valid_node(Node) ->
|
||||
false
|
||||
end.
|
||||
|
||||
caps_features_schema() ->
|
||||
{record_info(fields, caps_features), #caps_features{}}.
|
||||
|
||||
export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
@ -559,24 +552,8 @@ import_next(_LServer, _DBType, '$end_of_table') ->
|
||||
ok;
|
||||
import_next(LServer, DBType, NodePair) ->
|
||||
Features = [F || {_, F} <- ets:lookup(caps_features_tmp, NodePair)],
|
||||
case Features of
|
||||
[I] when is_integer(I), DBType == mnesia ->
|
||||
mnesia:dirty_write(
|
||||
#caps_features{node_pair = NodePair, features = I});
|
||||
[I] when is_integer(I), DBType == riak ->
|
||||
ejabberd_riak:put(
|
||||
#caps_features{node_pair = NodePair, features = I},
|
||||
caps_features_schema());
|
||||
_ when DBType == mnesia ->
|
||||
mnesia:dirty_write(
|
||||
#caps_features{node_pair = NodePair, features = Features});
|
||||
_ when DBType == riak ->
|
||||
ejabberd_riak:put(
|
||||
#caps_features{node_pair = NodePair, features = Features},
|
||||
caps_features_schema());
|
||||
_ when DBType == sql ->
|
||||
ok
|
||||
end,
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, NodePair, Features),
|
||||
import_next(LServer, DBType, ets:next(caps_features_tmp, NodePair)).
|
||||
|
||||
mod_opt_type(cache_life_time) ->
|
||||
|
@ -10,7 +10,7 @@
|
||||
-behaviour(mod_caps).
|
||||
|
||||
%% API
|
||||
-export([init/2, caps_read/2, caps_write/3]).
|
||||
-export([init/2, caps_read/2, caps_write/3, import/3]).
|
||||
|
||||
-include("mod_caps.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -46,6 +46,13 @@ caps_write(_LServer, Node, Features) ->
|
||||
mnesia:dirty_write(#caps_features{node_pair = Node,
|
||||
features = Features}).
|
||||
|
||||
import(_LServer, NodePair, [I]) when is_integer(I) ->
|
||||
mnesia:dirty_write(
|
||||
#caps_features{node_pair = NodePair, features = I});
|
||||
import(_LServer, NodePair, Features) ->
|
||||
mnesia:dirty_write(
|
||||
#caps_features{node_pair = NodePair, features = Features}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
@ -10,7 +10,7 @@
|
||||
-behaviour(mod_caps).
|
||||
|
||||
%% API
|
||||
-export([init/2, caps_read/2, caps_write/3]).
|
||||
-export([init/2, caps_read/2, caps_write/3, import/3]).
|
||||
|
||||
-include("mod_caps.hrl").
|
||||
|
||||
@ -31,6 +31,15 @@ caps_write(_LServer, Node, Features) ->
|
||||
features = Features},
|
||||
caps_features_schema()).
|
||||
|
||||
import(_LServer, NodePair, [I]) when is_integer(I) ->
|
||||
ejabberd_riak:put(
|
||||
#caps_features{node_pair = NodePair, features = I},
|
||||
caps_features_schema());
|
||||
import(_LServer, NodePair, Features) ->
|
||||
ejabberd_riak:put(
|
||||
#caps_features{node_pair = NodePair, features = Features},
|
||||
caps_features_schema()).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
@ -12,7 +12,7 @@
|
||||
-compile([{parse_transform, ejabberd_sql_pt}]).
|
||||
|
||||
%% API
|
||||
-export([init/2, caps_read/2, caps_write/3, export/1]).
|
||||
-export([init/2, caps_read/2, caps_write/3, export/1, import/3]).
|
||||
|
||||
-include("mod_caps.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
@ -53,6 +53,9 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(_, _, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
|
@ -344,7 +344,9 @@ disco_identity(Acc, _From, To, <<"">>, _Lang, Type) ->
|
||||
empty when Identities /= [] -> {result, Identities};
|
||||
{result, Ids} -> {result, Ids ++ Identities};
|
||||
Acc -> Acc
|
||||
end.
|
||||
end;
|
||||
disco_identity(Acc, _From, _To, _Node, _Lang, _Type) ->
|
||||
Acc.
|
||||
|
||||
my_features(ejabberd_local) -> [?NS_DELEGATION];
|
||||
my_features(ejabberd_sm) -> [].
|
||||
|
@ -360,7 +360,8 @@ handle_cast(Request, State) ->
|
||||
|
||||
-spec handle_info(timeout | _, state()) -> {noreply, state()}.
|
||||
|
||||
handle_info({route, From, To, #iq{} = IQ}, State) ->
|
||||
handle_info({route, From, To, #iq{} = Packet}, State) ->
|
||||
IQ = xmpp:decode_els(Packet),
|
||||
{Reply, NewState} = case process_iq(From, IQ, State) of
|
||||
R when is_record(R, iq) ->
|
||||
{R, State};
|
||||
|
@ -34,8 +34,8 @@
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1, process_local_iq/1, export/1,
|
||||
process_sm_iq/1, on_presence_update/4, import/1,
|
||||
import/3, store_last_info/4, get_last_info/2,
|
||||
process_sm_iq/1, on_presence_update/4, import_info/0,
|
||||
import/5, import_start/2, store_last_info/4, get_last_info/2,
|
||||
remove_user/2, transform_options/1, mod_opt_type/1,
|
||||
opt_type/1, register_user/2, depends/2]).
|
||||
|
||||
@ -207,18 +207,28 @@ remove_user(User, Server) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:remove_user(LUser, LServer).
|
||||
|
||||
import_info() ->
|
||||
[{<<"last">>, 3}].
|
||||
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:init(LServer, []).
|
||||
|
||||
import(LServer, {sql, _}, DBType, <<"last">>, [LUser, TimeStamp, State]) ->
|
||||
TS = case TimeStamp of
|
||||
<<"">> -> 0;
|
||||
_ -> binary_to_integer(TimeStamp)
|
||||
end,
|
||||
LA = #last_activity{us = {LUser, LServer},
|
||||
timestamp = TS,
|
||||
status = State},
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, LA).
|
||||
|
||||
export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
|
||||
import(LServer, DBType, LA) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, LA).
|
||||
|
||||
transform_options(Opts) ->
|
||||
lists:foldl(fun transform_options/2, [], Opts).
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, get_last/2, store_last_info/4, remove_user/2,
|
||||
import/1, import/2, export/1]).
|
||||
import/2, export/1]).
|
||||
|
||||
-include("mod_last.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -43,9 +43,6 @@ store_last_info(LUser, LServer, TimeStamp, Status) ->
|
||||
remove_user(LUser, LServer) ->
|
||||
sql_queries:del_last(LServer, LUser).
|
||||
|
||||
import(_LServer, _LA) ->
|
||||
pass.
|
||||
|
||||
export(_Server) ->
|
||||
[{last_activity,
|
||||
fun(Host, #last_activity{us = {LUser, LServer},
|
||||
@ -58,15 +55,5 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select username, seconds, state from last">>,
|
||||
fun([LUser, TimeStamp, State]) ->
|
||||
#last_activity{us = {LUser, LServer},
|
||||
timestamp = binary_to_integer(
|
||||
TimeStamp),
|
||||
status = State}
|
||||
end}].
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
import(_LServer, _LA) ->
|
||||
pass.
|
||||
|
243
src/mod_muc.erl
243
src/mod_muc.erl
@ -51,8 +51,9 @@
|
||||
process_mucsub/1,
|
||||
broadcast_service_message/2,
|
||||
export/1,
|
||||
import/1,
|
||||
import/3,
|
||||
import_info/0,
|
||||
import/5,
|
||||
import_start/2,
|
||||
opts_to_binary/1,
|
||||
can_use_nick/4]).
|
||||
|
||||
@ -62,7 +63,7 @@
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_muc.hrl").
|
||||
|
||||
@ -79,7 +80,7 @@
|
||||
|
||||
-type muc_room_opts() :: [{atom(), any()}].
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #muc_room{} | #muc_registered{}) -> ok | pass.
|
||||
-callback import(binary(), binary(), [binary()]) -> ok.
|
||||
-callback store_room(binary(), binary(), binary(), list()) -> {atomic, any()}.
|
||||
-callback restore_room(binary(), binary(), binary()) -> muc_room_opts() | error.
|
||||
-callback forget_room(binary(), binary(), binary()) -> {atomic, any()}.
|
||||
@ -175,8 +176,10 @@ init([Host, Opts]) ->
|
||||
<<"conference.@HOST@">>),
|
||||
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
||||
Mod:init(Host, [{host, MyHost}|Opts]),
|
||||
update_tables(),
|
||||
mnesia:create_table(muc_online_room,
|
||||
[{ram_copies, [node()]},
|
||||
{type, ordered_set},
|
||||
{attributes, record_info(fields, muc_online_room)}]),
|
||||
mnesia:add_table_copy(muc_online_room, node(), ram_copies),
|
||||
catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]),
|
||||
@ -497,8 +500,12 @@ process_disco_items(#iq{type = get, from = From, to = To, lang = Lang,
|
||||
ServerHost, ?MODULE, max_rooms_discoitems,
|
||||
fun(I) when is_integer(I), I>=0 -> I end,
|
||||
100),
|
||||
Items = iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM),
|
||||
xmpp:make_iq_result(IQ, #disco_items{node = Node, items = Items});
|
||||
case iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM) of
|
||||
{error, Err} ->
|
||||
xmpp:make_error(IQ, Err);
|
||||
{result, Result} ->
|
||||
xmpp:make_iq_result(IQ, Result)
|
||||
end;
|
||||
process_disco_items(#iq{lang = Lang} = IQ) ->
|
||||
Txt = <<"No module is handling this query">>,
|
||||
xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)).
|
||||
@ -597,76 +604,112 @@ register_room(Host, Room, Pid) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, <<"">>, undefined) ->
|
||||
Rooms = get_vh_rooms(Host),
|
||||
case erlang:length(Rooms) < MaxRoomsDiscoItems of
|
||||
true ->
|
||||
iq_disco_items_list(Host, Rooms, {get_disco_item, all, From, Lang});
|
||||
false ->
|
||||
iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, <<"nonemptyrooms">>, undefined)
|
||||
end;
|
||||
iq_disco_items(Host, From, Lang, _MaxRoomsDiscoItems, <<"nonemptyrooms">>, undefined) ->
|
||||
Empty = #disco_item{jid = jid:make(<<"conference.localhost">>),
|
||||
node = <<"emptyrooms">>,
|
||||
name = translate:translate(Lang, <<"Empty Rooms">>)},
|
||||
Query = {get_disco_item, only_non_empty, From, Lang},
|
||||
[Empty | iq_disco_items_list(Host, get_vh_rooms(Host), Query)];
|
||||
iq_disco_items(Host, From, Lang, _MaxRoomsDiscoItems, <<"emptyrooms">>, undefined) ->
|
||||
iq_disco_items_list(Host, get_vh_rooms(Host), {get_disco_item, 0, From, Lang});
|
||||
iq_disco_items(Host, From, Lang, _MaxRoomsDiscoItems, _DiscoNode, Rsm) ->
|
||||
{Rooms, RsmO} = get_vh_rooms(Host, Rsm),
|
||||
RsmOut = jlib:rsm_encode(RsmO),
|
||||
iq_disco_items_list(Host, Rooms, {get_disco_item, all, From, Lang}) ++ RsmOut.
|
||||
-spec iq_disco_items(binary(), jid(), binary(), integer(), binary(),
|
||||
rsm_set() | undefined) ->
|
||||
{result, disco_items()} | {error, stanza_error()}.
|
||||
iq_disco_items(Host, From, Lang, MaxRoomsDiscoItems, Node, RSM)
|
||||
when Node == <<"">>; Node == <<"nonemptyrooms">>; Node == <<"emptyrooms">> ->
|
||||
Count = get_vh_rooms_count(Host),
|
||||
Query = if Node == <<"">>, RSM == undefined, Count > MaxRoomsDiscoItems ->
|
||||
{get_disco_item, only_non_empty, From, Lang};
|
||||
Node == <<"nonemptyrooms">> ->
|
||||
{get_disco_item, only_non_empty, From, Lang};
|
||||
Node == <<"emptyrooms">> ->
|
||||
{get_disco_item, 0, From, Lang};
|
||||
true ->
|
||||
{get_disco_item, all, From, Lang}
|
||||
end,
|
||||
Items = get_vh_rooms(Host, Query, RSM),
|
||||
ResRSM = case Items of
|
||||
[_|_] when RSM /= undefined ->
|
||||
#disco_item{jid = #jid{luser = First}} = hd(Items),
|
||||
#disco_item{jid = #jid{luser = Last}} = lists:last(Items),
|
||||
#rsm_set{first = #rsm_first{data = First},
|
||||
last = Last,
|
||||
count = Count};
|
||||
[] when RSM /= undefined ->
|
||||
#rsm_set{count = Count};
|
||||
_ ->
|
||||
undefined
|
||||
end,
|
||||
{result, #disco_items{node = Node, items = Items, rsm = ResRSM}};
|
||||
iq_disco_items(_Host, _From, Lang, _MaxRoomsDiscoItems, _Node, _RSM) ->
|
||||
{error, xmpp:err_item_not_found(<<"Node not found">>, Lang)}.
|
||||
|
||||
iq_disco_items_list(Host, Rooms, Query) ->
|
||||
lists:zf(
|
||||
fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) ->
|
||||
case catch gen_fsm:sync_send_all_state_event(Pid, Query, 100) of
|
||||
{item, Desc} ->
|
||||
flush(),
|
||||
{true, #disco_item{jid = jid:make(Name, Host),
|
||||
name = Desc}};
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end, Rooms).
|
||||
-spec get_vh_rooms(binary, term(), rsm_set() | undefined) -> [disco_item()].
|
||||
get_vh_rooms(Host, Query,
|
||||
#rsm_set{max = Max, 'after' = After, before = undefined})
|
||||
when is_binary(After), After /= <<"">> ->
|
||||
lists:reverse(get_vh_rooms(next, {After, Host}, Host, Query, 0, Max, []));
|
||||
get_vh_rooms(Host, Query,
|
||||
#rsm_set{max = Max, 'after' = undefined, before = Before})
|
||||
when is_binary(Before), Before /= <<"">> ->
|
||||
get_vh_rooms(prev, {Before, Host}, Host, Query, 0, Max, []);
|
||||
get_vh_rooms(Host, Query,
|
||||
#rsm_set{max = Max, 'after' = undefined, before = <<"">>}) ->
|
||||
get_vh_rooms(last, {<<"">>, Host}, Host, Query, 0, Max, []);
|
||||
get_vh_rooms(Host, Query, #rsm_set{max = Max}) ->
|
||||
lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Host, Query, 0, Max, []));
|
||||
get_vh_rooms(Host, Query, undefined) ->
|
||||
lists:reverse(get_vh_rooms(first, {<<"">>, Host}, Host, Query, 0, undefined, [])).
|
||||
|
||||
get_vh_rooms(_, _) ->
|
||||
todo.
|
||||
%% AllRooms = lists:sort(get_vh_rooms(Host)),
|
||||
%% Count = erlang:length(AllRooms),
|
||||
%% Guard = case Direction of
|
||||
%% _ when Index =/= undefined -> [{'==', {element, 2, '$1'}, Host}];
|
||||
%% aft -> [{'==', {element, 2, '$1'}, Host}, {'>=',{element, 1, '$1'} ,I}];
|
||||
%% before when I =/= []-> [{'==', {element, 2, '$1'}, Host}, {'=<',{element, 1, '$1'} ,I}];
|
||||
%% _ -> [{'==', {element, 2, '$1'}, Host}]
|
||||
%% end,
|
||||
%% L = lists:sort(
|
||||
%% mnesia:dirty_select(muc_online_room,
|
||||
%% [{#muc_online_room{name_host = '$1', _ = '_'},
|
||||
%% Guard,
|
||||
%% ['$_']}])),
|
||||
%% L2 = if
|
||||
%% Index == undefined andalso Direction == before ->
|
||||
%% lists:reverse(lists:sublist(lists:reverse(L), 1, M));
|
||||
%% Index == undefined ->
|
||||
%% lists:sublist(L, 1, M);
|
||||
%% Index > Count orelse Index < 0 ->
|
||||
%% [];
|
||||
%% true ->
|
||||
%% lists:sublist(L, Index+1, M)
|
||||
%% end,
|
||||
%% if L2 == [] -> {L2, #rsm_out{count = Count}};
|
||||
%% true ->
|
||||
%% H = hd(L2),
|
||||
%% NewIndex = get_room_pos(H, AllRooms),
|
||||
%% T = lists:last(L2),
|
||||
%% {F, _} = H#muc_online_room.name_host,
|
||||
%% {Last, _} = T#muc_online_room.name_host,
|
||||
%% {L2,
|
||||
%% #rsm_out{first = F, last = Last, count = Count,
|
||||
%% index = NewIndex}}
|
||||
%% end.
|
||||
-spec get_vh_rooms(prev | next | last | first,
|
||||
{binary(), binary()}, binary(), term(),
|
||||
non_neg_integer(), non_neg_integer() | undefined,
|
||||
[disco_item()]) -> [disco_item()].
|
||||
get_vh_rooms(_Action, _Key, _Host, _Query, Count, Max, Items) when Count >= Max ->
|
||||
Items;
|
||||
get_vh_rooms(Action, Key, Host, Query, Count, Max, Items) ->
|
||||
Call = fun() ->
|
||||
case Action of
|
||||
prev -> mnesia:dirty_prev(muc_online_room, Key);
|
||||
next -> mnesia:dirty_next(muc_online_room, Key);
|
||||
last -> mnesia:dirty_last(muc_online_room);
|
||||
first -> mnesia:dirty_first(muc_online_room)
|
||||
end
|
||||
end,
|
||||
NewAction = case Action of
|
||||
last -> prev;
|
||||
first -> next;
|
||||
_ -> Action
|
||||
end,
|
||||
try Call() of
|
||||
'$end_of_table' ->
|
||||
Items;
|
||||
{_, Host} = NewKey ->
|
||||
case get_room_disco_item(NewKey, Query) of
|
||||
{ok, Item} ->
|
||||
get_vh_rooms(NewAction, NewKey, Host, Query,
|
||||
Count + 1, Max, [Item|Items]);
|
||||
{error, _} ->
|
||||
get_vh_rooms(NewAction, NewKey, Host, Query,
|
||||
Count, Max, Items)
|
||||
end;
|
||||
NewKey ->
|
||||
get_vh_rooms(NewAction, NewKey, Host, Query, Count, Max, Items)
|
||||
catch _:{aborted, {badarg, _}} ->
|
||||
Items
|
||||
end.
|
||||
|
||||
-spec get_room_disco_item({binary(), binary()}, term()) -> {ok, disco_item()} |
|
||||
{error, timeout | notfound}.
|
||||
get_room_disco_item({Name, Host}, Query) ->
|
||||
case mnesia:dirty_read(muc_online_room, {Name, Host}) of
|
||||
[#muc_online_room{pid = Pid}|_] ->
|
||||
RoomJID = jid:make(Name, Host),
|
||||
try gen_fsm:sync_send_all_state_event(Pid, Query, 100) of
|
||||
{item, Desc} ->
|
||||
{ok, #disco_item{jid = RoomJID, name = Desc}};
|
||||
false ->
|
||||
{error, notfound}
|
||||
catch _:{timeout, _} ->
|
||||
{error, timeout};
|
||||
_:{noproc, _} ->
|
||||
{error, notfound}
|
||||
end;
|
||||
_ ->
|
||||
{error, notfound}
|
||||
end.
|
||||
|
||||
get_subscribed_rooms(_ServerHost, Host, From) ->
|
||||
Rooms = get_vh_rooms(Host),
|
||||
@ -681,21 +724,6 @@ get_subscribed_rooms(_ServerHost, Host, From) ->
|
||||
[]
|
||||
end, Rooms).
|
||||
|
||||
%% @doc Return the position of desired room in the list of rooms.
|
||||
%% The room must exist in the list. The count starts in 0.
|
||||
%% @spec (Desired::muc_online_room(), Rooms::[muc_online_room()]) -> integer()
|
||||
get_room_pos(Desired, Rooms) ->
|
||||
get_room_pos(Desired, Rooms, 0).
|
||||
|
||||
get_room_pos(Desired, [HeadRoom | _], HeadPosition)
|
||||
when Desired#muc_online_room.name_host ==
|
||||
HeadRoom#muc_online_room.name_host ->
|
||||
HeadPosition;
|
||||
get_room_pos(Desired, [_ | Rooms], HeadPosition) ->
|
||||
get_room_pos(Desired, Rooms, HeadPosition + 1).
|
||||
|
||||
flush() -> receive _ -> flush() after 0 -> ok end.
|
||||
|
||||
get_nick(ServerHost, Host, From) ->
|
||||
LServer = jid:nameprep(ServerHost),
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
@ -782,6 +810,13 @@ get_vh_rooms(Host) ->
|
||||
[{'==', {element, 2, '$1'}, Host}],
|
||||
['$_']}]).
|
||||
|
||||
-spec get_vh_rooms_count(binary()) -> non_neg_integer().
|
||||
get_vh_rooms_count(Host) ->
|
||||
ets:select_count(muc_online_room,
|
||||
ets:fun2ms(
|
||||
fun(#muc_online_room{name_host = {_, H}}) ->
|
||||
H == Host
|
||||
end)).
|
||||
|
||||
clean_table_from_bad_node(Node) ->
|
||||
F = fun() ->
|
||||
@ -811,6 +846,23 @@ clean_table_from_bad_node(Node, Host) ->
|
||||
end,
|
||||
mnesia:async_dirty(F).
|
||||
|
||||
update_tables() ->
|
||||
try
|
||||
case mnesia:table_info(muc_online_room, type) of
|
||||
ordered_set -> ok;
|
||||
_ ->
|
||||
case mnesia:delete_table(muc_online_room) of
|
||||
{atomic, ok} -> ok;
|
||||
Err -> erlang:error(Err)
|
||||
end
|
||||
end
|
||||
catch _:{aborted, {no_exists, muc_online_room}} -> ok;
|
||||
_:{aborted, {no_exists, muc_online_room, type}} -> ok;
|
||||
E:R ->
|
||||
?ERROR_MSG("failed to update mnesia table '~s': ~p",
|
||||
[muc_online_room, {E, R}])
|
||||
end.
|
||||
|
||||
opts_to_binary(Opts) ->
|
||||
lists:map(
|
||||
fun({title, Title}) ->
|
||||
@ -853,13 +905,16 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
import_info() ->
|
||||
[{<<"muc_room">>, 4}, {<<"muc_registered">>, 4}].
|
||||
|
||||
import(LServer, DBType, Data) ->
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Data).
|
||||
Mod:init(LServer, []).
|
||||
|
||||
import(LServer, {sql, _}, DBType, Tab, L) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Tab, L).
|
||||
|
||||
mod_opt_type(access) ->
|
||||
fun acl:access_rules_validator/1;
|
||||
|
@ -9,11 +9,15 @@
|
||||
-module(mod_muc_mnesia).
|
||||
|
||||
-behaviour(mod_muc).
|
||||
-behaviour(mod_muc_room).
|
||||
|
||||
%% API
|
||||
-export([init/2, import/2, store_room/4, restore_room/3, forget_room/3,
|
||||
-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
|
||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
|
||||
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
||||
get_affiliations/3, search_affiliation/4]).
|
||||
|
||||
-include("jlib.hrl").
|
||||
-include("mod_muc.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
@ -113,10 +117,33 @@ set_nick(_LServer, Host, From, Nick) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #muc_room{} = R) ->
|
||||
mnesia:dirty_write(R);
|
||||
import(_LServer, #muc_registered{} = R) ->
|
||||
mnesia:dirty_write(R).
|
||||
set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
set_affiliations(_ServerHost, _Room, _Host, _Affiliations) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
get_affiliations(_ServerHost, _Room, _Host) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
import(_LServer, <<"muc_room">>,
|
||||
[Name, RoomHost, SOpts, _TimeStamp]) ->
|
||||
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
||||
mnesia:dirty_write(
|
||||
#muc_room{name_host = {Name, RoomHost},
|
||||
opts = Opts});
|
||||
import(_LServer, <<"muc_registered">>,
|
||||
[J, RoomHost, Nick, _TimeStamp]) ->
|
||||
#jid{user = U, server = S} = jid:from_string(J),
|
||||
mnesia:dirty_write(
|
||||
#muc_registered{us_host = {{U, S}, RoomHost},
|
||||
nick = Nick}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -9,11 +9,15 @@
|
||||
-module(mod_muc_riak).
|
||||
|
||||
-behaviour(mod_muc).
|
||||
-behaviour(mod_muc_room).
|
||||
|
||||
%% API
|
||||
-export([init/2, import/2, store_room/4, restore_room/3, forget_room/3,
|
||||
-export([init/2, import/3, store_room/4, restore_room/3, forget_room/3,
|
||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4]).
|
||||
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
||||
get_affiliations/3, search_affiliation/4]).
|
||||
|
||||
-include("jlib.hrl").
|
||||
-include("mod_muc.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
@ -101,11 +105,33 @@ set_nick(LServer, Host, From, Nick) ->
|
||||
end
|
||||
end}.
|
||||
|
||||
import(_LServer, #muc_room{} = R) ->
|
||||
ejabberd_riak:put(R, muc_room_schema());
|
||||
import(_LServer, #muc_registered{us_host = {_, Host}, nick = Nick} = R) ->
|
||||
set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
set_affiliations(_ServerHost, _Room, _Host, _Affiliations) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
get_affiliations(_ServerHost, _Room, _Host) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
import(_LServer, <<"muc_room">>,
|
||||
[Name, RoomHost, SOpts, _TimeStamp]) ->
|
||||
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
||||
ejabberd_riak:put(
|
||||
#muc_room{name_host = {Name, RoomHost}, opts = Opts},
|
||||
muc_room_schema());
|
||||
import(_LServer, <<"muc_registered">>,
|
||||
[J, RoomHost, Nick, _TimeStamp]) ->
|
||||
#jid{user = U, server = S} = jid:from_string(J),
|
||||
R = #muc_registered{us_host = {{U, S}, RoomHost}, nick = Nick},
|
||||
ejabberd_riak:put(R, muc_registered_schema(),
|
||||
[{'2i', [{<<"nick_host">>, {Nick, Host}}]}]).
|
||||
[{'2i', [{<<"nick_host">>, {Nick, RoomHost}}]}]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -504,8 +504,7 @@ handle_event(_Event, StateName, StateData) ->
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
handle_sync_event({get_disco_item, Filter, JID, Lang}, _From, StateName, StateData) ->
|
||||
Len = ?DICT:fold(fun(_, _, Acc) -> Acc + 1 end, 0,
|
||||
StateData#state.users),
|
||||
Len = ?DICT:size(StateData#state.users),
|
||||
Reply = case (Filter == all) or (Filter == Len) or ((Filter /= 0) and (Len /= 0)) of
|
||||
true ->
|
||||
get_roomdesc_reply(JID, StateData,
|
||||
|
@ -11,11 +11,14 @@
|
||||
-compile([{parse_transform, ejabberd_sql_pt}]).
|
||||
|
||||
-behaviour(mod_muc).
|
||||
-behaviour(mod_muc_room).
|
||||
|
||||
%% API
|
||||
-export([init/2, store_room/4, restore_room/3, forget_room/3,
|
||||
can_use_nick/4, get_rooms/2, get_nick/3, set_nick/4,
|
||||
import/1, import/2, export/1]).
|
||||
import/3, export/1]).
|
||||
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
|
||||
get_affiliations/3, search_affiliation/4]).
|
||||
|
||||
-include("jid.hrl").
|
||||
-include("mod_muc.hrl").
|
||||
@ -127,6 +130,21 @@ set_nick(LServer, Host, From, Nick) ->
|
||||
end,
|
||||
ejabberd_sql:sql_transaction(LServer, F).
|
||||
|
||||
set_affiliation(_ServerHost, _Room, _Host, _JID, _Affiliation, _Reason) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
set_affiliations(_ServerHost, _Room, _Host, _Affiliations) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
get_affiliation(_ServerHost, _Room, _Host, _LUser, _LServer) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
get_affiliations(_ServerHost, _Room, _Host) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
search_affiliation(_ServerHost, _Room, _Host, _Affiliation) ->
|
||||
{error, not_implemented}.
|
||||
|
||||
export(_Server) ->
|
||||
[{muc_room,
|
||||
fun(Host, #muc_room{name_host = {Name, RoomHost}, opts = Opts}) ->
|
||||
@ -158,21 +176,8 @@ export(_Server) ->
|
||||
end
|
||||
end}].
|
||||
|
||||
import(_LServer) ->
|
||||
[{<<"select name, host, opts from muc_room;">>,
|
||||
fun([Name, RoomHost, SOpts]) ->
|
||||
Opts = mod_muc:opts_to_binary(ejabberd_sql:decode_term(SOpts)),
|
||||
#muc_room{name_host = {Name, RoomHost}, opts = Opts}
|
||||
end},
|
||||
{<<"select jid, host, nick from muc_registered;">>,
|
||||
fun([J, RoomHost, Nick]) ->
|
||||
#jid{user = U, server = S} = jid:from_string(J),
|
||||
#muc_registered{us_host = {{U, S}, RoomHost},
|
||||
nick = Nick}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_, _, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -53,8 +53,9 @@
|
||||
remove_expired_messages/1,
|
||||
remove_old_messages/2,
|
||||
remove_user/2,
|
||||
import/1,
|
||||
import/3,
|
||||
import_info/0,
|
||||
import_start/2,
|
||||
import/5,
|
||||
export/1,
|
||||
get_queue_length/2,
|
||||
count_offline_messages/2,
|
||||
@ -90,7 +91,7 @@
|
||||
|
||||
-type us() :: {binary(), binary()}.
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #offline_msg{}) -> ok | pass.
|
||||
-callback import(#offline_msg{}) -> ok.
|
||||
-callback store_messages(binary(), us(), [#offline_msg{}],
|
||||
non_neg_integer(), non_neg_integer()) ->
|
||||
{atomic, any()}.
|
||||
@ -851,13 +852,35 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
import_info() ->
|
||||
[{<<"spool">>, 4}].
|
||||
|
||||
import(LServer, DBType, Data) ->
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Data).
|
||||
Mod:import(LServer, []).
|
||||
|
||||
import(LServer, {sql, _}, DBType, <<"spool">>,
|
||||
[LUser, XML, _Seq, _TimeStamp]) ->
|
||||
El = fxml_stream:parse_element(XML),
|
||||
From = #jid{} = jid:from_string(
|
||||
fxml:get_attr_s(<<"from">>, El#xmlel.attrs)),
|
||||
To = #jid{} = jid:from_string(
|
||||
fxml:get_attr_s(<<"to">>, El#xmlel.attrs)),
|
||||
Stamp = fxml:get_path_s(El, [{elem, <<"delay">>},
|
||||
{attr, <<"stamp">>}]),
|
||||
TS = try xmpp_util:decode_timestamp(Stamp) of
|
||||
{MegaSecs, Secs, _} ->
|
||||
{MegaSecs, Secs, 0}
|
||||
catch _:_ ->
|
||||
p1_time_compat:timestamp()
|
||||
end,
|
||||
US = {LUser, LServer},
|
||||
Expire = find_x_expire(TS, El#xmlel.children),
|
||||
Msg = #offline_msg{us = US, packet = El,
|
||||
from = From, to = To,
|
||||
timestamp = TS, expire = Expire},
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(Msg).
|
||||
|
||||
mod_opt_type(access_max_user_messages) ->
|
||||
fun acl:shaper_rules_validator/1;
|
||||
|
@ -13,7 +13,7 @@
|
||||
-export([init/2, store_messages/5, pop_messages/2, remove_expired_messages/1,
|
||||
remove_old_messages/2, remove_user/2, read_message_headers/2,
|
||||
read_message/3, remove_message/3, read_all_messages/2,
|
||||
remove_all_messages/2, count_messages/2, import/2]).
|
||||
remove_all_messages/2, count_messages/2, import/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_offline.hrl").
|
||||
@ -164,7 +164,7 @@ count_messages(LUser, LServer) ->
|
||||
_ -> 0
|
||||
end.
|
||||
|
||||
import(_LServer, #offline_msg{} = Msg) ->
|
||||
import(#offline_msg{} = Msg) ->
|
||||
mnesia:dirty_write(Msg).
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -13,7 +13,7 @@
|
||||
-export([init/2, store_messages/5, pop_messages/2, remove_expired_messages/1,
|
||||
remove_old_messages/2, remove_user/2, read_message_headers/2,
|
||||
read_message/3, remove_message/3, read_all_messages/2,
|
||||
remove_all_messages/2, count_messages/2, import/2]).
|
||||
remove_all_messages/2, count_messages/2, import/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_offline.hrl").
|
||||
@ -133,7 +133,7 @@ count_messages(LUser, LServer) ->
|
||||
0
|
||||
end.
|
||||
|
||||
import(_LServer, #offline_msg{us = US, timestamp = TS} = M) ->
|
||||
import(#offline_msg{us = US, timestamp = TS} = M) ->
|
||||
ejabberd_riak:put(M, offline_msg_schema(),
|
||||
[{i, TS}, {'2i', [{<<"us">>, US}]}]).
|
||||
|
||||
|
@ -15,8 +15,7 @@
|
||||
-export([init/2, store_messages/5, pop_messages/2, remove_expired_messages/1,
|
||||
remove_old_messages/2, remove_user/2, read_message_headers/2,
|
||||
read_message/3, remove_message/3, read_all_messages/2,
|
||||
remove_all_messages/2, count_messages/2, import/1, import/2,
|
||||
export/1]).
|
||||
remove_all_messages/2, count_messages/2, import/1, export/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_offline.hrl").
|
||||
@ -193,29 +192,8 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select username, xml from spool;">>,
|
||||
fun([LUser, XML]) ->
|
||||
El = #xmlel{} = fxml_stream:parse_element(XML),
|
||||
#message{} = Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]),
|
||||
From = Pkt#message.from,
|
||||
To = case Pkt#message.to of
|
||||
undefined -> jid:make(LUser, LServer);
|
||||
JID -> JID
|
||||
end,
|
||||
TS = case xmpp:get_subtag(Pkt, #delay{}) of
|
||||
#delay{stamp = Stamp} -> Stamp;
|
||||
false -> p1_time_compat:timestamp()
|
||||
end,
|
||||
Expire = mod_offline:find_x_expire(TS, Pkt),
|
||||
#offline_msg{us = {LUser, LServer},
|
||||
from = From, to = To,
|
||||
packet = El,
|
||||
timestamp = TS, expire = Expire}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -31,11 +31,12 @@
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1, process_iq/1, export/1, import/1,
|
||||
-export([start/2, stop/1, process_iq/1, export/1, import_info/0,
|
||||
process_iq_set/3, process_iq_get/3, get_user_list/3,
|
||||
check_packet/6, remove_user/2, encode_list_item/1,
|
||||
is_list_needdb/1, updated_list/3,
|
||||
item_to_xml/1, get_user_lists/2, import/3,
|
||||
import_start/2, import_stop/2,
|
||||
item_to_xml/1, get_user_lists/2, import/5,
|
||||
set_privacy_list/1, mod_opt_type/1, depends/2]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
@ -46,7 +47,7 @@
|
||||
-include("mod_privacy.hrl").
|
||||
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #privacy{}) -> ok | pass.
|
||||
-callback import(#privacy{}) -> ok.
|
||||
-callback process_lists_get(binary(), binary()) -> {none | binary(), [binary()]} | error.
|
||||
-callback process_list_get(binary(), binary(), binary()) -> [listitem()] | error | not_found.
|
||||
-callback process_default_set(binary(), binary(), binary() | none) -> {atomic, any()}.
|
||||
@ -544,18 +545,108 @@ updated_list(_, #userlist{name = OldName} = Old,
|
||||
true -> Old
|
||||
end.
|
||||
|
||||
numeric_to_binary(<<0, 0, _/binary>>) ->
|
||||
<<"0">>;
|
||||
numeric_to_binary(<<0, _, _:6/binary, T/binary>>) ->
|
||||
Res = lists:foldl(
|
||||
fun(X, Sum) ->
|
||||
Sum*10000 + X
|
||||
end, 0, [X || <<X:16>> <= T]),
|
||||
integer_to_binary(Res).
|
||||
|
||||
bool_to_binary(<<0>>) -> <<"0">>;
|
||||
bool_to_binary(<<1>>) -> <<"1">>.
|
||||
|
||||
prepare_list_data(mysql, [ID|Row]) ->
|
||||
[binary_to_integer(ID)|Row];
|
||||
prepare_list_data(pgsql, [<<ID:64>>,
|
||||
SType, SValue, SAction, SOrder, SMatchAll,
|
||||
SMatchIQ, SMatchMessage, SMatchPresenceIn,
|
||||
SMatchPresenceOut]) ->
|
||||
[ID, SType, SValue, SAction,
|
||||
numeric_to_binary(SOrder),
|
||||
bool_to_binary(SMatchAll),
|
||||
bool_to_binary(SMatchIQ),
|
||||
bool_to_binary(SMatchMessage),
|
||||
bool_to_binary(SMatchPresenceIn),
|
||||
bool_to_binary(SMatchPresenceOut)].
|
||||
|
||||
prepare_id(mysql, ID) ->
|
||||
binary_to_integer(ID);
|
||||
prepare_id(pgsql, <<ID:32>>) ->
|
||||
ID.
|
||||
|
||||
import_info() ->
|
||||
[{<<"privacy_default_list">>, 2},
|
||||
{<<"privacy_list_data">>, 10},
|
||||
{<<"privacy_list">>, 4}].
|
||||
|
||||
import_start(LServer, DBType) ->
|
||||
ets:new(privacy_default_list_tmp, [private, named_table]),
|
||||
ets:new(privacy_list_data_tmp, [private, named_table, bag]),
|
||||
ets:new(privacy_list_tmp, [private, named_table, bag,
|
||||
{keypos, #privacy.us}]),
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:init(LServer, []).
|
||||
|
||||
import(LServer, {sql, _}, _DBType, <<"privacy_default_list">>, [LUser, Name]) ->
|
||||
US = {LUser, LServer},
|
||||
ets:insert(privacy_default_list_tmp, {US, Name}),
|
||||
ok;
|
||||
import(LServer, {sql, SQLType}, _DBType, <<"privacy_list_data">>, Row1) ->
|
||||
[ID|Row] = prepare_list_data(SQLType, Row1),
|
||||
case mod_privacy_sql:raw_to_item(Row) of
|
||||
[Item] ->
|
||||
IS = {ID, LServer},
|
||||
ets:insert(privacy_list_data_tmp, {IS, Item}),
|
||||
ok;
|
||||
[] ->
|
||||
ok
|
||||
end;
|
||||
import(LServer, {sql, SQLType}, _DBType, <<"privacy_list">>,
|
||||
[LUser, Name, ID, _TimeStamp]) ->
|
||||
US = {LUser, LServer},
|
||||
IS = {prepare_id(SQLType, ID), LServer},
|
||||
Default = case ets:lookup(privacy_default_list_tmp, US) of
|
||||
[{_, Name}] -> Name;
|
||||
_ -> none
|
||||
end,
|
||||
case [Item || {_, Item} <- ets:lookup(privacy_list_data_tmp, IS)] of
|
||||
[_|_] = Items ->
|
||||
Privacy = #privacy{us = {LUser, LServer},
|
||||
default = Default,
|
||||
lists = [{Name, Items}]},
|
||||
ets:insert(privacy_list_tmp, Privacy),
|
||||
ets:delete(privacy_list_data_tmp, IS),
|
||||
ok;
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
|
||||
import_stop(_LServer, DBType) ->
|
||||
import_next(DBType, ets:first(privacy_list_tmp)),
|
||||
ets:delete(privacy_default_list_tmp),
|
||||
ets:delete(privacy_list_data_tmp),
|
||||
ets:delete(privacy_list_tmp),
|
||||
ok.
|
||||
|
||||
import_next(_DBType, '$end_of_table') ->
|
||||
ok;
|
||||
import_next(DBType, US) ->
|
||||
[P|_] = Ps = ets:lookup(privacy_list_tmp, US),
|
||||
Lists = lists:flatmap(
|
||||
fun(#privacy{lists = Lists}) ->
|
||||
Lists
|
||||
end, Ps),
|
||||
Privacy = P#privacy{lists = Lists},
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(Privacy),
|
||||
import_next(DBType, ets:next(privacy_list_tmp, US)).
|
||||
|
||||
export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
|
||||
import(LServer, DBType, Data) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Data).
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
process_default_set/3, process_active_set/3,
|
||||
remove_privacy_list/3, set_privacy_list/1,
|
||||
set_privacy_list/4, get_user_list/2, get_user_lists/2,
|
||||
remove_user/2, import/2]).
|
||||
remove_user/2, import/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_privacy.hrl").
|
||||
@ -144,7 +144,7 @@ remove_user(LUser, LServer) ->
|
||||
F = fun () -> mnesia:delete({privacy, {LUser, LServer}}) end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #privacy{} = P) ->
|
||||
import(#privacy{} = P) ->
|
||||
mnesia:dirty_write(P).
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -15,7 +15,7 @@
|
||||
process_default_set/3, process_active_set/3,
|
||||
remove_privacy_list/3, set_privacy_list/1,
|
||||
set_privacy_list/4, get_user_list/2, get_user_lists/2,
|
||||
remove_user/2, import/2]).
|
||||
remove_user/2, import/1]).
|
||||
|
||||
-export([privacy_schema/0]).
|
||||
|
||||
@ -145,7 +145,7 @@ get_user_lists(LUser, LServer) ->
|
||||
remove_user(LUser, LServer) ->
|
||||
{atomic, ejabberd_riak:delete(privacy, {LUser, LServer})}.
|
||||
|
||||
import(_LServer, #privacy{} = P) ->
|
||||
import(#privacy{} = P) ->
|
||||
ejabberd_riak:put(P, privacy_schema()).
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -17,7 +17,7 @@
|
||||
process_default_set/3, process_active_set/3,
|
||||
remove_privacy_list/3, set_privacy_list/1,
|
||||
set_privacy_list/4, get_user_list/2, get_user_lists/2,
|
||||
remove_user/2, import/1, import/2, export/1]).
|
||||
remove_user/2, import/1, export/1]).
|
||||
|
||||
-export([item_to_raw/1, raw_to_item/1,
|
||||
sql_add_privacy_list/2,
|
||||
@ -249,37 +249,8 @@ get_id() ->
|
||||
put(id, ID + 1),
|
||||
ID + 1.
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select username from privacy_list;">>,
|
||||
fun([LUser]) ->
|
||||
Default = case sql_get_default_privacy_list_t(LUser) of
|
||||
{selected, [<<"name">>], []} ->
|
||||
none;
|
||||
{selected, [<<"name">>], [[DefName]]} ->
|
||||
DefName;
|
||||
_ ->
|
||||
none
|
||||
end,
|
||||
{selected, [<<"name">>], Names} =
|
||||
sql_get_privacy_list_names_t(LUser),
|
||||
Lists = lists:flatmap(
|
||||
fun([Name]) ->
|
||||
case sql_get_privacy_list_data_t(LUser, Name) of
|
||||
{selected, _, RItems} ->
|
||||
[{Name,
|
||||
lists:map(fun raw_to_item/1,
|
||||
RItems)}];
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
end, Names),
|
||||
#privacy{default = Default,
|
||||
us = {LUser, LServer},
|
||||
lists = Lists}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -31,9 +31,9 @@
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1, process_sm_iq/1, import/3,
|
||||
remove_user/2, get_data/2, get_data/3, export/1, import/1,
|
||||
mod_opt_type/1, set_data/3, depends/2]).
|
||||
-export([start/2, stop/1, process_sm_iq/1, import_info/0,
|
||||
remove_user/2, get_data/2, get_data/3, export/1,
|
||||
import/5, import_start/2, mod_opt_type/1, set_data/3, depends/2]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -42,7 +42,7 @@
|
||||
-include("mod_private.hrl").
|
||||
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #private_storage{}) -> ok | pass.
|
||||
-callback import(binary(), binary(), [binary()]) -> ok.
|
||||
-callback set_data(binary(), binary(), [{binary(), xmlel()}]) -> {atomic, any()}.
|
||||
-callback get_data(binary(), binary(), binary()) -> {ok, xmlel()} | error.
|
||||
-callback get_all_data(binary(), binary()) -> [xmlel()].
|
||||
@ -124,17 +124,20 @@ remove_user(User, Server) ->
|
||||
Mod = gen_mod:db_mod(Server, ?MODULE),
|
||||
Mod:remove_user(LUser, LServer).
|
||||
|
||||
import_info() ->
|
||||
[{<<"private_storage">>, 4}].
|
||||
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:init(LServer, []).
|
||||
|
||||
export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
|
||||
import(LServer, DBType, PD) ->
|
||||
import(LServer, {sql, _}, DBType, Tab, L) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, PD).
|
||||
Mod:import(LServer, Tab, L).
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2,
|
||||
import/2]).
|
||||
import/3]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_private.hrl").
|
||||
@ -72,7 +72,10 @@ remove_user(LUser, LServer) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #private_storage{} = PS) ->
|
||||
import(LServer, <<"private_storage">>,
|
||||
[LUser, XMLNS, XML, _TimeStamp]) ->
|
||||
El = #xmlel{} = fxml_stream:parse_element(XML),
|
||||
PS = #private_storage{usns = {LUser, LServer, XMLNS}, xml = El},
|
||||
mnesia:dirty_write(PS).
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2,
|
||||
import/2]).
|
||||
import/3]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_private.hrl").
|
||||
@ -56,7 +56,10 @@ remove_user(LUser, LServer) ->
|
||||
{atomic, ejabberd_riak:delete_by_index(private_storage,
|
||||
<<"us">>, {LUser, LServer})}.
|
||||
|
||||
import(_LServer, #private_storage{usns = {LUser, LServer, _}} = PS) ->
|
||||
import(LServer, <<"private_storage">>,
|
||||
[LUser, XMLNS, XML, _TimeStamp]) ->
|
||||
El = #xmlel{} = fxml_stream:parse_element(XML),
|
||||
PS = #private_storage{usns = {LUser, LServer, XMLNS}, xml = El},
|
||||
ejabberd_riak:put(PS, private_storage_schema(),
|
||||
[{'2i', [{<<"us">>, {LUser, LServer}}]}]).
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, set_data/3, get_data/3, get_all_data/2, remove_user/2,
|
||||
import/1, import/2, export/1]).
|
||||
import/3, export/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_private.hrl").
|
||||
@ -77,16 +77,8 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select username, namespace, data from private_storage;">>,
|
||||
fun([LUser, XMLNS, XML]) ->
|
||||
El = #xmlel{} = fxml_stream:parse_element(XML),
|
||||
#private_storage{usns = {LUser, LServer, XMLNS},
|
||||
xml = El}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_, _, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -42,8 +42,9 @@
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1, process_iq/1, export/1,
|
||||
import/1, process_local_iq/1, get_user_roster/2,
|
||||
import/3, get_subscription_lists/3, get_roster/2,
|
||||
import_info/0, process_local_iq/1, get_user_roster/2,
|
||||
import/5, get_subscription_lists/3, get_roster/2,
|
||||
import_start/2, import_stop/2,
|
||||
get_in_pending_subscriptions/3, in_subscription/6,
|
||||
out_subscription/4, set_items/3, remove_user/2,
|
||||
get_jid_info/4, encode_item/1, webadmin_page/3,
|
||||
@ -65,7 +66,7 @@
|
||||
-export_type([subscription/0]).
|
||||
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #roster{} | #roster_version{}) -> ok | pass.
|
||||
-callback import(binary(), binary(), #roster{} | [binary()]) -> ok.
|
||||
-callback read_roster_version(binary(), binary()) -> binary() | error.
|
||||
-callback write_roster_version(binary(), binary(), boolean(), binary()) -> any().
|
||||
-callback get_roster(binary(), binary()) -> [#roster{}].
|
||||
@ -1022,13 +1023,34 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
import_info() ->
|
||||
[{<<"roster_version">>, 2},
|
||||
{<<"rostergroups">>, 3},
|
||||
{<<"rosterusers">>, 10}].
|
||||
|
||||
import(LServer, DBType, R) ->
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, R).
|
||||
ets:new(rostergroups_tmp, [private, named_table, bag]),
|
||||
Mod:init(LServer, []),
|
||||
ok.
|
||||
|
||||
import_stop(_LServer, _DBType) ->
|
||||
ets:delete(rostergroups_tmp),
|
||||
ok.
|
||||
|
||||
import(LServer, {sql, _}, _DBType, <<"rostergroups">>, [LUser, SJID, Group]) ->
|
||||
LJID = jid:tolower(jid:from_string(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)),
|
||||
Groups = [G || {_, G} <- ets:lookup(rostergroups_tmp, I#roster.usj)],
|
||||
RosterItem = I#roster{groups = Groups},
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, <<"rosterusers">>, RosterItem);
|
||||
import(LServer, {sql, _}, DBType, <<"roster_version">>, [LUser, Ver]) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, <<"roster_version">>, [LUser, Ver]).
|
||||
|
||||
mod_opt_type(access) ->
|
||||
fun acl:access_rules_validator/1;
|
||||
|
@ -15,7 +15,7 @@
|
||||
get_roster/2, get_roster_by_jid/3, get_only_items/2,
|
||||
roster_subscribe/4, get_roster_by_jid_with_groups/3,
|
||||
remove_user/2, update_roster/4, del_roster/3, transaction/2,
|
||||
read_subscription_and_groups/3, import/2]).
|
||||
read_subscription_and_groups/3, import/3, create_roster/1]).
|
||||
|
||||
-include("mod_roster.hrl").
|
||||
-include("logger.hrl").
|
||||
@ -103,9 +103,13 @@ read_subscription_and_groups(LUser, LServer, LJID) ->
|
||||
transaction(_LServer, F) ->
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #roster{} = R) ->
|
||||
create_roster(RItem) ->
|
||||
mnesia:dirty_write(RItem).
|
||||
|
||||
import(_LServer, <<"rosterusers">>, #roster{} = R) ->
|
||||
mnesia:dirty_write(R);
|
||||
import(_LServer, #roster_version{} = RV) ->
|
||||
import(LServer, <<"roster_version">>, [LUser, Ver]) ->
|
||||
RV = #roster_version{us = {LUser, LServer}, version = Ver},
|
||||
mnesia:dirty_write(RV).
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -13,10 +13,10 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, read_roster_version/2, write_roster_version/4,
|
||||
get_roster/2, get_roster_by_jid/3,
|
||||
get_roster/2, get_roster_by_jid/3, create_roster/1,
|
||||
roster_subscribe/4, get_roster_by_jid_with_groups/3,
|
||||
remove_user/2, update_roster/4, del_roster/3, transaction/2,
|
||||
read_subscription_and_groups/3, get_only_items/2, import/2]).
|
||||
read_subscription_and_groups/3, get_only_items/2, import/3]).
|
||||
|
||||
-include("mod_roster.hrl").
|
||||
|
||||
@ -96,10 +96,17 @@ read_subscription_and_groups(LUser, LServer, LJID) ->
|
||||
error
|
||||
end.
|
||||
|
||||
import(_LServer, #roster{us = {LUser, LServer}} = R) ->
|
||||
ejabberd_riak:put(R, roster_schema(),
|
||||
create_roster(#roster{us = {LUser, LServer}} = RItem) ->
|
||||
ejabberd_riak:put(
|
||||
RItem, roster_schema(),
|
||||
[{'2i', [{<<"us">>, {LUser, LServer}}]}]).
|
||||
|
||||
import(_LServer, <<"rosterusers">>, RosterItem) ->
|
||||
{LUser, LServer} = RosterItem#roster.us,
|
||||
ejabberd_riak:put(RosterItem, roster_schema(),
|
||||
[{'2i', [{<<"us">>, {LUser, LServer}}]}]);
|
||||
import(_LServer, #roster_version{} = RV) ->
|
||||
import(LServer, <<"roster_version">>, [LUser, Ver]) ->
|
||||
RV = #roster_version{us = {LUser, LServer}, version = Ver},
|
||||
ejabberd_riak:put(RV, roster_version_schema()).
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -18,7 +18,7 @@
|
||||
roster_subscribe/4, get_roster_by_jid_with_groups/3,
|
||||
remove_user/2, update_roster/4, del_roster/3, transaction/2,
|
||||
read_subscription_and_groups/3, get_only_items/2,
|
||||
import/1, import/2, export/1]).
|
||||
import/3, export/1, raw_to_record/2]).
|
||||
|
||||
-include("mod_roster.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
@ -185,27 +185,8 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select username, jid, nick, subscription, "
|
||||
"ask, askmessage, server, subscribe, type from rosterusers;">>,
|
||||
fun([LUser, JID|_] = Row) ->
|
||||
Item = raw_to_record(LServer, Row),
|
||||
Username = ejabberd_sql:escape(LUser),
|
||||
SJID = ejabberd_sql:escape(JID),
|
||||
{selected, _, Rows} =
|
||||
ejabberd_sql:sql_query_t(
|
||||
[<<"select grp from rostergroups where username='">>,
|
||||
Username, <<"' and jid='">>, SJID, <<"'">>]),
|
||||
Groups = [Grp || [Grp] <- Rows],
|
||||
Item#roster{groups = Groups}
|
||||
end},
|
||||
{<<"select username, version from roster_version;">>,
|
||||
fun([LUser, Ver]) ->
|
||||
#roster_version{us = {LUser, LServer}, version = Ver}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_, _, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -30,9 +30,9 @@
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/2, stop/1, export/1,
|
||||
import/1, webadmin_menu/3, webadmin_page/3,
|
||||
import_info/0, webadmin_menu/3, webadmin_page/3,
|
||||
get_user_roster/2, get_subscription_lists/3,
|
||||
get_jid_info/4, import/3, process_item/2,
|
||||
get_jid_info/4, import/5, process_item/2, import_start/2,
|
||||
in_subscription/6, out_subscription/4, user_available/1,
|
||||
unset_presence/4, register_user/2, remove_user/2,
|
||||
list_groups/1, create_group/2, create_group/3,
|
||||
@ -56,7 +56,7 @@
|
||||
|
||||
-type group_options() :: [{atom(), any()}].
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback import(binary(), #sr_user{} | #sr_group{}) -> ok | pass.
|
||||
-callback import(binary(), binary(), [binary()]) -> ok.
|
||||
-callback list_groups(binary()) -> [binary()].
|
||||
-callback groups_with_opts(binary()) -> [{binary(), group_options()}].
|
||||
-callback create_group(binary(), binary(), group_options()) -> {atomic, any()}.
|
||||
@ -1072,13 +1072,16 @@ export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
import_info() ->
|
||||
[{<<"sr_group">>, 3}, {<<"sr_user">>, 3}].
|
||||
|
||||
import(LServer, DBType, Data) ->
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Data).
|
||||
Mod:init(LServer, []).
|
||||
|
||||
import(LServer, {sql, _}, DBType, Tab, L) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Tab, L).
|
||||
|
||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||
mod_opt_type(_) -> [db_type].
|
||||
|
@ -15,11 +15,12 @@
|
||||
delete_group/2, get_group_opts/2, set_group_opts/3,
|
||||
get_user_groups/2, get_group_explicit_users/2,
|
||||
get_user_displayed_groups/3, is_user_in_group/3,
|
||||
add_user_to_group/3, remove_user_from_group/3, import/2]).
|
||||
add_user_to_group/3, remove_user_from_group/3, import/3]).
|
||||
|
||||
-include("mod_roster.hrl").
|
||||
-include("mod_shared_roster.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
@ -118,10 +119,14 @@ remove_user_from_group(Host, US, Group) ->
|
||||
F = fun () -> mnesia:delete_object(R) end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #sr_group{} = G) ->
|
||||
import(LServer, <<"sr_group">>, [Group, SOpts, _TimeStamp]) ->
|
||||
G = #sr_group{group_host = {Group, LServer},
|
||||
opts = ejabberd_sql:decode_term(SOpts)},
|
||||
mnesia:dirty_write(G);
|
||||
import(_LServer, #sr_user{} = U) ->
|
||||
mnesia:dirty_write(U).
|
||||
import(LServer, <<"sr_user">>, [SJID, Group, _TimeStamp]) ->
|
||||
#jid{luser = U, lserver = S} = jid:from_string(SJID),
|
||||
User = #sr_user{us = {U, S}, group_host = {Group, LServer}},
|
||||
mnesia:dirty_write(User).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -15,10 +15,11 @@
|
||||
delete_group/2, get_group_opts/2, set_group_opts/3,
|
||||
get_user_groups/2, get_group_explicit_users/2,
|
||||
get_user_displayed_groups/3, is_user_in_group/3,
|
||||
add_user_to_group/3, remove_user_from_group/3, import/2]).
|
||||
add_user_to_group/3, remove_user_from_group/3, import/3]).
|
||||
|
||||
-include("mod_roster.hrl").
|
||||
-include("mod_shared_roster.hrl").
|
||||
-include("xmpp.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
@ -120,13 +121,17 @@ add_user_to_group(Host, US, Group) ->
|
||||
remove_user_from_group(Host, US, Group) ->
|
||||
{atomic, ejabberd_riak:delete(sr_group, {US, {Group, Host}})}.
|
||||
|
||||
import(_LServer, #sr_group{group_host = {_, Host}} = G) ->
|
||||
ejabberd_riak:put(G, sr_group_schema(), [{'2i', [{<<"host">>, Host}]}]);
|
||||
import(_LServer, #sr_user{us = US, group_host = {Group, Host}} = User) ->
|
||||
import(LServer, <<"sr_group">>, [Group, SOpts, _TimeStamp]) ->
|
||||
G = #sr_group{group_host = {Group, LServer},
|
||||
opts = ejabberd_sql:decode_term(SOpts)},
|
||||
ejabberd_riak:put(G, sr_group_schema(), [{'2i', [{<<"host">>, LServer}]}]);
|
||||
import(LServer, <<"sr_user">>, [SJID, Group|_]) ->
|
||||
#jid{luser = U, lserver = S} = jid:from_string(SJID),
|
||||
User = #sr_user{us = {U, S}, group_host = {Group, LServer}},
|
||||
ejabberd_riak:put(User, sr_user_schema(),
|
||||
[{i, {US, {Group, Host}}},
|
||||
{'2i', [{<<"us">>, US},
|
||||
{<<"group_host">>, {Group, Host}}]}]).
|
||||
[{i, {{U, S}, {Group, LServer}}},
|
||||
{'2i', [{<<"us">>, {U, S}},
|
||||
{<<"group_host">>, {Group, LServer}}]}]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -17,8 +17,8 @@
|
||||
delete_group/2, get_group_opts/2, set_group_opts/3,
|
||||
get_user_groups/2, get_group_explicit_users/2,
|
||||
get_user_displayed_groups/3, is_user_in_group/3,
|
||||
add_user_to_group/3, remove_user_from_group/3, import/1,
|
||||
import/2, export/1]).
|
||||
add_user_to_group/3, remove_user_from_group/3, import/3,
|
||||
export/1]).
|
||||
|
||||
-include("jid.hrl").
|
||||
-include("mod_roster.hrl").
|
||||
@ -177,20 +177,8 @@ export(_Server) ->
|
||||
[]
|
||||
end}].
|
||||
|
||||
import(LServer) ->
|
||||
[{<<"select name, opts from sr_group;">>,
|
||||
fun([Group, SOpts]) ->
|
||||
#sr_group{group_host = {Group, LServer},
|
||||
opts = ejabberd_sql:decode_term(SOpts)}
|
||||
end},
|
||||
{<<"select jid, grp from sr_user;">>,
|
||||
fun([SJID, Group]) ->
|
||||
#jid{luser = U, lserver = S} = jid:from_string(SJID),
|
||||
#sr_user{us = {U, S}, group_host = {Group, LServer}}
|
||||
end}].
|
||||
|
||||
import(_, _) ->
|
||||
pass.
|
||||
import(_, _, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -34,8 +34,8 @@
|
||||
|
||||
-export([start/2, init/3, stop/1, get_sm_features/5,
|
||||
process_local_iq/1, process_sm_iq/1, string2lower/1,
|
||||
remove_user/2, export/1, import/1, import/3, depends/2,
|
||||
process_search/1, process_vcard/1, get_vcard/2,
|
||||
remove_user/2, export/1, import_info/0, import/5, import_start/2,
|
||||
depends/2, process_search/1, process_vcard/1, get_vcard/2,
|
||||
disco_items/5, disco_features/5, disco_identity/5,
|
||||
decode_iq_subel/1, mod_opt_type/1, set_vcard/3, make_vcard_search/4]).
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
|
||||
-callback init(binary(), gen_mod:opts()) -> any().
|
||||
-callback stop(binary()) -> any().
|
||||
-callback import(binary(), #vcard{} | #vcard_search{}) -> ok | pass.
|
||||
-callback import(binary(), binary(), [binary()]) -> ok.
|
||||
-callback get_vcard(binary(), binary()) -> [xmlel()] | error.
|
||||
-callback set_vcard(binary(), binary(),
|
||||
xmlel(), #vcard_search{}) -> {atomic, any()}.
|
||||
@ -59,6 +59,7 @@
|
||||
-callback search(binary(), [{binary(), [binary()]}], boolean(),
|
||||
infinity | pos_integer()) -> [{binary(), binary()}].
|
||||
-callback remove_user(binary(), binary()) -> {atomic, any()}.
|
||||
-callback is_search_supported(binary()) -> boolean().
|
||||
|
||||
start(Host, Opts) ->
|
||||
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
||||
@ -105,6 +106,15 @@ init(Host, ServerHost, Search) ->
|
||||
false -> loop(Host, ServerHost);
|
||||
_ ->
|
||||
ejabberd_router:register_route(Host, ServerHost),
|
||||
Mod = gen_mod:db_mod(ServerHost, ?MODULE),
|
||||
case Mod:is_search_supported(ServerHost) of
|
||||
false ->
|
||||
?WARNING_MSG("vcard search functionality is "
|
||||
"not implemented for ~s backend",
|
||||
[gen_mod:db_type(ServerHost, ?MODULE)]);
|
||||
true ->
|
||||
ejabberd_router:register_route(Host, ServerHost)
|
||||
end,
|
||||
loop(Host, ServerHost)
|
||||
end.
|
||||
|
||||
@ -438,18 +448,21 @@ remove_user(User, Server) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:remove_user(LUser, LServer).
|
||||
|
||||
import_info() ->
|
||||
[{<<"vcard">>, 3}, {<<"vcard_search">>, 24}].
|
||||
|
||||
import_start(LServer, DBType) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:init(LServer, []).
|
||||
|
||||
import(LServer, {sql, _}, DBType, Tab, L) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, Tab, L).
|
||||
|
||||
export(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:export(LServer).
|
||||
|
||||
import(LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Mod:import(LServer).
|
||||
|
||||
import(LServer, DBType, VCard) ->
|
||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||
Mod:import(LServer, VCard).
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[].
|
||||
|
||||
|
@ -8,14 +8,17 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(mod_vcard_ldap).
|
||||
|
||||
-behaviour(ejabberd_config).
|
||||
|
||||
-behaviour(gen_server).
|
||||
-behaviour(mod_vcard).
|
||||
|
||||
%% API
|
||||
-export([start_link/2]).
|
||||
-export([init/2, stop/1, get_vcard/2, set_vcard/4, search/4,
|
||||
remove_user/2, import/2, search_fields/1, search_reported/1,
|
||||
remove_user/2, import/3, search_fields/1, search_reported/1,
|
||||
mod_opt_type/1, opt_type/1]).
|
||||
-export([is_search_supported/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
@ -70,6 +73,9 @@ stop(Host) ->
|
||||
supervisor:terminate_child(ejabberd_sup, Proc),
|
||||
supervisor:delete_child(ejabberd_sup, Proc).
|
||||
|
||||
is_search_supported(_LServer) ->
|
||||
true.
|
||||
|
||||
get_vcard(LUser, LServer) ->
|
||||
{ok, State} = eldap_utils:get_state(LServer, ?PROCNAME),
|
||||
VCardMap = State#state.vcard_map,
|
||||
@ -157,7 +163,7 @@ search_items(Entries, State) ->
|
||||
remove_user(_User, _Server) ->
|
||||
{atomic, not_implemented}.
|
||||
|
||||
import(_, _) ->
|
||||
import(_, _, _) ->
|
||||
pass.
|
||||
|
||||
%%%===================================================================
|
||||
|
@ -11,8 +11,9 @@
|
||||
-behaviour(mod_vcard).
|
||||
|
||||
%% API
|
||||
-export([init/2, stop/1, import/2, get_vcard/2, set_vcard/4, search/4,
|
||||
-export([init/2, stop/1, import/3, get_vcard/2, set_vcard/4, search/4,
|
||||
search_fields/1, search_reported/1, remove_user/2]).
|
||||
-export([is_search_supported/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("xmpp.hrl").
|
||||
@ -47,6 +48,9 @@ init(_Host, _Opts) ->
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
is_search_supported(_ServerHost) ->
|
||||
true.
|
||||
|
||||
get_vcard(LUser, LServer) ->
|
||||
US = {LUser, LServer},
|
||||
F = fun () -> mnesia:read({vcard, US}) end,
|
||||
@ -121,10 +125,29 @@ remove_user(LUser, LServer) ->
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
import(_LServer, #vcard{} = VCard) ->
|
||||
import(LServer, <<"vcard">>, [LUser, XML, _TimeStamp]) ->
|
||||
#xmlel{} = El = fxml_stream:parse_element(XML),
|
||||
VCard = #vcard{us = {LUser, LServer}, vcard = El},
|
||||
mnesia:dirty_write(VCard);
|
||||
import(_LServer, #vcard_search{} = S) ->
|
||||
mnesia:dirty_write(S).
|
||||
import(LServer, <<"vcard_search">>,
|
||||
[User, LUser, FN, LFN,
|
||||
Family, LFamily, Given, LGiven,
|
||||
Middle, LMiddle, Nickname, LNickname,
|
||||
BDay, LBDay, CTRY, LCTRY, Locality, LLocality,
|
||||
EMail, LEMail, OrgName, LOrgName, OrgUnit, LOrgUnit]) ->
|
||||
mnesia:dirty_write(
|
||||
#vcard_search{us = {LUser, LServer},
|
||||
user = {User, LServer}, luser = LUser,
|
||||
fn = FN, lfn = LFN, family = Family,
|
||||
lfamily = LFamily, given = Given,
|
||||
lgiven = LGiven, middle = Middle,
|
||||
lmiddle = LMiddle, nickname = Nickname,
|
||||
lnickname = LNickname, bday = BDay,
|
||||
lbday = LBDay, ctry = CTRY, lctry = LCTRY,
|
||||
locality = Locality, llocality = LLocality,
|
||||
email = EMail, lemail = LEMail,
|
||||
orgname = OrgName, lorgname = LOrgName,
|
||||
orgunit = OrgUnit, lorgunit = LOrgUnit}).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
@ -12,7 +12,8 @@
|
||||
|
||||
%% API
|
||||
-export([init/2, get_vcard/2, set_vcard/4, search/4, remove_user/2,
|
||||
search_fields/1, search_reported/1, import/2, stop/1]).
|
||||
search_fields/1, search_reported/1, import/3, stop/1]).
|
||||
-export([is_search_supported/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_vcard.hrl").
|
||||
@ -26,6 +27,9 @@ init(_Host, _Opts) ->
|
||||
stop(_Host) ->
|
||||
ok.
|
||||
|
||||
is_search_supported(_LServer) ->
|
||||
false.
|
||||
|
||||
get_vcard(LUser, LServer) ->
|
||||
case ejabberd_riak:get(vcard, vcard_schema(), {LUser, LServer}) of
|
||||
{ok, R} ->
|
||||
@ -101,7 +105,9 @@ search_reported(_LServer) ->
|
||||
remove_user(LUser, LServer) ->
|
||||
{atomic, ejabberd_riak:delete(vcard, {LUser, LServer})}.
|
||||
|
||||
import(_LServer, #vcard{us = {LUser, LServer}, vcard = El} = VCard) ->
|
||||
import(LServer, <<"vcard">>, [LUser, XML, _TimeStamp]) ->
|
||||
El = fxml_stream:parse_element(XML),
|
||||
VCard = #vcard{us = {LUser, LServer}, vcard = El},
|
||||
#vcard_search{fn = FN,
|
||||
lfn = LFN,
|
||||
family = Family,
|
||||
@ -150,7 +156,7 @@ import(_LServer, #vcard{us = {LUser, LServer}, vcard = El} = VCard) ->
|
||||
{<<"lorgname">>, LOrgName},
|
||||
{<<"orgunit">>, OrgUnit},
|
||||
{<<"lorgunit">>, LOrgUnit}]}]);
|
||||
import(_LServer, #vcard_search{}) ->
|
||||
import(_LServer, <<"vcard_search">>, _) ->
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user