diff options
Diffstat (limited to 'src/mod_pubsub')
-rw-r--r-- | src/mod_pubsub/mod_pubsub.erl | 138 |
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. |