diff --git a/include/mod_irc.hrl b/include/mod_irc.hrl new file mode 100644 index 000000000..b9696a88b --- /dev/null +++ b/include/mod_irc.hrl @@ -0,0 +1,15 @@ +-type conn_param() :: {binary(), binary(), inet:port_number(), binary()} | + {binary(), binary(), inet:port_number()} | + {binary(), binary()} | + {binary()}. + +-type irc_data() :: [{username, binary()} | {connections_params, [conn_param()]}]. + +-record(irc_connection, + {jid_server_host = {#jid{}, <<"">>, <<"">>} :: {jid(), binary(), binary()}, + pid = self() :: pid()}). + +-record(irc_custom, + {us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()}, + binary()}, + data = [] :: irc_data()}). diff --git a/src/mod_irc.erl b/src/mod_irc.erl index f6e452d82..e0c658dea 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -33,7 +33,8 @@ %% API -export([start_link/2, start/2, stop/1, export/1, import/1, - import/3, closed_connection/3, get_connection_params/3]). + import/3, closed_connection/3, get_connection_params/3, + data_to_binary/2]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, @@ -46,6 +47,8 @@ -include("adhoc.hrl"). +-include("mod_irc.hrl"). + -define(DEFAULT_IRC_ENCODING, <<"iso8859-15">>). -define(DEFAULT_IRC_PORT, 6667). @@ -58,27 +61,19 @@ [<<"koi8-r">>, <<"iso8859-15">>, <<"iso8859-1">>, <<"iso8859-2">>, <<"utf-8">>, <<"utf-8+latin-1">>]). --type conn_param() :: {binary(), binary(), inet:port_number(), binary()} | - {binary(), binary(), inet:port_number()} | - {binary(), binary()} | - {binary()}. - --record(irc_connection, - {jid_server_host = {#jid{}, <<"">>, <<"">>} :: {jid(), binary(), binary()}, - pid = self() :: pid()}). - --record(irc_custom, - {us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()}, - binary()}, - data = [] :: [{username, binary()} | - {connections_params, [conn_param()]}]}). - -record(state, {host = <<"">> :: binary(), server_host = <<"">> :: binary(), access = all :: atom()}). -define(PROCNAME, ejabberd_mod_irc). +-callback init(binary(), gen_mod:opts()) -> any(). +-callback import(binary(), #irc_custom{}) -> ok | pass. +-callback get_data(binary(), binary(), {binary(), binary()}) -> + error | empty | irc_data(). +-callback set_data(binary(), binary(), {binary(), binary()}, irc_data()) -> + {atomic, any()}. + %%==================================================================== %% API %%==================================================================== @@ -119,14 +114,8 @@ init([Host, Opts]) -> ejabberd:start_app(iconv), MyHost = gen_mod:get_opt_host(Host, Opts, <<"irc.@HOST@">>), - case gen_mod:db_type(Host, Opts) of - mnesia -> - mnesia:create_table(irc_custom, - [{disc_copies, [node()]}, - {attributes, record_info(fields, irc_custom)}]), - update_table(); - _ -> ok - end, + Mod = gen_mod:db_mod(Host, Opts, ?MODULE), + Mod:init(Host, Opts), Access = gen_mod:get_opt(access, Opts, fun(A) when is_atom(A) -> A end, all), @@ -597,43 +586,8 @@ process_irc_register(ServerHost, Host, From, _To, get_data(ServerHost, Host, From) -> LServer = jid:nameprep(ServerHost), - get_data(LServer, Host, From, - gen_mod:db_type(LServer, ?MODULE)). - -get_data(_LServer, Host, From, mnesia) -> - #jid{luser = LUser, lserver = LServer} = From, - US = {LUser, LServer}, - case catch mnesia:dirty_read({irc_custom, {US, Host}}) - of - {'EXIT', _Reason} -> error; - [] -> empty; - [#irc_custom{data = Data}] -> Data - end; -get_data(LServer, Host, From, riak) -> - #jid{luser = LUser, lserver = LServer} = From, - US = {LUser, LServer}, - case ejabberd_riak:get(irc_custom, irc_custom_schema(), {US, Host}) of - {ok, #irc_custom{data = Data}} -> - Data; - {error, notfound} -> - empty; - _Err -> - error - end; -get_data(LServer, Host, From, odbc) -> - SJID = - ejabberd_odbc:escape(jid:to_string(jid:tolower(jid:remove_resource(From)))), - SHost = ejabberd_odbc:escape(Host), - case catch ejabberd_odbc:sql_query(LServer, - [<<"select data from irc_custom where jid='">>, - SJID, <<"' and host='">>, SHost, - <<"';">>]) - of - {selected, [<<"data">>], [[SData]]} -> - data_to_binary(From, ejabberd_odbc:decode_term(SData)); - {'EXIT', _} -> error; - {selected, _, _} -> empty - end. + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:get_data(LServer, Host, From). get_form(ServerHost, Host, From, [], Lang) -> #jid{user = User, server = Server} = From, @@ -743,37 +697,8 @@ get_form(_ServerHost, _Host, _, _, _Lang) -> set_data(ServerHost, Host, From, Data) -> LServer = jid:nameprep(ServerHost), - set_data(LServer, Host, From, data_to_binary(From, Data), - gen_mod:db_type(LServer, ?MODULE)). - -set_data(_LServer, Host, From, Data, mnesia) -> - {LUser, LServer, _} = jid:tolower(From), - US = {LUser, LServer}, - F = fun () -> - mnesia:write(#irc_custom{us_host = {US, Host}, - data = Data}) - end, - mnesia:transaction(F); -set_data(LServer, Host, From, Data, riak) -> - {LUser, LServer, _} = jid:tolower(From), - US = {LUser, LServer}, - {atomic, ejabberd_riak:put(#irc_custom{us_host = {US, Host}, - data = Data}, - irc_custom_schema())}; -set_data(LServer, Host, From, Data, odbc) -> - SJID = - ejabberd_odbc:escape(jid:to_string(jid:tolower(jid:remove_resource(From)))), - SHost = ejabberd_odbc:escape(Host), - SData = ejabberd_odbc:encode_term(Data), - F = fun () -> - odbc_queries:update_t(<<"irc_custom">>, - [<<"jid">>, <<"host">>, <<"data">>], - [SJID, SHost, SData], - [<<"jid='">>, SJID, <<"' and host='">>, - SHost, <<"'">>]), - ok - end, - ejabberd_odbc:sql_transaction(LServer, F). + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:set_data(LServer, Host, From, data_to_binary(From, Data)). set_form(ServerHost, Host, From, [], Lang, XData) -> case {lists:keysearch(<<"username">>, 1, XData), @@ -1314,66 +1239,17 @@ conn_params_to_list(Params) -> Port, binary_to_list(P)} end, Params). -irc_custom_schema() -> - {record_info(fields, irc_custom), #irc_custom{}}. +export(LServer) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:export(LServer). -update_table() -> - Fields = record_info(fields, irc_custom), - case mnesia:table_info(irc_custom, attributes) of - Fields -> - ejabberd_config:convert_table_to_binary( - irc_custom, Fields, set, - fun(#irc_custom{us_host = {_, H}}) -> H end, - fun(#irc_custom{us_host = {{U, S}, H}, - data = Data} = R) -> - JID = jid:make(U, S, <<"">>), - R#irc_custom{us_host = {{iolist_to_binary(U), - iolist_to_binary(S)}, - iolist_to_binary(H)}, - data = data_to_binary(JID, Data)} - end); - _ -> - ?INFO_MSG("Recreating irc_custom table", []), - mnesia:transform_table(irc_custom, ignore, Fields) - end. +import(LServer) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:import(LServer). -export(_Server) -> - [{irc_custom, - fun(Host, #irc_custom{us_host = {{U, S}, IRCHost}, - data = Data}) -> - case str:suffix(Host, IRCHost) of - true -> - SJID = ejabberd_odbc:escape( - jid:to_string( - jid:make(U, S, <<"">>))), - SIRCHost = ejabberd_odbc:escape(IRCHost), - SData = ejabberd_odbc:encode_term(Data), - [[<<"delete from irc_custom where jid='">>, SJID, - <<"' and host='">>, SIRCHost, <<"';">>], - [<<"insert into irc_custom(jid, host, " - "data) values ('">>, - SJID, <<"', '">>, SIRCHost, <<"', '">>, SData, - <<"');">>]]; - false -> - [] - end - end}]. - -import(_LServer) -> - [{<<"select jid, host, data from irc_custom;">>, - fun([SJID, IRCHost, SData]) -> - #jid{luser = U, lserver = S} = jid:from_string(SJID), - Data = ejabberd_odbc:decode_term(SData), - #irc_custom{us_host = {{U, S}, IRCHost}, - data = Data} - end}]. - -import(_LServer, mnesia, #irc_custom{} = R) -> - mnesia:dirty_write(R); -import(_LServer, riak, #irc_custom{} = R) -> - ejabberd_riak:put(R, irc_custom_schema()); -import(_, _, _) -> - pass. +import(LServer, DBType, Data) -> + Mod = gen_mod:db_mod(DBType, ?MODULE), + Mod:import(LServer, Data). mod_opt_type(access) -> fun (A) when is_atom(A) -> A end; diff --git a/src/mod_irc_mnesia.erl b/src/mod_irc_mnesia.erl new file mode 100644 index 000000000..9f8117ad3 --- /dev/null +++ b/src/mod_irc_mnesia.erl @@ -0,0 +1,69 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 14 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_irc_mnesia). + +-behaviour(mod_irc). + +%% API +-export([init/2, get_data/3, set_data/4, import/2]). + +-include("jlib.hrl"). +-include("mod_irc.hrl"). +-include("logger.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + mnesia:create_table(irc_custom, + [{disc_copies, [node()]}, + {attributes, record_info(fields, irc_custom)}]), + update_table(). + +get_data(_LServer, Host, From) -> + {U, S, _} = jid:tolower(From), + case catch mnesia:dirty_read({irc_custom, {{U, S}, Host}}) of + {'EXIT', _Reason} -> error; + [] -> empty; + [#irc_custom{data = Data}] -> Data + end. + +set_data(_LServer, Host, From, Data) -> + {U, S, _} = jid:tolower(From), + F = fun () -> + mnesia:write(#irc_custom{us_host = {{U, S}, Host}, + data = Data}) + end, + mnesia:transaction(F). + +import(_LServer, #irc_custom{} = R) -> + mnesia:dirty_write(R). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +update_table() -> + Fields = record_info(fields, irc_custom), + case mnesia:table_info(irc_custom, attributes) of + Fields -> + ejabberd_config:convert_table_to_binary( + irc_custom, Fields, set, + fun(#irc_custom{us_host = {_, H}}) -> H end, + fun(#irc_custom{us_host = {{U, S}, H}, + data = Data} = R) -> + JID = jid:make(U, S, <<"">>), + R#irc_custom{us_host = {{iolist_to_binary(U), + iolist_to_binary(S)}, + iolist_to_binary(H)}, + data = mod_irc:data_to_binary(JID, Data)} + end); + _ -> + ?INFO_MSG("Recreating irc_custom table", []), + mnesia:transform_table(irc_custom, ignore, Fields) + end. diff --git a/src/mod_irc_riak.erl b/src/mod_irc_riak.erl new file mode 100644 index 000000000..6ac7befdf --- /dev/null +++ b/src/mod_irc_riak.erl @@ -0,0 +1,49 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 14 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_irc_riak). + +-behaviour(mod_irc). + +%% API +-export([init/2, get_data/3, set_data/4, import/2]). + +-include("jlib.hrl"). +-include("mod_irc.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + ok. + +get_data(_LServer, Host, From) -> + {U, S, _} = jid:tolower(From), + case ejabberd_riak:get(irc_custom, irc_custom_schema(), {{U, S}, Host}) of + {ok, #irc_custom{data = Data}} -> + Data; + {error, notfound} -> + empty; + _Err -> + error + end. + +set_data(_LServer, Host, From, Data) -> + {U, S, _} = jid:tolower(From), + {atomic, ejabberd_riak:put(#irc_custom{us_host = {{U, S}, Host}, + data = Data}, + irc_custom_schema())}. + +import(_LServer, #irc_custom{} = R) -> + ejabberd_riak:put(R, irc_custom_schema()). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +irc_custom_schema() -> + {record_info(fields, irc_custom), #irc_custom{}}. diff --git a/src/mod_irc_sql.erl b/src/mod_irc_sql.erl new file mode 100644 index 000000000..bf6dbb48e --- /dev/null +++ b/src/mod_irc_sql.erl @@ -0,0 +1,91 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov +%%% @copyright (C) 2016, Evgeny Khramtsov +%%% @doc +%%% +%%% @end +%%% Created : 14 Apr 2016 by Evgeny Khramtsov +%%%------------------------------------------------------------------- +-module(mod_irc_sql). + +-behaviour(mod_irc). + +%% API +-export([init/2, get_data/3, set_data/4, import/1, import/2, export/1]). + +-include("jlib.hrl"). +-include("mod_irc.hrl"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init(_Host, _Opts) -> + ok. + +get_data(LServer, Host, From) -> + LJID = jid:tolower(jid:remove_resource(From)), + SJID = ejabberd_odbc:escape(jid:to_string(LJID)), + SHost = ejabberd_odbc:escape(Host), + case catch ejabberd_odbc:sql_query( + LServer, + [<<"select data from irc_custom where jid='">>, + SJID, <<"' and host='">>, SHost, + <<"';">>]) of + {selected, [<<"data">>], [[SData]]} -> + mod_irc:data_to_binary(From, ejabberd_odbc:decode_term(SData)); + {'EXIT', _} -> error; + {selected, _, _} -> empty + end. + +set_data(LServer, Host, From, Data) -> + LJID = jid:tolower(jid:remove_resource(From)), + SJID = ejabberd_odbc:escape(jid:to_string(LJID)), + SHost = ejabberd_odbc:escape(Host), + SData = ejabberd_odbc:encode_term(Data), + F = fun () -> + odbc_queries:update_t(<<"irc_custom">>, + [<<"jid">>, <<"host">>, <<"data">>], + [SJID, SHost, SData], + [<<"jid='">>, SJID, <<"' and host='">>, + SHost, <<"'">>]), + ok + end, + ejabberd_odbc:sql_transaction(LServer, F). + +export(_Server) -> + [{irc_custom, + fun(Host, #irc_custom{us_host = {{U, S}, IRCHost}, + data = Data}) -> + case str:suffix(Host, IRCHost) of + true -> + SJID = ejabberd_odbc:escape( + jid:to_string( + jid:make(U, S, <<"">>))), + SIRCHost = ejabberd_odbc:escape(IRCHost), + SData = ejabberd_odbc:encode_term(Data), + [[<<"delete from irc_custom where jid='">>, SJID, + <<"' and host='">>, SIRCHost, <<"';">>], + [<<"insert into irc_custom(jid, host, " + "data) values ('">>, + SJID, <<"', '">>, SIRCHost, <<"', '">>, SData, + <<"');">>]]; + false -> + [] + end + end}]. + +import(_LServer) -> + [{<<"select jid, host, data from irc_custom;">>, + fun([SJID, IRCHost, SData]) -> + #jid{luser = U, lserver = S} = jid:from_string(SJID), + Data = ejabberd_odbc:decode_term(SData), + #irc_custom{us_host = {{U, S}, IRCHost}, + data = Data} + end}]. + +import(_, _) -> + pass. + +%%%=================================================================== +%%% Internal functions +%%%===================================================================