aboutsummaryrefslogtreecommitdiff
path: root/src/mod_roster.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_roster.erl')
-rw-r--r--src/mod_roster.erl197
1 files changed, 133 insertions, 64 deletions
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 724b8d682..88db5d192 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -15,31 +15,27 @@
-export([start/1, stop/0,
process_iq/3,
process_local_iq/3,
- get_subscription_lists/2,
- in_subscription/4,
- out_subscription/3,
- set_items/2,
- remove_user/1,
- get_jid_info/3]).
+ get_user_roster/2,
+ get_subscription_lists/3,
+ in_subscription/5,
+ out_subscription/4,
+ set_items/3,
+ remove_user/2,
+ get_jid_info/4]).
-include("ejabberd.hrl").
-include("jlib.hrl").
+-include("mod_roster.hrl").
--record(roster, {uj,
- user,
- jid,
- name = "",
- subscription = none,
- ask = none,
- groups = [],
- xattrs = [],
- xs = []}).
start(Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
mnesia:create_table(roster,[{disc_copies, [node()]},
{attributes, record_info(fields, roster)}]),
- mnesia:add_table_index(roster, user),
+ update_table(),
+ mnesia:add_table_index(roster, us),
+ ejabberd_hooks:add(roster_get,
+ ?MODULE, get_user_roster, 50),
ejabberd_hooks:add(roster_in_subscription,
?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription,
@@ -54,6 +50,8 @@ start(Opts) ->
?MODULE, process_iq, IQDisc).
stop() ->
+ ejabberd_hooks:delete(roster_get,
+ ?MODULE, get_user_roster, 50),
ejabberd_hooks:delete(roster_in_subscription,
?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription,
@@ -74,8 +72,8 @@ stop() ->
process_iq(From, To, IQ) ->
#iq{sub_el = SubEl} = IQ,
#jid{lserver = LServer} = From,
- case ?MYNAME of
- LServer ->
+ case lists:member(LServer, ?MYHOSTS) of
+ true ->
ResIQ = process_local_iq(From, To, IQ),
ejabberd_router:route(From, From,
jlib:iq_to_xml(ResIQ)),
@@ -89,8 +87,8 @@ process_iq(From, To, IQ) ->
process_iq(From, To, IQ) ->
#iq{sub_el = SubEl} = IQ,
#jid{lserver = LServer} = From,
- case ?MYNAME of
- LServer ->
+ case lists:member(LServer, ?MYHOSTS) of
+ true ->
process_local_iq(From, To, IQ);
_ ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
@@ -109,8 +107,10 @@ process_local_iq(From, To, #iq{type = Type} = IQ) ->
process_iq_get(From, _To, #iq{sub_el = SubEl} = IQ) ->
- #jid{luser = LUser} = From,
- case catch mnesia:dirty_index_read(roster, LUser, #roster.user) of
+ LUser = From#jid.luser,
+ LServer = From#jid.lserver,
+ US = {LUser, LServer},
+ case catch ejabberd_hooks:run_fold(roster_get, [], [US]) of
Items when is_list(Items) ->
XItems = lists:map(fun item_to_xml/1, Items),
IQ#iq{type = result,
@@ -121,6 +121,17 @@ process_iq_get(From, _To, #iq{sub_el = SubEl} = IQ) ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
end.
+get_user_roster(Acc, US) ->
+ case catch mnesia:dirty_index_read(roster, US, #roster.us) of
+ Items when is_list(Items) ->
+ Items ++ Acc;
+ _ ->
+ Acc
+ end.
+
+
+
+
item_to_xml(Item) ->
Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}],
Attrs2 = case Item#roster.name of
@@ -164,7 +175,7 @@ process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
- #jid{user = User, luser = LUser} = From,
+ #jid{user = User, luser = LUser, lserver = LServer} = From,
case JID1 of
error ->
ok;
@@ -172,15 +183,14 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource},
LJID = jlib:jid_tolower(JID1),
F = fun() ->
- Res = mnesia:read({roster, {LUser, LJID}}),
+ Res = mnesia:read({roster, {LUser, LServer, LJID}}),
Item = case Res of
[] ->
- #roster{uj = {LUser, LJID},
- user = LUser,
+ #roster{usj = {LUser, LServer, LJID},
+ us = {LUser, LServer},
jid = JID};
[I] ->
- I#roster{user = LUser,
- jid = JID,
+ I#roster{jid = JID,
name = "",
groups = [],
xattrs = [],
@@ -190,7 +200,7 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
Item2 = process_item_els(Item1, Els),
case Item2#roster.subscription of
remove ->
- mnesia:delete({roster, {LUser, LJID}});
+ mnesia:delete({roster, {LUser, LServer, LJID}});
_ ->
mnesia:write(Item2)
end,
@@ -198,7 +208,7 @@ process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) ->
end,
case mnesia:transaction(F) of
{atomic, {OldItem, Item}} ->
- push_item(User, To, Item),
+ push_item(User, LServer, To, Item),
case Item#roster.subscription of
remove ->
IsTo = case OldItem#roster.subscription of
@@ -292,47 +302,49 @@ process_item_els(Item, []) ->
Item.
-push_item(User, From, Item) ->
+push_item(User, Server, From, Item) ->
ejabberd_sm:route(jlib:make_jid("", "", ""),
- jlib:make_jid(User, "", ""),
+ jlib:make_jid(User, Server, ""),
{xmlelement, "broadcast", [],
[{item,
Item#roster.jid,
Item#roster.subscription}]}),
lists:foreach(fun(Resource) ->
- push_item(User, Resource, From, Item)
- end, ejabberd_sm:get_user_resources(User)).
+ push_item(User, Server, Resource, From, Item)
+ end, ejabberd_sm:get_user_resources(User, Server)).
% TODO: don't push to those who not load roster
-ifdef(PSI_ROSTER_WORKAROUND).
-push_item(User, Resource, _From, Item) ->
+push_item(User, Server, Resource, _From, Item) ->
ResIQ = #iq{type = set, xmlns = ?NS_ROSTER,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
[item_to_xml(Item)]}]},
ejabberd_router:route(
- jlib:make_jid(User, ?MYNAME, Resource),
- jlib:make_jid(User, ?MYNAME, Resource),
+ jlib:make_jid(User, Server, Resource),
+ jlib:make_jid(User, Server, Resource),
jlib:iq_to_xml(ResIQ)).
-else.
-push_item(User, Resource, From, Item) ->
+push_item(User, Server, Resource, From, Item) ->
ResIQ = #iq{type = set, xmlns = ?NS_ROSTER,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
[item_to_xml(Item)]}]},
ejabberd_router:route(
From,
- jlib:make_jid(User, ?MYNAME, Resource),
+ jlib:make_jid(User, Server, Resource),
jlib:iq_to_xml(ResIQ)).
-endif.
-get_subscription_lists(_, User) ->
+get_subscription_lists(_, User, Server) ->
LUser = jlib:nodeprep(User),
- case mnesia:dirty_index_read(roster, LUser, #roster.user) of
+ LServer = jlib:nameprep(Server),
+ US = {LUser, LServer},
+ case mnesia:dirty_index_read(roster, US, #roster.us) of
Items when is_list(Items) ->
fill_subscription_lists(Items, [], []);
_ ->
@@ -340,7 +352,7 @@ get_subscription_lists(_, User) ->
end.
fill_subscription_lists([I | Is], F, T) ->
- J = element(2, I#roster.uj),
+ J = element(3, I#roster.usj),
case I#roster.subscription of
both ->
fill_subscription_lists(Is, [J | F], [J | T]);
@@ -360,23 +372,25 @@ ask_to_pending(Ask) -> Ask.
-in_subscription(_, User, JID, Type) ->
- process_subscription(in, User, JID, Type).
+in_subscription(_, User, Server, JID, Type) ->
+ process_subscription(in, User, Server, JID, Type).
-out_subscription(User, JID, Type) ->
- process_subscription(out, User, JID, Type).
+out_subscription(User, Server, JID, Type) ->
+ process_subscription(out, User, Server, JID, Type).
-process_subscription(Direction, User, JID1, Type) ->
+process_subscription(Direction, User, Server, JID1, Type) ->
LUser = jlib:nodeprep(User),
+ LServer = jlib:nameprep(Server),
+ US = {LUser, LServer},
LJID = jlib:jid_tolower(JID1),
F = fun() ->
- Item = case mnesia:read({roster, {LUser, LJID}}) of
+ Item = case mnesia:read({roster, {LUser, LServer, LJID}}) of
[] ->
JID = {JID1#jid.user,
JID1#jid.server,
JID1#jid.resource},
- #roster{uj = {LUser, LJID},
- user = LUser,
+ #roster{usj = {LUser, LServer, LJID},
+ us = US,
jid = JID};
[I] ->
I
@@ -420,12 +434,13 @@ process_subscription(Direction, User, JID1, Type) ->
unsubscribed -> "unsubscribed"
end,
ejabberd_router:route(
- jlib:make_jid(User, ?MYNAME, ""), JID1,
+ jlib:make_jid(User, Server, ""), JID1,
{xmlelement, "presence", [{"type", T}], []})
end,
case Push of
{push, Item} ->
- push_item(User, jlib:make_jid("", ?MYNAME, ""), Item),
+ push_item(User, Server,
+ jlib:make_jid("", Server, ""), Item),
true;
none ->
false
@@ -525,27 +540,32 @@ in_auto_reply(both, none, unsubscribe) -> unsubscribed;
in_auto_reply(_, _, _) -> none.
-remove_user(User) ->
+remove_user(User, Server) ->
LUser = jlib:nodeprep(User),
+ LServer = jlib:nameprep(Server),
+ US = {LUser, LServer},
F = fun() ->
lists:foreach(fun(R) ->
mnesia:delete_object(R)
end,
- mnesia:index_read(roster, LUser, #roster.user))
+ mnesia:index_read(roster, US, #roster.us))
end,
mnesia:transaction(F).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-set_items(User, SubEl) ->
+set_items(User, Server, SubEl) ->
{xmlelement, _Name, _Attrs, Els} = SubEl,
LUser = jlib:nodeprep(User),
+ LServer = jlib:nameprep(Server),
F = fun() ->
- lists:foreach(fun(El) -> process_item_set_t(LUser, El) end, Els)
+ lists:foreach(fun(El) ->
+ process_item_set_t(LUser, LServer, El)
+ end, Els)
end,
mnesia:transaction(F).
-process_item_set_t(LUser, {xmlelement, _Name, Attrs, Els}) ->
+process_item_set_t(LUser, LServer, {xmlelement, _Name, Attrs, Els}) ->
JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
case JID1 of
error ->
@@ -553,19 +573,19 @@ process_item_set_t(LUser, {xmlelement, _Name, Attrs, Els}) ->
_ ->
JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource},
LJID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource},
- Item = #roster{uj = {LUser, LJID},
- user = LUser,
+ Item = #roster{usj = {LUser, LServer, LJID},
+ us = {LUser, LServer},
jid = JID},
Item1 = process_item_attrs_ws(Item, Attrs),
Item2 = process_item_els(Item1, Els),
case Item2#roster.subscription of
remove ->
- mnesia:delete({roster, {LUser, LJID}});
+ mnesia:delete({roster, {LUser, LServer, LJID}});
_ ->
mnesia:write(Item2)
end
end;
-process_item_set_t(_LUser, _) ->
+process_item_set_t(_LUser, _LServer, _) ->
ok.
process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) ->
@@ -613,10 +633,11 @@ process_item_attrs_ws(Item, []) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-get_jid_info(_, User, JID) ->
+get_jid_info(_, User, Server, JID) ->
LUser = jlib:nodeprep(User),
LJID = jlib:jid_tolower(JID),
- case catch mnesia:dirty_read(roster, {LUser, LJID}) of
+ LServer = jlib:nameprep(Server),
+ case catch mnesia:dirty_read(roster, {LUser, LServer, LJID}) of
[#roster{subscription = Subscription, groups = Groups}] ->
{Subscription, Groups};
_ ->
@@ -625,7 +646,8 @@ get_jid_info(_, User, JID) ->
LRJID == LJID ->
{none, []};
true ->
- case catch mnesia:dirty_read(roster, {LUser, LRJID}) of
+ case catch mnesia:dirty_read(
+ roster, {LUser, LServer, LRJID}) of
[#roster{subscription = Subscription,
groups = Groups}] ->
{Subscription, Groups};
@@ -635,4 +657,51 @@ get_jid_info(_, User, JID) ->
end
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+update_table() ->
+ Fields = record_info(fields, roster),
+ case mnesia:table_info(roster, attributes) of
+ Fields ->
+ ok;
+ [uj, user, jid, name, subscription, ask, groups, xattrs, xs] ->
+ ?INFO_MSG("Converting roster table from "
+ "{uj, user, jid, name, subscription, ask, groups, xattrs, xs} format", []),
+ Host = ?MYNAME,
+ {atomic, ok} = mnesia:create_table(
+ mod_roster_tmp_table,
+ [{disc_only_copies, [node()]},
+ {type, bag},
+ {local_content, true},
+ {record_name, roster},
+ {attributes, record_info(fields, roster)}]),
+ mnesia:del_table_index(roster, user),
+ mnesia:transform_table(roster, ignore, Fields),
+ F1 = fun() ->
+ mnesia:write_lock_table(mod_roster_tmp_table),
+ mnesia:foldl(
+ fun(#roster{usj = {U, JID}, us = U} = R, _) ->
+ mnesia:dirty_write(
+ mod_roster_tmp_table,
+ R#roster{usj = {U, Host, JID},
+ us = {U, Host}})
+ end, ok, roster)
+ end,
+ mnesia:transaction(F1),
+ mnesia:clear_table(roster),
+ F2 = fun() ->
+ mnesia:write_lock_table(roster),
+ mnesia:foldl(
+ fun(R, _) ->
+ mnesia:dirty_write(R)
+ end, ok, mod_roster_tmp_table)
+ end,
+ mnesia:transaction(F2),
+ mnesia:delete_table(mod_roster_tmp_table);
+ _ ->
+ ?INFO_MSG("Recreating roster table", []),
+ mnesia:transform_table(roster, ignore, Fields)
+ end.
+