diff options
Diffstat (limited to 'src/mod_privacy.erl')
-rw-r--r-- | src/mod_privacy.erl | 1583 |
1 files changed, 795 insertions, 788 deletions
diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 4163551be..17b9299c5 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -25,963 +25,911 @@ %%%---------------------------------------------------------------------- -module(mod_privacy). + -author('alexey@process-one.net'). -behaviour(gen_mod). --export([start/2, stop/1, - process_iq/3, - process_iq_set/4, - process_iq_get/5, - get_user_list/3, - check_packet/6, - remove_user/2, - item_to_raw/1, - raw_to_item/1, - is_list_needdb/1, - updated_list/3]). +-export([start/2, stop/1, process_iq/3, export/1, + process_iq_set/4, process_iq_get/5, get_user_list/3, + check_packet/6, remove_user/2, item_to_raw/1, + raw_to_item/1, is_list_needdb/1, updated_list/3, + item_to_xml/1, get_user_lists/2]). %% For mod_blocking -export([sql_add_privacy_list/2, - sql_get_default_privacy_list/2, - sql_get_default_privacy_list_t/1, - sql_get_privacy_list_data/3, - sql_get_privacy_list_data_by_id_t/1, - sql_get_privacy_list_id_t/2, - sql_set_default_privacy_list/2, - sql_set_privacy_list/2]). + sql_get_default_privacy_list/2, + sql_get_default_privacy_list_t/1, + sql_get_privacy_list_data/3, + sql_get_privacy_list_data_by_id_t/1, + sql_get_privacy_list_id_t/2, + sql_set_default_privacy_list/2, + sql_set_privacy_list/2]). -include("ejabberd.hrl"). + -include("jlib.hrl"). --include("mod_privacy.hrl"). +-include("mod_privacy.hrl"). start(Host, Opts) -> - IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, + one_queue), case gen_mod:db_type(Opts) of - mnesia -> - mnesia:create_table(privacy, - [{disc_copies, [node()]}, - {attributes, record_info(fields, privacy)}]), - update_table(); - _ -> - ok + mnesia -> + mnesia:create_table(privacy, + [{disc_copies, [node()]}, + {attributes, record_info(fields, privacy)}]), + update_table(); + _ -> ok end, - ejabberd_hooks:add(privacy_iq_get, Host, - ?MODULE, process_iq_get, 50), - ejabberd_hooks:add(privacy_iq_set, Host, - ?MODULE, process_iq_set, 50), - ejabberd_hooks:add(privacy_get_user_list, Host, - ?MODULE, get_user_list, 50), - ejabberd_hooks:add(privacy_check_packet, Host, - ?MODULE, check_packet, 50), - ejabberd_hooks:add(privacy_updated_list, Host, - ?MODULE, updated_list, 50), - ejabberd_hooks:add(remove_user, Host, - ?MODULE, remove_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY, - ?MODULE, process_iq, IQDisc). + ejabberd_hooks:add(privacy_iq_get, Host, ?MODULE, + process_iq_get, 50), + ejabberd_hooks:add(privacy_iq_set, Host, ?MODULE, + process_iq_set, 50), + ejabberd_hooks:add(privacy_get_user_list, Host, ?MODULE, + get_user_list, 50), + ejabberd_hooks:add(privacy_check_packet, Host, ?MODULE, + check_packet, 50), + ejabberd_hooks:add(privacy_updated_list, Host, ?MODULE, + updated_list, 50), + ejabberd_hooks:add(remove_user, Host, ?MODULE, + remove_user, 50), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, + ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(privacy_iq_get, Host, - ?MODULE, process_iq_get, 50), - ejabberd_hooks:delete(privacy_iq_set, Host, - ?MODULE, process_iq_set, 50), + ejabberd_hooks:delete(privacy_iq_get, Host, ?MODULE, + process_iq_get, 50), + ejabberd_hooks:delete(privacy_iq_set, Host, ?MODULE, + process_iq_set, 50), ejabberd_hooks:delete(privacy_get_user_list, Host, ?MODULE, get_user_list, 50), ejabberd_hooks:delete(privacy_check_packet, Host, ?MODULE, check_packet, 50), ejabberd_hooks:delete(privacy_updated_list, Host, ?MODULE, updated_list, 50), - ejabberd_hooks:delete(remove_user, Host, - ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). + ejabberd_hooks:delete(remove_user, Host, ?MODULE, + remove_user, 50), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, + ?NS_PRIVACY). process_iq(_From, _To, IQ) -> SubEl = IQ#iq.sub_el, IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. - process_iq_get(_, From, _To, #iq{sub_el = SubEl}, #userlist{name = Active}) -> #jid{luser = LUser, lserver = LServer} = From, - {xmlelement, _, _, Els} = SubEl, + #xmlel{children = Els} = SubEl, case xml:remove_cdata(Els) of - [] -> - process_lists_get(LUser, LServer, Active); - [{xmlelement, Name, Attrs, _SubEls}] -> - case Name of - "list" -> - ListName = xml:get_attr("name", Attrs), - process_list_get(LUser, LServer, ListName); - _ -> - {error, ?ERR_BAD_REQUEST} - end; - _ -> - {error, ?ERR_BAD_REQUEST} + [] -> process_lists_get(LUser, LServer, Active); + [#xmlel{name = Name, attrs = Attrs}] -> + case Name of + <<"list">> -> + ListName = xml:get_attr(<<"name">>, Attrs), + process_list_get(LUser, LServer, ListName); + _ -> {error, ?ERR_BAD_REQUEST} + end; + _ -> {error, ?ERR_BAD_REQUEST} end. process_lists_get(LUser, LServer, Active) -> case process_lists_get(LUser, LServer, Active, - gen_mod:db_type(LServer, ?MODULE)) of - error -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - {_Default, []} -> - {result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], []}]}; - {Default, LItems} -> - DItems = - case Default of - none -> - LItems; - _ -> - [{xmlelement, "default", - [{"name", Default}], []} | LItems] - end, - ADItems = - case Active of - none -> - DItems; - _ -> - [{xmlelement, "active", - [{"name", Active}], []} | DItems] - end, - {result, - [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - ADItems}]} + gen_mod:db_type(LServer, ?MODULE)) + of + error -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + {_Default, []} -> + {result, + [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_PRIVACY}], children = []}]}; + {Default, LItems} -> + DItems = case Default of + none -> LItems; + _ -> + [#xmlel{name = <<"default">>, + attrs = [{<<"name">>, Default}], children = []} + | LItems] + end, + ADItems = case Active of + none -> DItems; + _ -> + [#xmlel{name = <<"active">>, + attrs = [{<<"name">>, Active}], children = []} + | DItems] + end, + {result, + [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_PRIVACY}], + children = ADItems}]} end. process_lists_get(LUser, LServer, _Active, mnesia) -> - case catch mnesia:dirty_read(privacy, {LUser, LServer}) of - {'EXIT', _Reason} -> - error; - [] -> - {none, []}; - [#privacy{default = Default, lists = Lists}] -> - LItems = lists:map( - fun({N, _}) -> - {xmlelement, "list", [{"name", N}], []} - end, Lists), - {Default, LItems} + case catch mnesia:dirty_read(privacy, {LUser, LServer}) + of + {'EXIT', _Reason} -> error; + [] -> {none, []}; + [#privacy{default = Default, lists = Lists}] -> + LItems = lists:map(fun ({N, _}) -> + #xmlel{name = <<"list">>, + attrs = [{<<"name">>, N}], + children = []} + end, + Lists), + {Default, LItems} end; process_lists_get(LUser, LServer, _Active, odbc) -> - Default = case catch sql_get_default_privacy_list(LUser, LServer) of - {selected, ["name"], []} -> - none; - {selected, ["name"], [{DefName}]} -> - DefName; - _ -> - none + Default = case catch sql_get_default_privacy_list(LUser, + LServer) + of + {selected, [<<"name">>], []} -> none; + {selected, [<<"name">>], [[DefName]]} -> DefName; + _ -> none end, case catch sql_get_privacy_list_names(LUser, LServer) of - {selected, ["name"], Names} -> - LItems = lists:map( - fun({N}) -> - {xmlelement, "list", [{"name", N}], []} - end, Names), - {Default, LItems}; - _ -> - error + {selected, [<<"name">>], Names} -> + LItems = lists:map(fun ([N]) -> + #xmlel{name = <<"list">>, + attrs = [{<<"name">>, N}], + children = []} + end, + Names), + {Default, LItems}; + _ -> error end. process_list_get(LUser, LServer, {value, Name}) -> case process_list_get(LUser, LServer, Name, - gen_mod:db_type(LServer, ?MODULE)) of - error -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - not_found -> - {error, ?ERR_ITEM_NOT_FOUND}; - Items -> - LItems = lists:map(fun item_to_xml/1, Items), - {result, - [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - [{xmlelement, "list", - [{"name", Name}], LItems}]}]} + gen_mod:db_type(LServer, ?MODULE)) + of + error -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + not_found -> {error, ?ERR_ITEM_NOT_FOUND}; + Items -> + LItems = lists:map(fun item_to_xml/1, Items), + {result, + [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_PRIVACY}], + children = + [#xmlel{name = <<"list">>, attrs = [{<<"name">>, Name}], + children = LItems}]}]} end; process_list_get(_LUser, _LServer, false) -> {error, ?ERR_BAD_REQUEST}. process_list_get(LUser, LServer, Name, mnesia) -> - case catch mnesia:dirty_read(privacy, {LUser, LServer}) of - {'EXIT', _Reason} -> - error; - [] -> - not_found; - [#privacy{lists = Lists}] -> - case lists:keysearch(Name, 1, Lists) of - {value, {_, List}} -> - List; - _ -> - not_found - end + case catch mnesia:dirty_read(privacy, {LUser, LServer}) + of + {'EXIT', _Reason} -> error; + [] -> not_found; + [#privacy{lists = Lists}] -> + case lists:keysearch(Name, 1, Lists) of + {value, {_, List}} -> List; + _ -> not_found + end end; process_list_get(LUser, LServer, Name, odbc) -> - case catch sql_get_privacy_list_id(LUser, LServer, Name) of - {selected, ["id"], []} -> - not_found; - {selected, ["id"], [{ID}]} -> - case catch sql_get_privacy_list_data_by_id(ID, LServer) of - {selected, ["t", "value", "action", "ord", "match_all", - "match_iq", "match_message", - "match_presence_in", "match_presence_out"], - RItems} -> - lists:map(fun raw_to_item/1, RItems); - _ -> - error - end; - _ -> - error + case catch sql_get_privacy_list_id(LUser, LServer, Name) + of + {selected, [<<"id">>], []} -> not_found; + {selected, [<<"id">>], [[ID]]} -> + case catch sql_get_privacy_list_data_by_id(ID, LServer) + of + {selected, + [<<"t">>, <<"value">>, <<"action">>, <<"ord">>, + <<"match_all">>, <<"match_iq">>, <<"match_message">>, + <<"match_presence_in">>, <<"match_presence_out">>], + RItems} -> + lists:map(fun raw_to_item/1, RItems); + _ -> error + end; + _ -> error end. item_to_xml(Item) -> - Attrs1 = [{"action", action_to_list(Item#listitem.action)}, - {"order", order_to_list(Item#listitem.order)}], + Attrs1 = [{<<"action">>, + action_to_list(Item#listitem.action)}, + {<<"order">>, order_to_list(Item#listitem.order)}], Attrs2 = case Item#listitem.type of - none -> - Attrs1; - Type -> - [{"type", type_to_list(Item#listitem.type)}, - {"value", value_to_list(Type, Item#listitem.value)} | - Attrs1] + none -> Attrs1; + Type -> + [{<<"type">>, type_to_list(Item#listitem.type)}, + {<<"value">>, value_to_list(Type, Item#listitem.value)} + | Attrs1] end, SubEls = case Item#listitem.match_all of - true -> - []; - false -> - SE1 = case Item#listitem.match_iq of - true -> - [{xmlelement, "iq", [], []}]; - false -> - [] - end, - SE2 = case Item#listitem.match_message of - true -> - [{xmlelement, "message", [], []} | SE1]; - false -> - SE1 - end, - SE3 = case Item#listitem.match_presence_in of - true -> - [{xmlelement, "presence-in", [], []} | SE2]; - false -> - SE2 - end, - SE4 = case Item#listitem.match_presence_out of - true -> - [{xmlelement, "presence-out", [], []} | SE3]; - false -> - SE3 - end, - SE4 + true -> []; + false -> + SE1 = case Item#listitem.match_iq of + true -> + [#xmlel{name = <<"iq">>, attrs = [], + children = []}]; + false -> [] + end, + SE2 = case Item#listitem.match_message of + true -> + [#xmlel{name = <<"message">>, attrs = [], + children = []} + | SE1]; + false -> SE1 + end, + SE3 = case Item#listitem.match_presence_in of + true -> + [#xmlel{name = <<"presence-in">>, attrs = [], + children = []} + | SE2]; + false -> SE2 + end, + SE4 = case Item#listitem.match_presence_out of + true -> + [#xmlel{name = <<"presence-out">>, attrs = [], + children = []} + | SE3]; + false -> SE3 + end, + SE4 end, - {xmlelement, "item", Attrs2, SubEls}. - + #xmlel{name = <<"item">>, attrs = Attrs2, + children = SubEls}. action_to_list(Action) -> case Action of - allow -> "allow"; - deny -> "deny" + allow -> <<"allow">>; + deny -> <<"deny">> end. order_to_list(Order) -> - integer_to_list(Order). + iolist_to_binary(integer_to_list(Order)). type_to_list(Type) -> case Type of - jid -> "jid"; - group -> "group"; - subscription -> "subscription" + jid -> <<"jid">>; + group -> <<"group">>; + subscription -> <<"subscription">> end. value_to_list(Type, Val) -> case Type of - jid -> jlib:jid_to_string(Val); - group -> Val; - subscription -> - case Val of - both -> "both"; - to -> "to"; - from -> "from"; - none -> "none" - end + jid -> jlib:jid_to_string(Val); + group -> Val; + subscription -> + case Val of + both -> <<"both">>; + to -> <<"to">>; + from -> <<"from">>; + none -> <<"none">> + end end. - - list_to_action(S) -> case S of - "allow" -> allow; - "deny" -> deny + <<"allow">> -> allow; + <<"deny">> -> deny end. - - process_iq_set(_, From, _To, #iq{sub_el = SubEl}) -> #jid{luser = LUser, lserver = LServer} = From, - {xmlelement, _, _, Els} = SubEl, + #xmlel{children = Els} = SubEl, case xml:remove_cdata(Els) of - [{xmlelement, Name, Attrs, SubEls}] -> - ListName = xml:get_attr("name", Attrs), - case Name of - "list" -> - process_list_set(LUser, LServer, ListName, - xml:remove_cdata(SubEls)); - "active" -> - process_active_set(LUser, LServer, ListName); - "default" -> - process_default_set(LUser, LServer, ListName); - _ -> - {error, ?ERR_BAD_REQUEST} - end; - _ -> - {error, ?ERR_BAD_REQUEST} + [#xmlel{name = Name, attrs = Attrs, + children = SubEls}] -> + ListName = xml:get_attr(<<"name">>, Attrs), + case Name of + <<"list">> -> + process_list_set(LUser, LServer, ListName, + xml:remove_cdata(SubEls)); + <<"active">> -> + process_active_set(LUser, LServer, ListName); + <<"default">> -> + process_default_set(LUser, LServer, ListName); + _ -> {error, ?ERR_BAD_REQUEST} + end; + _ -> {error, ?ERR_BAD_REQUEST} end. process_default_set(LUser, LServer, Value) -> case process_default_set(LUser, LServer, Value, - gen_mod:db_type(LServer, ?MODULE)) of - {atomic, error} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - {atomic, not_found} -> - {error, ?ERR_ITEM_NOT_FOUND}; - {atomic, ok} -> - {result, []}; - _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + gen_mod:db_type(LServer, ?MODULE)) + of + {atomic, error} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + {atomic, not_found} -> {error, ?ERR_ITEM_NOT_FOUND}; + {atomic, ok} -> {result, []}; + _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} end. -process_default_set(LUser, LServer, {value, Name}, mnesia) -> - F = fun() -> +process_default_set(LUser, LServer, {value, Name}, + mnesia) -> + F = fun () -> case mnesia:read({privacy, {LUser, LServer}}) of - [] -> - not_found; - [#privacy{lists = Lists} = P] -> - case lists:keymember(Name, 1, Lists) of - true -> - mnesia:write(P#privacy{default = Name, - lists = Lists}), - ok; - false -> - not_found - end + [] -> not_found; + [#privacy{lists = Lists} = P] -> + case lists:keymember(Name, 1, Lists) of + true -> + mnesia:write(P#privacy{default = Name, + lists = Lists}), + ok; + false -> not_found + end end end, mnesia:transaction(F); -process_default_set(LUser, LServer, {value, Name}, odbc) -> - F = fun() -> +process_default_set(LUser, LServer, {value, Name}, + odbc) -> + F = fun () -> case sql_get_privacy_list_names_t(LUser) of - {selected, ["name"], []} -> - not_found; - {selected, ["name"], Names} -> - case lists:member({Name}, Names) of - true -> - sql_set_default_privacy_list(LUser, Name), - ok; - false -> - not_found - end + {selected, [<<"name">>], []} -> not_found; + {selected, [<<"name">>], Names} -> + case lists:member([Name], Names) of + true -> sql_set_default_privacy_list(LUser, Name), ok; + false -> not_found + end end end, odbc_queries:sql_transaction(LServer, F); process_default_set(LUser, LServer, false, mnesia) -> - F = fun() -> + F = fun () -> case mnesia:read({privacy, {LUser, LServer}}) of - [] -> - ok; - [R] -> - mnesia:write(R#privacy{default = none}) + [] -> ok; + [R] -> mnesia:write(R#privacy{default = none}) end end, mnesia:transaction(F); process_default_set(LUser, LServer, false, odbc) -> - case catch sql_unset_default_privacy_list(LUser, LServer) of - {'EXIT', _Reason} -> - {atomic, error}; - {error, _Reason} -> - {atomic, error}; - _ -> - {atomic, ok} + case catch sql_unset_default_privacy_list(LUser, + LServer) + of + {'EXIT', _Reason} -> {atomic, error}; + {error, _Reason} -> {atomic, error}; + _ -> {atomic, ok} end. process_active_set(LUser, LServer, {value, Name}) -> case process_active_set(LUser, LServer, Name, - gen_mod:db_type(LServer, ?MODULE)) of - error -> - {error, ?ERR_ITEM_NOT_FOUND}; - Items -> - NeedDb = is_list_needdb(Items), - {result, [], #userlist{name = Name, list = Items, needdb = NeedDb}} + gen_mod:db_type(LServer, ?MODULE)) + of + error -> {error, ?ERR_ITEM_NOT_FOUND}; + Items -> + NeedDb = is_list_needdb(Items), + {result, [], + #userlist{name = Name, list = Items, needdb = NeedDb}} end; process_active_set(_LUser, _LServer, false) -> {result, [], #userlist{}}. process_active_set(LUser, LServer, Name, mnesia) -> - case catch mnesia:dirty_read(privacy, {LUser, LServer}) of - [] -> - error; - [#privacy{lists = Lists}] -> - case lists:keysearch(Name, 1, Lists) of - {value, {_, List}} -> - List; - false -> - error - end + case catch mnesia:dirty_read(privacy, {LUser, LServer}) + of + [] -> error; + [#privacy{lists = Lists}] -> + case lists:keysearch(Name, 1, Lists) of + {value, {_, List}} -> List; + false -> error + end end; process_active_set(LUser, LServer, Name, odbc) -> - case catch sql_get_privacy_list_id(LUser, LServer, Name) of - {selected, ["id"], []} -> - error; - {selected, ["id"], [{ID}]} -> - case catch sql_get_privacy_list_data_by_id(ID, LServer) of - {selected, ["t", "value", "action", "ord", "match_all", - "match_iq", "match_message", - "match_presence_in", "match_presence_out"], - RItems} -> - lists:map(fun raw_to_item/1, RItems); - _ -> - error - end; - _ -> - error + case catch sql_get_privacy_list_id(LUser, LServer, Name) + of + {selected, [<<"id">>], []} -> error; + {selected, [<<"id">>], [[ID]]} -> + case catch sql_get_privacy_list_data_by_id(ID, LServer) + of + {selected, + [<<"t">>, <<"value">>, <<"action">>, <<"ord">>, + <<"match_all">>, <<"match_iq">>, <<"match_message">>, + <<"match_presence_in">>, <<"match_presence_out">>], + RItems} -> + lists:map(fun raw_to_item/1, RItems); + _ -> error + end; + _ -> error end. remove_privacy_list(LUser, LServer, Name, mnesia) -> - F = fun() -> - case mnesia:read({privacy, {LUser, LServer}}) of - [] -> - ok; - [#privacy{default = Default, lists = Lists} = P] -> - %% TODO: check active - if - Name == Default -> - conflict; - true -> - NewLists = - lists:keydelete(Name, 1, Lists), - mnesia:write( - P#privacy{lists = NewLists}) - end - end - end, + F = fun () -> + case mnesia:read({privacy, {LUser, LServer}}) of + [] -> ok; + [#privacy{default = Default, lists = Lists} = P] -> + if Name == Default -> conflict; + true -> + NewLists = lists:keydelete(Name, 1, Lists), + mnesia:write(P#privacy{lists = NewLists}) + end + end + end, mnesia:transaction(F); remove_privacy_list(LUser, LServer, Name, odbc) -> - F = fun() -> - case sql_get_default_privacy_list_t(LUser) of - {selected, ["name"], []} -> - sql_remove_privacy_list(LUser, Name), - ok; - {selected, ["name"], [{Default}]} -> - %% TODO: check active - if - Name == Default -> - conflict; - true -> - sql_remove_privacy_list(LUser, Name), - ok - end - end - end, + F = fun () -> + case sql_get_default_privacy_list_t(LUser) of + {selected, [<<"name">>], []} -> + sql_remove_privacy_list(LUser, Name), ok; + {selected, [<<"name">>], [[Default]]} -> + if Name == Default -> conflict; + true -> sql_remove_privacy_list(LUser, Name), ok + end + end + end, odbc_queries:sql_transaction(LServer, F). set_privacy_list(LUser, LServer, Name, List, mnesia) -> - F = fun() -> - case mnesia:wread({privacy, {LUser, LServer}}) of - [] -> - NewLists = [{Name, List}], - mnesia:write(#privacy{us = {LUser, LServer}, - lists = NewLists}); - [#privacy{lists = Lists} = P] -> - NewLists1 = lists:keydelete(Name, 1, Lists), - NewLists = [{Name, List} | NewLists1], - mnesia:write(P#privacy{lists = NewLists}) + F = fun () -> + case mnesia:wread({privacy, {LUser, LServer}}) of + [] -> + NewLists = [{Name, List}], + mnesia:write(#privacy{us = {LUser, LServer}, + lists = NewLists}); + [#privacy{lists = Lists} = P] -> + NewLists1 = lists:keydelete(Name, 1, Lists), + NewLists = [{Name, List} | NewLists1], + mnesia:write(P#privacy{lists = NewLists}) end - end, + end, mnesia:transaction(F); set_privacy_list(LUser, LServer, Name, List, odbc) -> RItems = lists:map(fun item_to_raw/1, List), - F = fun() -> - ID = - case sql_get_privacy_list_id_t(LUser, Name) of - {selected, ["id"], []} -> - sql_add_privacy_list(LUser, Name), - {selected, ["id"], [{I}]} = - sql_get_privacy_list_id_t(LUser, Name), - I; - {selected, ["id"], [{I}]} -> - I - end, - sql_set_privacy_list(ID, RItems), - ok - end, + F = fun () -> + ID = case sql_get_privacy_list_id_t(LUser, Name) of + {selected, [<<"id">>], []} -> + sql_add_privacy_list(LUser, Name), + {selected, [<<"id">>], [[I]]} = + sql_get_privacy_list_id_t(LUser, Name), + I; + {selected, [<<"id">>], [[I]]} -> I + end, + sql_set_privacy_list(ID, RItems), + ok + end, odbc_queries:sql_transaction(LServer, F). process_list_set(LUser, LServer, {value, Name}, Els) -> case parse_items(Els) of - false -> - {error, ?ERR_BAD_REQUEST}; - remove -> - case remove_privacy_list(LUser, LServer, Name, - gen_mod:db_type(LServer, ?MODULE)) of - {atomic, conflict} -> - {error, ?ERR_CONFLICT}; - {atomic, ok} -> - ejabberd_router:route( - jlib:make_jid(LUser, LServer, ""), - jlib:make_jid(LUser, LServer, ""), - {xmlelement, "broadcast", [], - [{privacy_list, - #userlist{name = Name, list = []}, - Name}]}), - {result, []}; - _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} - end; - List -> - case set_privacy_list(LUser, LServer, Name, List, - gen_mod:db_type(LServer, ?MODULE)) of - {atomic, ok} -> - NeedDb = is_list_needdb(List), - ejabberd_router:route( - jlib:make_jid(LUser, LServer, ""), - jlib:make_jid(LUser, LServer, ""), - {xmlelement, "broadcast", [], - [{privacy_list, - #userlist{name = Name, list = List, needdb = NeedDb}, - Name}]}), - {result, []}; - _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} - end + false -> {error, ?ERR_BAD_REQUEST}; + remove -> + case remove_privacy_list(LUser, LServer, Name, + gen_mod:db_type(LServer, ?MODULE)) + of + {atomic, conflict} -> {error, ?ERR_CONFLICT}; + {atomic, ok} -> + ejabberd_sm:route(jlib:make_jid(LUser, LServer, + <<"">>), + jlib:make_jid(LUser, LServer, <<"">>), + {broadcast, {privacy_list, + #userlist{name = Name, + list = []}, + Name}}), + {result, []}; + _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} + end; + List -> + case set_privacy_list(LUser, LServer, Name, List, + gen_mod:db_type(LServer, ?MODULE)) + of + {atomic, ok} -> + NeedDb = is_list_needdb(List), + ejabberd_sm:route(jlib:make_jid(LUser, LServer, + <<"">>), + jlib:make_jid(LUser, LServer, <<"">>), + {broadcast, {privacy_list, + #userlist{name = Name, + list = List, + needdb = NeedDb}, + Name}}), + {result, []}; + _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} + end end; - process_list_set(_LUser, _LServer, false, _Els) -> {error, ?ERR_BAD_REQUEST}. - -parse_items([]) -> - remove; -parse_items(Els) -> - parse_items(Els, []). +parse_items([]) -> remove; +parse_items(Els) -> parse_items(Els, []). parse_items([], Res) -> - %% Sort the items by their 'order' attribute lists:keysort(#listitem.order, Res); -parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> - Type = xml:get_attr("type", Attrs), - Value = xml:get_attr("value", Attrs), - SAction = xml:get_attr("action", Attrs), - SOrder = xml:get_attr("order", Attrs), - Action = case catch list_to_action(element(2, SAction)) of - {'EXIT', _} -> false; - Val -> Val +parse_items([#xmlel{name = <<"item">>, attrs = Attrs, + children = SubEls} + | Els], + Res) -> + Type = xml:get_attr(<<"type">>, Attrs), + Value = xml:get_attr(<<"value">>, Attrs), + SAction = xml:get_attr(<<"action">>, Attrs), + SOrder = xml:get_attr(<<"order">>, Attrs), + Action = case catch list_to_action(element(2, SAction)) + of + {'EXIT', _} -> false; + Val -> Val end, - Order = case catch list_to_integer(element(2, SOrder)) of - {'EXIT', _} -> - false; - IntVal -> - if - IntVal >= 0 -> - IntVal; - true -> - false - end + Order = case catch jlib:binary_to_integer(element(2, + SOrder)) + of + {'EXIT', _} -> false; + IntVal -> + if IntVal >= 0 -> IntVal; + true -> false + end end, - if - (Action /= false) and (Order /= false) -> - I1 = #listitem{action = Action, order = Order}, - I2 = case {Type, Value} of - {{value, T}, {value, V}} -> - case T of - "jid" -> - case jlib:string_to_jid(V) of - error -> - false; - JID -> - I1#listitem{ - type = jid, - value = jlib:jid_tolower(JID)} - end; - "group" -> - I1#listitem{type = group, - value = V}; - "subscription" -> - case V of - "none" -> - I1#listitem{type = subscription, - value = none}; - "both" -> - I1#listitem{type = subscription, - value = both}; - "from" -> - I1#listitem{type = subscription, - value = from}; - "to" -> - I1#listitem{type = subscription, - value = to}; - _ -> - false - end - end; - {{value, _}, false} -> - false; - _ -> - I1 - end, - case I2 of - false -> - false; - _ -> - case parse_matches(I2, xml:remove_cdata(SubEls)) of - false -> - false; - I3 -> - parse_items(Els, [I3 | Res]) - end - end; - true -> - false + if (Action /= false) and (Order /= false) -> + I1 = #listitem{action = Action, order = Order}, + I2 = case {Type, Value} of + {{value, T}, {value, V}} -> + case T of + <<"jid">> -> + case jlib:string_to_jid(V) of + error -> false; + JID -> + I1#listitem{type = jid, + value = jlib:jid_tolower(JID)} + end; + <<"group">> -> I1#listitem{type = group, value = V}; + <<"subscription">> -> + case V of + <<"none">> -> + I1#listitem{type = subscription, + value = none}; + <<"both">> -> + I1#listitem{type = subscription, + value = both}; + <<"from">> -> + I1#listitem{type = subscription, + value = from}; + <<"to">> -> + I1#listitem{type = subscription, value = to}; + _ -> false + end + end; + {{value, _}, false} -> false; + _ -> I1 + end, + case I2 of + false -> false; + _ -> + case parse_matches(I2, xml:remove_cdata(SubEls)) of + false -> false; + I3 -> parse_items(Els, [I3 | Res]) + end + end; + true -> false end; - -parse_items(_, _Res) -> - false. - +parse_items(_, _Res) -> false. parse_matches(Item, []) -> Item#listitem{match_all = true}; -parse_matches(Item, Els) -> - parse_matches1(Item, Els). - -parse_matches1(Item, []) -> - Item; -parse_matches1(Item, [{xmlelement, "message", _, _} | Els]) -> - parse_matches1(Item#listitem{match_message = true}, Els); -parse_matches1(Item, [{xmlelement, "iq", _, _} | Els]) -> +parse_matches(Item, Els) -> parse_matches1(Item, Els). + +parse_matches1(Item, []) -> Item; +parse_matches1(Item, + [#xmlel{name = <<"message">>} | Els]) -> + parse_matches1(Item#listitem{match_message = true}, + Els); +parse_matches1(Item, [#xmlel{name = <<"iq">>} | Els]) -> parse_matches1(Item#listitem{match_iq = true}, Els); -parse_matches1(Item, [{xmlelement, "presence-in", _, _} | Els]) -> - parse_matches1(Item#listitem{match_presence_in = true}, Els); -parse_matches1(Item, [{xmlelement, "presence-out", _, _} | Els]) -> - parse_matches1(Item#listitem{match_presence_out = true}, Els); -parse_matches1(_Item, [{xmlelement, _, _, _} | _Els]) -> - false. - - - - - - +parse_matches1(Item, + [#xmlel{name = <<"presence-in">>} | Els]) -> + parse_matches1(Item#listitem{match_presence_in = true}, + Els); +parse_matches1(Item, + [#xmlel{name = <<"presence-out">>} | Els]) -> + parse_matches1(Item#listitem{match_presence_out = true}, + Els); +parse_matches1(_Item, [#xmlel{} | _Els]) -> false. is_list_needdb(Items) -> - lists:any( - fun(X) -> - case X#listitem.type of - subscription -> true; - group -> true; - _ -> false - end - end, Items). + lists:any(fun (X) -> + case X#listitem.type of + subscription -> true; + group -> true; + _ -> false + end + end, + Items). get_user_list(Acc, User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), {Default, Items} = get_user_list(Acc, LUser, LServer, - gen_mod:db_type(LServer, ?MODULE)), + gen_mod:db_type(LServer, ?MODULE)), NeedDb = is_list_needdb(Items), - #userlist{name = Default, list = Items, needdb = NeedDb}. + #userlist{name = Default, list = Items, + needdb = NeedDb}. get_user_list(_, LUser, LServer, mnesia) -> - case catch mnesia:dirty_read(privacy, {LUser, LServer}) of - [] -> - {none, []}; - [#privacy{default = Default, lists = Lists}] -> - case Default of - none -> - {none, []}; - _ -> - case lists:keysearch(Default, 1, Lists) of - {value, {_, List}} -> - {Default, List}; - _ -> - {none, []} - end - end; - _ -> - {none, []} + case catch mnesia:dirty_read(privacy, {LUser, LServer}) + of + [] -> {none, []}; + [#privacy{default = Default, lists = Lists}] -> + case Default of + none -> {none, []}; + _ -> + case lists:keysearch(Default, 1, Lists) of + {value, {_, List}} -> {Default, List}; + _ -> {none, []} + end + end; + _ -> {none, []} end; get_user_list(_, LUser, LServer, odbc) -> - case catch sql_get_default_privacy_list(LUser, LServer) of - {selected, ["name"], []} -> - {none, []}; - {selected, ["name"], [{Default}]} -> - case catch sql_get_privacy_list_data(LUser, LServer, Default) of - {selected, ["t", "value", "action", "ord", "match_all", - "match_iq", "match_message", - "match_presence_in", "match_presence_out"], - RItems} -> - {Default, lists:map(fun raw_to_item/1, RItems)}; - _ -> - {none, []} - end; - _ -> - {none, []} + case catch sql_get_default_privacy_list(LUser, LServer) + of + {selected, [<<"name">>], []} -> {none, []}; + {selected, [<<"name">>], [[Default]]} -> + case catch sql_get_privacy_list_data(LUser, LServer, + Default) + of + {selected, + [<<"t">>, <<"value">>, <<"action">>, <<"ord">>, + <<"match_all">>, <<"match_iq">>, <<"match_message">>, + <<"match_presence_in">>, <<"match_presence_out">>], + RItems} -> + {Default, lists:map(fun raw_to_item/1, RItems)}; + _ -> {none, []} + end; + _ -> {none, []} + end. + +get_user_lists(User, Server) -> + LUser = jlib:nodeprep(User), + LServer = jlib:nameprep(Server), + get_user_lists(LUser, LServer, gen_mod:db_type(LServer, ?MODULE)). + +get_user_lists(LUser, LServer, mnesia) -> + case catch mnesia:dirty_read(privacy, {LUser, LServer}) of + [#privacy{} = P] -> + {ok, P}; + _ -> + error + end; +get_user_lists(LUser, LServer, odbc) -> + Default = case catch sql_get_default_privacy_list(LUser, LServer) of + {selected, [<<"name">>], []} -> + none; + {selected, [<<"name">>], [[DefName]]} -> + DefName; + _ -> + none + end, + case catch sql_get_privacy_list_names(LUser, LServer) of + {selected, [<<"name">>], Names} -> + Lists = + lists:flatmap( + fun([Name]) -> + case catch sql_get_privacy_list_data( + LUser, LServer, Name) of + {selected, + [<<"t">>, <<"value">>, <<"action">>, + <<"ord">>, <<"match_all">>, <<"match_iq">>, + <<"match_message">>, <<"match_presence_in">>, + <<"match_presence_out">>], + RItems} -> + [{Name, lists:map(fun raw_to_item/1, RItems)}]; + _ -> + [] + end + end, Names), + {ok, #privacy{default = Default, + us = {LUser, LServer}, + lists = Lists}}; + _ -> + error end. %% From is the sender, To is the destination. %% If Dir = out, User@Server is the sender account (From). %% If Dir = in, User@Server is the destination account (To). -check_packet(_, _User, _Server, - _UserList, - {#jid{luser = "", lserver = Server} = _From, - #jid{lserver = Server} = _To, - _}, +check_packet(_, _User, _Server, _UserList, + {#jid{luser = <<"">>, lserver = Server} = _From, + #jid{lserver = Server} = _To, _}, in) -> allow; -check_packet(_, _User, _Server, - _UserList, +check_packet(_, _User, _Server, _UserList, {#jid{lserver = Server} = _From, - #jid{luser = "", lserver = Server} = _To, - _}, + #jid{luser = <<"">>, lserver = Server} = _To, _}, out) -> allow; -check_packet(_, _User, _Server, - _UserList, +check_packet(_, _User, _Server, _UserList, {#jid{luser = User, lserver = Server} = _From, - #jid{luser = User, lserver = Server} = _To, - _}, + #jid{luser = User, lserver = Server} = _To, _}, _Dir) -> allow; check_packet(_, User, Server, #userlist{list = List, needdb = NeedDb}, - {From, To, {xmlelement, PName, Attrs, _}}, - Dir) -> + {From, To, #xmlel{name = PName, attrs = Attrs}}, Dir) -> case List of - [] -> - allow; - _ -> - PType = case PName of - "message" -> message; - "iq" -> iq; - "presence" -> - case xml:get_attr_s("type", Attrs) of - %% notification - "" -> presence; - "unavailable" -> presence; - %% subscribe, subscribed, unsubscribe, - %% unsubscribed, error, probe, or other - _ -> other - end - end, - PType2 = case {PType, Dir} of - {message, in} -> message; - {iq, in} -> iq; - {presence, in} -> presence_in; - {presence, out} -> presence_out; - {_, _} -> other - end, - LJID = case Dir of - in -> jlib:jid_tolower(From); - out -> jlib:jid_tolower(To) + [] -> allow; + _ -> + PType = case PName of + <<"message">> -> message; + <<"iq">> -> iq; + <<"presence">> -> + case xml:get_attr_s(<<"type">>, Attrs) of + %% notification + <<"">> -> presence; + <<"unavailable">> -> presence; + %% subscribe, subscribed, unsubscribe, + %% unsubscribed, error, probe, or other + _ -> other + end + end, + PType2 = case {PType, Dir} of + {message, in} -> message; + {iq, in} -> iq; + {presence, in} -> presence_in; + {presence, out} -> presence_out; + {_, _} -> other end, - {Subscription, Groups} = - case NeedDb of - true -> ejabberd_hooks:run_fold(roster_get_jid_info, - jlib:nameprep(Server), - {none, []}, - [User, Server, LJID]); - false -> {[], []} - end, - check_packet_aux(List, PType2, LJID, Subscription, Groups) + LJID = case Dir of + in -> jlib:jid_tolower(From); + out -> jlib:jid_tolower(To) + end, + {Subscription, Groups} = case NeedDb of + true -> + ejabberd_hooks:run_fold(roster_get_jid_info, + jlib:nameprep(Server), + {none, []}, + [User, Server, + LJID]); + false -> {[], []} + end, + check_packet_aux(List, PType2, LJID, Subscription, + Groups) end. %% Ptype = mesage | iq | presence_in | presence_out | other -check_packet_aux([], _PType, _JID, _Subscription, _Groups) -> +check_packet_aux([], _PType, _JID, _Subscription, + _Groups) -> allow; -check_packet_aux([Item | List], PType, JID, Subscription, Groups) -> - #listitem{type = Type, value = Value, action = Action} = Item, +check_packet_aux([Item | List], PType, JID, + Subscription, Groups) -> + #listitem{type = Type, value = Value, action = Action} = + Item, case is_ptype_match(Item, PType) of - true -> - case Type of - none -> - Action; - _ -> - case is_type_match(Type, Value, - JID, Subscription, Groups) of - true -> - Action; - false -> - check_packet_aux(List, PType, - JID, Subscription, Groups) - end - end; - false -> - check_packet_aux(List, PType, JID, Subscription, Groups) + true -> + case Type of + none -> Action; + _ -> + case is_type_match(Type, Value, JID, Subscription, + Groups) + of + true -> Action; + false -> + check_packet_aux(List, PType, JID, Subscription, Groups) + end + end; + false -> + check_packet_aux(List, PType, JID, Subscription, Groups) end. - is_ptype_match(Item, PType) -> case Item#listitem.match_all of - true -> - true; - false -> - case PType of - message -> - Item#listitem.match_message; - iq -> - Item#listitem.match_iq; - presence_in -> - Item#listitem.match_presence_in; - presence_out -> - Item#listitem.match_presence_out; - other -> - false - end + true -> true; + false -> + case PType of + message -> Item#listitem.match_message; + iq -> Item#listitem.match_iq; + presence_in -> Item#listitem.match_presence_in; + presence_out -> Item#listitem.match_presence_out; + other -> false + end end. - is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of - jid -> - case Value of - {"", Server, ""} -> - case JID of - {_, Server, _} -> - true; - _ -> - false - end; - {User, Server, ""} -> - case JID of - {User, Server, _} -> - true; - _ -> - false - end; - _ -> - Value == JID - end; - subscription -> - Value == Subscription; - group -> - lists:member(Value, Groups) + jid -> + case Value of + {<<"">>, Server, <<"">>} -> + case JID of + {_, Server, _} -> true; + _ -> false + end; + {User, Server, <<"">>} -> + case JID of + {User, Server, _} -> true; + _ -> false + end; + _ -> Value == JID + end; + subscription -> Value == Subscription; + group -> lists:member(Value, Groups) end. - remove_user(User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), - remove_user(LUser, LServer, gen_mod:db_type(LServer, ?MODULE)). + remove_user(LUser, LServer, + gen_mod:db_type(LServer, ?MODULE)). remove_user(LUser, LServer, mnesia) -> - F = fun() -> - mnesia:delete({privacy, - {LUser, LServer}}) - end, + F = fun () -> mnesia:delete({privacy, {LUser, LServer}}) + end, mnesia:transaction(F); remove_user(LUser, LServer, odbc) -> sql_del_privacy_lists(LUser, LServer). -updated_list(_, - #userlist{name = OldName} = Old, +updated_list(_, #userlist{name = OldName} = Old, #userlist{name = NewName} = New) -> - if - OldName == NewName -> - New; - true -> - Old + if OldName == NewName -> New; + true -> Old end. -raw_to_item({SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, - SMatchMessage, SMatchPresenceIn, SMatchPresenceOut}) -> - {Type, Value} = - case SType of - "n" -> - {none, none}; - "j" -> - case jlib:string_to_jid(SValue) of - #jid{} = JID -> - {jid, jlib:jid_tolower(JID)} - end; - "g" -> - {group, SValue}; - "s" -> - case SValue of - "none" -> - {subscription, none}; - "both" -> - {subscription, both}; - "from" -> - {subscription, from}; - "to" -> - {subscription, to} - end - end, - Action = - case SAction of - "a" -> allow; - "d" -> deny - end, - Order = list_to_integer(SOrder), +raw_to_item([SType, SValue, SAction, SOrder, SMatchAll, + SMatchIQ, SMatchMessage, SMatchPresenceIn, + SMatchPresenceOut]) -> + {Type, Value} = case SType of + <<"n">> -> {none, none}; + <<"j">> -> + case jlib:string_to_jid(SValue) of + #jid{} = JID -> {jid, jlib:jid_tolower(JID)} + end; + <<"g">> -> {group, SValue}; + <<"s">> -> + case SValue of + <<"none">> -> {subscription, none}; + <<"both">> -> {subscription, both}; + <<"from">> -> {subscription, from}; + <<"to">> -> {subscription, to} + end + end, + Action = case SAction of + <<"a">> -> allow; + <<"d">> -> deny + end, + Order = jlib:binary_to_integer(SOrder), MatchAll = ejabberd_odbc:to_bool(SMatchAll), MatchIQ = ejabberd_odbc:to_bool(SMatchIQ), MatchMessage = ejabberd_odbc:to_bool(SMatchMessage), - MatchPresenceIn = ejabberd_odbc:to_bool(SMatchPresenceIn), - MatchPresenceOut = ejabberd_odbc:to_bool(SMatchPresenceOut), - #listitem{type = Type, - value = Value, - action = Action, - order = Order, - match_all = MatchAll, - match_iq = MatchIQ, + MatchPresenceIn = + ejabberd_odbc:to_bool(SMatchPresenceIn), + MatchPresenceOut = + ejabberd_odbc:to_bool(SMatchPresenceOut), + #listitem{type = Type, value = Value, action = Action, + order = Order, match_all = MatchAll, match_iq = MatchIQ, match_message = MatchMessage, match_presence_in = MatchPresenceIn, - match_presence_out = MatchPresenceOut - }. - -item_to_raw(#listitem{type = Type, - value = Value, - action = Action, - order = Order, - match_all = MatchAll, - match_iq = MatchIQ, - match_message = MatchMessage, + match_presence_out = MatchPresenceOut}. + +item_to_raw(#listitem{type = Type, value = Value, + action = Action, order = Order, match_all = MatchAll, + match_iq = MatchIQ, match_message = MatchMessage, match_presence_in = MatchPresenceIn, - match_presence_out = MatchPresenceOut - }) -> - {SType, SValue} = - case Type of - none -> - {"n", ""}; - jid -> - {"j", ejabberd_odbc:escape(jlib:jid_to_string(Value))}; - group -> - {"g", ejabberd_odbc:escape(Value)}; - subscription -> - case Value of - none -> - {"s", "none"}; - both -> - {"s", "both"}; - from -> - {"s", "from"}; - to -> - {"s", "to"} - end - end, - SAction = - case Action of - allow -> "a"; - deny -> "d" - end, - SOrder = integer_to_list(Order), - SMatchAll = if MatchAll -> "1"; true -> "0" end, - SMatchIQ = if MatchIQ -> "1"; true -> "0" end, - SMatchMessage = if MatchMessage -> "1"; true -> "0" end, - SMatchPresenceIn = if MatchPresenceIn -> "1"; true -> "0" end, - SMatchPresenceOut = if MatchPresenceOut -> "1"; true -> "0" end, + match_presence_out = MatchPresenceOut}) -> + {SType, SValue} = case Type of + none -> {<<"n">>, <<"">>}; + jid -> + {<<"j">>, + ejabberd_odbc:escape(jlib:jid_to_string(Value))}; + group -> {<<"g">>, ejabberd_odbc:escape(Value)}; + subscription -> + case Value of + none -> {<<"s">>, <<"none">>}; + both -> {<<"s">>, <<"both">>}; + from -> {<<"s">>, <<"from">>}; + to -> {<<"s">>, <<"to">>} + end + end, + SAction = case Action of + allow -> <<"a">>; + deny -> <<"d">> + end, + SOrder = iolist_to_binary(integer_to_list(Order)), + SMatchAll = if MatchAll -> <<"1">>; + true -> <<"0">> + end, + SMatchIQ = if MatchIQ -> <<"1">>; + true -> <<"0">> + end, + SMatchMessage = if MatchMessage -> <<"1">>; + true -> <<"0">> + end, + SMatchPresenceIn = if MatchPresenceIn -> <<"1">>; + true -> <<"0">> + end, + SMatchPresenceOut = if MatchPresenceOut -> <<"1">>; + true -> <<"0">> + end, [SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, SMatchMessage, SMatchPresenceIn, SMatchPresenceOut]. sql_get_default_privacy_list(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), - odbc_queries:get_default_privacy_list(LServer, Username). + odbc_queries:get_default_privacy_list(LServer, + Username). sql_get_default_privacy_list_t(LUser) -> Username = ejabberd_odbc:escape(LUser), @@ -998,7 +946,8 @@ sql_get_privacy_list_names_t(LUser) -> sql_get_privacy_list_id(LUser, LServer, Name) -> Username = ejabberd_odbc:escape(LUser), SName = ejabberd_odbc:escape(Name), - odbc_queries:get_privacy_list_id(LServer, Username, SName). + odbc_queries:get_privacy_list_id(LServer, Username, + SName). sql_get_privacy_list_id_t(LUser, Name) -> Username = ejabberd_odbc:escape(LUser), @@ -1008,7 +957,8 @@ sql_get_privacy_list_id_t(LUser, Name) -> sql_get_privacy_list_data(LUser, LServer, Name) -> Username = ejabberd_odbc:escape(LUser), SName = ejabberd_odbc:escape(Name), - odbc_queries:get_privacy_list_data(LServer, Username, SName). + odbc_queries:get_privacy_list_data(LServer, Username, + SName). sql_get_privacy_list_data_by_id(ID, LServer) -> odbc_queries:get_privacy_list_data_by_id(LServer, ID). @@ -1023,7 +973,8 @@ sql_set_default_privacy_list(LUser, Name) -> sql_unset_default_privacy_list(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), - odbc_queries:unset_default_privacy_list(LServer, Username). + odbc_queries:unset_default_privacy_list(LServer, + Username). sql_remove_privacy_list(LUser, Name) -> Username = ejabberd_odbc:escape(LUser), @@ -1041,48 +992,104 @@ sql_set_privacy_list(ID, RItems) -> sql_del_privacy_lists(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), Server = ejabberd_odbc:escape(LServer), - odbc_queries:del_privacy_lists(LServer, Server, Username). + odbc_queries:del_privacy_lists(LServer, Server, + Username). update_table() -> Fields = record_info(fields, privacy), case mnesia:table_info(privacy, attributes) of - Fields -> - ok; - [user, default, lists] -> - ?INFO_MSG("Converting privacy table from " - "{user, default, lists} format", []), - Host = ?MYNAME, - {atomic, ok} = mnesia:create_table( - mod_privacy_tmp_table, - [{disc_only_copies, [node()]}, - {type, bag}, - {local_content, true}, - {record_name, privacy}, - {attributes, record_info(fields, privacy)}]), - mnesia:transform_table(privacy, ignore, Fields), - F1 = fun() -> - mnesia:write_lock_table(mod_privacy_tmp_table), - mnesia:foldl( - fun(#privacy{us = U} = R, _) -> - mnesia:dirty_write( - mod_privacy_tmp_table, - R#privacy{us = {U, Host}}) - end, ok, privacy) - end, - mnesia:transaction(F1), - mnesia:clear_table(privacy), - F2 = fun() -> - mnesia:write_lock_table(privacy), - mnesia:foldl( - fun(R, _) -> - mnesia:dirty_write(R) - end, ok, mod_privacy_tmp_table) - end, - mnesia:transaction(F2), - mnesia:delete_table(mod_privacy_tmp_table); - _ -> - ?INFO_MSG("Recreating privacy table", []), - mnesia:transform_table(privacy, ignore, Fields) + Fields -> + ejabberd_config:convert_table_to_binary( + privacy, Fields, set, + fun(#privacy{us = {U, _}}) -> U end, + fun(#privacy{us = {U, S}, default = Def, lists = Lists} = R) -> + NewLists = + lists:map( + fun({Name, Ls}) -> + NewLs = + lists:map( + fun(#listitem{value = Val} = L) -> + NewVal = + case Val of + {LU, LS, LR} -> + {iolist_to_binary(LU), + iolist_to_binary(LS), + iolist_to_binary(LR)}; + none -> none; + both -> both; + from -> from; + to -> to; + _ -> iolist_to_binary(Val) + end, + L#listitem{value = NewVal} + end, Ls), + {iolist_to_binary(Name), NewLs} + end, Lists), + NewDef = case Def of + none -> none; + _ -> iolist_to_binary(Def) + end, + NewUS = {iolist_to_binary(U), iolist_to_binary(S)}, + R#privacy{us = NewUS, default = NewDef, + lists = NewLists} + end); + _ -> + ?INFO_MSG("Recreating privacy table", []), + mnesia:transform_table(privacy, ignore, Fields) end. - +export(Server) -> + case ejabberd_odbc:sql_query(jlib:nameprep(Server), + [<<"select id from privacy_list order by " + "id desc limit 1;">>]) of + {selected, [<<"id">>], [[I]]} -> + put(id, jlib:binary_to_integer(I)); + _ -> + put(id, 0) + end, + [{privacy, + fun(Host, #privacy{us = {LUser, LServer}, lists = Lists, + default = Default}) + when LServer == Host -> + Username = ejabberd_odbc:escape(LUser), + if Default /= none -> + SDefault = ejabberd_odbc:escape(Default), + [[<<"delete from privacy_default_list where ">>, + <<"username='">>, Username, <<"';">>], + [<<"insert into privacy_default_list(username, " + "name) ">>, + <<"values ('">>, Username, <<"', '">>, + SDefault, <<"');">>]]; + true -> + [] + end ++ + lists:flatmap( + fun({Name, List}) -> + SName = ejabberd_odbc:escape(Name), + RItems = lists:map(fun item_to_raw/1, List), + ID = jlib:integer_to_binary(get_id()), + [[<<"delete from privacy_list where username='">>, + Username, <<"' and name='">>, + SName, <<"';">>], + [<<"insert into privacy_list(username, " + "name, id) values ('">>, + Username, <<"', '">>, SName, + <<"', '">>, ID, <<"');">>], + [<<"delete from privacy_list_data where " + "id='">>, ID, <<"';">>]] ++ + [[<<"insert into privacy_list_data(id, t, " + "value, action, ord, match_all, match_iq, " + "match_message, match_presence_in, " + "match_presence_out) values ('">>, + ID, <<"', '">>, str:join(Items, <<"', '">>), + <<"');">>] || Items <- RItems] + end, + Lists); + (_Host, _R) -> + [] + end}]. + +get_id() -> + ID = get(id), + put(id, ID + 1), + ID + 1. |