diff options
Diffstat (limited to 'src/mod_mix_sql.erl')
-rw-r--r-- | src/mod_mix_sql.erl | 236 |
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]). |