aboutsummaryrefslogtreecommitdiff
path: root/src/mod_pubsub
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_pubsub')
-rw-r--r--src/mod_pubsub/mod_pubsub.erl138
1 files changed, 66 insertions, 72 deletions
diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
index 7bd1fae77..d8d3fdfe2 100644
--- a/src/mod_pubsub/mod_pubsub.erl
+++ b/src/mod_pubsub/mod_pubsub.erl
@@ -63,6 +63,7 @@
in_subscription/6,
out_subscription/4,
remove_user/2,
+ feature_check_packet/6,
disco_local_identity/5,
disco_local_features/5,
disco_local_items/5,
@@ -208,6 +209,7 @@ init([ServerHost, Opts]) ->
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHost, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc),
case lists:member(?PEPNODE, Plugins) of
true ->
+ ejabberd_hooks:add(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75),
ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
@@ -514,18 +516,13 @@ send_loop(State) ->
%% this makes that hack only work for local domain by now
if not State#state.ignore_pep_from_offline ->
{User, Server, Resource} = jlib:jid_tolower(JID),
- case mod_caps:get_caps({User, Server, Resource}) of
- nothing ->
- %% we don't have caps, no need to handle PEP items
- ok;
- _ ->
case catch ejabberd_c2s:get_subscribed(Pid) of
Contacts when is_list(Contacts) ->
lists:foreach(
fun({U, S, R}) ->
case S of
ServerHost -> %% local contacts
- case ejabberd_sm:get_user_resources(U, S) of
+ case user_resources(U, S) of
[] -> %% offline
PeerJID = jlib:make_jid(U, S, R),
self() ! {presence, User, Server, [Resource], PeerJID};
@@ -540,8 +537,7 @@ send_loop(State) ->
end, Contacts);
_ ->
ok
- end
- end;
+ end;
true ->
ok
end,
@@ -549,54 +545,35 @@ send_loop(State) ->
{presence, User, Server, Resources, JID} ->
%% get resources caps and check if processing is needed
spawn(fun() ->
- {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) ->
- case mod_caps:get_caps({User, Server, Resource}) of
- nothing -> {R, L};
- Caps -> {true, [{Resource, Caps} | L]}
- end
- end, {false, []}, Resources),
- case HasCaps of
- true ->
- Host = State#state.host,
- ServerHost = State#state.server_host,
- Owner = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
- lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) ->
+ Host = State#state.host,
+ ServerHost = State#state.server_host,
+ Owner = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
+ lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
- lists:foreach(fun({Resource, Caps}) ->
- CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of
- Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features);
- _ -> false
- end,
- case CapsNotify of
- true ->
- LJID = {User, Server, Resource},
- Subscribed = case get_option(Options, access_model) of
- open -> true;
- presence -> true;
- whitelist -> false; % subscribers are added manually
- authorize -> false; % likewise
- roster ->
- Grps = get_option(Options, roster_groups_allowed, []),
- {OU, OS, _} = Owner,
- element(2, get_roster_info(OU, OS, LJID, Grps))
- end,
- if Subscribed ->
- send_items(Owner, Node, NodeId, Type, LJID, last);
- true ->
- ok
- end;
- false ->
- ok
- end
- end, ResourcesCaps);
+ lists:foreach(
+ fun(Resource) ->
+ LJID = {User, Server, Resource},
+ Subscribed = case get_option(Options, access_model) of
+ open -> true;
+ presence -> true;
+ whitelist -> false; % subscribers are added manually
+ authorize -> false; % likewise
+ roster ->
+ Grps = get_option(Options, roster_groups_allowed, []),
+ {OU, OS, _} = Owner,
+ element(2, get_roster_info(OU, OS, LJID, Grps))
+ end,
+ if Subscribed ->
+ send_items(Owner, Node, NodeId, Type, LJID, last);
+ true ->
+ ok
+ end
+ end, Resources);
_ ->
ok
end
- end, tree_action(Host, get_nodes, [Owner, JID]));
- false ->
- ok
- end
+ end, tree_action(Host, get_nodes, [Owner, JID]))
end),
send_loop(State);
stop ->
@@ -878,6 +855,7 @@ terminate(_Reason, #state{host = Host,
ejabberd_router:unregister_route(Host),
case lists:member(?PEPNODE, Plugins) of
true ->
+ ejabberd_hooks:delete(feature_check_packet, ServerHost, ?MODULE, feature_check_packet, 75),
ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
@@ -3118,10 +3096,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp
spawn(fun() ->
LJIDs = lists:foldl(fun(R, Acc) ->
LJID = {U, S, R},
- case is_caps_notify(LServer, Node, LJID) of
- true -> [LJID | Acc];
- false -> Acc
- end
+ [LJID | Acc]
end, [], user_resources(U, S)),
lists:foreach(fun(To) ->
ejabberd_router:route(Sender, jlib:make_jid(To), Stanza)
@@ -3186,24 +3161,8 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
{_, JIDSubs} = lists:foldl(DepthsToDeliver, {[], []}, SubsByDepth),
JIDSubs.
-%% If we don't know the resource, just pick first if any
-%% If no resource available, check if caps anyway (remote online)
user_resources(User, Server) ->
- case ejabberd_sm:get_user_resources(User, Server) of
- [] -> mod_caps:get_user_resources(User, Server);
- Rs -> Rs
- end.
-
-is_caps_notify(Host, Node, LJID) ->
- case mod_caps:get_caps(LJID) of
- nothing ->
- false;
- Caps ->
- case catch mod_caps:get_features(Host, Caps) of
- Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features);
- _ -> false
- end
- end.
+ ejabberd_sm:get_user_resources(User, Server).
%%%%%%% Configuration handling
@@ -3785,3 +3744,38 @@ subid_shim(SubIDs) ->
[{xmlelement, "header", [{"name", "SubID"}],
[{xmlcdata, SubID}]} || SubID <- SubIDs].
+feature_check_packet(allow, _User, Server, Pres, {#jid{lserver = LServer}, _To, {xmlelement, "message", _, _} = El}, in) ->
+ Host = host(Server),
+ case LServer of
+ %% If the sender Server equals Host, the message comes from the Pubsub server
+ Host ->
+ allow;
+ %% Else, the message comes from PEP
+ _ ->
+ case xml:get_subtag(El, "event") of
+ {xmlelement, _, Attrs, _} = EventEl ->
+ case xml:get_attr_s("xmlns", Attrs) of
+ ?NS_PUBSUB_EVENT ->
+ Feature = xml:get_path_s(EventEl, [{elem, "items"}, {attr, "node"}]),
+ case is_feature_supported(Pres, Feature) of
+ true ->
+ allow;
+ false ->
+ deny
+ end;
+ _ ->
+ allow
+ end;
+ _ ->
+ allow
+ end
+ end;
+
+feature_check_packet(Acc, _User, _Server, _Pres, _Packet, _Direction) ->
+ Acc.
+
+is_feature_supported({xmlelement, "presence", _, Els}, Feature) ->
+ case mod_caps:read_caps(Els) of
+ nothing -> false;
+ Caps -> lists:member(Feature ++ "+notify", mod_caps:get_features(Caps))
+ end.