diff options
Diffstat (limited to 'src/mod_private.erl')
-rw-r--r-- | src/mod_private.erl | 254 |
1 files changed, 52 insertions, 202 deletions
diff --git a/src/mod_private.erl b/src/mod_private.erl index a03d83e5a..029789e63 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -33,18 +33,20 @@ -export([start/2, stop/1, process_sm_iq/3, import/3, remove_user/2, get_data/2, export/1, import/1, - mod_opt_type/1]). + mod_opt_type/1, set_data/3]). -include("ejabberd.hrl"). -include("logger.hrl"). -include("jlib.hrl"). - --record(private_storage, - {usns = {<<"">>, <<"">>, <<"">>} :: {binary(), binary(), binary() | - '$1' | '_'}, - xml = #xmlel{} :: xmlel() | '_' | '$1'}). - +-include("mod_private.hrl"). + +-callback init(binary(), gen_mod:opts()) -> any(). +-callback import(binary(), #private_storage{}) -> ok | pass. +-callback set_data(binary(), binary(), [{binary(), xmlel()}]) -> {atomic, any()}. +-callback get_data(binary(), binary(), binary()) -> {ok, xmlel()} | error. +-callback get_all_data(binary(), binary()) -> [xmlel()]. + -define(Xmlel_Query(Attrs, Children), #xmlel{name = <<"query">>, attrs = Attrs, children = Children}). @@ -52,15 +54,8 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, one_queue), - case gen_mod:db_type(Host, Opts) of - mnesia -> - mnesia:create_table(private_storage, - [{disc_only_copies, [node()]}, - {attributes, - record_info(fields, private_storage)}]), - update_table(); - _ -> ok - end, + Mod = gen_mod:db_mod(Host, Opts, ?MODULE), + Mod:init(Host, Opts), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, @@ -73,255 +68,110 @@ stop(Host) -> ?NS_PRIVATE). process_sm_iq(#jid{luser = LUser, lserver = LServer}, - #jid{luser = LUser, lserver = LServer}, IQ) + #jid{luser = LUser, lserver = LServer}, #iq{lang = Lang} = IQ) when IQ#iq.type == set -> case IQ#iq.sub_el of #xmlel{name = <<"query">>, children = Xmlels} -> case filter_xmlels(Xmlels) of [] -> + Txt = <<"No private data found in this query">>, IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERR_NOT_ACCEPTABLE]}; + sub_el = [IQ#iq.sub_el, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)]}; Data -> - DBType = gen_mod:db_type(LServer, ?MODULE), - F = fun () -> - lists:foreach(fun (Datum) -> - set_data(LUser, LServer, - Datum, DBType) - end, - Data) - end, - case DBType of - odbc -> ejabberd_odbc:sql_transaction(LServer, F); - mnesia -> mnesia:transaction(F); - riak -> F() - end, + set_data(LUser, LServer, Data), IQ#iq{type = result, sub_el = []} end; _ -> + Txt = <<"No query found">>, IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERR_NOT_ACCEPTABLE]} + sub_el = [IQ#iq.sub_el, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)]} end; %% process_sm_iq(#jid{luser = LUser, lserver = LServer}, - #jid{luser = LUser, lserver = LServer}, IQ) + #jid{luser = LUser, lserver = LServer}, #iq{lang = Lang} = IQ) when IQ#iq.type == get -> case IQ#iq.sub_el of #xmlel{name = <<"query">>, attrs = Attrs, children = Xmlels} -> case filter_xmlels(Xmlels) of [] -> + Txt = <<"No private data found in this query">>, IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERR_BAD_FORMAT]}; + sub_el = [IQ#iq.sub_el, ?ERRT_BAD_FORMAT(Lang, Txt)]}; Data -> case catch get_data(LUser, LServer, Data) of {'EXIT', _Reason} -> + Txt = <<"Database failure">>, IQ#iq{type = error, sub_el = - [IQ#iq.sub_el, ?ERR_INTERNAL_SERVER_ERROR]}; + [IQ#iq.sub_el, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]}; Storage_Xmlels -> IQ#iq{type = result, sub_el = [?Xmlel_Query(Attrs, Storage_Xmlels)]} end end; _ -> + Txt = <<"No query found">>, IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERR_BAD_FORMAT]} + sub_el = [IQ#iq.sub_el, ?ERRT_BAD_FORMAT(Lang, Txt)]} end; %% -process_sm_iq(_From, _To, IQ) -> +process_sm_iq(_From, _To, #iq{lang = Lang} = IQ) -> + Txt = <<"Query to another users is forbidden">>, IQ#iq{type = error, - sub_el = [IQ#iq.sub_el, ?ERR_FORBIDDEN]}. + sub_el = [IQ#iq.sub_el, ?ERRT_FORBIDDEN(Lang, Txt)]}. filter_xmlels(Xmlels) -> filter_xmlels(Xmlels, []). filter_xmlels([], Data) -> lists:reverse(Data); filter_xmlels([#xmlel{attrs = Attrs} = Xmlel | Xmlels], Data) -> - case xml:get_attr_s(<<"xmlns">>, Attrs) of + case fxml:get_attr_s(<<"xmlns">>, Attrs) of <<"">> -> []; XmlNS -> filter_xmlels(Xmlels, [{XmlNS, Xmlel} | Data]) end; filter_xmlels([_ | Xmlels], Data) -> filter_xmlels(Xmlels, Data). -set_data(LUser, LServer, {XmlNS, Xmlel}, mnesia) -> - mnesia:write(#private_storage{usns = - {LUser, LServer, XmlNS}, - xml = Xmlel}); -set_data(LUser, LServer, {XMLNS, El}, odbc) -> - Username = ejabberd_odbc:escape(LUser), - LXMLNS = ejabberd_odbc:escape(XMLNS), - SData = ejabberd_odbc:escape(xml:element_to_binary(El)), - odbc_queries:set_private_data(LServer, Username, LXMLNS, - SData); -set_data(LUser, LServer, {XMLNS, El}, riak) -> - ejabberd_riak:put(#private_storage{usns = {LUser, LServer, XMLNS}, - xml = El}, - private_storage_schema(), - [{'2i', [{<<"us">>, {LUser, LServer}}]}]). +set_data(LUser, LServer, Data) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:set_data(LUser, LServer, Data). get_data(LUser, LServer, Data) -> - get_data(LUser, LServer, - gen_mod:db_type(LServer, ?MODULE), Data, []). + Mod = gen_mod:db_mod(LServer, ?MODULE), + get_data(LUser, LServer, Data, Mod, []). -get_data(_LUser, _LServer, _DBType, [], - Storage_Xmlels) -> +get_data(_LUser, _LServer, [], _Mod, Storage_Xmlels) -> lists:reverse(Storage_Xmlels); -get_data(LUser, LServer, mnesia, - [{XmlNS, Xmlel} | Data], Storage_Xmlels) -> - case mnesia:dirty_read(private_storage, - {LUser, LServer, XmlNS}) - of - [#private_storage{xml = Storage_Xmlel}] -> - get_data(LUser, LServer, mnesia, Data, - [Storage_Xmlel | Storage_Xmlels]); - _ -> - get_data(LUser, LServer, mnesia, Data, - [Xmlel | Storage_Xmlels]) - end; -get_data(LUser, LServer, odbc, [{XMLNS, El} | Els], - Res) -> - Username = ejabberd_odbc:escape(LUser), - LXMLNS = ejabberd_odbc:escape(XMLNS), - case catch odbc_queries:get_private_data(LServer, - Username, LXMLNS) - of - {selected, [<<"data">>], [[SData]]} -> - case xml_stream:parse_element(SData) of - Data when is_record(Data, xmlel) -> - get_data(LUser, LServer, odbc, Els, [Data | Res]) - end; - _ -> get_data(LUser, LServer, odbc, Els, [El | Res]) - end; -get_data(LUser, LServer, riak, [{XMLNS, El} | Els], - Res) -> - case ejabberd_riak:get(private_storage, private_storage_schema(), - {LUser, LServer, XMLNS}) of - {ok, #private_storage{xml = NewEl}} -> - get_data(LUser, LServer, riak, Els, [NewEl|Res]); - _ -> - get_data(LUser, LServer, riak, Els, [El|Res]) +get_data(LUser, LServer, [{XmlNS, Xmlel} | Data], Mod, Storage_Xmlels) -> + case Mod:get_data(LUser, LServer, XmlNS) of + {ok, Storage_Xmlel} -> + get_data(LUser, LServer, Data, Mod, [Storage_Xmlel | Storage_Xmlels]); + error -> + get_data(LUser, LServer, Data, Mod, [Xmlel | Storage_Xmlels]) end. get_data(LUser, LServer) -> - get_all_data(LUser, LServer, - gen_mod:db_type(LServer, ?MODULE)). - -get_all_data(LUser, LServer, mnesia) -> - lists:flatten( - mnesia:dirty_select(private_storage, - [{#private_storage{usns = {LUser, LServer, '_'}, - xml = '$1'}, - [], ['$1']}])); -get_all_data(LUser, LServer, odbc) -> - Username = ejabberd_odbc:escape(LUser), - case catch odbc_queries:get_private_data(LServer, Username) of - {selected, [<<"namespace">>, <<"data">>], Res} -> - lists:flatmap( - fun([_, SData]) -> - case xml_stream:parse_element(SData) of - #xmlel{} = El -> - [El]; - _ -> - [] - end - end, Res); - _ -> - [] - end; -get_all_data(LUser, LServer, riak) -> - case ejabberd_riak:get_by_index( - private_storage, private_storage_schema(), - <<"us">>, {LUser, LServer}) of - {ok, Res} -> - [El || #private_storage{xml = El} <- Res]; - _ -> - [] - end. - -private_storage_schema() -> - {record_info(fields, private_storage), #private_storage{}}. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:get_all_data(LUser, LServer). remove_user(User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), - remove_user(LUser, LServer, - gen_mod:db_type(Server, ?MODULE)). + Mod = gen_mod:db_mod(Server, ?MODULE), + Mod:remove_user(LUser, LServer). -remove_user(LUser, LServer, mnesia) -> - F = fun () -> - Namespaces = mnesia:select(private_storage, - [{#private_storage{usns = - {LUser, - LServer, - '$1'}, - _ = '_'}, - [], ['$$']}]), - lists:foreach(fun ([Namespace]) -> - mnesia:delete({private_storage, - {LUser, LServer, - Namespace}}) - end, - Namespaces) - end, - mnesia:transaction(F); -remove_user(LUser, LServer, odbc) -> - Username = ejabberd_odbc:escape(LUser), - odbc_queries:del_user_private_storage(LServer, - Username); -remove_user(LUser, LServer, riak) -> - {atomic, ejabberd_riak:delete_by_index(private_storage, - <<"us">>, {LUser, LServer})}. - -update_table() -> - Fields = record_info(fields, private_storage), - case mnesia:table_info(private_storage, attributes) of - Fields -> - ejabberd_config:convert_table_to_binary( - private_storage, Fields, set, - fun(#private_storage{usns = {U, _, _}}) -> U end, - fun(#private_storage{usns = {U, S, NS}, xml = El} = R) -> - R#private_storage{usns = {iolist_to_binary(U), - iolist_to_binary(S), - iolist_to_binary(NS)}, - xml = xml:to_xmlel(El)} - end); - _ -> - ?INFO_MSG("Recreating private_storage table", []), - mnesia:transform_table(private_storage, ignore, Fields) - end. - -export(_Server) -> - [{private_storage, - fun(Host, #private_storage{usns = {LUser, LServer, XMLNS}, - xml = Data}) - when LServer == Host -> - Username = ejabberd_odbc:escape(LUser), - LXMLNS = ejabberd_odbc:escape(XMLNS), - SData = - ejabberd_odbc:escape(xml:element_to_binary(Data)), - odbc_queries:set_private_data_sql(Username, LXMLNS, - SData); - (_Host, _R) -> - [] - end}]. +export(LServer) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:export(LServer). import(LServer) -> - [{<<"select username, namespace, data from private_storage;">>, - fun([LUser, XMLNS, XML]) -> - El = #xmlel{} = xml_stream:parse_element(XML), - #private_storage{usns = {LUser, LServer, XMLNS}, - xml = El} - end}]. - -import(_LServer, mnesia, #private_storage{} = PS) -> - mnesia:dirty_write(PS); + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:import(LServer). -import(_LServer, riak, #private_storage{usns = {LUser, LServer, _}} = PS) -> - ejabberd_riak:put(PS, private_storage_schema(), - [{'2i', [{<<"us">>, {LUser, LServer}}]}]); -import(_, _, _) -> - pass. +import(LServer, DBType, PD) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, PD). mod_opt_type(db_type) -> fun gen_mod:v_db/1; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; |