Files
@ 42dcd95799f8
Branch filter:
Location: portage-overlay.git/net-im/ejabberd/files/e211bf522ecfa0f8177f20c5e7ff21a1a47f940b.patch
42dcd95799f8
7.0 KiB
text/x-diff
commit old change
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | From e211bf522ecfa0f8177f20c5e7ff21a1a47f940b Mon Sep 17 00:00:00 2001
From: Badlop <badlop@process-one.net>
Date: Wed, 26 Feb 2014 18:01:47 +0100
Subject: [PATCH] Support XEP-0321: Remote Roster Management (EJAB-1381)
---
doc/guide.tex | 15 +++++++-
src/mod_roster.erl | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 109 insertions(+), 6 deletions(-)
diff --git a/doc/guide.tex b/doc/guide.tex
index 4656356..5d5bf2f 100644
--- a/doc/guide.tex
+++ b/doc/guide.tex
@@ -4052,15 +4052,28 @@
not add/remove/modify contacts,
or subscribe/unsubscribe presence.
By default there aren't restrictions.
+ \titem{managers} \ind{options!managers}
+ List of remote entities that can manage users rosters using Remote Roster Management
+ (\xepref{0321}).
+ The protocol sections implemented are:
+ \term{4.2. The remote entity requests current user's roster}.
+ \term{4.3. The user updates roster}.
+ \term{4.4. The remote entity updates the user's roster}.
+ A remote entity cab only get or modify roster items that have the same domain as the entity.
+ Default value is: \term{[]}.
\end{description}
-This example configuration enables Roster Versioning with storage of current id:
+This example configuration enables Roster Versioning with storage of current id.
+The ICQ and MSN transports can get ICQ and MSN contacts, add them, or remove them for any local account:
\begin{verbatim}
modules:
...
mod_roster:
versioning: true
store_current_id: true
+ managers:
+ - "icq.example.org"
+ - "msn.example.org"
...
\end{verbatim}
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 7415aa3..4851b8f 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -130,6 +130,9 @@ stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host,
?NS_ROSTER).
+process_iq(From, To, IQ) when ((From#jid.luser == <<"">>) andalso (From#jid.resource == <<"">>)) ->
+ process_iq_manager(From, To, IQ);
+
process_iq(From, To, IQ) ->
#iq{sub_el = SubEl} = IQ,
#jid{lserver = LServer} = From,
@@ -465,15 +468,16 @@ try_process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
process_iq_set(From, To, IQ)
end.
-process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
+process_iq_set(From, To, #iq{sub_el = SubEl, id = Id} = IQ) ->
#xmlel{children = Els} = SubEl,
- lists:foreach(fun (El) -> process_item_set(From, To, El)
+ Managed = is_managed_from_id(Id),
+ lists:foreach(fun (El) -> process_item_set(From, To, El, Managed)
end,
Els),
IQ#iq{type = result, sub_el = []}.
process_item_set(From, To,
- #xmlel{attrs = Attrs, children = Els}) ->
+ #xmlel{attrs = Attrs, children = Els}, Managed) ->
JID1 = jlib:string_to_jid(xml:get_attr_s(<<"jid">>,
Attrs)),
#jid{user = User, luser = LUser, lserver = LServer} =
@@ -484,12 +488,13 @@ process_item_set(From, To,
LJID = jlib:jid_tolower(JID1),
F = fun () ->
Item = get_roster_by_jid_t(LUser, LServer, LJID),
- Item1 = process_item_attrs(Item, Attrs),
+ Item1 = process_item_attrs_managed(Item, Attrs, Managed),
Item2 = process_item_els(Item1, Els),
case Item2#roster.subscription of
remove -> del_roster_t(LUser, LServer, LJID);
_ -> update_roster_t(LUser, LServer, LJID, Item2)
end,
+ send_itemset_to_managers(From, Item2, Managed),
Item3 = ejabberd_hooks:run_fold(roster_process_item,
LServer, Item2,
[LServer]),
@@ -511,7 +516,7 @@ process_item_set(From, To,
?DEBUG("ROSTER: roster item set error: ~p~n", [E]), ok
end
end;
-process_item_set(_From, _To, _) -> ok.
+process_item_set(_From, _To, _, _Managed) -> ok.
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
case Attr of
@@ -1554,6 +1559,91 @@ webadmin_user(Acc, _User, _Server, Lang) ->
Acc ++
[?XE(<<"h3">>, [?ACT(<<"roster/">>, <<"Roster">>)])].
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Implement XEP-0321 Remote Roster Management
+
+process_iq_manager(From, To, IQ) ->
+ %% Check what access is allowed for From to To
+ MatchDomain = From#jid.lserver,
+ case is_domain_managed(MatchDomain, To#jid.lserver) of
+ true ->
+ process_iq_manager2(MatchDomain, To, IQ);
+ false ->
+ #iq{sub_el = SubEl} = IQ,
+ IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
+ end.
+
+process_iq_manager2(MatchDomain, To, IQ) ->
+ %% If IQ is SET, filter the input IQ
+ IQFiltered = maybe_filter_request(MatchDomain, IQ),
+ %% Call the standard function with reversed JIDs
+ IdInitial = IQFiltered#iq.id,
+ ResIQ = process_iq(To, To, IQFiltered#iq{id = <<"roster-remotely-managed">>}),
+ %% Filter the output IQ
+ filter_stanza(MatchDomain, ResIQ#iq{id = IdInitial}).
+
+is_domain_managed(ContactHost, UserHost) ->
+ Managers = gen_mod:get_module_opt(UserHost, ?MODULE, managers,
+ fun(B) when is_list(B) -> B end,
+ []),
+ lists:member(ContactHost, Managers).
+
+maybe_filter_request(MatchDomain, IQ) when IQ#iq.type == set ->
+ filter_stanza(MatchDomain, IQ);
+maybe_filter_request(_MatchDomain, IQ) ->
+ IQ.
+
+filter_stanza(_MatchDomain, #iq{sub_el = []} = IQ) ->
+ IQ;
+filter_stanza(MatchDomain, #iq{sub_el = [SubEl | _]} = IQ) ->
+ #iq{sub_el = SubElFiltered} = IQRes =
+ filter_stanza(MatchDomain, IQ#iq{sub_el = SubEl}),
+ IQRes#iq{sub_el = [SubElFiltered]};
+filter_stanza(MatchDomain, #iq{sub_el = SubEl} = IQ) ->
+ #xmlel{name = Type, attrs = Attrs, children = Items} = SubEl,
+ ItemsFiltered = lists:filter(
+ fun(Item) ->
+ is_item_of_domain(MatchDomain, Item) end, Items),
+ SubElFiltered = #xmlel{name=Type, attrs = Attrs, children = ItemsFiltered},
+ IQ#iq{sub_el = SubElFiltered}.
+
+is_item_of_domain(MatchDomain, #xmlel{} = El) ->
+ lists:any(fun(Attr) -> is_jid_of_domain(MatchDomain, Attr) end, El#xmlel.attrs);
+is_item_of_domain(_MatchDomain, {xmlcdata, _}) ->
+ false.
+
+is_jid_of_domain(MatchDomain, {<<"jid">>, JIDString}) ->
+ case jlib:string_to_jid(JIDString) of
+ JID when JID#jid.lserver == MatchDomain -> true;
+ _ -> false
+ end;
+is_jid_of_domain(_, _) ->
+ false.
+
+process_item_attrs_managed(Item, Attrs, true) ->
+ process_item_attrs_ws(Item, Attrs);
+process_item_attrs_managed(Item, _Attrs, false) ->
+ process_item_attrs(Item, _Attrs).
+
+send_itemset_to_managers(_From, _Item, true) ->
+ ok;
+send_itemset_to_managers(From, Item, false) ->
+ {_, UserHost} = Item#roster.us,
+ {_ContactUser, ContactHost, _ContactResource} = Item#roster.jid,
+ %% Check if the component is an allowed manager
+ IsManager = is_domain_managed(ContactHost, UserHost),
+ case IsManager of
+ true -> push_item(<<"">>, ContactHost, <<"">>, From, Item);
+ false -> ok
+ end.
+
+is_managed_from_id(<<"roster-remotely-managed">>) ->
+ true;
+is_managed_from_id(_Id) ->
+ false.
+
+
export(_Server) ->
[{roster,
fun(Host, #roster{usj = {LUser, LServer, LJID}} = R)
--
1.8.5.5
|