aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mix.exs2
-rw-r--r--mix.lock23
-rw-r--r--rebar.config18
-rw-r--r--src/ejabberd_admin.erl1
-rw-r--r--src/ejabberd_c2s.erl19
-rw-r--r--src/ejabberd_commands.erl7
-rw-r--r--src/ejabberd_oauth.erl4
-rw-r--r--src/mod_announce.erl12
-rw-r--r--src/mod_client_state.erl51
-rw-r--r--src/mod_mam.erl102
-rw-r--r--src/mod_muc_admin.erl72
-rw-r--r--src/mod_muc_room.erl74
-rw-r--r--src/mod_offline.erl55
13 files changed, 283 insertions, 157 deletions
diff --git a/mix.exs b/mix.exs
index 7453ea473..2c83a319b 100644
--- a/mix.exs
+++ b/mix.exs
@@ -63,7 +63,7 @@ defmodule Ejabberd.Mixfile do
# version 3.20:
{:relx, "~> 3.19.0", only: :dev},
{:meck, "~> 0.8.4", only: :test},
- {:moka, github: "processone/moka", tag: "1.0.5b", only: :test}]
+ {:moka, github: "processone/moka", tag: "1.0.5c", only: :test}]
end
defp package do
diff --git a/mix.lock b/mix.lock
index 467f142ba..17be772ea 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,29 +1,30 @@
%{"bbmustache": {:hex, :bbmustache, "1.0.4", "7ba94f971c5afd7b6617918a4bb74705e36cab36eb84b19b6a1b7ee06427aa38", [:rebar], []},
- "cache_tab": {:hex, :cache_tab, "1.0.3", "0e3c40dde2fe2a6a4db241d7583cea0cc1bcf29e546a0a22f15b75366b2f336e", [:rebar3], [{:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}]},
+ "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], []},
"eredis": {:hex, :eredis, "1.0.8", "ab4fda1c4ba7fbe6c19c26c249dc13da916d762502c4b4fa2df401a8d51c5364", [:rebar], []},
"erlware_commons": {:hex, :erlware_commons, "0.19.0", "7b43caf2c91950c5f60dc20451e3c3afba44d3d4f7f27bcdc52469285a5a3e70", [:rebar3], [{:cf, "0.2.1", [hex: :cf, optional: false]}]},
- "esip": {:hex, :esip, "1.0.7", "f75f6a5cac6814e506f0ff96141fbe276dee3261fca1471c8edfdde25b74f877", [:rebar3], [{:fast_tls, "1.0.6", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}, {:stun, "1.0.6", [hex: :stun, 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]}]},
"exrm": {:hex, :exrm, "1.0.8", "5aa8990cdfe300282828b02cefdc339e235f7916388ce99f9a1f926a9271a45d", [:mix], [{:relx, "~> 3.5", [hex: :relx, optional: false]}]},
"ezlib": {:hex, :ezlib, "1.0.1", "add8b2770a1a70c174aaea082b4a8668c0c7fdb03ee6cc81c6c68d3a6c3d767d", [:rebar3], []},
- "fast_tls": {:hex, :fast_tls, "1.0.6", "750a74aabb05056f0f222910f0955883649e6c5d67df6ca504ff676160d22b89", [:rebar3], [{:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}]},
- "fast_xml": {:hex, :fast_xml, "1.1.14", "23d4de66e645bca1d8a557444e83062cc42f235d7a7e2d4072d525bac3986f04", [:rebar3], [{:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}]},
- "fast_yaml": {:hex, :fast_yaml, "1.0.5", "a67772c75abb84181c6c9899e1f988b08ac214ea0d764ff1f9889bb7e27f74d4", [:rebar3], [{:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}]},
+ "fast_tls": {:hex, :fast_tls, "1.0.7", "9b72ecfcdcad195ab072c196fab8334f49d8fea76bf1a51f536d69e7527d902a", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
+ "fast_xml": {:hex, :fast_xml, "1.1.15", "6d23eb7f874e1357cf80a48d75a7bd0c8f6318029dc4b70122e9f54911f57f83", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
+ "fast_yaml": {:hex, :fast_yaml, "1.0.6", "3fe6feb7935ae8028b337e53e1db29e73ad3bca8041108f6a8f73b7175ece75c", [:rebar3], [{:p1_utils, "1.0.5", [hex: :p1_utils, optional: false]}]},
"getopt": {:hex, :getopt, "0.8.2", "b17556db683000ba50370b16c0619df1337e7af7ecbf7d64fbf8d1d6bce3109b", [:rebar], []},
"goldrush": {:hex, :goldrush, "0.1.7", "349a351d17c71c2fdaa18a6c2697562abe136fec945f147b381f0cf313160228", [:rebar3], []},
- "iconv": {:hex, :iconv, "1.0.1", "dbb8700070577e7a021a095cc5ead221069a0c4034bfadca2516c1f1109ee7fd", [:rebar3], [{:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}]},
+ "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], []},
"lager": {:hex, :lager, "3.0.2", "25dc81bc3659b62f5ab9bd073e97ddd894fc4c242019fccef96f3889d7366c97", [:rebar3], [{:goldrush, "0.1.7", [hex: :goldrush, optional: false]}]},
"meck": {:hex, :meck, "0.8.4", "59ca1cd971372aa223138efcf9b29475bde299e1953046a0c727184790ab1520", [:rebar, :make], []},
- "moka": {:git, "https://github.com/processone/moka.git", "768efea96443c57125e6247dbebee687f17be149", [tag: "1.0.5b"]},
+ "moka": {:git, "https://github.com/processone/moka.git", "3eed3a6dd7dedb70a6cd18f86c7561a18626eb3b", [tag: "1.0.5c"]},
"p1_mysql": {:hex, :p1_mysql, "1.0.1", "d2be1cfc71bb4f1391090b62b74c3f5cb8e7a45b0076b8cb290cd6b2856c581b", [:rebar3], []},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.1", "4e021250cc198c538b097393671a41e7cebf463c248980320e038fe0316eb56b", [:rebar3], []},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.0", "ca525c42878eac095e5feb19563acc9915c845648f48fdec7ba6266c625d4ac7", [:rebar3], []},
- "p1_utils": {:hex, :p1_utils, "1.0.4", "7face65db102b5d1ebe7ad3c7517c5ee8cfbe174c6658e3affbb00eb66e06787", [:rebar3], []},
+ "p1_utils": {:hex, :p1_utils, "1.0.5", "3e698354fdc1fea5491d991457b0cb986c0a00a47d224feb841dc3ec82b9f721", [:rebar3], []},
"p1_xmlrpc": {:hex, :p1_xmlrpc, "1.15.1", "a382b62dc21bb372281c2488f99294d84f2b4020ed0908a1c4ad710ace3cf35a", [:rebar3], []},
+ "pc": {:hex, :pc, "1.2.0", "5e07731d1f8bf997a8d0271510983e570f910b42cd59bf612e664ad6dc35742e", [:rebar3], []},
"providers": {:hex, :providers, "1.6.0", "db0e2f9043ae60c0155205fcd238d68516331d0e5146155e33d1e79dc452964a", [:rebar3], [{:getopt, "0.8.2", [hex: :getopt, optional: false]}]},
"relx": {:hex, :relx, "3.19.0", "286dd5244b4786f56aac75d5c8e2d1fb4cfd306810d4ec8548f3ae1b3aadb8f7", [:rebar3], [{:bbmustache, "1.0.4", [hex: :bbmustache, optional: false]}, {:cf, "0.2.1", [hex: :cf, optional: false]}, {:erlware_commons, "0.19.0", [hex: :erlware_commons, optional: false]}, {:getopt, "0.8.2", [hex: :getopt, optional: false]}, {:providers, "1.6.0", [hex: :providers, optional: false]}]},
- "samerlib": {:git, "https://github.com/processone/samerlib", "9158f65d18ec63f8b409543b6fb46dd5fce46160", [tag: "0.8.0b"]},
+ "samerlib": {:git, "https://github.com/processone/samerlib", "fbbba035b1548ac4e681df00d61bf609645333a0", [tag: "0.8.0c"]},
"sqlite3": {:hex, :sqlite3, "1.1.5", "794738b6d07b6d36ec6d42492cb9d629bad9cf3761617b8b8d728e765db19840", [:rebar3], []},
- "stringprep": {:hex, :stringprep, "1.0.5", "f29395275c35af5051b29bf875b44ac632dc4d0287880f0e143b536c61fd0ed5", [:rebar3], [{:p1_utils, "1.0.4", [hex: :p1_utils, optional: false]}]},
- "stun": {:hex, :stun, "1.0.6", "1ca9dea574e09f60971bd8de9cb7e34f327cbf435462cf56aa30f05c1ee2f231", [:rebar3], [{:fast_tls, "1.0.6", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.4", [hex: :p1_utils, 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]}]}}
diff --git a/rebar.config b/rebar.config
index 693f4f58b..ab5562858 100644
--- a/rebar.config
+++ b/rebar.config
@@ -9,13 +9,13 @@
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.5"}}},
- {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.3"}}},
- {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.6"}}},
- {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.5"}}},
- {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.14"}}},
- {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.6"}}},
- {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.7"}}},
- {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.5"}}},
+ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.4"}}},
+ {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.15"}}},
+ {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"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.7"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.1"}}},
{p1_xmlrpc, ".*", {git, "https://github.com/processone/p1_xmlrpc", {tag, "1.15.1"}}},
@@ -44,11 +44,11 @@
{if_var_true, elixir, {rebar_elixir_plugin, ".*",
{git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}},
{if_var_true, iconv, {iconv, ".*", {git, "https://github.com/processone/iconv",
- {tag, "1.0.1"}}}},
+ {tag, "1.0.2"}}}},
{if_var_true, tools, {meck, "0.8.*", {git, "https://github.com/eproxus/meck",
{tag, "0.8.4"}}}},
{if_var_true, tools, {moka, ".*", {git, "https://github.com/processone/moka.git",
- {tag, "1.0.5b"}}}},
+ {tag, "1.0.5c"}}}},
{if_var_true, redis, {eredis, ".*", {git, "https://github.com/wooga/eredis",
{tag, "v1.0.8"}}}}]}.
diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl
index 615459f77..ae2fac3e1 100644
--- a/src/ejabberd_admin.erl
+++ b/src/ejabberd_admin.erl
@@ -131,7 +131,6 @@ get_commands_spec() ->
#ejabberd_commands{name = register, tags = [accounts],
desc = "Register a user",
policy = admin,
- access = [{mod_register, access, configure}],
module = ?MODULE, function = register,
args = [{user, binary}, {host, binary}, {password, binary}],
result = {res, restuple}},
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 74b78512a..270ef1dc5 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -2800,8 +2800,7 @@ handle_resume(StateData, Attrs) ->
#xmlel{name = <<"r">>,
attrs = [{<<"xmlns">>, AttrXmlns}],
children = []}),
- FlushedState = csi_flush_queue(NewState),
- NewStateData = FlushedState#state{csi_state = active},
+ NewStateData = csi_flush_queue(NewState),
?INFO_MSG("Resumed session for ~s",
[jid:to_string(NewStateData#state.jid)]),
{ok, NewStateData};
@@ -3048,13 +3047,13 @@ inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) ->
pres_timestamp = OldStateData#state.pres_timestamp,
privacy_list = OldStateData#state.privacy_list,
aux_fields = OldStateData#state.aux_fields,
- csi_state = OldStateData#state.csi_state,
mgmt_xmlns = OldStateData#state.mgmt_xmlns,
mgmt_queue = OldStateData#state.mgmt_queue,
mgmt_timeout = OldStateData#state.mgmt_timeout,
mgmt_stanzas_in = OldStateData#state.mgmt_stanzas_in,
mgmt_stanzas_out = OldStateData#state.mgmt_stanzas_out,
- mgmt_state = active}};
+ mgmt_state = active,
+ csi_state = active}};
{error, Msg} ->
{error, Msg};
_ ->
@@ -3081,20 +3080,22 @@ add_resent_delay_info(#state{server = From}, El, Time) ->
%%% XEP-0352
%%%----------------------------------------------------------------------
-csi_filter_stanza(#state{csi_state = CsiState, server = Server} = StateData,
- Stanza) ->
+csi_filter_stanza(#state{csi_state = CsiState, jid = JID, server = Server} =
+ StateData, Stanza) ->
{StateData1, Stanzas} = ejabberd_hooks:run_fold(csi_filter_stanza, Server,
{StateData, [Stanza]},
- [Server, Stanza]),
+ [Server, JID, Stanza]),
StateData2 = lists:foldl(fun(CurStanza, AccState) ->
send_stanza(AccState, CurStanza)
end, StateData1#state{csi_state = active},
Stanzas),
StateData2#state{csi_state = CsiState}.
-csi_flush_queue(#state{csi_state = CsiState, server = Server} = StateData) ->
+csi_flush_queue(#state{csi_state = CsiState, jid = JID, server = Server} =
+ StateData) ->
{StateData1, Stanzas} = ejabberd_hooks:run_fold(csi_flush_queue, Server,
- {StateData, []}, [Server]),
+ {StateData, []},
+ [Server, JID]),
StateData2 = lists:foldl(fun(CurStanza, AccState) ->
send_stanza(AccState, CurStanza)
end, StateData1#state{csi_state = active},
diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl
index a8b3e25ab..d5649b2d7 100644
--- a/src/ejabberd_commands.erl
+++ b/src/ejabberd_commands.erl
@@ -274,7 +274,6 @@ get_commands_spec() ->
args_example = ["/home/me/docs/api.html", "mod_admin", "java,json"],
result_example = ok}].
init() ->
- mnesia:delete_table(ejabberd_commands),
mnesia:create_table(ejabberd_commands,
[{ram_copies, [node()]},
{local_content, true},
@@ -538,6 +537,9 @@ execute_check_policy(
_Auth, _JID, #ejabberd_commands{policy = open} = Command, Arguments) ->
do_execute_command(Command, Arguments);
execute_check_policy(
+ noauth, _JID, Command, Arguments) ->
+ do_execute_command(Command, Arguments);
+execute_check_policy(
_Auth, _JID, #ejabberd_commands{policy = restricted} = Command, Arguments) ->
do_execute_command(Command, Arguments);
execute_check_policy(
@@ -547,9 +549,6 @@ execute_check_policy(
admin, JID, #ejabberd_commands{policy = user} = Command, Arguments) ->
execute_check_access(JID, Command, Arguments);
execute_check_policy(
- noauth, _JID, #ejabberd_commands{policy = user} = Command, Arguments) ->
- do_execute_command(Command, Arguments);
-execute_check_policy(
{User, Server, _, _}, JID, #ejabberd_commands{policy = user} = Command, Arguments) ->
execute_check_access(JID, Command, [User, Server | Arguments]).
diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl
index ca0693645..36c679cb6 100644
--- a/src/ejabberd_oauth.erl
+++ b/src/ejabberd_oauth.erl
@@ -102,7 +102,9 @@ get_commands_spec() ->
args = [{jid, string},{ttl, integer}, {scopes, string}],
policy = restricted,
args_example = ["user@server.com", "connected_users_number;muc_online_rooms"],
- args_desc = ["List of scopes to allow, separated by ';'"],
+ args_desc = ["Jid for which issue token",
+ "Time to live of generated token in seconds",
+ "List of scopes to allow, separated by ';'"],
result = {result, {tuple, [{token, string}, {scopes, string}, {expires_in, string}]}}
},
#ejabberd_commands{name = oauth_list_tokens, tags = [oauth],
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 52ff2de92..d74c46bf9 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -696,7 +696,7 @@ announce_all(From, To, Packet) ->
lists:foreach(
fun({User, Server}) ->
Dest = jid:make(User, Server, <<>>),
- ejabberd_router:route(Local, Dest, Packet)
+ ejabberd_router:route(Local, Dest, add_store_hint(Packet))
end, ejabberd_auth:get_vh_registered_users(Host))
end.
@@ -713,7 +713,7 @@ announce_all_hosts_all(From, To, Packet) ->
lists:foreach(
fun({User, Server}) ->
Dest = jid:make(User, Server, <<>>),
- ejabberd_router:route(Local, Dest, Packet)
+ ejabberd_router:route(Local, Dest, add_store_hint(Packet))
end, ejabberd_auth:dirty_get_registered_users())
end.
@@ -899,7 +899,7 @@ send_announcement_to_all(Host, SubjectS, BodyS) ->
lists:foreach(
fun({U, S, R}) ->
Dest = jid:make(U, S, R),
- ejabberd_router:route(Local, Dest, Packet)
+ ejabberd_router:route(Local, Dest, add_store_hint(Packet))
end, Sessions).
-spec get_access(global | binary()) -> atom().
@@ -909,6 +909,12 @@ get_access(Host) ->
fun(A) -> A end,
none).
+-spec add_store_hint(xmlel()) -> xmlel().
+
+add_store_hint(El) ->
+ Hint = #xmlel{name = <<"store">>, attrs = [{<<"xmlns">>, ?NS_HINTS}]},
+ fxml:append_subtags(El, [Hint]).
+
%%-------------------------------------------------------------------------
export(LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
diff --git a/src/mod_client_state.erl b/src/mod_client_state.erl
index 036175cce..9d37d4f5b 100644
--- a/src/mod_client_state.erl
+++ b/src/mod_client_state.erl
@@ -34,8 +34,8 @@
-export([start/2, stop/1, mod_opt_type/1, depends/2]).
%% ejabberd_hooks callbacks.
--export([filter_presence/3, filter_chat_states/3, filter_pep/3, filter_other/3,
- flush_queue/2, add_stream_feature/2]).
+-export([filter_presence/4, filter_chat_states/4, filter_pep/4, filter_other/4,
+ flush_queue/3, add_stream_feature/2]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -151,69 +151,70 @@ depends(_Host, _Opts) ->
%% ejabberd_hooks callbacks.
%%--------------------------------------------------------------------
--spec filter_presence({term(), [xmlel()]}, binary(), xmlel())
+-spec filter_presence({term(), [xmlel()]}, binary(), jid(), xmlel())
-> {term(), [xmlel()]} | {stop, {term(), [xmlel()]}}.
-filter_presence({C2SState, _OutStanzas} = Acc, Host,
+filter_presence({C2SState, _OutStanzas} = Acc, Host, To,
#xmlel{name = <<"presence">>, attrs = Attrs} = Stanza) ->
case fxml:get_attr(<<"type">>, Attrs) of
{value, Type} when Type /= <<"unavailable">> ->
Acc;
_ ->
- ?DEBUG("Got availability presence stanza", []),
+ ?DEBUG("Got availability presence stanza for ~s",
+ [jid:to_string(To)]),
queue_add(presence, Stanza, Host, C2SState)
end;
-filter_presence(Acc, _Host, _Stanza) -> Acc.
+filter_presence(Acc, _Host, _To, _Stanza) -> Acc.
--spec filter_chat_states({term(), [xmlel()]}, binary(), xmlel())
+-spec filter_chat_states({term(), [xmlel()]}, binary(), jid(), xmlel())
-> {term(), [xmlel()]} | {stop, {term(), [xmlel()]}}.
-filter_chat_states({C2SState, _OutStanzas} = Acc, Host,
+filter_chat_states({C2SState, _OutStanzas} = Acc, Host, To,
#xmlel{name = <<"message">>} = Stanza) ->
case jlib:is_standalone_chat_state(Stanza) of
true ->
From = fxml:get_tag_attr_s(<<"from">>, Stanza),
- To = fxml:get_tag_attr_s(<<"to">>, Stanza),
- case {jid:from_string(From), jid:from_string(To)} of
+ case {jid:from_string(From), To} of
{#jid{luser = U, lserver = S}, #jid{luser = U, lserver = S}} ->
%% Don't queue (carbon copies of) chat states from other
%% resources, as they might be used to sync the state of
%% conversations across clients.
Acc;
_ ->
- ?DEBUG("Got standalone chat state notification", []),
+ ?DEBUG("Got standalone chat state notification for ~s",
+ [jid:to_string(To)]),
queue_add(chatstate, Stanza, Host, C2SState)
end;
false ->
Acc
end;
-filter_chat_states(Acc, _Host, _Stanza) -> Acc.
+filter_chat_states(Acc, _Host, _To, _Stanza) -> Acc.
--spec filter_pep({term(), [xmlel()]}, binary(), xmlel())
+-spec filter_pep({term(), [xmlel()]}, binary(), jid(), xmlel())
-> {term(), [xmlel()]} | {stop, {term(), [xmlel()]}}.
-filter_pep({C2SState, _OutStanzas} = Acc, Host,
+filter_pep({C2SState, _OutStanzas} = Acc, Host, To,
#xmlel{name = <<"message">>} = Stanza) ->
case get_pep_node(Stanza) of
{value, Node} ->
- ?DEBUG("Got PEP notification", []),
+ ?DEBUG("Got PEP notification for ~s", [jid:to_string(To)]),
queue_add({pep, Node}, Stanza, Host, C2SState);
false ->
Acc
end;
-filter_pep(Acc, _Host, _Stanza) -> Acc.
+filter_pep(Acc, _Host, _To, _Stanza) -> Acc.
--spec filter_other({term(), [xmlel()]}, binary(), xmlel())
- -> {stop, {term(), [xmlel()]}}.
+-spec filter_other({term(), [xmlel()]}, binary(), jid(), xmlel())
+ -> {term(), [xmlel()]}.
-filter_other({C2SState, _OutStanzas}, Host, Stanza) ->
- ?DEBUG("Won't add stanza to CSI queue", []),
+filter_other({C2SState, _OutStanzas}, Host, To, Stanza) ->
+ ?DEBUG("Won't add stanza for ~s to CSI queue", [jid:to_string(To)]),
queue_take(Stanza, Host, C2SState).
--spec flush_queue({term(), [xmlel()]}, binary()) -> {term(), [xmlel()]}.
+-spec flush_queue({term(), [xmlel()]}, binary(), jid()) -> {term(), [xmlel()]}.
-flush_queue({C2SState, _OutStanzas}, Host) ->
- ?DEBUG("Going to flush CSI queue", []),
+flush_queue({C2SState, _OutStanzas}, Host, JID) ->
+ ?DEBUG("Going to flush CSI queue of ~s", [jid:to_string(JID)]),
Queue = get_queue(C2SState),
NewState = set_queue([], C2SState),
{NewState, get_stanzas(Queue, Host)}.
@@ -249,7 +250,7 @@ queue_add(Type, Stanza, Host, C2SState) ->
{stop, {NewState, []}}
end.
--spec queue_take(xmlel(), binary(), term()) -> {stop, {term(), [xmlel()]}}.
+-spec queue_take(xmlel(), binary(), term()) -> {term(), [xmlel()]}.
queue_take(Stanza, Host, C2SState) ->
From = fxml:get_tag_attr_s(<<"from">>, Stanza),
@@ -259,7 +260,7 @@ queue_take(Stanza, Host, C2SState) ->
U == LUser andalso S == LServer
end, get_queue(C2SState)),
NewState = set_queue(Rest, C2SState),
- {stop, {NewState, get_stanzas(Selected, Host) ++ [Stanza]}}.
+ {NewState, get_stanzas(Selected, Host) ++ [Stanza]}.
-spec set_queue(csi_queue(), term()) -> term().
diff --git a/src/mod_mam.erl b/src/mod_mam.erl
index 7e1460695..6ea757223 100644
--- a/src/mod_mam.erl
+++ b/src/mod_mam.erl
@@ -111,15 +111,12 @@ start(Host, Opts) ->
ejabberd_hooks:add(anonymous_purge_hook, Host, ?MODULE,
remove_user, 50),
case gen_mod:get_opt(assume_mam_usage, Opts,
- fun(if_enabled) -> if_enabled;
- (on_request) -> on_request;
- (never) -> never
- end, never) of
- never ->
- ok;
- _ ->
+ fun(B) when is_boolean(B) -> B end, false) of
+ true ->
ejabberd_hooks:add(message_is_archived, Host, ?MODULE,
- message_is_archived, 50)
+ message_is_archived, 50);
+ false ->
+ ok
end,
ejabberd_commands:register_commands(get_commands_spec()),
ok.
@@ -164,15 +161,12 @@ stop(Host) ->
ejabberd_hooks:delete(anonymous_purge_hook, Host,
?MODULE, remove_user, 50),
case gen_mod:get_module_opt(Host, ?MODULE, assume_mam_usage,
- fun(if_enabled) -> if_enabled;
- (on_request) -> on_request;
- (never) -> never
- end, never) of
- never ->
- ok;
- _ ->
+ fun(B) when is_boolean(B) -> B end, false) of
+ true ->
ejabberd_hooks:delete(message_is_archived, Host, ?MODULE,
- message_is_archived, 50)
+ message_is_archived, 50);
+ false ->
+ ok
end,
ejabberd_commands:unregister_commands(get_commands_spec()),
ok.
@@ -381,32 +375,13 @@ message_is_archived(true, _C2SState, _Peer, _JID, _Pkt) ->
true;
message_is_archived(false, C2SState, Peer,
#jid{luser = LUser, lserver = LServer}, Pkt) ->
- Res = case gen_mod:get_module_opt(LServer, ?MODULE, assume_mam_usage,
- fun(if_enabled) -> if_enabled;
- (on_request) -> on_request;
- (never) -> never
- end, never) of
- if_enabled ->
- case get_prefs(LUser, LServer) of
- #archive_prefs{} = P ->
- {ok, P};
- error ->
- error
- end;
- on_request ->
- Mod = gen_mod:db_mod(LServer, ?MODULE),
- cache_tab:lookup(archive_prefs, {LUser, LServer},
- fun() ->
- Mod:get_prefs(LUser, LServer)
- end);
- never ->
- error
- end,
- case Res of
- {ok, Prefs} ->
+ case gen_mod:get_module_opt(LServer, ?MODULE, assume_mam_usage,
+ fun(B) when is_boolean(B) -> B end, false) of
+ true ->
should_archive(strip_my_archived_tag(Pkt, LServer), LServer)
- andalso should_archive_peer(C2SState, Prefs, Peer);
- error ->
+ andalso should_archive_peer(C2SState, get_prefs(LUser, LServer),
+ Peer);
+ false ->
false
end.
@@ -580,29 +555,29 @@ parse_query_v0_2(Query) ->
end, Query#xmlel.children).
should_archive(#xmlel{name = <<"message">>} = Pkt, LServer) ->
- case fxml:get_attr_s(<<"type">>, Pkt#xmlel.attrs) of
- <<"error">> ->
- false;
- <<"groupchat">> ->
+ case is_resent(Pkt, LServer) of
+ true ->
false;
- _ ->
- case is_resent(Pkt, LServer) of
- true ->
+ false ->
+ case {check_store_hint(Pkt),
+ fxml:get_attr_s(<<"type">>, Pkt#xmlel.attrs)} of
+ {_Hint, <<"error">>} ->
false;
- false ->
- case check_store_hint(Pkt) of
- store ->
- true;
- no_store ->
+ {store, _Type} ->
+ true;
+ {no_store, _Type} ->
+ false;
+ {none, <<"groupchat">>} ->
+ false;
+ {none, <<"headline">>} ->
+ false;
+ {none, _Type} ->
+ case fxml:get_subtag_cdata(Pkt, <<"body">>) of
+ <<>> ->
+ %% Empty body
false;
- none ->
- case fxml:get_subtag_cdata(Pkt, <<"body">>) of
- <<>> ->
- %% Empty body
- false;
- _ ->
- true
- end
+ _ ->
+ true
end
end
end;
@@ -1088,10 +1063,7 @@ get_commands_spec() ->
result = {res, rescode}}].
mod_opt_type(assume_mam_usage) ->
- fun(if_enabled) -> if_enabled;
- (on_request) -> on_request;
- (never) -> never
- end;
+ fun (B) when is_boolean(B) -> B end;
mod_opt_type(cache_life_time) ->
fun (I) when is_integer(I), I > 0 -> I end;
mod_opt_type(cache_size) ->
diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl
index 0b5e79f60..e1d48cdab 100644
--- a/src/mod_muc_admin.erl
+++ b/src/mod_muc_admin.erl
@@ -20,6 +20,7 @@
change_room_option/4, get_room_options/2,
set_room_affiliation/4, get_room_affiliations/2,
web_menu_main/2, web_page_main/2, web_menu_host/3,
+ subscribe_room/4, unsubscribe_room/2,
web_page_host/3, mod_opt_type/1, get_commands_spec/0]).
-include("ejabberd.hrl").
@@ -151,7 +152,17 @@ get_commands_spec() ->
{value, string}
]}}
}}},
-
+ #ejabberd_commands{name = subscribe_room, tags = [muc_room],
+ desc = "Subscribe to a MUC conference",
+ module = ?MODULE, function = subscribe_room,
+ args = [{user, binary}, {nick, binary}, {room, binary},
+ {nodes, binary}],
+ result = {nodes, {list, {node, string}}}},
+ #ejabberd_commands{name = unsubscribe_room, tags = [muc_room],
+ desc = "Unsubscribe from a MUC conference",
+ module = ?MODULE, function = unsubscribe_room,
+ args = [{user, binary}, {room, binary}],
+ result = {res, rescode}},
#ejabberd_commands{name = set_room_affiliation, tags = [muc_room],
desc = "Change an affiliation in a MUC room",
module = ?MODULE, function = set_room_affiliation,
@@ -884,6 +895,65 @@ set_room_affiliation(Name, Service, JID, AffiliationString) ->
error
end.
+%%%
+%%% MUC Subscription
+%%%
+
+subscribe_room(_User, Nick, _Room, _Nodes) when Nick == <<"">> ->
+ throw({error, "Nickname must be set"});
+subscribe_room(User, Nick, Room, Nodes) ->
+ NodeList = re:split(Nodes, "\\h*,\\h*"),
+ case jid:from_string(Room) of
+ #jid{luser = Name, lserver = Host} when Name /= <<"">> ->
+ case jid:from_string(User) of
+ error ->
+ throw({error, "Malformed user JID"});
+ #jid{lresource = <<"">>} ->
+ throw({error, "User's JID should have a resource"});
+ UserJID ->
+ case get_room_pid(Name, Host) of
+ Pid when is_pid(Pid) ->
+ case gen_fsm:sync_send_all_state_event(
+ Pid,
+ {muc_subscribe, UserJID, Nick, NodeList}) of
+ {ok, SubscribedNodes} ->
+ SubscribedNodes;
+ {error, Reason} ->
+ throw({error, binary_to_list(Reason)})
+ end;
+ _ ->
+ throw({error, "The room does not exist"})
+ end
+ end;
+ _ ->
+ throw({error, "Malformed room JID"})
+ end.
+
+unsubscribe_room(User, Room) ->
+ case jid:from_string(Room) of
+ #jid{luser = Name, lserver = Host} when Name /= <<"">> ->
+ case jid:from_string(User) of
+ error ->
+ throw({error, "Malformed user JID"});
+ UserJID ->
+ case get_room_pid(Name, Host) of
+ Pid when is_pid(Pid) ->
+ case gen_fsm:sync_send_all_state_event(
+ Pid,
+ {muc_unsubscribe, UserJID}) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ throw({error, binary_to_list(Reason)})
+ end;
+ _ ->
+ throw({error, "The room does not exist"})
+ end
+ end;
+ _ ->
+ throw({error, "Malformed room JID"})
+ end.
+
make_opts(StateData) ->
Config = StateData#state.config,
[
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index 773953c4a..e5ed4cc68 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -749,6 +749,60 @@ handle_sync_event({change_state, NewStateData}, _From,
handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData) ->
NSD = process_item_change(Item, StateData, UJID),
{reply, {ok, NSD}, StateName, NSD};
+handle_sync_event({muc_subscribe, From, Nick, Nodes}, _From,
+ StateName, StateData) ->
+ SubEl = #xmlel{name = <<"subscribe">>,
+ attrs = [{<<"xmlns">>, ?NS_MUCSUB}, {<<"nick">>, Nick}],
+ children = [#xmlel{name = <<"event">>,
+ attrs = [{<<"node">>, Node}]}
+ || Node <- Nodes]},
+ IQ = #iq{type = set, id = randoms:get_string(),
+ xmlns = ?NS_MUCSUB, sub_el = SubEl},
+ Packet = jlib:iq_to_xml(IQ#iq{sub_el = [SubEl]}),
+ Config = StateData#state.config,
+ CaptchaRequired = Config#config.captcha_protected,
+ PasswordProtected = Config#config.password_protected,
+ TmpConfig = Config#config{captcha_protected = false,
+ password_protected = false},
+ TmpState = StateData#state{config = TmpConfig},
+ case process_iq_mucsub(From, Packet, IQ, TmpState) of
+ {result, _, NewState} ->
+ NewConfig = (NewState#state.config)#config{
+ captcha_protected = CaptchaRequired,
+ password_protected = PasswordProtected},
+ {reply, {ok, get_subscription_nodes(Packet)}, StateName,
+ NewState#state{config = NewConfig}};
+ {ignore, NewState} ->
+ NewConfig = (NewState#state.config)#config{
+ captcha_protected = CaptchaRequired,
+ password_protected = PasswordProtected},
+ {reply, {error, <<"Requrest is ignored">>},
+ NewState#state{config = NewConfig}};
+ {error, Err, NewState} ->
+ NewConfig = (NewState#state.config)#config{
+ captcha_protected = CaptchaRequired,
+ password_protected = PasswordProtected},
+ {reply, {error, get_error_text(Err)}, StateName,
+ NewState#state{config = NewConfig}};
+ {error, Err} ->
+ {reply, {error, get_error_text(Err)}, StateName, StateData}
+ end;
+handle_sync_event({muc_unsubscribe, From}, _From, StateName, StateData) ->
+ SubEl = #xmlel{name = <<"unsubscribe">>,
+ attrs = [{<<"xmlns">>, ?NS_MUCSUB}]},
+ IQ = #iq{type = set, id = randoms:get_string(),
+ xmlns = ?NS_MUCSUB, sub_el = SubEl},
+ Packet = jlib:iq_to_xml(IQ),
+ case process_iq_mucsub(From, Packet, IQ, StateData) of
+ {result, _, NewState} ->
+ {reply, ok, StateName, NewState};
+ {ignore, NewState} ->
+ {reply, {error, <<"Requrest is ignored">>}, NewState};
+ {error, Err, NewState} ->
+ {reply, {error, get_error_text(Err)}, StateName, NewState};
+ {error, Err} ->
+ {reply, {error, get_error_text(Err)}, StateName, StateData}
+ end;
handle_sync_event(_Event, _From, StateName,
StateData) ->
Reply = ok, {reply, Reply, StateName, StateData}.
@@ -1346,6 +1400,14 @@ get_error_condition2(Packet) ->
<- EEls],
{condition, Condition}.
+get_error_text(Error) ->
+ case fxml:get_subtag_with_xmlns(Error, <<"text">>, ?NS_STANZAS) of
+ #xmlel{} = Tag ->
+ fxml:get_tag_cdata(Tag);
+ false ->
+ <<"">>
+ end.
+
make_reason(Packet, From, StateData, Reason1) ->
{ok, #user{nick = FromNick}} = (?DICT):find(jid:tolower(From), StateData#state.users),
Condition = get_error_condition(Packet),
@@ -4608,6 +4670,18 @@ process_iq_mucsub(From, _Packet,
NewStateData = remove_subscription(From, User, StateData),
store_room(NewStateData),
{result, [], NewStateData};
+ error when From#jid.lresource == <<"">> ->
+ {LUser, LServer, _} = LJID,
+ NewStateData =
+ dict:fold(
+ fun({U, S, _}, #user{jid = J, is_subscriber = true} = User,
+ AccState) when U == LUser, S == LServer ->
+ remove_subscription(J, User, AccState);
+ (_, _, AccState) ->
+ AccState
+ end, StateData, StateData#state.users),
+ store_room(NewStateData),
+ {result, [], NewStateData};
_ ->
{result, [], StateData}
end;
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 799605c69..87a136853 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -437,35 +437,36 @@ remove_msg_by_node(To, Seq) ->
end.
need_to_store(LServer, Packet) ->
- Type = fxml:get_tag_attr_s(<<"type">>, Packet),
- if (Type /= <<"error">>) and (Type /= <<"groupchat">>)
- and (Type /= <<"headline">>) ->
- case has_offline_tag(Packet) of
- false ->
- case check_store_hint(Packet) of
- store ->
+ case has_offline_tag(Packet) of
+ false ->
+ case {check_store_hint(Packet),
+ fxml:get_tag_attr_s(<<"type">>, Packet)} of
+ {_Hint, <<"error">>} ->
+ false;
+ {store, _Type} ->
+ true;
+ {no_store, _Type} ->
+ false;
+ {none, <<"groupchat">>} ->
+ false;
+ {none, <<"headline">>} ->
+ false;
+ {none, _Type} ->
+ case gen_mod:get_module_opt(
+ LServer, ?MODULE, store_empty_body,
+ fun(V) when is_boolean(V) -> V;
+ (unless_chat_state) -> unless_chat_state
+ end,
+ unless_chat_state) of
+ true ->
true;
- no_store ->
- false;
- none ->
- case gen_mod:get_module_opt(
- LServer, ?MODULE, store_empty_body,
- fun(V) when is_boolean(V) -> V;
- (unless_chat_state) -> unless_chat_state
- end,
- unless_chat_state) of
- false ->
- fxml:get_subtag(Packet, <<"body">>) /= false;
- unless_chat_state ->
- not jlib:is_standalone_chat_state(Packet);
- true ->
- true
- end
- end;
- true ->
- false
+ false ->
+ fxml:get_subtag(Packet, <<"body">>) /= false;
+ unless_chat_state ->
+ not jlib:is_standalone_chat_state(Packet)
+ end
end;
- true ->
+ true ->
false
end.