From b5d1ce795f798af7c98d650b14b95cda1d2e6eb0 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 13 Apr 2016 13:04:04 +0300 Subject: [PATCH] Clean mod_announce.erl from DB specific code --- include/mod_announce.hrl | 5 + src/mod_announce.erl | 324 +++++------------------------------- src/mod_announce_mnesia.erl | 129 ++++++++++++++ src/mod_announce_riak.erl | 87 ++++++++++ src/mod_announce_sql.erl | 132 +++++++++++++++ 5 files changed, 391 insertions(+), 286 deletions(-) create mode 100644 include/mod_announce.hrl create mode 100644 src/mod_announce_mnesia.erl create mode 100644 src/mod_announce_riak.erl create mode 100644 src/mod_announce_sql.erl diff --git a/include/mod_announce.hrl b/include/mod_announce.hrl new file mode 100644 index 000000000..83d72aaf1 --- /dev/null +++ b/include/mod_announce.hrl @@ -0,0 +1,5 @@ +-record(motd, {server = <<"">> :: binary(), + packet = #xmlel{} :: xmlel()}). + +-record(motd_users, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1', + dummy = [] :: [] | '_'}). diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 0cf8c5349..d7251c50b 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -41,11 +41,16 @@ -include("logger.hrl"). -include("jlib.hrl"). -include("adhoc.hrl"). +-include("mod_announce.hrl"). --record(motd, {server = <<"">> :: binary(), - packet = #xmlel{} :: xmlel()}). --record(motd_users, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1', - dummy = [] :: [] | '_'}). +-callback init(binary(), gen_mod:opts()) -> any(). +-callback import(binary(), #motd{} | #motd_users{}) -> ok | pass. +-callback set_motd_users(binary(), [{binary(), binary(), binary()}]) -> {atomic, any()}. +-callback set_motd(binary(), xmlel()) -> {atomic, any()}. +-callback delete_motd(binary()) -> {atomic, any()}. +-callback get_motd(binary()) -> {ok, xmlel()} | error. +-callback is_motd_user(binary(), binary()) -> boolean(). +-callback set_motd_user(binary(), binary()) -> {atomic, any()}. -define(PROCNAME, ejabberd_announce). @@ -55,20 +60,8 @@ tokenize(Node) -> str:tokens(Node, <<"/#">>). start(Host, Opts) -> - case gen_mod:db_type(Host, Opts) of - mnesia -> - mnesia:create_table(motd, - [{disc_copies, [node()]}, - {attributes, - record_info(fields, motd)}]), - mnesia:create_table(motd_users, - [{disc_copies, [node()]}, - {attributes, - record_info(fields, motd_users)}]), - update_tables(); - _ -> - ok - end, + Mod = gen_mod:db_mod(Host, Opts, ?MODULE), + Mod:init(Host, Opts), ejabberd_hooks:add(local_send_to_resource_hook, Host, ?MODULE, announce, 50), ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, disco_identity, 50), @@ -789,41 +782,8 @@ announce_motd(Host, Packet) -> announce_motd_update(LServer, Packet), Sessions = ejabberd_sm:get_vh_session_list(LServer), announce_online1(Sessions, LServer, Packet), - case gen_mod:db_type(LServer, ?MODULE) of - mnesia -> - F = fun() -> - lists:foreach( - fun({U, S, _R}) -> - mnesia:write(#motd_users{us = {U, S}}) - end, Sessions) - end, - mnesia:transaction(F); - riak -> - try - lists:foreach( - fun({U, S, _R}) -> - ok = ejabberd_riak:put(#motd_users{us = {U, S}}, - motd_users_schema(), - [{'2i', [{<<"server">>, S}]}]) - end, Sessions), - {atomic, ok} - catch _:{badmatch, Err} -> - {atomic, Err} - end; - odbc -> - F = fun() -> - lists:foreach( - fun({U, _S, _R}) -> - Username = ejabberd_odbc:escape(U), - odbc_queries:update_t( - <<"motd">>, - [<<"username">>, <<"xml">>], - [Username, <<"">>], - [<<"username='">>, Username, <<"'">>]) - end, Sessions) - end, - ejabberd_odbc:sql_transaction(LServer, F) - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:set_motd_users(LServer, Sessions). announce_motd_update(From, To, Packet) -> Host = To#jid.lserver, @@ -853,27 +813,8 @@ announce_all_hosts_motd_update(From, To, Packet) -> announce_motd_update(LServer, Packet) -> announce_motd_delete(LServer), - case gen_mod:db_type(LServer, ?MODULE) of - mnesia -> - F = fun() -> - mnesia:write(#motd{server = LServer, packet = Packet}) - end, - mnesia:transaction(F); - riak -> - {atomic, ejabberd_riak:put(#motd{server = LServer, - packet = Packet}, - motd_schema())}; - odbc -> - XML = ejabberd_odbc:escape(fxml:element_to_binary(Packet)), - F = fun() -> - odbc_queries:update_t( - <<"motd">>, - [<<"username">>, <<"xml">>], - [<<"">>, XML], - [<<"username=''">>]) - end, - ejabberd_odbc:sql_transaction(LServer, F) - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:set_motd(LServer, Packet). announce_motd_delete(From, To, Packet) -> Host = To#jid.lserver, @@ -902,112 +843,30 @@ announce_all_hosts_motd_delete(From, To, Packet) -> end. announce_motd_delete(LServer) -> - case gen_mod:db_type(LServer, ?MODULE) of - mnesia -> - F = fun() -> - mnesia:delete({motd, LServer}), - mnesia:write_lock_table(motd_users), - Users = mnesia:select( - motd_users, - [{#motd_users{us = '$1', _ = '_'}, - [{'==', {element, 2, '$1'}, LServer}], - ['$1']}]), - lists:foreach(fun(US) -> - mnesia:delete({motd_users, US}) - end, Users) - end, - mnesia:transaction(F); - riak -> - try - ok = ejabberd_riak:delete(motd, LServer), - ok = ejabberd_riak:delete_by_index(motd_users, - <<"server">>, - LServer), - {atomic, ok} - catch _:{badmatch, Err} -> - {atomic, Err} - end; - odbc -> - F = fun() -> - ejabberd_odbc:sql_query_t([<<"delete from motd;">>]) - end, - ejabberd_odbc:sql_transaction(LServer, F) - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:delete_motd(LServer). -send_motd(JID) -> - send_motd(JID, gen_mod:db_type(JID#jid.lserver, ?MODULE)). - -send_motd(#jid{luser = LUser, lserver = LServer} = JID, mnesia) -> - case catch mnesia:dirty_read({motd, LServer}) of - [#motd{packet = Packet}] -> - US = {LUser, LServer}, - case catch mnesia:dirty_read({motd_users, US}) of - [#motd_users{}] -> - ok; - _ -> +send_motd(#jid{luser = LUser, lserver = LServer} = JID) when LUser /= <<>> -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + case Mod:get_motd(LServer) of + {ok, Packet} -> + case Mod:is_motd_user(LUser, LServer) of + false -> Local = jid:make(<<>>, LServer, <<>>), ejabberd_router:route(Local, JID, Packet), - F = fun() -> - mnesia:write(#motd_users{us = US}) - end, - mnesia:transaction(F) + Mod:set_motd_user(LUser, LServer); + true -> + ok end; - _ -> + error -> ok end; -send_motd(#jid{luser = LUser, lserver = LServer} = JID, riak) -> - case catch ejabberd_riak:get(motd, motd_schema(), LServer) of - {ok, #motd{packet = Packet}} -> - US = {LUser, LServer}, - case ejabberd_riak:get(motd_users, motd_users_schema(), US) of - {ok, #motd_users{}} -> - ok; - _ -> - Local = jid:make(<<>>, LServer, <<>>), - ejabberd_router:route(Local, JID, Packet), - {atomic, ejabberd_riak:put( - #motd_users{us = US}, motd_users_schema(), - [{'2i', [{<<"server">>, LServer}]}])} - end; - _ -> - ok - end; -send_motd(#jid{luser = LUser, lserver = LServer} = JID, odbc) when LUser /= <<>> -> - case catch ejabberd_odbc:sql_query( - LServer, [<<"select xml from motd where username='';">>]) of - {selected, [<<"xml">>], [[XML]]} -> - case fxml_stream:parse_element(XML) of - {error, _} -> - ok; - Packet -> - Username = ejabberd_odbc:escape(LUser), - case catch ejabberd_odbc:sql_query( - LServer, - [<<"select username from motd " - "where username='">>, Username, <<"';">>]) of - {selected, [<<"username">>], []} -> - Local = jid:make(<<"">>, LServer, <<"">>), - ejabberd_router:route(Local, JID, Packet), - F = fun() -> - odbc_queries:update_t( - <<"motd">>, - [<<"username">>, <<"xml">>], - [Username, <<"">>], - [<<"username='">>, Username, <<"'">>]) - end, - ejabberd_odbc:sql_transaction(LServer, F); - _ -> - ok - end - end; - _ -> - ok - end; -send_motd(_, odbc) -> +send_motd(_) -> ok. get_stored_motd(LServer) -> - case get_stored_motd_packet(LServer, gen_mod:db_type(LServer, ?MODULE)) of + Mod = gen_mod:db_mod(LServer, ?MODULE), + case Mod:get_motd(LServer) of {ok, Packet} -> {fxml:get_subtag_cdata(Packet, <<"subject">>), fxml:get_subtag_cdata(Packet, <<"body">>)}; @@ -1015,34 +874,6 @@ get_stored_motd(LServer) -> {<<>>, <<>>} end. -get_stored_motd_packet(LServer, mnesia) -> - case catch mnesia:dirty_read({motd, LServer}) of - [#motd{packet = Packet}] -> - {ok, Packet}; - _ -> - error - end; -get_stored_motd_packet(LServer, riak) -> - case ejabberd_riak:get(motd, motd_schema(), LServer) of - {ok, #motd{packet = Packet}} -> - {ok, Packet}; - _ -> - error - end; -get_stored_motd_packet(LServer, odbc) -> - case catch ejabberd_odbc:sql_query( - LServer, [<<"select xml from motd where username='';">>]) of - {selected, [<<"xml">>], [[XML]]} -> - case fxml_stream:parse_element(XML) of - {error, _} -> - error; - Packet -> - {ok, Packet} - end; - _ -> - error - end. - %% This function is similar to others, but doesn't perform any ACL verification send_announcement_to_all(Host, SubjectS, BodyS) -> SubjectEls = if SubjectS /= <<>> -> @@ -1076,96 +907,17 @@ get_access(Host) -> none). %%------------------------------------------------------------------------- - -update_tables() -> - update_motd_table(), - update_motd_users_table(). - -update_motd_table() -> - Fields = record_info(fields, motd), - case mnesia:table_info(motd, attributes) of - Fields -> - ejabberd_config:convert_table_to_binary( - motd, Fields, set, - fun(#motd{server = S}) -> S end, - fun(#motd{server = S, packet = P} = R) -> - NewS = iolist_to_binary(S), - NewP = fxml:to_xmlel(P), - R#motd{server = NewS, packet = NewP} - end); - _ -> - ?INFO_MSG("Recreating motd table", []), - mnesia:transform_table(motd, ignore, Fields) - end. - - -update_motd_users_table() -> - Fields = record_info(fields, motd_users), - case mnesia:table_info(motd_users, attributes) of - Fields -> - ejabberd_config:convert_table_to_binary( - motd_users, Fields, set, - fun(#motd_users{us = {U, _}}) -> U end, - fun(#motd_users{us = {U, S}} = R) -> - NewUS = {iolist_to_binary(U), - iolist_to_binary(S)}, - R#motd_users{us = NewUS} - end); - _ -> - ?INFO_MSG("Recreating motd_users table", []), - mnesia:transform_table(motd_users, ignore, Fields) - end. - -motd_schema() -> - {record_info(fields, motd), #motd{}}. - -motd_users_schema() -> - {record_info(fields, motd_users), #motd_users{}}. - -export(_Server) -> - [{motd, - fun(Host, #motd{server = LServer, packet = El}) - when LServer == Host -> - [[<<"delete from motd where username='';">>], - [<<"insert into motd(username, xml) values ('', '">>, - ejabberd_odbc:escape(fxml:element_to_binary(El)), - <<"');">>]]; - (_Host, _R) -> - [] - end}, - {motd_users, - fun(Host, #motd_users{us = {LUser, LServer}}) - when LServer == Host, LUser /= <<"">> -> - Username = ejabberd_odbc:escape(LUser), - [[<<"delete from motd where username='">>, Username, <<"';">>], - [<<"insert into motd(username, xml) values ('">>, - Username, <<"', '');">>]]; - (_Host, _R) -> - [] - end}]. +export(LServer) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:export(LServer). import(LServer) -> - [{<<"select xml from motd where username='';">>, - fun([XML]) -> - El = fxml_stream:parse_element(XML), - #motd{server = LServer, packet = El} - end}, - {<<"select username from motd where xml='';">>, - fun([LUser]) -> - #motd_users{us = {LUser, LServer}} - end}]. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:import(LServer). -import(_LServer, mnesia, #motd{} = Motd) -> - mnesia:dirty_write(Motd); -import(_LServer, mnesia, #motd_users{} = Users) -> - mnesia:dirty_write(Users); -import(_LServer, riak, #motd{} = Motd) -> - ejabberd_riak:put(Motd, motd_schema()); -import(_LServer, riak, #motd_users{us = {_, S}} = Users) -> - ejabberd_riak:put(Users, motd_users_schema(), - [{'2i', [{<<"server">>, S}]}]); -import(_, _, _) -> - pass. +import(LServer, DBType, LA) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, LA). mod_opt_type(access) -> fun (A) when is_atom(A) -> A end; diff --git a/src/mod_announce_mnesia.erl b/src/mod_announce_mnesia.erl new file mode 100644 index 000000000..c43eb853b --- /dev/null +++ b/src/mod_announce_mnesia.erl @@ -0,0 +1,129 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 13 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_announce_mnesia). +-behaviour(mod_announce). + +%% API +-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, + get_motd/1, is_motd_user/2, set_motd_user/2, import/2]). + +-include("jlib.hrl"). +-include("mod_announce.hrl"). +-include("logger.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + mnesia:create_table(motd, + [{disc_copies, [node()]}, + {attributes, + record_info(fields, motd)}]), + mnesia:create_table(motd_users, + [{disc_copies, [node()]}, + {attributes, + record_info(fields, motd_users)}]), + update_tables(). + +set_motd_users(_LServer, USRs) -> + F = fun() -> + lists:foreach( + fun({U, S, _R}) -> + mnesia:write(#motd_users{us = {U, S}}) + end, USRs) + end, + mnesia:transaction(F). + +set_motd(LServer, Packet) -> + F = fun() -> + mnesia:write(#motd{server = LServer, packet = Packet}) + end, + mnesia:transaction(F). + +delete_motd(LServer) -> + F = fun() -> + mnesia:delete({motd, LServer}), + mnesia:write_lock_table(motd_users), + Users = mnesia:select( + motd_users, + [{#motd_users{us = '$1', _ = '_'}, + [{'==', {element, 2, '$1'}, LServer}], + ['$1']}]), + lists:foreach(fun(US) -> + mnesia:delete({motd_users, US}) + end, Users) + end, + mnesia:transaction(F). + +get_motd(LServer) -> + case mnesia:dirty_read({motd, LServer}) of + [#motd{packet = Packet}] -> + {ok, Packet}; + _ -> + error + end. + +is_motd_user(LUser, LServer) -> + case mnesia:dirty_read({motd_users, {LUser, LServer}}) of + [#motd_users{}] -> true; + _ -> false + end. + +set_motd_user(LUser, LServer) -> + F = fun() -> + mnesia:write(#motd_users{us = {LUser, LServer}}) + end, + mnesia:transaction(F). + +import(_LServer, #motd{} = Motd) -> + mnesia:dirty_write(Motd); +import(_LServer, #motd_users{} = Users) -> + mnesia:dirty_write(Users). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +update_tables() -> + update_motd_table(), + update_motd_users_table(). + +update_motd_table() -> + Fields = record_info(fields, motd), + case mnesia:table_info(motd, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + motd, Fields, set, + fun(#motd{server = S}) -> S end, + fun(#motd{server = S, packet = P} = R) -> + NewS = iolist_to_binary(S), + NewP = fxml:to_xmlel(P), + R#motd{server = NewS, packet = NewP} + end); + _ -> + ?INFO_MSG("Recreating motd table", []), + mnesia:transform_table(motd, ignore, Fields) + end. + + +update_motd_users_table() -> + Fields = record_info(fields, motd_users), + case mnesia:table_info(motd_users, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + motd_users, Fields, set, + fun(#motd_users{us = {U, _}}) -> U end, + fun(#motd_users{us = {U, S}} = R) -> + NewUS = {iolist_to_binary(U), + iolist_to_binary(S)}, + R#motd_users{us = NewUS} + end); + _ -> + ?INFO_MSG("Recreating motd_users table", []), + mnesia:transform_table(motd_users, ignore, Fields) + end. diff --git a/src/mod_announce_riak.erl b/src/mod_announce_riak.erl new file mode 100644 index 000000000..7ced0b3ce --- /dev/null +++ b/src/mod_announce_riak.erl @@ -0,0 +1,87 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 13 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_announce_riak). +-behaviour(mod_announce). + +%% API +-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, + get_motd/1, is_motd_user/2, set_motd_user/2, import/2]). + +-include("jlib.hrl"). +-include("mod_announce.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + ok. + +set_motd_users(_LServer, USRs) -> + try + lists:foreach( + fun({U, S, _R}) -> + ok = ejabberd_riak:put(#motd_users{us = {U, S}}, + motd_users_schema(), + [{'2i', [{<<"server">>, S}]}]) + end, USRs), + {atomic, ok} + catch _:{badmatch, Err} -> + {atomic, Err} + end. + +set_motd(LServer, Packet) -> + {atomic, ejabberd_riak:put(#motd{server = LServer, + packet = Packet}, + motd_schema())}. + +delete_motd(LServer) -> + try + ok = ejabberd_riak:delete(motd, LServer), + ok = ejabberd_riak:delete_by_index(motd_users, + <<"server">>, + LServer), + {atomic, ok} + catch _:{badmatch, Err} -> + {atomic, Err} + end. + +get_motd(LServer) -> + case ejabberd_riak:get(motd, motd_schema(), LServer) of + {ok, #motd{packet = Packet}} -> + {ok, Packet}; + _ -> + error + end. + +is_motd_user(LUser, LServer) -> + case ejabberd_riak:get(motd_users, motd_users_schema(), + {LUser, LServer}) of + {ok, #motd_users{}} -> true; + _ -> false + end. + +set_motd_user(LUser, LServer) -> + {atomic, ejabberd_riak:put( + #motd_users{us = {LUser, LServer}}, motd_users_schema(), + [{'2i', [{<<"server">>, LServer}]}])}. + +import(_LServer, #motd{} = Motd) -> + ejabberd_riak:put(Motd, motd_schema()); +import(_LServer, #motd_users{us = {_, S}} = Users) -> + ejabberd_riak:put(Users, motd_users_schema(), + [{'2i', [{<<"server">>, S}]}]). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +motd_schema() -> + {record_info(fields, motd), #motd{}}. + +motd_users_schema() -> + {record_info(fields, motd_users), #motd_users{}}. diff --git a/src/mod_announce_sql.erl b/src/mod_announce_sql.erl new file mode 100644 index 000000000..cf10ffd85 --- /dev/null +++ b/src/mod_announce_sql.erl @@ -0,0 +1,132 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 13 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_announce_sql). +-behaviour(mod_announce). + +%% API +-export([init/2, set_motd_users/2, set_motd/2, delete_motd/1, + get_motd/1, is_motd_user/2, set_motd_user/2, import/1, + import/2, export/1]). + +-include("jlib.hrl"). +-include("mod_announce.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + ok. + +set_motd_users(LServer, USRs) -> + F = fun() -> + lists:foreach( + fun({U, _S, _R}) -> + Username = ejabberd_odbc:escape(U), + odbc_queries:update_t( + <<"motd">>, + [<<"username">>, <<"xml">>], + [Username, <<"">>], + [<<"username='">>, Username, <<"'">>]) + end, USRs) + end, + ejabberd_odbc:sql_transaction(LServer, F). + +set_motd(LServer, Packet) -> + XML = ejabberd_odbc:escape(fxml:element_to_binary(Packet)), + F = fun() -> + odbc_queries:update_t( + <<"motd">>, + [<<"username">>, <<"xml">>], + [<<"">>, XML], + [<<"username=''">>]) + end, + ejabberd_odbc:sql_transaction(LServer, F). + +delete_motd(LServer) -> + F = fun() -> + ejabberd_odbc:sql_query_t([<<"delete from motd;">>]) + end, + ejabberd_odbc:sql_transaction(LServer, F). + +get_motd(LServer) -> + case catch ejabberd_odbc:sql_query( + LServer, [<<"select xml from motd where username='';">>]) of + {selected, [<<"xml">>], [[XML]]} -> + case fxml_stream:parse_element(XML) of + {error, _} -> + error; + Packet -> + {ok, Packet} + end; + _ -> + error + end. + +is_motd_user(LUser, LServer) -> + Username = ejabberd_odbc:escape(LUser), + case catch ejabberd_odbc:sql_query( + LServer, + [<<"select username from motd " + "where username='">>, Username, <<"';">>]) of + {selected, [<<"username">>], [_|_]} -> + true; + _ -> + false + end. + +set_motd_user(LUser, LServer) -> + Username = ejabberd_odbc:escape(LUser), + F = fun() -> + odbc_queries:update_t( + <<"motd">>, + [<<"username">>, <<"xml">>], + [Username, <<"">>], + [<<"username='">>, Username, <<"'">>]) + end, + ejabberd_odbc:sql_transaction(LServer, F). + +export(_Server) -> + [{motd, + fun(Host, #motd{server = LServer, packet = El}) + when LServer == Host -> + [[<<"delete from motd where username='';">>], + [<<"insert into motd(username, xml) values ('', '">>, + ejabberd_odbc:escape(fxml:element_to_binary(El)), + <<"');">>]]; + (_Host, _R) -> + [] + end}, + {motd_users, + fun(Host, #motd_users{us = {LUser, LServer}}) + when LServer == Host, LUser /= <<"">> -> + Username = ejabberd_odbc:escape(LUser), + [[<<"delete from motd where username='">>, Username, <<"';">>], + [<<"insert into motd(username, xml) values ('">>, + Username, <<"', '');">>]]; + (_Host, _R) -> + [] + end}]. + +import(LServer) -> + [{<<"select xml from motd where username='';">>, + fun([XML]) -> + El = fxml_stream:parse_element(XML), + #motd{server = LServer, packet = El} + end}, + {<<"select username from motd where xml='';">>, + fun([LUser]) -> + #motd_users{us = {LUser, LServer}} + end}]. + +import(_, _) -> + pass. + +%%%=================================================================== +%%% Internal functions +%%%===================================================================