summaryrefslogblamecommitdiff
path: root/src/mod_privacy_sql.erl
blob: 6b996fa8b462a299e42089b5130ecb6b38652d5a (plain) (tree)














































































                                                                              
                                            































                                                                         
                                            



















                                                                               
                                            














                                                                      
                                            















































                                                                                     
                                                           










                                                                           
                                                    
                                   
                                                              










                                                                       
                                                              









































































































                                                                                

                                                                        















                                                            
                                                         

                                        
                                                  

                                             
                                                       

                                      
                                                

                                                
                                                          

                                         
                                                   

                                                  
                                                            

                                           


                                                         

                                               
                                                         

                                        
                                                  

                                            
                                                      

                                                 
                                                           

                                       
                                                 

                                    
                                              

                                   
                                             

                                        
                                                  
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2016, Evgeny Khramtsov
%%% @doc
%%%
%%% @end
%%% Created : 14 Apr 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
-module(mod_privacy_sql).

-behaviour(mod_privacy).

%% API
-export([init/2, process_lists_get/2, process_list_get/3,
	 process_default_set/3, process_active_set/3,
	 remove_privacy_list/3, set_privacy_list/1,
	 set_privacy_list/4, get_user_list/2, get_user_lists/2,
	 remove_user/2, import/1, import/2, export/1]).

-export([item_to_raw/1, raw_to_item/1,
	 sql_add_privacy_list/2,
	 sql_get_default_privacy_list/2,
	 sql_get_default_privacy_list_t/1,
	 sql_get_privacy_list_data/3,
	 sql_get_privacy_list_data_by_id_t/1,
	 sql_get_privacy_list_id_t/2,
	 sql_set_default_privacy_list/2, sql_set_privacy_list/2]).

-include("jlib.hrl").
-include("mod_privacy.hrl").
-include("logger.hrl").

%%%===================================================================
%%% API
%%%===================================================================
init(_Host, _Opts) ->
    ok.

process_lists_get(LUser, LServer) ->
    Default = case catch sql_get_default_privacy_list(LUser, LServer) of
		{selected, []} -> none;
		{selected, [{DefName}]} -> DefName;
		_ -> none
	      end,
    case catch sql_get_privacy_list_names(LUser, LServer) of
      {selected, Names} ->
	  LItems = lists:map(fun ({N}) ->
				     #xmlel{name = <<"list">>,
					    attrs = [{<<"name">>, N}],
					    children = []}
			     end,
			     Names),
	  {Default, LItems};
      _ -> error
    end.

process_list_get(LUser, LServer, Name) ->
    case catch sql_get_privacy_list_id(LUser, LServer, Name) of
      {selected, []} -> not_found;
      {selected, [{ID}]} ->
	  case catch sql_get_privacy_list_data_by_id(ID, LServer) of
	    {selected, RItems} ->
		lists:flatmap(fun raw_to_item/1, RItems);
	    _ -> error
	  end;
      _ -> error
    end.

process_default_set(LUser, LServer, {value, Name}) ->
    F = fun () ->
		case sql_get_privacy_list_names_t(LUser) of
		  {selected, []} -> not_found;
		  {selected, Names} ->
		      case lists:member({Name}, Names) of
			true -> sql_set_default_privacy_list(LUser, Name), ok;
			false -> not_found
		      end
		end
	end,
    sql_queries:sql_transaction(LServer, F);
process_default_set(LUser, LServer, false) ->
    case catch sql_unset_default_privacy_list(LUser,
					      LServer)
	of
      {'EXIT', _Reason} -> {atomic, error};
      {error, _Reason} -> {atomic, error};
      _ -> {atomic, ok}
    end.

process_active_set(LUser, LServer, Name) ->
    case catch sql_get_privacy_list_id(LUser, LServer, Name) of
      {selected, []} -> error;
      {selected, [{ID}]} ->
	  case catch sql_get_privacy_list_data_by_id(ID, LServer) of
	    {selected, RItems} ->
		lists:flatmap(fun raw_to_item/1, RItems);
	    _ -> error
	  end;
      _ -> error
    end.

remove_privacy_list(LUser, LServer, Name) ->
    F = fun () ->
		case sql_get_default_privacy_list_t(LUser) of
		  {selected, []} ->
		      sql_remove_privacy_list(LUser, Name), ok;
		  {selected, [{Default}]} ->
		      if Name == Default -> conflict;
			 true -> sql_remove_privacy_list(LUser, Name), ok
		      end
		end
	end,
    sql_queries:sql_transaction(LServer, F).

set_privacy_list(#privacy{us = {LUser, LServer},
			  default = Default,
			  lists = Lists}) ->
    F = fun() ->
		lists:foreach(
		  fun({Name, List}) ->
			  sql_add_privacy_list(LUser, Name),
			  {selected, [<<"id">>], [[I]]} =
			      sql_get_privacy_list_id_t(LUser, Name),
			  RItems = lists:map(fun item_to_raw/1, List),
			  sql_set_privacy_list(I, RItems),
			  if is_binary(Default) ->
				  sql_set_default_privacy_list(LUser, Default),
				  ok;
			     true ->
				  ok
			  end
		  end, Lists)
	end,
    sql_queries:sql_transaction(LServer, F).

set_privacy_list(LUser, LServer, Name, List) ->
    RItems = lists:map(fun item_to_raw/1, List),
    F = fun () ->
		ID = case sql_get_privacy_list_id_t(LUser, Name) of
                         {selected, []} ->
			   sql_add_privacy_list(LUser, Name),
			   {selected, [{I}]} =
			       sql_get_privacy_list_id_t(LUser, Name),
			   I;
		       {selected, [{I}]} -> I
		     end,
		sql_set_privacy_list(ID, RItems),
		ok
	end,
    sql_queries:sql_transaction(LServer, F).

get_user_list(LUser, LServer) ->
    case catch sql_get_default_privacy_list(LUser, LServer)
	of
      {selected, []} -> {none, []};
      {selected, [{Default}]} ->
	  case catch sql_get_privacy_list_data(LUser, LServer,
					       Default) of
              {selected, RItems} ->
		{Default, lists:flatmap(fun raw_to_item/1, RItems)};
	    _ -> {none, []}
	  end;
      _ -> {none, []}
    end.

get_user_lists(LUser, LServer) ->
    Default = case catch sql_get_default_privacy_list(LUser, LServer) of
                  {selected, []} ->
                      none;
                  {selected, [{DefName}]} ->
                      DefName;
                  _ ->
                      none
	      end,
    case catch sql_get_privacy_list_names(LUser, LServer) of
        {selected, Names} ->
            Lists =
                lists:flatmap(
                  fun({Name}) ->
                          case catch sql_get_privacy_list_data(
                                       LUser, LServer, Name) of
                              {selected, RItems} ->
                                  [{Name, lists:flatmap(fun raw_to_item/1, RItems)}];
                              _ ->
                                  []
                          end
                  end, Names),
            {ok, #privacy{default = Default,
                          us = {LUser, LServer},
                          lists = Lists}};
        _ ->
            error
    end.

remove_user(LUser, LServer) ->
    sql_del_privacy_lists(LUser, LServer).

export(Server) ->
    case catch ejabberd_sql:sql_query(jid:nameprep(Server),
				 [<<"select id from privacy_list order by "
				    "id desc limit 1;">>]) of
        {selected, [<<"id">>], [[I]]} ->
            put(id, jlib:binary_to_integer(I));
        _ ->
            put(id, 0)
    end,
    [{privacy,
      fun(Host, #privacy{us = {LUser, LServer}, lists = Lists,
                         default = Default})
            when LServer == Host ->
              Username = ejabberd_sql:escape(LUser),
              if Default /= none ->
                      SDefault = ejabberd_sql:escape(Default),
                      [[<<"delete from privacy_default_list where ">>,
                        <<"username='">>, Username, <<"';">>],
                       [<<"insert into privacy_default_list(username, "
                          "name) ">>,
                        <<"values ('">>, Username, <<"', '">>,
                        SDefault, <<"');">>]];
                 true ->
                      []
              end ++
                  lists:flatmap(
                    fun({Name, List}) ->
                            SName = ejabberd_sql:escape(Name),
                            RItems = lists:map(fun item_to_raw/1, List),
                            ID = jlib:integer_to_binary(get_id()),
                            [[<<"delete from privacy_list where username='">>,
                              Username, <<"' and name='">>,
                              SName, <<"';">>],
                             [<<"insert into privacy_list(username, "
                                "name, id) values ('">>,
                              Username, <<"', '">>, SName,
                              <<"', '">>, ID, <<"');">>],
                             [<<"delete from privacy_list_data where "
                                "id='">>, ID, <<"';">>]] ++
                                [[<<"insert into privacy_list_data(id, t, "
                                    "value, action, ord, match_all, match_iq, "
                                    "match_message, match_presence_in, "
                                    "match_presence_out) values ('">>,
                                  ID, <<"', '">>, str:join(Items, <<"', '">>),
                                  <<"');">>] || Items <- RItems]
                    end,
                    Lists);
         (_Host, _R) ->
              []
      end}].

get_id() ->
    ID = get(id),
    put(id, ID + 1),
    ID + 1.

import(LServer) ->
    [{<<"select username from privacy_list;">>,
      fun([LUser]) ->
              Default = case sql_get_default_privacy_list_t(LUser) of
                            {selected, [<<"name">>], []} ->
                                none;
                            {selected, [<<"name">>], [[DefName]]} ->
                                DefName;
                            _ ->
                                none
                        end,
              {selected, [<<"name">>], Names} =
                  sql_get_privacy_list_names_t(LUser),
              Lists = lists:flatmap(
                        fun([Name]) ->
                                case sql_get_privacy_list_data_t(LUser, Name) of
                                    {selected, _, RItems} ->
                                        [{Name,
                                          lists:map(fun raw_to_item/1,
                                                    RItems)}];
                                    _ ->
                                        []
                                end
                        end, Names),
              #privacy{default = Default,
                       us = {LUser, LServer},
                       lists = Lists}
      end}].

import(_, _) ->
    pass.

%%%===================================================================
%%% Internal functions
%%%===================================================================
raw_to_item({SType, SValue, SAction, Order, MatchAll,
	     MatchIQ, MatchMessage, MatchPresenceIn,
	     MatchPresenceOut} = Row) ->
    try
        {Type, Value} = case SType of
                            <<"n">> -> {none, none};
                            <<"j">> ->
                                case jid:from_string(SValue) of
                                    #jid{} = JID ->
                                        {jid, jid:tolower(JID)}
                                end;
                            <<"g">> -> {group, SValue};
                            <<"s">> ->
                                case SValue of
                                    <<"none">> -> {subscription, none};
                                    <<"both">> -> {subscription, both};
                                    <<"from">> -> {subscription, from};
                                    <<"to">> -> {subscription, to}
                                end
                        end,
        Action = case SAction of
                     <<"a">> -> allow;
                     <<"d">> -> deny
                 end,
        [#listitem{type = Type, value = Value, action = Action,
                   order = Order, match_all = MatchAll, match_iq = MatchIQ,
                   match_message = MatchMessage,
                   match_presence_in = MatchPresenceIn,
                   match_presence_out = MatchPresenceOut}]
    catch _:_ ->
            ?WARNING_MSG("failed to parse row: ~p", [Row]),
            []
    end.

item_to_raw(#listitem{type = Type, value = Value,
		      action = Action, order = Order, match_all = MatchAll,
		      match_iq = MatchIQ, match_message = MatchMessage,
		      match_presence_in = MatchPresenceIn,
		      match_presence_out = MatchPresenceOut}) ->
    {SType, SValue} = case Type of
			none -> {<<"n">>, <<"">>};
			jid ->
			    {<<"j">>,
			     ejabberd_sql:escape(jid:to_string(Value))};
			group -> {<<"g">>, ejabberd_sql:escape(Value)};
			subscription ->
			    case Value of
			      none -> {<<"s">>, <<"none">>};
			      both -> {<<"s">>, <<"both">>};
			      from -> {<<"s">>, <<"from">>};
			      to -> {<<"s">>, <<"to">>}
			    end
		      end,
    SAction = case Action of
		allow -> <<"a">>;
		deny -> <<"d">>
	      end,
    {SType, SValue, SAction, Order, MatchAll, MatchIQ,
     MatchMessage, MatchPresenceIn, MatchPresenceOut}.

sql_get_default_privacy_list(LUser, LServer) ->
    sql_queries:get_default_privacy_list(LServer, LUser).

sql_get_default_privacy_list_t(LUser) ->
    sql_queries:get_default_privacy_list_t(LUser).

sql_get_privacy_list_names(LUser, LServer) ->
    sql_queries:get_privacy_list_names(LServer, LUser).

sql_get_privacy_list_names_t(LUser) ->
    sql_queries:get_privacy_list_names_t(LUser).

sql_get_privacy_list_id(LUser, LServer, Name) ->
    sql_queries:get_privacy_list_id(LServer, LUser, Name).

sql_get_privacy_list_id_t(LUser, Name) ->
    sql_queries:get_privacy_list_id_t(LUser, Name).

sql_get_privacy_list_data(LUser, LServer, Name) ->
    sql_queries:get_privacy_list_data(LServer, LUser, Name).

sql_get_privacy_list_data_t(LUser, Name) ->
    Username = ejabberd_sql:escape(LUser),
    SName = ejabberd_sql:escape(Name),
    sql_queries:get_privacy_list_data_t(Username, SName).

sql_get_privacy_list_data_by_id(ID, LServer) ->
    sql_queries:get_privacy_list_data_by_id(LServer, ID).

sql_get_privacy_list_data_by_id_t(ID) ->
    sql_queries:get_privacy_list_data_by_id_t(ID).

sql_set_default_privacy_list(LUser, Name) ->
    sql_queries:set_default_privacy_list(LUser, Name).

sql_unset_default_privacy_list(LUser, LServer) ->
    sql_queries:unset_default_privacy_list(LServer, LUser).

sql_remove_privacy_list(LUser, Name) ->
    sql_queries:remove_privacy_list(LUser, Name).

sql_add_privacy_list(LUser, Name) ->
    sql_queries:add_privacy_list(LUser, Name).

sql_set_privacy_list(ID, RItems) ->
    sql_queries:set_privacy_list(ID, RItems).

sql_del_privacy_lists(LUser, LServer) ->
    sql_queries:del_privacy_lists(LServer, LUser).