1 |
|
%%% ==================================================================== |
2 |
|
%%% ``The contents of this file are subject to the Erlang Public License, |
3 |
|
%%% Version 1.1, (the "License"); you may not use this file except in |
4 |
|
%%% compliance with the License. You should have received a copy of the |
5 |
|
%%% Erlang Public License along with this software. If not, it can be |
6 |
|
%%% retrieved via the world wide web at http://www.erlang.org/. |
7 |
|
%%% |
8 |
|
%%% |
9 |
|
%%% Software distributed under the License is distributed on an "AS IS" |
10 |
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
11 |
|
%%% the License for the specific language governing rights and limitations |
12 |
|
%%% under the License. |
13 |
|
%%% |
14 |
|
%%% |
15 |
|
%%% The Initial Developer of the Original Code is ProcessOne. |
16 |
|
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne |
17 |
|
%%% All Rights Reserved.'' |
18 |
|
%%% This software is copyright 2006-2015, ProcessOne. |
19 |
|
%%% |
20 |
|
%%% @copyright 2006-2015 ProcessOne |
21 |
|
%%% @author Christophe Romain <christophe.romain@process-one.net> |
22 |
|
%%% [http://www.process-one.net/] |
23 |
|
%%% @end |
24 |
|
%%% ==================================================================== |
25 |
|
|
26 |
|
-module(node_pep). |
27 |
|
-behaviour(gen_pubsub_node). |
28 |
|
-author('christophe.romain@process-one.net'). |
29 |
|
|
30 |
|
-include("mongoose.hrl"). |
31 |
|
-include("pubsub.hrl"). |
32 |
|
-include("jlib.hrl"). |
33 |
|
|
34 |
|
%%% @doc The module <strong>{@module}</strong> is the pep PubSub plugin. |
35 |
|
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p> |
36 |
|
|
37 |
|
-export([based_on/0, init/3, terminate/2, options/0, features/0, |
38 |
|
create_node_permission/6, delete_node/1, |
39 |
|
unsubscribe_node/4, node_to_path/1, |
40 |
|
get_entity_affiliations/2, get_entity_affiliations/3, |
41 |
|
get_entity_subscriptions/2, get_entity_subscriptions/4, |
42 |
|
should_delete_when_owner_removed/0 |
43 |
|
]). |
44 |
|
|
45 |
|
-ignore_xref([get_entity_affiliations/3, get_entity_subscriptions/4]). |
46 |
|
|
47 |
109 |
based_on() -> node_flat. |
48 |
|
|
49 |
|
init(Host, ServerHost, Opts) -> |
50 |
3 |
node_flat:init(Host, ServerHost, Opts), |
51 |
3 |
complain_if_modcaps_disabled(ServerHost), |
52 |
3 |
ok. |
53 |
|
|
54 |
|
terminate(Host, ServerHost) -> |
55 |
3 |
node_flat:terminate(Host, ServerHost), |
56 |
3 |
ok. |
57 |
|
|
58 |
|
options() -> |
59 |
12 |
[{deliver_payloads, true}, |
60 |
|
{notify_config, false}, |
61 |
|
{notify_delete, false}, |
62 |
|
{notify_retract, false}, |
63 |
|
{purge_offline, false}, |
64 |
|
{persist_items, true}, |
65 |
|
{max_items, 1}, |
66 |
|
{subscribe, true}, |
67 |
|
{access_model, presence}, |
68 |
|
{roster_groups_allowed, []}, |
69 |
|
{publish_model, publishers}, |
70 |
|
{notification_type, headline}, |
71 |
|
{max_payload_size, ?MAX_PAYLOAD_SIZE}, |
72 |
|
{send_last_published_item, on_sub_and_presence}, |
73 |
|
{deliver_notifications, true}, |
74 |
|
{presence_based_delivery, true}]. |
75 |
|
|
76 |
|
features() -> |
77 |
148 |
[<<"create-nodes">>, |
78 |
|
<<"auto-create">>, |
79 |
|
<<"auto-subscribe">>, |
80 |
|
<<"delete-nodes">>, |
81 |
|
<<"delete-items">>, |
82 |
|
<<"filtered-notifications">>, |
83 |
|
<<"modify-affiliations">>, |
84 |
|
<<"outcast-affiliation">>, |
85 |
|
<<"persistent-items">>, |
86 |
|
<<"publish">>, |
87 |
|
<<"publish-options">>, |
88 |
|
<<"purge-nodes">>, |
89 |
|
<<"retract-items">>, |
90 |
|
<<"retrieve-affiliations">>, |
91 |
|
<<"retrieve-items">>, |
92 |
|
<<"retrieve-subscriptions">>, |
93 |
|
<<"subscribe">>]. |
94 |
|
|
95 |
|
create_node_permission(Host, _ServerHost, _Node, _ParentNode, |
96 |
|
#jid{ luser = <<>>, lserver = Host, lresource = <<>> }, _Access) -> |
97 |
:-( |
{result, true}; % pubsub service always allowed |
98 |
|
create_node_permission(Host, ServerHost, _Node, _ParentNode, |
99 |
|
#jid{ luser = User, lserver = Server } = Owner, Access) -> |
100 |
12 |
{ok, HostType} = mongoose_domain_api:get_domain_host_type(ServerHost), |
101 |
12 |
case acl:match_rule(HostType, ServerHost, Access, Owner) of |
102 |
|
allow -> |
103 |
12 |
case Host of |
104 |
12 |
{User, Server, _} -> {result, true}; |
105 |
:-( |
_ -> {result, false} |
106 |
|
end; |
107 |
|
_ -> |
108 |
:-( |
{result, false} |
109 |
|
end. |
110 |
|
|
111 |
|
delete_node(Nodes) -> |
112 |
3 |
{result, {_, _, Result}} = node_flat:delete_node(Nodes), |
113 |
3 |
{result, {[], Result}}. |
114 |
|
|
115 |
|
unsubscribe_node(Nidx, Sender, Subscriber, SubId) -> |
116 |
:-( |
case node_flat:unsubscribe_node(Nidx, Sender, Subscriber, SubId) of |
117 |
:-( |
{error, Error} -> {error, Error}; |
118 |
:-( |
{result, _} -> {result, []} |
119 |
|
end. |
120 |
|
|
121 |
|
get_entity_affiliations(Host, #jid{ lserver = D } = Owner) -> |
122 |
:-( |
get_entity_affiliations(Host, D, jid:to_lower(Owner)); |
123 |
|
get_entity_affiliations(Host, {_, D, _} = Owner) -> |
124 |
42 |
get_entity_affiliations(Host, D, Owner). |
125 |
|
|
126 |
|
get_entity_affiliations(Host, D, Owner) -> |
127 |
42 |
{ok, States} = mod_pubsub_db_backend:get_states_by_bare(Owner), |
128 |
42 |
HT = mod_pubsub:host_to_host_type(Host), |
129 |
42 |
NodeTree = mod_pubsub:tree(HT), |
130 |
42 |
Reply = lists:foldl(fun (#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -> |
131 |
14 |
case gen_pubsub_nodetree:get_node(NodeTree, N) of |
132 |
7 |
#pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, A} | Acc]; |
133 |
7 |
_ -> Acc |
134 |
|
end |
135 |
|
end, |
136 |
|
[], States), |
137 |
42 |
{result, Reply}. |
138 |
|
|
139 |
|
get_entity_subscriptions(Host, #jid{ lserver = D, lresource = R } = Owner) -> |
140 |
47 |
get_entity_subscriptions(Host, D, R, Owner); |
141 |
|
get_entity_subscriptions(Host, {_, D, R} = Owner) -> |
142 |
:-( |
get_entity_subscriptions(Host, D, R, Owner). |
143 |
|
|
144 |
|
get_entity_subscriptions(Host, D, R, Owner) -> |
145 |
47 |
LOwner = jid:to_lower(Owner), |
146 |
47 |
States = case R of |
147 |
|
<<>> -> |
148 |
5 |
{ok, States0} = mod_pubsub_db_backend:get_states_by_lus(LOwner), |
149 |
5 |
States0; |
150 |
|
_ -> |
151 |
42 |
{ok, States0} = mod_pubsub_db_backend:get_states_by_bare_and_full(LOwner), |
152 |
42 |
States0 |
153 |
|
end, |
154 |
47 |
HT = mod_pubsub:host_to_host_type(Host), |
155 |
47 |
NodeTree = mod_pubsub:tree(HT), |
156 |
47 |
Reply = lists:foldl(fun (#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -> |
157 |
1 |
case gen_pubsub_nodetree:get_node(NodeTree, N) of |
158 |
|
#pubsub_node{nodeid = {{_, D, _}, _}} = Node -> |
159 |
1 |
accumulate_entity_subscriptions(J, Node, Ss, Acc); |
160 |
|
_ -> |
161 |
:-( |
Acc |
162 |
|
end |
163 |
|
end, |
164 |
|
[], States), |
165 |
47 |
{result, Reply}. |
166 |
|
|
167 |
|
accumulate_entity_subscriptions(J, Node, Ss, Acc) -> |
168 |
1 |
lists:foldl(fun({subscribed, SubId}, Acc2) -> |
169 |
:-( |
[{Node, subscribed, SubId, J} | Acc2]; |
170 |
|
({pending, _SubId}, Acc2) -> |
171 |
1 |
[{Node, pending, J} | Acc2]; |
172 |
|
(S, Acc2) -> |
173 |
:-( |
[{Node, S, J} | Acc2] |
174 |
|
end, Acc, Ss). |
175 |
|
|
176 |
|
|
177 |
|
node_to_path(Node) -> |
178 |
12 |
node_flat:node_to_path(Node). |
179 |
|
|
180 |
9 |
should_delete_when_owner_removed() -> true. |
181 |
|
|
182 |
|
%%% |
183 |
|
%%% Internal |
184 |
|
%%% |
185 |
|
|
186 |
|
%% @doc Check mod_caps is enabled, otherwise show warning. |
187 |
|
%% The PEP plugin for mod_pubsub requires mod_caps to be enabled in the host. |
188 |
|
%% Check that the mod_caps module is enabled in that Jabber Host |
189 |
|
%% If not, log a warning message. |
190 |
|
complain_if_modcaps_disabled(ServerHost) -> |
191 |
3 |
?WARNING_MSG_IF( |
192 |
3 |
not gen_mod:is_loaded(ServerHost, mod_caps), |
193 |
|
"The PEP plugin is enabled in mod_pubsub " |
194 |
|
"of host ~p. This plugin requires mod_caps " |
195 |
|
"to be enabled, but it isn't.", |
196 |
:-( |
[ServerHost]). |