aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2004-12-19 20:47:35 +0000
committerAlexey Shchepin <alexey@process-one.net>2004-12-19 20:47:35 +0000
commit50bef3787af73806f7311404bb1210a837999a15 (patch)
tree34cb72131fbd3d1834e7d781cfd028d885379111 /src
parent* src/ejabberd_sm.erl: Updated missed message passing from (diff)
* 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
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_auth_internal.erl12
-rw-r--r--src/ejabberd_auth_odbc.erl12
-rw-r--r--src/ejabberd_c2s.erl22
-rw-r--r--src/ejabberd_sm.erl28
-rw-r--r--src/mod_last.erl9
-rw-r--r--src/mod_last_odbc.erl9
-rw-r--r--src/mod_offline.erl4
-rw-r--r--src/mod_offline_odbc.erl4
-rw-r--r--src/mod_privacy.erl12
-rw-r--r--src/mod_private.erl4
-rw-r--r--src/mod_roster.erl45
-rw-r--r--src/mod_roster_odbc.erl745
-rw-r--r--src/mod_vcard.erl4
13 files changed, 853 insertions, 57 deletions
diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl
index b502eaf95..1743c8478 100644
--- a/src/ejabberd_auth_internal.erl
+++ b/src/ejabberd_auth_internal.erl
@@ -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;
diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl
index 8003338f1..35d1f92d0 100644
--- a/src/ejabberd_auth_odbc.erl
+++ b/src/ejabberd_auth_odbc.erl
@@ -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;
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 92b3fb214..c46e77ca3 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -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),
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index 4bf59fb12..85b9b8456 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -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}
diff --git a/src/mod_last.erl b/src/mod_last.erl
index 3e7a73fd9..c20b83b0a 100644
--- a/src/mod_last.erl
+++ b/src/mod_last.erl
@@ -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
diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl
index 4937778db..1a670afc1 100644
--- a/src/mod_last_odbc.erl
+++ b/src/mod_last_odbc.erl
@@ -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
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 6959dbcef..b59987e4b 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -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.
diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl
index abc06b471..e2f87c67c 100644
--- a/src/mod_offline_odbc.erl
+++ b/src/mod_offline_odbc.erl
@@ -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.
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl
index b89012e96..166a11c40 100644
--- a/src/mod_privacy.erl
+++ b/src/mod_privacy.erl
@@ -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);
_ ->
diff --git a/src/mod_private.erl b/src/mod_private.erl
index fa77ab5a1..487386fd9 100644
--- a/src/mod_private.erl
+++ b/src/mod_private.erl
@@ -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).
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index b356b412e..724b8d682 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -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
diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl
new file mode 100644
index 000000000..bc6a8e324
--- /dev/null
+++ b/src/mod_roster_odbc.erl
@@ -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')"].
+
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index 786bca78b..08789f115 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -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),