Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 410017 | Differences between
and this patch

Collapse All | Expand All

(-)a/doc/guide.tex (-2 / +12 lines)
Lines 3864-3869 It also supports Roster Versioning (\xepref{0237}). Link Here
3864
Options:
3864
Options:
3865
\begin{description}
3865
\begin{description}
3866
\iqdiscitem{Roster Management (\ns{jabber:iq:roster})}
3866
\iqdiscitem{Roster Management (\ns{jabber:iq:roster})}
3867
  \titem{\{managers, [Domainname]\}} \ind{options!managers}
3868
  List of components (or servers) that can manage users rosters using
3869
  \footahref{http://jkaluza.fedorapeople.org/remote-roster.html}{XEP-xxxx: Remote Roster Management}.
3870
  The protocol sections implemented are:
3871
  \term{2.3. Component requests user's roster},
3872
  \term{2.4. Client sends roster update},
3873
  \term{2.5. Component sends roster update}.
3874
  A component only gets or can modify roster items that have the same domain as the component.
3875
  Default value is: \term{[]}.
3867
  \titem{\{versioning, false|true\}} \ind{options!versioning}Enables
3876
  \titem{\{versioning, false|true\}} \ind{options!versioning}Enables
3868
  Roster Versioning.
3877
  Roster Versioning.
3869
  This option is disabled by default.
3878
  This option is disabled by default.
Lines 3877-3888 Options: Link Here
3877
  Important: if you use \modsharedroster, you must disable this option.
3886
  Important: if you use \modsharedroster, you must disable this option.
3878
\end{description}
3887
\end{description}
3879
3888
3880
This example configuration enables Roster Versioning with storage of current id:
3889
This example configuration enables Roster Versioning with storage of current id.
3890
The ICQ and MSN transports can get ICQ and MSN contacts, add them, or remove them for any local account:
3881
\begin{verbatim}
3891
\begin{verbatim}
3882
{modules,
3892
{modules,
3883
 [
3893
 [
3884
  ...
3894
  ...
3885
  {mod_roster, [{versioning, true}, {store_current_id, true}]},
3895
  {mod_roster, [{versioning, true}, {store_current_id, true}, {["icq.example.org", "msn.example.org"]} ]},
3886
  ...
3896
  ...
3887
 ]}.
3897
 ]}.
3888
\end{verbatim}
3898
\end{verbatim}
(-)a/src/mod_roster.erl (-5 / +96 lines)
Lines 123-128 stop(Host) -> Link Here
123
			  ?MODULE, webadmin_user, 50),
123
			  ?MODULE, webadmin_user, 50),
124
    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER).
124
    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER).
125
125
126
process_iq(From, To, IQ) when ((From#jid.luser == "") andalso (From#jid.lresource == "")) ->
127
    process_iq_manager(From, To, IQ);
126
128
127
process_iq(From, To, IQ) ->
129
process_iq(From, To, IQ) ->
128
    #iq{sub_el = SubEl} = IQ,
130
    #iq{sub_el = SubEl} = IQ,
Lines 281-292 item_to_xml(Item) -> Link Here
281
    {xmlelement, "item", Attrs4, SubEls}.
283
    {xmlelement, "item", Attrs4, SubEls}.
282
284
283
285
284
process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
286
process_iq_set(From, To, #iq{sub_el = SubEl, id = Id} = IQ) ->
285
    {xmlelement, _Name, _Attrs, Els} = SubEl,
287
    {xmlelement, _Name, _Attrs, Els} = SubEl,
286
    lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els),
288
    Managed = is_managed_from_id(Id),
289
    lists:foreach(fun(El) -> process_item_set(From, To, El, Managed) end, Els),
287
    IQ#iq{type = result, sub_el = []}.
290
    IQ#iq{type = result, sub_el = []}.
288
291
289
process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
292
process_item_set(From, To, {xmlelement, _Name, Attrs, Els}, Managed) ->
290
    JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
293
    JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
291
    #jid{user = User, luser = LUser, lserver = LServer} = From,
294
    #jid{user = User, luser = LUser, lserver = LServer} = From,
292
    case JID1 of
295
    case JID1 of
Lines 308-314 process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> Link Here
308
						groups = [],
311
						groups = [],
309
						xs = []}
312
						xs = []}
310
			       end,
313
			       end,
311
			Item1 = process_item_attrs(Item, Attrs),
314
%			Item11 = process_item_attrs(Item, Attrs),
315
			Item1 = process_item_attrs_managed(Item, Attrs, Managed),
312
			Item2 = process_item_els(Item1, Els),
316
			Item2 = process_item_els(Item1, Els),
313
			case Item2#roster.subscription of
317
			case Item2#roster.subscription of
314
			    remove ->
318
			    remove ->
Lines 316-321 process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> Link Here
316
			    _ ->
320
			    _ ->
317
				mnesia:write(Item2)
321
				mnesia:write(Item2)
318
			end,
322
			end,
323
			send_itemset_to_managers(From, Item2, Managed),
319
			%% If the item exist in shared roster, take the
324
			%% If the item exist in shared roster, take the
320
			%% subscription information from there:
325
			%% subscription information from there:
321
			Item3 = ejabberd_hooks:run_fold(roster_process_item,
326
			Item3 = ejabberd_hooks:run_fold(roster_process_item,
Lines 341-347 process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> Link Here
341
		    ok
346
		    ok
342
	    end
347
	    end
343
    end;
348
    end;
344
process_item_set(_From, _To, _) ->
349
process_item_set(_From, _To, _, _Managed) ->
345
    ok.
350
    ok.
346
351
347
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
352
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
Lines 1098-1100 us_to_list({User, Server}) -> Link Here
1098
webadmin_user(Acc, _User, _Server, Lang) ->
1103
webadmin_user(Acc, _User, _Server, Lang) ->
1099
    Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])].
1104
    Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])].
1100
1105
1106
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107
1108
%% Implement http://jkaluza.fedorapeople.org/remote-roster.html#sect-id188012
1109
1110
%% Handle 2.3 and 2.5
1111
1112
process_iq_manager(From, To, IQ) ->
1113
    %% Check what access is allowed for From to To
1114
    MatchDomain = From#jid.lserver,
1115
    case is_domain_managed(MatchDomain, To#jid.lserver) of
1116
	true ->
1117
	    process_iq_manager2(MatchDomain, To, IQ);
1118
	false ->
1119
	    #iq{sub_el = SubEl} = IQ,
1120
	    IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
1121
    end.
1122
1123
process_iq_manager2(MatchDomain, To, IQ) ->
1124
    %% If IQ is SET, filter the input IQ
1125
    IQFiltered = maybe_filter_request(MatchDomain, IQ),
1126
    %% Call the standard function with reversed JIDs
1127
    IdInitial = IQFiltered#iq.id,
1128
    ResIQ = process_iq(To, To, IQFiltered#iq{id = "roster-remotely-managed"}),
1129
    %% Filter the output IQ
1130
    filter_stanza(MatchDomain, ResIQ#iq{id = IdInitial}).
1131
1132
is_domain_managed(ContactHost, UserHost) ->
1133
    Managers = gen_mod:get_module_opt(UserHost, ?MODULE, managers, []),
1134
    lists:member(ContactHost, Managers).
1135
1136
maybe_filter_request(MatchDomain, IQ) when IQ#iq.type == set ->
1137
    filter_stanza(MatchDomain, IQ);
1138
maybe_filter_request(_MatchDomain, IQ) ->
1139
    IQ.
1140
1141
filter_stanza(_MatchDomain, #iq{sub_el = []} = IQ) ->
1142
    IQ;
1143
filter_stanza(MatchDomain, #iq{sub_el = [SubEl | _]} = IQ) ->
1144
    #iq{sub_el = SubElFiltered} = IQRes =
1145
	filter_stanza(MatchDomain, IQ#iq{sub_el = SubEl}),
1146
    IQRes#iq{sub_el = [SubElFiltered]};
1147
filter_stanza(MatchDomain, #iq{sub_el = SubEl} = IQ) ->
1148
    {xmlelement, Type, Attrs, Items} = SubEl,
1149
    ItemsFiltered = lists:filter(
1150
		      fun(Item) ->
1151
			      is_item_of_domain(MatchDomain, Item) end, Items),
1152
    SubElFiltered = {xmlelement, Type, Attrs, ItemsFiltered},
1153
    IQ#iq{sub_el = SubElFiltered}.
1154
1155
is_item_of_domain(MatchDomain, {xmlelement, _, Attrs, _}) ->
1156
    lists:any(fun(Attr) -> is_jid_of_domain(MatchDomain, Attr) end, Attrs);
1157
is_item_of_domain(_MatchDomain, {xmlcdata, _}) ->
1158
    false.
1159
1160
is_jid_of_domain(MatchDomain, {"jid", JIDString}) ->
1161
    case jlib:string_to_jid(JIDString) of
1162
	JID when JID#jid.lserver == MatchDomain -> true;
1163
	_ -> false
1164
    end;
1165
is_jid_of_domain(_, _) ->
1166
    false.
1167
1168
%% Handle 2.5
1169
process_item_attrs_managed(Item, Attrs, true) ->
1170
    process_item_attrs_ws(Item, Attrs);
1171
process_item_attrs_managed(Item, _Attrs, false) ->
1172
    process_item_attrs(Item, _Attrs).
1173
1174
%% Handle 2.4
1175
send_itemset_to_managers(_From, _Item, true) ->
1176
    ok;
1177
send_itemset_to_managers(From, Item, false) ->
1178
    {_, UserHost} = Item#roster.us,
1179
    {_ContactUser, ContactHost, _ContactResource} = Item#roster.jid,
1180
1181
    %% Check if the component is an allowed manager
1182
    IsManager = is_domain_managed(ContactHost, UserHost),
1183
    case IsManager of
1184
	true -> push_item("", ContactHost, "", From, Item);
1185
	false -> ok
1186
    end.
1187
1188
is_managed_from_id("roster-remotely-managed") ->
1189
    true;
1190
is_managed_from_id(_Id) ->
1191
    false.
(-)a/src/mod_roster_odbc.erl (-5 / +97 lines)
Lines 113-118 stop(Host) -> Link Here
113
			  ?MODULE, webadmin_user, 50),
113
			  ?MODULE, webadmin_user, 50),
114
    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER).
114
    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER).
115
115
116
process_iq(From, To, IQ) when ((From#jid.luser == "") andalso (From#jid.lresource == "")) ->
117
    process_iq_manager(From, To, IQ);
116
118
117
process_iq(From, To, IQ) ->
119
process_iq(From, To, IQ) ->
118
    #iq{sub_el = SubEl} = IQ,
120
    #iq{sub_el = SubEl} = IQ,
Lines 306-317 item_to_xml(Item) -> Link Here
306
    {xmlelement, "item", Attrs, SubEls}.
308
    {xmlelement, "item", Attrs, SubEls}.
307
309
308
310
309
process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
311
process_iq_set(From, To, #iq{sub_el = SubEl, id = Id} = IQ) ->
310
    {xmlelement, _Name, _Attrs, Els} = SubEl,
312
    {xmlelement, _Name, _Attrs, Els} = SubEl,
311
    lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els),
313
    Managed = is_managed_from_id(Id),
314
    lists:foreach(fun(El) -> process_item_set(From, To, El, Managed) end, Els),
312
    IQ#iq{type = result, sub_el = []}.
315
    IQ#iq{type = result, sub_el = []}.
313
316
314
process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
317
process_item_set(From, To, {xmlelement, _Name, Attrs, Els}, Managed) ->
315
    JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
318
    JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
316
    #jid{user = User, luser = LUser, lserver = LServer} = From,
319
    #jid{user = User, luser = LUser, lserver = LServer} = From,
317
    case JID1 of
320
    case JID1 of
Lines 347-353 process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> Link Here
347
						 name = ""}
350
						 name = ""}
348
				       end
351
				       end
349
			       end,
352
			       end,
350
			Item1 = process_item_attrs(Item, Attrs),
353
%			Item11 = process_item_attrs(Item, Attrs),
354
			Item1 = process_item_attrs_managed(Item, Attrs, Managed),
351
			Item2 = process_item_els(Item1, Els),
355
			Item2 = process_item_els(Item1, Els),
352
			case Item2#roster.subscription of
356
			case Item2#roster.subscription of
353
			    remove ->
357
			    remove ->
Lines 357-362 process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> Link Here
357
				ItemGroups = groups_to_string(Item2),
361
				ItemGroups = groups_to_string(Item2),
358
				odbc_queries:update_roster(LServer, Username, SJID, ItemVals, ItemGroups)
362
				odbc_queries:update_roster(LServer, Username, SJID, ItemVals, ItemGroups)
359
			end,
363
			end,
364
			send_itemset_to_managers(From, Item2, Managed),
360
			%% If the item exist in shared roster, take the
365
			%% If the item exist in shared roster, take the
361
			%% subscription information from there:
366
			%% subscription information from there:
362
			Item3 = ejabberd_hooks:run_fold(roster_process_item,
367
			Item3 = ejabberd_hooks:run_fold(roster_process_item,
Lines 382-388 process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> Link Here
382
		    ok
387
		    ok
383
	    end
388
	    end
384
    end;
389
    end;
385
process_item_set(_From, _To, _) ->
390
process_item_set(_From, _To, _, _Managed) ->
386
    ok.
391
    ok.
387
392
388
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
393
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
Lines 1197-1199 us_to_list({User, Server}) -> Link Here
1197
1202
1198
webadmin_user(Acc, _User, _Server, Lang) ->
1203
webadmin_user(Acc, _User, _Server, Lang) ->
1199
    Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])].
1204
    Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])].
1205
1206
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207
1208
%% Implement http://jkaluza.fedorapeople.org/remote-roster.html#sect-id188012
1209
1210
%% Handle 2.3 and 2.5
1211
1212
process_iq_manager(From, To, IQ) ->
1213
    %% Check what access is allowed for From to To
1214
    MatchDomain = From#jid.lserver,
1215
    case is_domain_managed(MatchDomain, To#jid.lserver) of
1216
	true ->
1217
	    process_iq_manager2(MatchDomain, To, IQ);
1218
	false ->
1219
	    #iq{sub_el = SubEl} = IQ,
1220
	    IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
1221
    end.
1222
1223
process_iq_manager2(MatchDomain, To, IQ) ->
1224
    %% If IQ is SET, filter the input IQ
1225
    IQFiltered = maybe_filter_request(MatchDomain, IQ),
1226
    %% Call the standard function with reversed JIDs
1227
    IdInitial = IQFiltered#iq.id,
1228
    ResIQ = process_iq(To, To, IQFiltered#iq{id = "roster-remotely-managed"}),
1229
    %% Filter the output IQ
1230
    filter_stanza(MatchDomain, ResIQ#iq{id = IdInitial}).
1231
1232
is_domain_managed(ContactHost, UserHost) ->
1233
    Managers = gen_mod:get_module_opt(UserHost, ?MODULE, managers, []),
1234
    lists:member(ContactHost, Managers).
1235
1236
maybe_filter_request(MatchDomain, IQ) when IQ#iq.type == set ->
1237
    filter_stanza(MatchDomain, IQ);
1238
maybe_filter_request(_MatchDomain, IQ) ->
1239
    IQ.
1240
1241
filter_stanza(_MatchDomain, #iq{sub_el = []} = IQ) ->
1242
    IQ;
1243
filter_stanza(MatchDomain, #iq{sub_el = [SubEl | _]} = IQ) ->
1244
    #iq{sub_el = SubElFiltered} = IQRes =
1245
	filter_stanza(MatchDomain, IQ#iq{sub_el = SubEl}),
1246
    IQRes#iq{sub_el = [SubElFiltered]};
1247
filter_stanza(MatchDomain, #iq{sub_el = SubEl} = IQ) ->
1248
    {xmlelement, Type, Attrs, Items} = SubEl,
1249
    ItemsFiltered = lists:filter(
1250
		      fun(Item) ->
1251
			      is_item_of_domain(MatchDomain, Item) end, Items),
1252
    SubElFiltered = {xmlelement, Type, Attrs, ItemsFiltered},
1253
    IQ#iq{sub_el = SubElFiltered}.
1254
1255
is_item_of_domain(MatchDomain, {xmlelement, _, Attrs, _}) ->
1256
    lists:any(fun(Attr) -> is_jid_of_domain(MatchDomain, Attr) end, Attrs);
1257
is_item_of_domain(_MatchDomain, {xmlcdata, _}) ->
1258
    false.
1259
1260
is_jid_of_domain(MatchDomain, {"jid", JIDString}) ->
1261
    case jlib:string_to_jid(JIDString) of
1262
	JID when JID#jid.lserver == MatchDomain -> true;
1263
	_ -> false
1264
    end;
1265
is_jid_of_domain(_, _) ->
1266
    false.
1267
1268
%% Handle 2.5
1269
process_item_attrs_managed(Item, Attrs, true) ->
1270
    process_item_attrs_ws(Item, Attrs);
1271
process_item_attrs_managed(Item, _Attrs, false) ->
1272
    process_item_attrs(Item, _Attrs).
1273
1274
%% Handle 2.4
1275
send_itemset_to_managers(_From, _Item, true) ->
1276
    ok;
1277
send_itemset_to_managers(From, Item, false) ->
1278
    {_, UserHost} = Item#roster.us,
1279
    {_ContactUser, ContactHost, _ContactResource} = Item#roster.jid,
1280
1281
    %% Check if the component is an allowed manager
1282
    IsManager = is_domain_managed(ContactHost, UserHost),
1283
    case IsManager of
1284
	true -> push_item("", ContactHost, "", From, Item);
1285
	false -> ok
1286
    end.
1287
1288
is_managed_from_id("roster-remotely-managed") ->
1289
    true;
1290
is_managed_from_id(_Id) ->
1291
    false.

Return to bug 410017