aboutsummaryrefslogtreecommitdiff
path: root/src/mod_mix_sql.erl
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/mod_mix_sql.erl236
1 files changed, 236 insertions, 0 deletions
diff --git a/src/mod_mix_sql.erl b/src/mod_mix_sql.erl
new file mode 100644
index 000000000..16f7c0d17
--- /dev/null
+++ b/src/mod_mix_sql.erl
@@ -0,0 +1,236 @@
+%%%-------------------------------------------------------------------
+%%% Created : 1 Dec 2018 by Evgeny Khramtsov <ekhramtsov@process-one.net>
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
+-module(mod_mix_sql).
+-behaviour(mod_mix).
+-compile([{parse_transform, ejabberd_sql_pt}]).
+
+%% API
+-export([init/2]).
+-export([set_channel/6, get_channels/2, get_channel/3, del_channel/3]).
+-export([set_participant/6, get_participant/4, get_participants/3, del_participant/4]).
+-export([subscribe/5, unsubscribe/4, unsubscribe/5, get_subscribed/4]).
+
+-include("logger.hrl").
+-include("ejabberd_sql_pt.hrl").
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+init(_Host, _Opts) ->
+ %% TODO
+ ok.
+
+set_channel(LServer, Channel, Service, CreatorJID, Hidden, Key) ->
+ {User, Domain, _} = jid:tolower(CreatorJID),
+ RawJID = jid:encode(jid:remove_resource(CreatorJID)),
+ case ?SQL_UPSERT(LServer, "mix_channel",
+ ["!channel=%(Channel)s",
+ "!service=%(Service)s",
+ "username=%(User)s",
+ "domain=%(Domain)s",
+ "jid=%(RawJID)s",
+ "hidden=%(Hidden)b",
+ "hmac_key=%(Key)s"]) of
+ ok -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+get_channels(LServer, Service) ->
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(channel)s, @(hidden)b from mix_channel "
+ "where service=%(Service)s")) of
+ {selected, Ret} ->
+ {ok, [Channel || {Channel, Hidden} <- Ret, Hidden == false]};
+ _Err ->
+ {error, db_failure}
+ end.
+
+get_channel(LServer, Channel, Service) ->
+ SQL = ?SQL("select @(jid)s, @(hidden)b, @(hmac_key)s from mix_channel "
+ "where channel=%(Channel)s and service=%(Service)s"),
+ case ejabberd_sql:sql_query(LServer, SQL) of
+ {selected, [{RawJID, Hidden, Key}]} ->
+ try jid:decode(RawJID) of
+ JID -> {ok, {JID, Hidden, Key}}
+ catch _:{bad_jid, _} ->
+ report_corrupted(jid, SQL),
+ {error, db_failure}
+ end;
+ {selected, []} -> {error, notfound};
+ _Err -> {error, db_failure}
+ end.
+
+del_channel(LServer, Channel, Service) ->
+ F = fun() ->
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from mix_channel where "
+ "channel=%(Channel)s and service=%(Service)s")),
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from mix_participant where "
+ "channel=%(Channel)s and service=%(Service)s")),
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from mix_subscription where "
+ "channel=%(Channel)s and service=%(Service)s"))
+ end,
+ case ejabberd_sql:sql_transaction(LServer, F) of
+ {atomic, _} -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+set_participant(LServer, Channel, Service, JID, ID, Nick) ->
+ {User, Domain, _} = jid:tolower(JID),
+ RawJID = jid:encode(jid:remove_resource(JID)),
+ case ?SQL_UPSERT(LServer, "mix_participant",
+ ["!channel=%(Channel)s",
+ "!service=%(Service)s",
+ "!username=%(User)s",
+ "!domain=%(Domain)s",
+ "jid=%(RawJID)s",
+ "id=%(ID)s",
+ "nick=%(Nick)s"]) of
+ ok -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+get_participant(LServer, Channel, Service, JID) ->
+ {User, Domain, _} = jid:tolower(JID),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("select @(id)s, @(nick)s from mix_participant "
+ "where channel=%(Channel)s and service=%(Service)s "
+ "and username=%(User)s and domain=%(Domain)s")) of
+ {selected, [Ret]} -> {ok, Ret};
+ {selected, []} -> {error, notfound};
+ _Err -> {error, db_failure}
+ end.
+
+get_participants(LServer, Channel, Service) ->
+ SQL = ?SQL("select @(jid)s, @(id)s, @(nick)s from mix_participant "
+ "where channel=%(Channel)s and service=%(Service)s"),
+ case ejabberd_sql:sql_query(LServer, SQL) of
+ {selected, Ret} ->
+ {ok, lists:filtermap(
+ fun({RawJID, ID, Nick}) ->
+ try jid:decode(RawJID) of
+ JID -> {true, {JID, ID, Nick}}
+ catch _:{bad_jid, _} ->
+ report_corrupted(jid, SQL),
+ false
+ end
+ end, Ret)};
+ _Err ->
+ {error, db_failure}
+ end.
+
+del_participant(LServer, Channel, Service, JID) ->
+ {User, Domain, _} = jid:tolower(JID),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("delete from mix_participant where "
+ "channel=%(Channel)s and service=%(Service)s "
+ "and username=%(User)s and domain=%(Domain)s")) of
+ {updated, _} -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+subscribe(_LServer, _Channel, _Service, _JID, []) ->
+ ok;
+subscribe(LServer, Channel, Service, JID, Nodes) ->
+ {User, Domain, _} = jid:tolower(JID),
+ RawJID = jid:encode(jid:remove_resource(JID)),
+ F = fun() ->
+ lists:foreach(
+ fun(Node) ->
+ ?SQL_UPSERT_T(
+ "mix_subscription",
+ ["!channel=%(Channel)s",
+ "!service=%(Service)s",
+ "!username=%(User)s",
+ "!domain=%(Domain)s",
+ "!node=%(Node)s",
+ "jid=%(RawJID)s"])
+ end, Nodes)
+ end,
+ case ejabberd_sql:sql_transaction(LServer, F) of
+ {atomic, _} -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+get_subscribed(LServer, Channel, Service, Node) ->
+ SQL = ?SQL("select @(jid)s from mix_subscription "
+ "where channel=%(Channel)s and service=%(Service)s "
+ "and node=%(Node)s"),
+ case ejabberd_sql:sql_query(LServer, SQL) of
+ {selected, Ret} ->
+ {ok, lists:filtermap(
+ fun({RawJID}) ->
+ try jid:decode(RawJID) of
+ JID -> {true, JID}
+ catch _:{bad_jid, _} ->
+ report_corrupted(jid, SQL),
+ false
+ end
+ end, Ret)};
+ _Err ->
+ {error, db_failure}
+ end.
+
+unsubscribe(LServer, Channel, Service, JID) ->
+ {User, Domain, _} = jid:tolower(JID),
+ case ejabberd_sql:sql_query(
+ LServer,
+ ?SQL("delete from mix_subscription "
+ "where channel=%(Channel)s and service=%(Service)s "
+ "and username=%(User)s and domain=%(Domain)s")) of
+ {updated, _} -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+unsubscribe(_LServer, _Channel, _Service, _JID, []) ->
+ ok;
+unsubscribe(LServer, Channel, Service, JID, Nodes) ->
+ {User, Domain, _} = jid:tolower(JID),
+ F = fun() ->
+ lists:foreach(
+ fun(Node) ->
+ ejabberd_sql:sql_query_t(
+ ?SQL("delete from mix_subscription "
+ "where channel=%(Channel)s "
+ "and service=%(Service)s "
+ "and username=%(User)s "
+ "and domain=%(Domain)s "
+ "and node=%(Node)s"))
+ end, Nodes)
+ end,
+ case ejabberd_sql:sql_transaction(LServer, F) of
+ {atomic, ok} -> ok;
+ _Err -> {error, db_failure}
+ end.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+-spec report_corrupted(atom(), iolist()) -> ok.
+report_corrupted(Column, SQL) ->
+ ?ERROR_MSG("Corrupted value of '~s' column returned by "
+ "SQL request: ~s", [Column, SQL]).