* src/mod_roster_odbc.erl: Roster support via ODBC (not completed)

* src/ejabberd_auth_internal.erl: Added remove_user hook
* src/ejabberd_auth_odbc.erl: Likewise
* src/mod_roster.erl: Use remove_user hook
* src/mod_offline.erl: Likewise
* src/mod_offline_odbc.erl: Likewise
* src/mod_last.erl: Likewise
* src/mod_last_odbc.erl: Likewise
* src/mod_vcard.erl: Likewise
* src/mod_private.erl: Likewise

* src/mod_roster.erl: Added hooks for functions exported by
mod_roster
* src/ejabberd_c2s.erl: Likewise
* src/ejabberd_sm.erl: Likewise
* src/mod_privacy.erl: Likewise
* src/mod_last.erl: Likewise
* src/mod_last_odbc.erl: Likewise

SVN Revision: 294
This commit is contained in:
Alexey Shchepin 2004-12-19 20:47:35 +00:00
parent 7c900deff9
commit 50bef3787a
14 changed files with 875 additions and 57 deletions

View File

@ -1,3 +1,25 @@
2004-12-19 Alexey Shchepin <alexey@sevcom.net>
* src/mod_roster_odbc.erl: Roster support via ODBC (not completed)
* src/ejabberd_auth_internal.erl: Added remove_user hook
* src/ejabberd_auth_odbc.erl: Likewise
* src/mod_roster.erl: Use remove_user hook
* src/mod_offline.erl: Likewise
* src/mod_offline_odbc.erl: Likewise
* src/mod_last.erl: Likewise
* src/mod_last_odbc.erl: Likewise
* src/mod_vcard.erl: Likewise
* src/mod_private.erl: Likewise
* src/mod_roster.erl: Added hooks for functions exported by
mod_roster
* src/ejabberd_c2s.erl: Likewise
* src/ejabberd_sm.erl: Likewise
* src/mod_privacy.erl: Likewise
* src/mod_last.erl: Likewise
* src/mod_last_odbc.erl: Likewise
2004-12-14 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_sm.erl: Updated missed message passing from

View File

@ -133,11 +133,7 @@ remove_user(User) ->
mnesia:delete({passwd, LUser})
end,
mnesia:transaction(F),
catch mod_roster:remove_user(User),
catch mod_offline:remove_user(User),
catch mod_last:remove_user(User),
catch mod_vcard:remove_user(User),
catch mod_private:remove_user(User).
ejabberd_hooks:run(remove_user, [User]).
remove_user(User, Password) ->
LUser = jlib:nodeprep(User),
@ -154,11 +150,7 @@ remove_user(User, Password) ->
end,
case mnesia:transaction(F) of
{atomic, ok} ->
catch mod_roster:remove_user(User),
catch mod_offline:remove_user(User),
catch mod_last:remove_user(User),
catch mod_vcard:remove_user(User),
catch mod_private:remove_user(User),
ejabberd_hooks:run(remove_user, [User]),
ok;
{atomic, Res} ->
Res;

View File

@ -174,11 +174,7 @@ remove_user(User) ->
Username = ejabberd_odbc:escape(LUser),
catch ejabberd_odbc:sql_query(
["delete from users where username='", Username ,"'"]),
catch mod_roster:remove_user(User),
catch mod_offline:remove_user(User),
catch mod_last:remove_user(User),
catch mod_vcard:remove_user(User),
catch mod_private:remove_user(User)
ejabberd_hooks:run(remove_user, [User])
end.
remove_user(User, Password) ->
@ -196,11 +192,7 @@ remove_user(User, Password) ->
"where username='", Username, "' and password='", Pass, "';"
"commit"]) of
{selected, ["password"], [{Password}]} ->
catch mod_roster:remove_user(User),
catch mod_offline:remove_user(User),
catch mod_last:remove_user(User),
catch mod_vcard:remove_user(User),
catch mod_private:remove_user(User),
ejabberd_hooks:run(remove_user, [User]),
ok;
{selected, ["password"], []} ->
not_exists;

View File

@ -314,7 +314,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
Res = setelement(4, Res1, []),
send_element(StateData, Res),
change_shaper(StateData, JID),
{Fs, Ts} = mod_roster:get_subscription_lists(U),
{Fs, Ts} = ejabberd_hooks:run_fold(
roster_get_subscription_lists,
{[], []},
[U]),
LJID = jlib:jid_tolower(
jlib:jid_remove_resource(JID)),
Fs1 = [LJID | Fs],
@ -606,7 +609,10 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
Res = jlib:make_result_iq_reply(El),
send_element(StateData, Res),
change_shaper(StateData, JID),
{Fs, Ts} = mod_roster:get_subscription_lists(U),
{Fs, Ts} = ejabberd_hooks:run_fold(
roster_get_subscription_lists,
{[], []},
[U]),
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
Fs1 = [LJID | Fs],
Ts1 = [LJID | Ts],
@ -1179,19 +1185,23 @@ presence_track(From, To, Packet, StateData) ->
pres_a = A};
"subscribe" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
mod_roster:out_subscription(User, To, subscribe),
ejabberd_hooks:run(roster_out_subscription,
[User, To, subscribe]),
StateData;
"subscribed" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
mod_roster:out_subscription(User, To, subscribed),
ejabberd_hooks:run(roster_out_subscription,
[User, To, subscribed]),
StateData;
"unsubscribe" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
mod_roster:out_subscription(User, To, unsubscribe),
ejabberd_hooks:run(roster_out_subscription,
[User, To, unsubscribe]),
StateData;
"unsubscribed" ->
ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet),
mod_roster:out_subscription(User, To, unsubscribed),
ejabberd_hooks:run(roster_out_subscription,
[User, To, unsubscribed]),
StateData;
"error" ->
ejabberd_router:route(From, To, Packet),

View File

@ -166,24 +166,28 @@ do_route(From, To, Packet) ->
{Pass, Subsc} =
case xml:get_attr_s("type", Attrs) of
"subscribe" ->
{mod_roster:in_subscription(User,
From,
subscribe),
{ejabberd_hooks:run_fold(
roster_in_subscription,
false,
[User, From, subscribe]),
true};
"subscribed" ->
{mod_roster:in_subscription(User,
From,
subscribed),
{ejabberd_hooks:run_fold(
roster_in_subscription,
false,
[User, From, subscribed]),
true};
"unsubscribe" ->
{mod_roster:in_subscription(User,
From,
unsubscribe),
{ejabberd_hooks:run_fold(
roster_in_subscription,
false,
[User, From, unsubscribe]),
true};
"unsubscribed" ->
{mod_roster:in_subscription(User,
From,
unsubscribed),
{ejabberd_hooks:run_fold(
roster_in_subscription,
false,
[User, From, unsubscribed]),
true};
_ ->
{true, false}

View File

@ -35,10 +35,16 @@ start(Opts) ->
?MODULE, process_local_iq, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST,
?MODULE, process_sm_iq, IQDisc),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
ejabberd_hooks:add(unset_presence_hook,
?MODULE, on_presence_update, 50).
stop() ->
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
ejabberd_hooks:delete(unset_presence_hook,
?MODULE, on_presence_update, 50),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_LAST).
@ -63,7 +69,8 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
get ->
User = To#jid.luser,
{Subscription, _Groups} =
mod_roster:get_jid_info(User, From),
ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, From]),
if
(Subscription == both) or (Subscription == from) ->
case catch mod_privacy:get_user_list(User) of

View File

@ -29,10 +29,16 @@ start(Opts) ->
?MODULE, process_local_iq, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST,
?MODULE, process_sm_iq, IQDisc),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
ejabberd_hooks:add(unset_presence_hook,
?MODULE, on_presence_update, 50).
stop() ->
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
ejabberd_hooks:delete(unset_presence_hook,
?MODULE, on_presence_update, 50),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_LAST).
@ -57,7 +63,8 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
get ->
User = To#jid.luser,
{Subscription, _Groups} =
mod_roster:get_jid_info(User, From),
ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, From]),
if
(Subscription == both) or (Subscription == from) ->
case catch mod_privacy:get_user_list(User) of

View File

@ -41,6 +41,8 @@ start(_) ->
?MODULE, store_packet, 50),
ejabberd_hooks:add(resend_offline_messages_hook,
?MODULE, pop_offline_messages, 50),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
register(?PROCNAME, spawn(?MODULE, init, [])).
init() ->
@ -84,6 +86,8 @@ stop() ->
?MODULE, store_packet, 50),
ejabberd_hooks:delete(resend_offline_messages_hook,
?MODULE, pop_offline_messages, 50),
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
exit(whereis(?PROCNAME), stop),
ok.

View File

@ -35,6 +35,8 @@ start(_) ->
?MODULE, store_packet, 50),
ejabberd_hooks:add(resend_offline_messages_hook,
?MODULE, pop_offline_messages, 50),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
register(?PROCNAME, spawn(?MODULE, init, [])).
init() ->
@ -100,6 +102,8 @@ stop() ->
?MODULE, store_packet, 50),
ejabberd_hooks:delete(resend_offline_messages_hook,
?MODULE, pop_offline_messages, 50),
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
exit(whereis(?PROCNAME), stop),
ok.

View File

@ -551,25 +551,29 @@ check_packet(User,
{message, in} ->
LJID = jlib:jid_tolower(From),
{Subscription, Groups} =
mod_roster:get_jid_info(User, LJID),
ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, LJID]),
check_packet_aux(List, message,
LJID, Subscription, Groups);
{iq, in} ->
LJID = jlib:jid_tolower(From),
{Subscription, Groups} =
mod_roster:get_jid_info(User, LJID),
ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, LJID]),
check_packet_aux(List, iq,
LJID, Subscription, Groups);
{presence, in} ->
LJID = jlib:jid_tolower(From),
{Subscription, Groups} =
mod_roster:get_jid_info(User, LJID),
ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, LJID]),
check_packet_aux(List, presence_in,
LJID, Subscription, Groups);
{presence, out} ->
LJID = jlib:jid_tolower(To),
{Subscription, Groups} =
mod_roster:get_jid_info(User, LJID),
ejabberd_hooks:run_fold(
roster_get_jid_info, {none, []}, [User, LJID]),
check_packet_aux(List, presence_out,
LJID, Subscription, Groups);
_ ->

View File

@ -27,10 +27,14 @@ start(Opts) ->
mnesia:create_table(private_storage,
[{disc_only_copies, [node()]},
{attributes, record_info(fields, private_storage)}]),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_PRIVATE,
?MODULE, process_sm_iq, IQDisc).
stop() ->
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_PRIVATE).

View File

@ -15,12 +15,12 @@
-export([start/1, stop/0,
process_iq/3,
process_local_iq/3,
get_subscription_lists/1,
in_subscription/3,
get_subscription_lists/2,
in_subscription/4,
out_subscription/3,
set_items/2,
remove_user/1,
get_jid_info/2]).
get_jid_info/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@ -40,10 +40,30 @@ start(Opts) ->
mnesia:create_table(roster,[{disc_copies, [node()]},
{attributes, record_info(fields, roster)}]),
mnesia:add_table_index(roster, user),
ejabberd_hooks:add(roster_in_subscription,
?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription,
?MODULE, out_subscription, 50),
ejabberd_hooks:add(roster_get_subscription_lists,
?MODULE, get_subscription_lists, 50),
ejabberd_hooks:add(roster_get_jid_info,
?MODULE, get_jid_info, 50),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_ROSTER,
?MODULE, process_iq, IQDisc).
stop() ->
ejabberd_hooks:delete(roster_in_subscription,
?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription,
?MODULE, out_subscription, 50),
ejabberd_hooks:delete(roster_get_subscription_lists,
?MODULE, get_subscription_lists, 50),
ejabberd_hooks:delete(roster_get_jid_info,
?MODULE, get_jid_info, 50),
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_ROSTER).
@ -273,13 +293,12 @@ process_item_els(Item, []) ->
push_item(User, From, Item) ->
ejabberd_sm ! {route,
jlib:make_jid("", "", ""),
jlib:make_jid(User, "", ""),
{xmlelement, "broadcast", [],
[{item,
Item#roster.jid,
Item#roster.subscription}]}},
ejabberd_sm:route(jlib:make_jid("", "", ""),
jlib:make_jid(User, "", ""),
{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)).
@ -311,7 +330,7 @@ push_item(User, Resource, From, Item) ->
-endif.
get_subscription_lists(User) ->
get_subscription_lists(_, User) ->
LUser = jlib:nodeprep(User),
case mnesia:dirty_index_read(roster, LUser, #roster.user) of
Items when is_list(Items) ->
@ -341,7 +360,7 @@ ask_to_pending(Ask) -> Ask.
in_subscription(User, JID, Type) ->
in_subscription(_, User, JID, Type) ->
process_subscription(in, User, JID, Type).
out_subscription(User, JID, Type) ->
@ -594,7 +613,7 @@ process_item_attrs_ws(Item, []) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
get_jid_info(User, JID) ->
get_jid_info(_, User, JID) ->
LUser = jlib:nodeprep(User),
LJID = jlib:jid_tolower(JID),
case catch mnesia:dirty_read(roster, {LUser, LJID}) of

745
src/mod_roster_odbc.erl Normal file
View File

@ -0,0 +1,745 @@
%%%----------------------------------------------------------------------
%%% File : mod_roster_odbc.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : Roster management
%%% Created : 15 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$
%%%----------------------------------------------------------------------
-module(mod_roster_odbc).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
-behaviour(gen_mod).
-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]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-record(roster, {user,
jid,
name = "",
subscription = none,
ask = none}).
start(Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
ejabberd_hooks:add(roster_out_subscription,
?MODULE, out_subscription, 50),
ejabberd_hooks:add(roster_in_subscription,
?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription,
?MODULE, out_subscription, 50),
ejabberd_hooks:add(roster_get_subscription_lists,
?MODULE, get_subscription_lists, 50),
ejabberd_hooks:add(roster_get_jid_info,
?MODULE, get_jid_info, 50),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_ROSTER,
?MODULE, process_iq, IQDisc).
stop() ->
ejabberd_hooks:delete(roster_in_subscription,
?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription,
?MODULE, out_subscription, 50),
ejabberd_hooks:delete(roster_get_subscription_lists,
?MODULE, get_subscription_lists, 50),
ejabberd_hooks:delete(roster_get_jid_info,
?MODULE, get_jid_info, 50),
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_ROSTER).
-define(PSI_ROSTER_WORKAROUND, true).
-ifdef(PSI_ROSTER_WORKAROUND).
process_iq(From, To, IQ) ->
#iq{sub_el = SubEl} = IQ,
#jid{lserver = LServer} = From,
case ?MYNAME of
LServer ->
ResIQ = process_local_iq(From, To, IQ),
ejabberd_router:route(From, From,
jlib:iq_to_xml(ResIQ)),
ignore;
_ ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
end.
-else.
process_iq(From, To, IQ) ->
#iq{sub_el = SubEl} = IQ,
#jid{lserver = LServer} = From,
case ?MYNAME of
LServer ->
process_local_iq(From, To, IQ);
_ ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
end.
-endif.
process_local_iq(From, To, #iq{type = Type} = IQ) ->
case Type of
set ->
process_iq_set(From, To, IQ);
get ->
process_iq_get(From, To, IQ)
end.
process_iq_get(From, _To, #iq{sub_el = SubEl} = IQ) ->
LUser = From#jid.luser,
Username = ejabberd_odbc:escape(LUser),
case catch ejabberd_odbc:sql_query(
["select username, jid, nick, subscription, ask, "
"server, subscribe, type from rosterusers "
"where username='", Username, "'"]) of
{selected, ["username", "jid", "nick", "subscription", "ask",
"server", "subscribe", "type"],
Items} when is_list(Items) ->
XItems = lists:flatmap(
fun(I) ->
case raw_to_record(I) of
error ->
[];
R ->
[item_to_xml(R)]
end
end, Items),
IQ#iq{type = result,
sub_el = [{xmlelement, "query",
[{"xmlns", ?NS_ROSTER}],
XItems}]};
_ ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
end.
item_to_xml(Item) ->
Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}],
Attrs2 = case Item#roster.name of
"" ->
Attrs1;
Name ->
[{"name", Name} | Attrs1]
end,
Attrs3 = case Item#roster.subscription of
none ->
[{"subscription", "none"} | Attrs2];
from ->
[{"subscription", "from"} | Attrs2];
to ->
[{"subscription", "to"} | Attrs2];
both ->
[{"subscription", "both"} | Attrs2];
remove ->
[{"subscription", "remove"} | Attrs2]
end,
Attrs = case ask_to_pending(Item#roster.ask) of
out ->
[{"ask", "subscribe"} | Attrs3];
both ->
[{"ask", "subscribe"} | Attrs3];
_ ->
Attrs3
end,
% TODO
%SubEls = lists:map(fun(G) ->
% {xmlelement, "group", [], [{xmlcdata, G}]}
% end, Item#roster.groups),
SubEls = [],
{xmlelement, "item", Attrs, SubEls}.
process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
{xmlelement, _Name, _Attrs, Els} = SubEl,
lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els),
IQ#iq{type = result, sub_el = []}.
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,
case JID1 of
error ->
ok;
_ ->
JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource},
LJID = jlib:jid_tolower(JID1),
Username = ejabberd_odbc:escape(LUser),
SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)),
case catch ejabberd_odbc:sql_query(
["select username, jid, nick, subscription, ask, "
"server, subscribe, type from rosterusers "
"where username='", Username, "' "
"and jid='", SJID, "'"]) of
{selected, ["username", "jid", "nick", "subscription", "ask",
"server", "subscribe", "type"],
Res} ->
Item = case Res of
[] ->
#roster{user = LUser,
jid = LJID};
[I] ->
(raw_to_record(I))#roster{user = LUser,
jid = JID,
name = ""}
end,
Item1 = process_item_attrs(Item, Attrs),
case Item1#roster.subscription of
remove ->
catch ejabberd_odbc:sql_query(
["begin;"
"delete from rosterusers "
" where username='", Username, "' "
" and jid='", SJID, "';"
"delete from rostergroups "
" where username='", Username, "' "
" and jid='", SJID, "';"
"commit"]);
_ ->
ItemVals = record_to_string(Item1),
catch ejabberd_odbc:sql_query(
["begin;"
"delete from rosterusers "
" where username='", Username, "' "
" and jid='", SJID, "';"
"insert into rosterusers("
" username, jid, nick, "
" subscription, ask, "
" server, subscribe, type) "
" values ", ItemVals, ";"
"delete from rostergroups "
" where username='", Username, "' "
" and jid='", SJID, "';"
% TODO
"commit"])
%mnesia:write(Item1)
end,
push_item(User, To, Item1),
case Item1#roster.subscription of
remove ->
IsTo = case Item#roster.subscription of
both -> true;
to -> true;
_ -> false
end,
IsFrom = case Item#roster.subscription of
both -> true;
from -> true;
_ -> false
end,
if IsTo ->
ejabberd_router:route(
jlib:jid_remove_resource(From),
jlib:make_jid(Item#roster.jid),
{xmlelement, "presence",
[{"type", "unsubscribe"}],
[]});
true -> ok
end,
if IsFrom ->
ejabberd_router:route(
jlib:jid_remove_resource(From),
jlib:make_jid(Item#roster.jid),
{xmlelement, "presence",
[{"type", "unsubscribed"}],
[]});
true -> ok
end,
ok;
_ ->
ok
end;
E ->
?DEBUG("ROSTER: roster item set error: ~p~n", [E]),
ok
end
end;
process_item_set(_From, _To, _) ->
ok.
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
case Attr of
"jid" ->
case jlib:string_to_jid(Val) of
error ->
process_item_attrs(Item, Attrs);
JID1 ->
JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource},
process_item_attrs(Item#roster{jid = JID}, Attrs)
end;
"name" ->
process_item_attrs(Item#roster{name = Val}, Attrs);
"subscription" ->
case Val of
"remove" ->
process_item_attrs(Item#roster{subscription = remove},
Attrs);
_ ->
process_item_attrs(Item, Attrs)
end;
"ask" ->
process_item_attrs(Item, Attrs);
_ ->
process_item_attrs(Item, Attrs)
end;
process_item_attrs(Item, []) ->
Item.
% TODO
%process_item_els(Item, [{xmlelement, Name, Attrs, SEls} | Els]) ->
% case Name of
% "group" ->
% Groups = [xml:get_cdata(SEls) | Item#roster.groups],
% process_item_els(Item#roster{groups = Groups}, Els);
% _ ->
% case xml:get_attr_s("xmlns", Attrs) of
% "" ->
% process_item_els(Item, Els);
% _ ->
% XEls = [{xmlelement, Name, Attrs, SEls} | Item#roster.xs],
% process_item_els(Item#roster{xs = XEls}, Els)
% end
% end;
process_item_els(Item, [{xmlcdata, _} | Els]) ->
process_item_els(Item, Els);
process_item_els(Item, []) ->
Item.
push_item(User, From, Item) ->
ejabberd_sm:route(jlib:make_jid("", "", ""),
jlib:make_jid(User, "", ""),
{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)).
% TODO: don't push to those who not load roster
-ifdef(PSI_ROSTER_WORKAROUND).
push_item(User, 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:iq_to_xml(ResIQ)).
-else.
push_item(User, 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:iq_to_xml(ResIQ)).
-endif.
get_subscription_lists(_, User) ->
LUser = jlib:nodeprep(User),
Username = ejabberd_odbc:escape(LUser),
case catch ejabberd_odbc:sql_query(
["select username, jid, nick, subscription, ask, "
"server, subscribe, type from rosterusers "
"where username='", Username, "'"]) of
{selected, ["username", "jid", "nick", "subscription", "ask",
"server", "subscribe", "type"],
Items} when is_list(Items) ->
fill_subscription_lists(Items, [], []);
_ ->
{[], []}
end.
fill_subscription_lists([I | Is], F, T) ->
J = I#roster.jid,
case I#roster.subscription of
both ->
fill_subscription_lists(Is, [J | F], [J | T]);
from ->
fill_subscription_lists(Is, [J | F], T);
to ->
fill_subscription_lists(Is, F, [J | T]);
_ ->
fill_subscription_lists(Is, F, T)
end;
fill_subscription_lists([], F, T) ->
{F, T}.
ask_to_pending(subscribe) -> out;
ask_to_pending(unsubscribe) -> none;
ask_to_pending(Ask) -> Ask.
in_subscription(_, User, JID, Type) ->
process_subscription(in, User, JID, Type).
out_subscription(User, JID, Type) ->
process_subscription(out, User, JID, Type).
process_subscription(Direction, User, JID1, Type) ->
LUser = jlib:nodeprep(User),
LJID = jlib:jid_tolower(JID1),
Username = ejabberd_odbc:escape(LUser),
SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)),
Item = case catch ejabberd_odbc:sql_query(
["select username, jid, nick, subscription, ask, "
"server, subscribe, type from rosterusers "
"where username='", Username, "' "
"and jid='", SJID, "'"]) of
{selected, ["username", "jid", "nick", "subscription", "ask",
"server", "subscribe", "type"],
[I]} ->
raw_to_record(I);
_ ->
#roster{user = LUser,
jid = LJID}
end,
NewState = case Direction of
out ->
out_state_change(Item#roster.subscription,
Item#roster.ask,
Type);
in ->
in_state_change(Item#roster.subscription,
Item#roster.ask,
Type)
end,
AutoReply = case Direction of
out ->
none;
in ->
in_auto_reply(Item#roster.subscription,
Item#roster.ask,
Type)
end,
Push = case NewState of
none ->
none;
{Subscription, Pending} ->
NewItem = Item#roster{subscription = Subscription,
ask = Pending},
ItemVals = record_to_string(NewItem),
catch ejabberd_odbc:sql_query(
["begin;"
"delete from rosterusers "
" where username='", Username, "' "
" and jid='", SJID, "';"
"insert into rosterusers("
" username, jid, nick, "
" subscription, ask, "
" server, subscribe, type) "
" values ", ItemVals, ";"
"commit"]),
{push, NewItem}
end,
case AutoReply of
none ->
ok;
_ ->
T = case AutoReply of
subscribed -> "subscribed";
unsubscribed -> "unsubscribed"
end,
ejabberd_router:route(
jlib:make_jid(User, ?MYNAME, ""), JID1,
{xmlelement, "presence", [{"type", T}], []})
end,
case Push of
{push, PushItem} ->
push_item(User, jlib:make_jid("", ?MYNAME, ""), PushItem),
true;
none ->
false
end.
%% in_state_change(Subscription, Pending, Type) -> NewState
%% NewState = none | {NewSubscription, NewPending}
in_state_change(none, none, subscribe) -> {none, in};
in_state_change(none, none, subscribed) -> {to, none}; % Workaround for gateways
%in_state_change(none, none, subscribed) -> none;
in_state_change(none, none, unsubscribe) -> none;
in_state_change(none, none, unsubscribed) -> none;
in_state_change(none, out, subscribe) -> {none, both};
in_state_change(none, out, subscribed) -> {to, none};
in_state_change(none, out, unsubscribe) -> none;
in_state_change(none, out, unsubscribed) -> {none, none};
in_state_change(none, in, subscribe) -> none;
in_state_change(none, in, subscribed) -> {to, in}; % Workaround for gateways
%in_state_change(none, in, subscribed) -> none;
in_state_change(none, in, unsubscribe) -> {none, none};
in_state_change(none, in, unsubscribed) -> none;
in_state_change(none, both, subscribe) -> none;
in_state_change(none, both, subscribed) -> {to, in};
in_state_change(none, both, unsubscribe) -> {none, out};
in_state_change(none, both, unsubscribed) -> {none, in};
in_state_change(to, none, subscribe) -> {to, in};
in_state_change(to, none, subscribed) -> none;
in_state_change(to, none, unsubscribe) -> none;
in_state_change(to, none, unsubscribed) -> {none, none};
in_state_change(to, in, subscribe) -> none;
in_state_change(to, in, subscribed) -> none;
in_state_change(to, in, unsubscribe) -> {to, none};
in_state_change(to, in, unsubscribed) -> {none, in};
in_state_change(from, none, subscribe) -> none;
in_state_change(from, none, subscribed) -> none;
in_state_change(from, none, unsubscribe) -> {none, none};
in_state_change(from, none, unsubscribed) -> none;
in_state_change(from, out, subscribe) -> none;
in_state_change(from, out, subscribed) -> {both, none};
in_state_change(from, out, unsubscribe) -> {none, out};
in_state_change(from, out, unsubscribed) -> {from, none};
in_state_change(both, none, subscribe) -> none;
in_state_change(both, none, subscribed) -> none;
in_state_change(both, none, unsubscribe) -> {to, none};
in_state_change(both, none, unsubscribed) -> {from, none}.
out_state_change(none, none, subscribe) -> {none, out};
out_state_change(none, none, subscribed) -> none;
out_state_change(none, none, unsubscribe) -> none;
out_state_change(none, none, unsubscribed) -> none;
out_state_change(none, out, subscribe) -> none;
out_state_change(none, out, subscribed) -> none;
out_state_change(none, out, unsubscribe) -> {none, none};
out_state_change(none, out, unsubscribed) -> none;
out_state_change(none, in, subscribe) -> {none, both};
out_state_change(none, in, subscribed) -> {from, none};
out_state_change(none, in, unsubscribe) -> none;
out_state_change(none, in, unsubscribed) -> {none, none};
out_state_change(none, both, subscribe) -> none;
out_state_change(none, both, subscribed) -> {from, out};
out_state_change(none, both, unsubscribe) -> {none, in};
out_state_change(none, both, unsubscribed) -> {none, out};
out_state_change(to, none, subscribe) -> none;
out_state_change(to, none, subscribed) -> none;
out_state_change(to, none, unsubscribe) -> {none, none};
out_state_change(to, none, unsubscribed) -> none;
out_state_change(to, in, subscribe) -> none;
out_state_change(to, in, subscribed) -> {both, none};
out_state_change(to, in, unsubscribe) -> {none, in};
out_state_change(to, in, unsubscribed) -> {to, none};
out_state_change(from, none, subscribe) -> {from, out};
out_state_change(from, none, subscribed) -> none;
out_state_change(from, none, unsubscribe) -> none;
out_state_change(from, none, unsubscribed) -> {none, none};
out_state_change(from, out, subscribe) -> none;
out_state_change(from, out, subscribed) -> none;
out_state_change(from, out, unsubscribe) -> {from, none};
out_state_change(from, out, unsubscribed) -> {none, out};
out_state_change(both, none, subscribe) -> none;
out_state_change(both, none, subscribed) -> none;
out_state_change(both, none, unsubscribe) -> {from, none};
out_state_change(both, none, unsubscribed) -> {to, none}.
in_auto_reply(from, none, subscribe) -> subscribed;
in_auto_reply(from, out, subscribe) -> subscribed;
in_auto_reply(both, none, subscribe) -> subscribed;
in_auto_reply(none, in, unsubscribe) -> unsubscribed;
in_auto_reply(none, both, unsubscribe) -> unsubscribed;
in_auto_reply(to, in, unsubscribe) -> unsubscribed;
in_auto_reply(from, none, unsubscribe) -> unsubscribed;
in_auto_reply(from, out, unsubscribe) -> unsubscribed;
in_auto_reply(both, none, unsubscribe) -> unsubscribed;
in_auto_reply(_, _, _) -> none.
remove_user(User) ->
LUser = jlib:nodeprep(User),
Username = ejabberd_odbc:escape(LUser),
catch ejabberd_odbc:sql_query(
["begin;"
"delete from rosterusers "
" where username='", Username, "';"
"delete from rostergroups "
" where username='", Username, "';"
"commit"]),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_items(User, SubEl) ->
{xmlelement, _Name, _Attrs, Els} = SubEl,
LUser = jlib:nodeprep(User),
F = fun() ->
lists:foreach(fun(El) -> process_item_set_t(LUser, El) end, Els)
end,
mnesia:transaction(F).
process_item_set_t(LUser, {xmlelement, _Name, Attrs, Els}) ->
JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)),
case JID1 of
error ->
ok;
_ ->
JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource},
LJID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource},
Item = #roster{user = LUser,
jid = LJID},
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:write(Item2)
end
end;
process_item_set_t(_LUser, _) ->
ok.
process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) ->
case Attr of
"jid" ->
case jlib:string_to_jid(Val) of
error ->
process_item_attrs_ws(Item, Attrs);
JID1 ->
JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource},
process_item_attrs_ws(Item#roster{jid = JID}, Attrs)
end;
"name" ->
process_item_attrs_ws(Item#roster{name = Val}, Attrs);
"subscription" ->
case Val of
"remove" ->
process_item_attrs_ws(Item#roster{subscription = remove},
Attrs);
"none" ->
process_item_attrs_ws(Item#roster{subscription = none},
Attrs);
"both" ->
process_item_attrs_ws(Item#roster{subscription = both},
Attrs);
"from" ->
process_item_attrs_ws(Item#roster{subscription = from},
Attrs);
"to" ->
process_item_attrs_ws(Item#roster{subscription = to},
Attrs);
_ ->
process_item_attrs_ws(Item, Attrs)
end;
"ask" ->
process_item_attrs_ws(Item, Attrs);
_ ->
process_item_attrs_ws(Item, Attrs)
end;
process_item_attrs_ws(Item, []) ->
Item.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
get_jid_info(_, User, JID) ->
% TODO
% LUser = jlib:nodeprep(User),
% LJID = jlib:jid_tolower(JID),
% case catch mnesia:dirty_read(roster, {LUser, LJID}) of
% [#roster{subscription = Subscription, groups = Groups}] ->
% {Subscription, Groups};
% _ ->
% LRJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
% if
% LRJID == LJID ->
% {none, []};
% true ->
% case catch mnesia:dirty_read(roster, {LUser, LRJID}) of
% [#roster{subscription = Subscription,
% groups = Groups}] ->
% {Subscription, Groups};
% _ ->
% {none, []}
% end
% end
% end.
{none, []}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
raw_to_record({User, SJID, Nick, SSubscription, SAsk,
_SServer, _SSubscribe, _SType}) ->
case jlib:string_to_jid(SJID) of
error ->
error;
JID ->
LJID = jlib:jid_tolower(JID),
Subscription = case SSubscription of
"B" -> both;
"T" -> to;
"F" -> from;
_ -> none
end,
Ask = case SAsk of
"S" -> subscribe;
"U" -> unsubscribe;
"B" -> both;
"O" -> out;
"I" -> in;
_ -> none
end,
#roster{user = User,
jid = LJID,
name = Nick,
subscription = Subscription,
ask = Ask}
end.
record_to_string(#roster{user = User,
jid = JID,
name = Name,
subscription = Subscription,
ask = Ask}) ->
Username = ejabberd_odbc:escape(User),
SJID = ejabberd_odbc:escape(jlib:jid_to_string(JID)),
Nick = ejabberd_odbc:escape(Name),
SSubscription = case Subscription of
both -> "B";
to -> "T";
from -> "F";
none -> "N"
end,
SAsk = case Ask of
subscribe -> "S";
unsubscribe -> "U";
both -> "B";
out -> "O";
in -> "I";
none -> "N"
end,
["("
"'", Username, "',"
"'", SJID, "',"
"'", Nick, "',"
"'", SSubscription, "',"
"'", SAsk, "',"
"'N', '', 'item')"].

View File

@ -60,6 +60,8 @@ start(Opts) ->
mnesia:add_table_index(vcard_search, lorgname),
mnesia:add_table_index(vcard_search, lorgunit),
ejabberd_hooks:add(remove_user,
?MODULE, remove_user, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_VCARD,
?MODULE, process_local_iq, IQDisc),
@ -98,6 +100,8 @@ loop(Host) ->
end.
stop() ->
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VCARD),
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_VCARD),
catch mod_disco:unregister_sm_feature(?NS_VCARD),