]> git.pld-linux.org Git - packages/ejabberd.git/commitdiff
- up to 2.1.12; vcard-access-get.patch needs update
authorArkadiusz Miśkiewicz <arekm@maven.pl>
Fri, 17 May 2013 06:43:04 +0000 (08:43 +0200)
committerArkadiusz Miśkiewicz <arekm@maven.pl>
Fri, 17 May 2013 06:43:04 +0000 (08:43 +0200)
ejabberd-mod_logdb.patch
ejabberd-vcard-access-get.patch
ejabberd.spec

index 30ea02a1358a3722e24c306785bb5f4c93128e7e..db65297ec35b93d8d5d4594d8eef46b022fb59aa 100644 (file)
---- mod_logdb.erl.orig 2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb.erl      2009-11-22 13:06:16.000000000 +0200
-@@ -0,0 +1,2095 @@
+diff --git src/gen_logdb.erl src/gen_logdb.erl
+new file mode 100644
+index 0000000..06a894b
+--- /dev/null
++++ src/gen_logdb.erl
+@@ -0,0 +1,164 @@
++%%%----------------------------------------------------------------------
++%%% File    : gen_logdb.erl
++%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
++%%% Purpose : Describes generic behaviour for mod_logdb backends.
++%%% Version : trunk
++%%% Id      : $Id: gen_logdb.erl 1273 2009-02-05 18:12:57Z malik $
++%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
++%%%----------------------------------------------------------------------
++
++-module(gen_logdb).
++-author('o.palij@gmail.com').
++
++-export([behaviour_info/1]).
++
++behaviour_info(callbacks) ->
++   [
++    % called from handle_info(start, _)
++    % it should logon database and return reference to started instance
++    % start(VHost, Opts) -> {ok, SPid} | error
++    %  Options - list of options to connect to db
++    %    Types: Options = list() -> [] |
++    %                              [{user, "logdb"},
++    %                               {pass, "1234"},
++    %                               {db, "logdb"}] | ...
++    %          VHost = list() -> "jabber.example.org"
++    {start, 2},
++
++    % called from cleanup/1
++    % it should logoff database and do cleanup
++    % stop(VHost)
++    %    Types: VHost = list() -> "jabber.example.org"
++    {stop, 1},
++
++    % called from handle_call({addlog, _}, _, _)
++    % it should log messages to database
++    % log_message(VHost, Msg) -> ok | error
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          Msg = record() -> #msg
++    {log_message, 2},
++
++    % called from ejabberdctl rebuild_stats
++    % it should rebuild stats table (if used) for vhost
++    % rebuild_stats(VHost)
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    {rebuild_stats, 1},
++
++    % it should rebuild stats table (if used) for vhost at Date
++    % rebuild_stats_at(VHost, Date)
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          Date = list() -> "2007-02-12"
++    {rebuild_stats_at, 2},
++
++    % called from user_messages_at_parse_query/5
++    % it should delete selected user messages at date
++    % delete_messages_by_user_at(VHost, Msgs, Date) -> ok | error
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          Msgs = list() -> [ #msg1, msg2, ... ]
++    %          Date = list() -> "2007-02-12"
++    {delete_messages_by_user_at, 3},
++
++    % called from user_messages_parse_query/4 | vhost_messages_at_parse_query/4
++    % it should delete all user messages at date
++    % delete_all_messages_by_user_at(User, VHost, Date) -> ok | error
++    %    Types:
++    %          User = list() -> "admin"
++    %          VHost = list() -> "jabber.example.org"
++    %          Date = list() -> "2007-02-12"
++    {delete_all_messages_by_user_at, 3},
++
++    % called from vhost_messages_parse_query/3
++    % it should delete messages for vhost at date and update stats
++    % delete_messages_at(VHost, Date) -> ok | error
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          Date = list() -> "2007-02-12"
++    {delete_messages_at, 2},
++
++    % called from ejabberd_web_admin:vhost_messages_stats/3
++    % it should return sorted list of count of messages by dates for vhost
++    % get_vhost_stats(VHost) -> {ok, [{Date1, Msgs_count1}, {Date2, Msgs_count2}, ... ]} |
++    %                           {error, Reason}
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          DateN = list() -> "2007-02-12"
++    %          Msgs_countN = number() -> 241
++    {get_vhost_stats, 1},
++
++    % called from ejabberd_web_admin:vhost_messages_stats_at/4
++    % it should return sorted list of count of messages by users at date for vhost
++    % get_vhost_stats_at(VHost, Date) -> {ok, [{User1, Msgs_count1}, {User2, Msgs_count2}, ....]} |
++    %                                    {error, Reason}
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          Date = list() -> "2007-02-12"
++    %          UserN = list() -> "admin"
++    %          Msgs_countN = number() -> 241
++    {get_vhost_stats_at, 2},
++
++    % called from ejabberd_web_admin:user_messages_stats/4
++    % it should return sorted list of count of messages by date for user at vhost
++    % get_user_stats(User, VHost) -> {ok, [{Date1, Msgs_count1}, {Date2, Msgs_count2}, ...]} |
++    %                                {error, Reason}
++    %    Types:
++    %          User = list() -> "admin"
++    %          VHost = list() -> "jabber.example.org"
++    %          DateN = list() -> "2007-02-12"
++    %          Msgs_countN = number() -> 241
++    {get_user_stats, 2},
++
++    % called from ejabberd_web_admin:user_messages_stats_at/5
++    % it should return all user messages at date
++    % get_user_messages_at(User, VHost, Date) -> {ok, Msgs} | {error, Reason}
++    %    Types:
++    %          User = list() -> "admin"
++    %          VHost = list() -> "jabber.example.org"
++    %          Date = list() -> "2007-02-12"
++    %          Msgs = list() -> [ #msg1, msg2, ... ]
++    {get_user_messages_at, 3},
++
++    % called from many places
++    % it should return list of dates for vhost
++    % get_dates(VHost) -> [Date1, Date2, ... ]
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    %          DateN = list() -> "2007-02-12"
++    {get_dates, 1},
++
++    % called from start
++    % it should return list with users settings for VHost in db
++    % get_users_settings(VHost) -> [#user_settings1, #user_settings2, ... ] | error
++    %    Types:
++    %          VHost = list() -> "jabber.example.org"
++    {get_users_settings, 1},
++
++    % called from many places
++    % it should return User settings at VHost from db
++    % get_user_settings(User, VHost) -> error | {ok, #user_settings}
++    %    Types:
++    %          User = list() -> "admin"
++    %          VHost = list() -> "jabber.example.org"
++    {get_user_settings, 2},
++
++    % called from web admin
++    % it should set User settings at VHost
++    % set_user_settings(User, VHost, #user_settings) -> ok | error
++    %    Types:
++    %          User = list() -> "admin"
++    %          VHost = list() -> "jabber.example.org"
++    {set_user_settings, 3},
++
++    % called from remove_user (ejabberd hook)
++    % it should remove user messages and settings at VHost
++    % drop_user(User, VHost) -> ok | error
++    %    Types:
++    %          User = list() -> "admin"
++    %          VHost = list() -> "jabber.example.org"
++    {drop_user, 2}
++   ];
++behaviour_info(_) ->
++   undefined.
+diff --git src/mod_logdb.erl src/mod_logdb.erl
+new file mode 100644
+index 0000000..7de346f
+--- /dev/null
++++ src/mod_logdb.erl
+@@ -0,0 +1,2087 @@
 +%%%----------------------------------------------------------------------
 +%%% File    : mod_logdb.erl
 +%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
 +%%% Purpose : Frontend for log user messages to db
 +%%% Version : trunk
-+%%% Id      : $Id$
++%%% Id      : $Id: mod_logdb.erl 1360 2009-07-30 06:00:14Z malik $
 +%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
 +%%%----------------------------------------------------------------------
 +
 +% gen_server
 +-export([code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]).
 +% hooks
-+-export([send_packet/3, receive_packet/4, offline_packet/3, remove_user/2]).
++-export([send_packet/3, receive_packet/4, remove_user/2]).
 +-export([get_local_identity/5,
-+         get_local_features/5, 
++         get_local_features/5,
 +         get_local_items/5,
 +         adhoc_local_items/4,
 +         adhoc_local_commands/4
 +    ejabberd_hooks:delete(remove_user, VHost, ?MODULE, remove_user, 90),
 +    ejabberd_hooks:delete(user_send_packet, VHost, ?MODULE, send_packet, 90),
 +    ejabberd_hooks:delete(user_receive_packet, VHost, ?MODULE, receive_packet, 90),
-+    ejabberd_hooks:delete(offline_message_hook, VHost, ?MODULE, offline_packet, 10),
 +    %ejabberd_hooks:delete(adhoc_sm_commands, VHost, ?MODULE, adhoc_sm_commands, 110),
 +    %ejabberd_hooks:delete(adhoc_sm_items, VHost, ?MODULE, adhoc_sm_items, 110),
 +    ejabberd_hooks:delete(adhoc_local_commands, VHost, ?MODULE, adhoc_local_commands, 110),
 +           {stop, db_connection_failed, State};
 +         {ok, SPid} ->
 +           ?INFO_MSG("~p connection established", [DBMod]),
-+           
++
 +           MonRef = erlang:monitor(process, SPid),
 +
 +           ets:new(ets_settings_table(VHost), [named_table,public,set,{keypos, #user_settings.owner_name}]),
 +           ejabberd_hooks:add(remove_user, VHost, ?MODULE, remove_user, 90),
 +           ejabberd_hooks:add(user_send_packet, VHost, ?MODULE, send_packet, 90),
 +           ejabberd_hooks:add(user_receive_packet, VHost, ?MODULE, receive_packet, 90),
-+           ejabberd_hooks:add(offline_message_hook, VHost, ?MODULE, offline_packet, 10),
 +
 +           ejabberd_hooks:add(disco_local_items, VHost, ?MODULE, get_local_items, 110),
 +           ejabberd_hooks:add(disco_local_features, VHost, ?MODULE, get_local_features, 110),
 +    Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
 +    gen_server:cast(Proc, {addlog, to, Owner, Peer, P}).
 +
-+offline_packet(Peer, Owner, P) ->
-+    VHost = Owner#jid.lserver,
-+    Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
-+    gen_server:cast(Proc, {addlog, from, Owner, Peer, P}).
-+
-+receive_packet(_JID, Peer, Owner, P) -> 
++receive_packet(_JID, Peer, Owner, P) ->
 +    VHost = Owner#jid.lserver,
 +    Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
 +    gen_server:cast(Proc, {addlog, from, Owner, Peer, P}).
 +                   Ni=lists:foldl(fun([{muc_online_room, {GName, GHost}, Pid}], Names) ->
 +                                   case gen_fsm:sync_send_all_state_event(Pid, {get_jid_nick,Owner}) of
 +                                        [] -> Names;
-+                                        Nick -> 
++                                        Nick ->
 +                                           lists:append(Names, [jlib:jid_to_string({GName, GHost, Nick})])
 +                                   end
 +                                  end, [], Rooms),
 +                 _ -> State#state.dolog_default
 +          end,
 +
-+    lists:all(fun(O) -> O end, 
++    lists:all(fun(O) -> O end,
 +              [not lists:member(OwnerStr, State#state.ignore_jids),
 +               not lists:member(PeerStr, State#state.ignore_jids),
 +               not lists:member(OwnerServ, State#state.ignore_jids),
 +    DateDiff = list_to_integer(Days)*24*60*60,
 +    ?MYDEBUG("Purging tables older than ~s days", [Days]),
 +    lists:foreach(fun(Date) ->
-+                    {ok, [Year, Month, Day]} = regexp:split(Date, "[^0-9]+"),
++                    [Year, Month, Day] = ejabberd_regexp:split(Date, "[^0-9]+"),
 +                    DateInSec = calendar:datetime_to_gregorian_seconds({{list_to_integer(Year), list_to_integer(Month), list_to_integer(Day)}, {0,0,1}}),
 +                    if
 +                     (DateNow - DateInSec) > DateDiff ->
 +                        gen_server:call(Proc, {delete_messages_at, Date});
-+                     true -> 
++                     true ->
 +                        ?MYDEBUG("Skipping messages at ~p", [Date])
 +                    end
 +              end, Dates).
 +sort_stats(Stats) ->
 +    % Stats = [{"2003-4-15",1}, {"2006-8-18",1}, ... ]
 +    CFun = fun({TableName, Count}) ->
-+                 {ok, [Year, Month, Day]} = regexp:split(TableName, "[^0-9]+"),
++                 [Year, Month, Day] = ejabberd_regexp:split(TableName, "[^0-9]+"),
 +                 { calendar:datetime_to_gregorian_seconds({{list_to_integer(Year), list_to_integer(Month), list_to_integer(Day)}, {0,0,1}}), Count }
 +           end,
 +    % convert to [{63364377601,1}, {63360662401,1}, ... ]
 +    FromDBMod = list_to_atom(atom_to_list(?MODULE) ++ "_" ++ atom_to_list(FromDBName)),
 +
 +    {ok, _FromPid} = FromDBMod:start(VHost, FromDBOpts),
-+ 
++
 +    Dates = FromDBMod:get_dates(VHost),
 +    DatesLength = length(Dates),
 +
 +
 +copy_messages_int_tc([FromDBMod, ToDBMod, VHost, Date]) ->
 +    ?INFO_MSG("Going to copy messages from ~p for ~p at ~p", [FromDBMod, VHost, Date]),
-+   
++
 +    ok = FromDBMod:rebuild_stats_at(VHost, Date),
 +    catch mod_logdb:rebuild_stats_at(VHost, Date),
 +    {ok, FromStats} = FromDBMod:get_vhost_stats_at(VHost, Date),
 +string_to_list([]) ->
 +    [];
 +string_to_list(String) ->
-+    {ok, List} = regexp:split(String, "\n"),
-+    List.
++    ejabberd_regexp:split(String, "\n").
 +
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +%
 +        Users ->
 +            SUsers = lists:sort([{S, U} || {U, S} <- Users]),
 +            case catch begin
-+                           {ok, [S1, S2]} = regexp:split(Diap, "-"),
++                           [S1, S2] = ejabberd_regexp:split(Diap, "-"),
 +                           N1 = list_to_integer(S1),
 +                           N2 = list_to_integer(S2),
 +                           Sub = lists:sublist(SUsers, N1, N2 - N1 + 1),
 +
 +parse_users_settings(XData) ->
 +    DLD = case lists:keysearch("dolog_default", 1, XData) of
-+               {value, {_, [String]}} when String == "true"; String == "false" -> 
++               {value, {_, [String]}} when String == "true"; String == "false" ->
 +                 list_to_bool(String);
 +               _ ->
 +                 throw(bad_request)
 +             ]
 +            )]
 +    end.
---- mod_logdb.hrl.orig 2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb.hrl      2009-02-05 20:12:58.000000000 +0200
+diff --git src/mod_logdb.hrl src/mod_logdb.hrl
+new file mode 100644
+index 0000000..50db897
+--- /dev/null
++++ src/mod_logdb.hrl
 @@ -0,0 +1,35 @@
 +%%%----------------------------------------------------------------------
 +%%% File    : mod_logdb.hrl
 +%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
 +%%% Purpose :
 +%%% Version : trunk
-+%%% Id      : $Id$
++%%% Id      : $Id: mod_logdb.hrl 1273 2009-02-05 18:12:57Z malik $
 +%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
 +%%%----------------------------------------------------------------------
 +
 +                      {"name", Name},
 +                      {"value", Value},
 +                      {"checked", "true"}])).
---- mod_logdb_mnesia.erl.orig  2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb_mnesia.erl       2009-02-05 20:12:58.000000000 +0200
+diff --git src/mod_logdb_mnesia.erl src/mod_logdb_mnesia.erl
+new file mode 100644
+index 0000000..783aaeb
+--- /dev/null
++++ src/mod_logdb_mnesia.erl
 @@ -0,0 +1,546 @@
 +%%%----------------------------------------------------------------------
 +%%% File    : mod_logdb_mnesia.erl
 +%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
 +%%% Purpose : mnesia backend for mod_logdb
 +%%% Version : trunk
-+%%% Id      : $Id$
++%%% Id      : $Id: mod_logdb_mnesia.erl 1273 2009-02-05 18:12:57Z malik $
 +%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
 +%%%----------------------------------------------------------------------
 +
 +
 +-behaviour(gen_logdb).
 +-behaviour(gen_server).
-+   
++
 +% gen_server
 +-export([code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]).
 +% gen_mod
 +         get_dates/1,
 +         get_users_settings/1, get_user_settings/2, set_user_settings/3,
 +         drop_user/2]).
-+ 
++
 +-define(PROCNAME, mod_logdb_mnesia).
 +-define(CALL_TIMEOUT, 10000).
-+  
++
 +-record(state, {vhost}).
 +
 +-record(stats, {user, at, count}).
 +    {reply, Reply, State};
 +handle_call({rebuild_stats_at, Date}, _From, #state{vhost=VHost}=State) ->
 +    Reply = rebuild_stats_at_int(VHost, Date),
-+    {reply, Reply, State}; 
++    {reply, Reply, State};
 +handle_call({delete_messages_by_user_at, Msgs, Date}, _From, #state{vhost=VHost}=State) ->
 +    Table = table_name(VHost, Date),
 +    Fun = fun() ->
 +    Tables = mnesia:system_info(tables),
 +    lists:foldl(fun(ATable, Dates) ->
 +                    Table = atom_to_list(ATable),
-+                    case regexp:match(Table, VHost++"$") of
-+                         {match, _, _} ->
-+                            case regexp:match(Table,"_[0-9]+-[0-9]+-[0-9]+_") of
-+                                 {match, S, E} ->
++                    case ejabberd_regexp:run(Table, VHost++"$") of
++                         match ->
++                            case re:run(Table, "_[0-9]+-[0-9]+-[0-9]+_") of
++                                 {match, [{S, E}]} ->
 +                                     lists:append(Dates, [lists:sublist(Table,S+1,E-2)]);
 +                                 nomatch ->
 +                                     Dates
 +               {type, bag},
 +               {attributes, record_info(fields, msg)},
 +               {record_name, msg}]).
---- mod_logdb_mysql.erl.orig   2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb_mysql.erl        2009-07-30 09:00:14.000000000 +0300
-@@ -0,0 +1,1053 @@
+diff --git src/mod_logdb_mnesia_old.erl src/mod_logdb_mnesia_old.erl
+new file mode 100644
+index 0000000..aef9956
+--- /dev/null
++++ src/mod_logdb_mnesia_old.erl
+@@ -0,0 +1,258 @@
 +%%%----------------------------------------------------------------------
-+%%% File    : mod_logdb_mysql.erl
++%%% File    : mod_logdb_mnesia_old.erl
 +%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
-+%%% Purpose : MySQL backend for mod_logdb
++%%% Purpose : mod_logmnesia backend for mod_logdb (should be used only for copy_tables functionality)
 +%%% Version : trunk
-+%%% Id      : $Id$
++%%% Id      : $Id: mod_logdb_mnesia_old.erl 1273 2009-02-05 18:12:57Z malik $
 +%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
 +%%%----------------------------------------------------------------------
 +
-+-module(mod_logdb_mysql).
++-module(mod_logdb_mnesia_old).
 +-author('o.palij@gmail.com').
 +
-+-include("mod_logdb.hrl").
 +-include("ejabberd.hrl").
 +-include("jlib.hrl").
 +
 +-behaviour(gen_logdb).
-+-behaviour(gen_server).
 +
-+% gen_server
-+-export([code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]).
-+% gen_mod
-+-export([start/2, stop/1]).
-+% gen_logdb
-+-export([log_message/2,
++-export([start/2, stop/1,
++         log_message/2,
 +         rebuild_stats/1,
 +         rebuild_stats_at/2,
++         rebuild_stats_at1/2,
 +         delete_messages_by_user_at/3, delete_all_messages_by_user_at/3, delete_messages_at/2,
 +         get_vhost_stats/1, get_vhost_stats_at/2, get_user_stats/2, get_user_messages_at/3,
 +         get_dates/1,
 +         get_users_settings/1, get_user_settings/2, set_user_settings/3,
 +         drop_user/2]).
 +
-+% gen_server call timeout
-+-define(CALL_TIMEOUT, 30000).
-+-define(MYSQL_TIMEOUT, 60000).
-+-define(INDEX_SIZE, integer_to_list(170)).
-+-define(PROCNAME, mod_logdb_mysql).
-+
-+-import(mod_logdb, [list_to_bool/1, bool_to_list/1,
-+                    list_to_string/1, string_to_list/1,
-+                    convert_timestamp_brief/1]).
-+
-+-record(state, {dbref, vhost, server, port, db, user, password}).
-+
-+% replace "." with "_"
-+escape_vhost(VHost) -> lists:map(fun(46) -> 95;
-+                                    (A) -> A
-+                                 end, VHost).
-+prefix() ->
-+   "`logdb_".
-+
-+suffix(VHost) ->
-+   "_" ++ escape_vhost(VHost) ++ "`".
-+
-+messages_table(VHost, Date) ->
-+   prefix() ++ "messages_" ++ Date ++ suffix(VHost).
-+
-+stats_table(VHost) ->
-+   prefix() ++ "stats" ++ suffix(VHost).
-+
-+temp_table(VHost) ->
-+   prefix() ++ "temp" ++ suffix(VHost).
-+
-+settings_table(VHost) ->
-+   prefix() ++ "settings" ++ suffix(VHost).
-+
-+users_table(VHost) ->
-+   prefix() ++ "users" ++ suffix(VHost).
-+servers_table(VHost) ->
-+   prefix() ++ "servers" ++ suffix(VHost).
-+resources_table(VHost) ->
-+   prefix() ++ "resources" ++ suffix(VHost).
++-record(stats, {user, server, table, count}).
++-record(msg,   {to_user, to_server, to_resource, from_user, from_server, from_resource, id, type, subject, body, timestamp}).
 +
-+ets_users_table(VHost) -> list_to_atom("logdb_users_" ++ VHost).
-+ets_servers_table(VHost) -> list_to_atom("logdb_servers_" ++ VHost).
-+ets_resources_table(VHost) -> list_to_atom("logdb_resources_" ++ VHost).
++tables_prefix() -> "messages_".
++% stats_table should not start with tables_prefix(VHost) !
++% i.e. lists:prefix(tables_prefix(VHost), atom_to_list(stats_table())) must be /= true
++stats_table() -> list_to_atom("messages-stats").
++% table name as atom from Date
++-define(ATABLE(Date), list_to_atom(tables_prefix() ++ Date)).
++-define(LTABLE(Date), tables_prefix() ++ Date).
 +
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +%
-+% gen_mod callbacks
++% gen_logdb callbacks
 +%
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+start(VHost, Opts) ->
-+   Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
-+   gen_server:start({local, Proc}, ?MODULE, [VHost, Opts], []).
-+
-+stop(VHost) ->
-+   Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
-+   gen_server:call(Proc, {stop}, ?CALL_TIMEOUT).
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++start(_Opts, _VHost) ->
++   case mnesia:system_info(is_running) of
++        yes ->
++          ok = create_stats_table(),
++          {ok, ok};
++        no ->
++          ?ERROR_MSG("Mnesia not running", []),
++          error;
++        Status ->
++          ?ERROR_MSG("Mnesia status: ~p", [Status]),
++          error
++   end.
++
++stop(_VHost) ->
++   ok.
++
++log_message(_VHost, _Msg) ->
++   error.
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +%
-+% gen_server callbacks
++% gen_logdb callbacks (maintaince)
 +%
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+init([VHost, Opts]) ->
-+   crypto:start(),
++rebuild_stats(_VHost) ->
++     ok.
 +
-+   Server = gen_mod:get_opt(server, Opts, "localhost"),
-+   Port = gen_mod:get_opt(port, Opts, 3306),
-+   DB = gen_mod:get_opt(db, Opts, "logdb"),
-+   User = gen_mod:get_opt(user, Opts, "root"),
-+   Password = gen_mod:get_opt(password, Opts, ""),
++rebuild_stats_at(VHost, Date) ->
++    Table = ?LTABLE(Date),
++    {Time, Value}=timer:tc(?MODULE, rebuild_stats_at1, [VHost, Table]),
++    ?INFO_MSG("rebuild_stats_at ~p elapsed ~p sec: ~p~n", [Date, Time/1000000, Value]),
++    Value.
++rebuild_stats_at1(VHost, Table) ->
++    CFun = fun(Msg, Stats) ->
++               To = Msg#msg.to_user ++ "@" ++ Msg#msg.to_server,
++               Stats_to = if
++                            Msg#msg.to_server == VHost ->
++                               case lists:keysearch(To, 1, Stats) of
++                                    {value, {Who_to, Count_to}} ->
++                                       lists:keyreplace(To, 1, Stats, {Who_to, Count_to + 1});
++                                    false ->
++                                        lists:append(Stats, [{To, 1}])
++                               end;
++                            true ->
++                               Stats
++                          end,
++               From = Msg#msg.from_user ++ "@" ++ Msg#msg.from_server,
++               Stats_from = if
++                              Msg#msg.from_server == VHost  ->
++                                 case lists:keysearch(From, 1, Stats_to) of
++                                      {value, {Who_from, Count_from}} ->
++                                         lists:keyreplace(From, 1, Stats_to, {Who_from, Count_from + 1});
++                                      false ->
++                                         lists:append(Stats_to, [{From, 1}])
++                                 end;
++                              true ->
++                                 Stats_to
++                            end,
++               Stats_from
++           end,
++    DFun = fun(#stats{table=STable, server=Server} = Stat, _Acc)
++                when STable == Table, Server == VHost ->
++                 mnesia:delete_object(stats_table(), Stat, write);
++              (_Stat, _Acc) -> ok
++           end,
++    case mnesia:transaction(fun() ->
++                               mnesia:write_lock_table(list_to_atom(Table)),
++                               mnesia:write_lock_table(stats_table()),
++                               % Calc stats for VHost at Date
++                               AStats = mnesia:foldl(CFun, [], list_to_atom(Table)),
++                               % Delete all stats for VHost at Date
++                               mnesia:foldl(DFun, [], stats_table()),
++                               % Write new calc'ed stats
++                               lists:foreach(fun({Who, Count}) ->
++                                                 Jid = jlib:string_to_jid(Who),
++                                                 JUser = Jid#jid.user,
++                                                 WStat = #stats{user=JUser, server=VHost, table=Table, count=Count},
++                                                 mnesia:write(stats_table(), WStat, write)
++                                             end, AStats)
++                            end) of
++         {aborted, Reason} ->
++              ?ERROR_MSG("Failed to rebuild_stats_at for ~p at ~p: ~p", [VHost, Table, Reason]),
++              error;
++         {atomic, _} ->
++              ok
++    end.
 +
-+   St = #state{vhost=VHost,
-+               server=Server, port=Port, db=DB,
-+               user=User, password=Password},
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%
++% gen_logdb callbacks (delete)
++%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++delete_messages_by_user_at(_VHost, _Msgs, _Date) ->
++    error.
 +
-+   case open_mysql_connection(St) of
-+       {ok, DBRef} ->
-+           State = St#state{dbref=DBRef},
-+           ok = create_stats_table(State),
-+           ok = create_settings_table(State),
-+           ok = create_users_table(State),
-+           % clear ets cache every ...
-+           timer:send_interval(timer:hours(12), clear_ets_tables),
-+           ok = create_servers_table(State),
-+           ok = create_resources_table(State),
-+           erlang:monitor(process, DBRef),
-+           {ok, State};
-+       {error, Reason} ->
-+           ?ERROR_MSG("MySQL connection failed: ~p~n", [Reason]),
-+           {stop, db_connection_failed}
-+   end.
++delete_all_messages_by_user_at(_User, _VHost, _Date) ->
++    error.
 +
-+open_mysql_connection(#state{server=Server, port=Port, db=DB,
-+                             user=DBUser, password=Password} = _State) ->
-+   LogFun = fun(debug, _Format, _Argument) ->
-+                 %?MYDEBUG(Format, Argument);
-+                 ok;
-+               (error, Format, Argument) ->
-+                 ?ERROR_MSG(Format, Argument);
-+               (Level, Format, Argument) ->
-+                 ?MYDEBUG("MySQL (~p)~n", [Level]),
-+                 ?MYDEBUG(Format, Argument)
-+            end,
-+   ?INFO_MSG("Opening mysql connection ~s@~s:~p/~s", [DBUser, Server, Port, DB]),
-+   mysql_conn:start(Server, Port, DBUser, Password, DB, LogFun).
++delete_messages_at(VHost, Date) ->
++   Table = list_to_atom(tables_prefix() ++ Date),
 +
-+close_mysql_connection(DBRef) ->
-+   ?MYDEBUG("Closing ~p mysql connection", [DBRef]),
-+   mysql_conn:stop(DBRef).
++   DFun = fun(#msg{to_server=To_server, from_server=From_server}=Msg, _Acc)
++                when To_server == VHost; From_server == VHost ->
++                   mnesia:delete_object(Table, Msg, write);
++             (_Msg, _Acc) -> ok
++          end,
 +
-+handle_call({log_message, Msg}, _From, #state{dbref=DBRef, vhost=VHost}=State) ->
-+    Date = convert_timestamp_brief(Msg#msg.timestamp),
++   case mnesia:transaction(fun() ->
++                            mnesia:foldl(DFun, [], Table)
++                           end) of
++        {aborted, Reason} ->
++            ?ERROR_MSG("Failed to delete_messages_at for ~p at ~p: ~p", [VHost, Date, Reason]),
++            error;
++        {atomic, _} ->
++            ok
++   end.
 +
-+    Table = messages_table(VHost, Date),
-+    Owner_id = get_user_id(DBRef, VHost, Msg#msg.owner_name),
-+    Peer_name_id = get_user_id(DBRef, VHost, Msg#msg.peer_name),
-+    Peer_server_id = get_server_id(DBRef, VHost, Msg#msg.peer_server),
-+    Peer_resource_id = get_resource_id(DBRef, VHost, Msg#msg.peer_resource),
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%
++% gen_logdb callbacks (get)
++%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++get_vhost_stats(_VHost) ->
++    {error, "does not emplemented"}.
 +
-+    Query = ["INSERT INTO ",Table," ",
-+               "(owner_id,",
-+                "peer_name_id,",
-+                "peer_server_id,",
-+                "peer_resource_id,",
-+                "direction,",
-+                "type,",
-+                "subject,",
-+                "body,",
-+                "timestamp) ",
-+               "VALUES ",
-+               "('", Owner_id, "',",
-+                 "'", Peer_name_id, "',",
-+                 "'", Peer_server_id, "',",
-+                 "'", Peer_resource_id, "',",
-+                 "'", atom_to_list(Msg#msg.direction), "',",
-+                 "'", Msg#msg.type, "',",
-+                 "'", ejabberd_odbc:escape(Msg#msg.subject), "',",
-+                 "'", ejabberd_odbc:escape(Msg#msg.body), "',",
-+                 "'", Msg#msg.timestamp, "');"],
++get_vhost_stats_at(VHost, Date) ->
++    Fun = fun() ->
++             Pat = #stats{user='$1', server=VHost, table=tables_prefix()++Date, count = '$2'},
++             mnesia:select(stats_table(), [{Pat, [], [['$1', '$2']]}])
++          end,
++    case mnesia:transaction(Fun) of
++         {atomic, Result} ->
++                   RFun = fun([User, Count]) ->
++                             {User, Count}
++                          end,
++                   {ok, lists:reverse(lists:keysort(2, lists:map(RFun, Result)))};
++         {aborted, Reason} -> {error, Reason}
++    end.
 +
-+    Reply =
-+       case sql_query_internal_silent(DBRef, Query) of
-+            {updated, _} ->
-+               ?MYDEBUG("Logged ok for ~p, peer: ~p", [Msg#msg.owner_name++"@"++VHost,
-+                                                       Msg#msg.peer_name++"@"++Msg#msg.peer_server]),
-+               increment_user_stats(DBRef, Msg#msg.owner_name, Owner_id, VHost, Peer_name_id, Peer_server_id, Date);
-+            {error, Reason} ->
-+               case regexp:match(Reason, "#42S02") of
-+                    % Table doesn't exist
-+                    {match, _, _} ->
-+                       case create_msg_table(DBRef, VHost, Date) of
-+                            error ->
-+                               error;
-+                            ok ->
-+                               {updated, _} = sql_query_internal(DBRef, Query),
-+                               increment_user_stats(DBRef, Msg#msg.owner_name, Owner_id, VHost, Peer_name_id, Peer_server_id, Date)
-+                       end;
-+                    _ ->
-+                       ?ERROR_MSG("Failed to log message: ~p", [Reason]),
-+                       error
-+               end
-+       end,
-+    {reply, Reply, State};
-+handle_call({rebuild_stats_at, Date}, _From, #state{dbref=DBRef, vhost=VHost}=State) ->
-+    Reply = rebuild_stats_at_int(DBRef, VHost, Date),
-+    {reply, Reply, State};
-+handle_call({delete_messages_by_user_at, [], _Date}, _From, State) ->
-+    {reply, error, State};
-+handle_call({delete_messages_by_user_at, Msgs, Date}, _From, #state{dbref=DBRef, vhost=VHost}=State) ->
-+    Temp = lists:flatmap(fun(#msg{timestamp=Timestamp} = _Msg) ->
-+                             ["\"",Timestamp,"\"",","]
-+                         end, Msgs),
++get_user_stats(_User, _VHost) ->
++    {error, "does not emplemented"}.
 +
-+    Temp1 = lists:append([lists:sublist(Temp, length(Temp)-1), ");"]),
++get_user_messages_at(User, VHost, Date) ->
++    Table_name = tables_prefix() ++ Date,
++    case mnesia:transaction(fun() ->
++                               Pat_to = #msg{to_user=User, to_server=VHost, _='_'},
++                               Pat_from = #msg{from_user=User, from_server=VHost,  _='_'},
++                               mnesia:select(list_to_atom(Table_name),
++                                             [{Pat_to, [], ['$_']},
++                                              {Pat_from, [], ['$_']}])
++                       end) of
++          {atomic, Result} ->
++                   Msgs = lists:map(fun(#msg{to_user=To_user, to_server=To_server, to_resource=To_res,
++                                             from_user=From_user, from_server=From_server, from_resource=From_res,
++                                             type=Type,
++                                             subject=Subj,
++                                             body=Body, timestamp=Timestamp} = _Msg) ->
++                                        Subject = case Subj of
++                                                       "None" -> "";
++                                                       _ -> Subj
++                                                  end,
++                                        {msg, To_user, To_server, To_res, From_user, From_server, From_res, Type, Subject, Body, Timestamp}
++                                    end, Result),
++                   {ok, Msgs};
++          {aborted, Reason} ->
++                   {error, Reason}
++    end.
 +
-+    Query = ["DELETE FROM ",messages_table(VHost, Date)," ",
-+                             "WHERE timestamp IN (", Temp1],
++get_dates(_VHost) ->
++    Tables = mnesia:system_info(tables),
++    MessagesTables =
++        lists:filter(fun(Table) ->
++                         lists:prefix(tables_prefix(), atom_to_list(Table))
++                     end,
++                     Tables),
++    lists:map(fun(Table) ->
++                  lists:sublist(atom_to_list(Table),
++                                length(tables_prefix())+1,
++                                length(atom_to_list(Table)))
++              end,
++              MessagesTables).
++
++get_users_settings(_VHost) ->
++    {ok, []}.
++get_user_settings(_User, _VHost) ->
++    {ok, []}.
++set_user_settings(_User, _VHost, _Set) ->
++    ok.
++drop_user(_User, _VHost) ->
++    ok.
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%
++% internal
++%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++% called from db_logon/2
++create_stats_table() ->
++    SName = stats_table(),
++    case mnesia:create_table(SName,
++                             [{disc_only_copies, [node()]},
++                              {type, bag},
++                              {attributes, record_info(fields, stats)},
++                              {record_name, stats}
++                             ]) of
++         {atomic, ok} ->
++             ?INFO_MSG("Created stats table", []),
++             ok;
++         {aborted, {already_exists, _}} ->
++             ok;
++         {aborted, Reason} ->
++             ?ERROR_MSG("Failed to create stats table: ~p", [Reason]),
++             error
++    end.
+diff --git src/mod_logdb_mysql.erl src/mod_logdb_mysql.erl
+new file mode 100644
+index 0000000..7c473ce
+--- /dev/null
++++ src/mod_logdb_mysql.erl
+@@ -0,0 +1,1052 @@
++%%%----------------------------------------------------------------------
++%%% File    : mod_logdb_mysql.erl
++%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
++%%% Purpose : MySQL backend for mod_logdb
++%%% Version : trunk
++%%% Id      : $Id: mod_logdb_mysql.erl 1360 2009-07-30 06:00:14Z malik $
++%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
++%%%----------------------------------------------------------------------
++
++-module(mod_logdb_mysql).
++-author('o.palij@gmail.com').
++
++-include("mod_logdb.hrl").
++-include("ejabberd.hrl").
++-include("jlib.hrl").
++
++-behaviour(gen_logdb).
++-behaviour(gen_server).
++
++% gen_server
++-export([code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]).
++% gen_mod
++-export([start/2, stop/1]).
++% gen_logdb
++-export([log_message/2,
++         rebuild_stats/1,
++         rebuild_stats_at/2,
++         delete_messages_by_user_at/3, delete_all_messages_by_user_at/3, delete_messages_at/2,
++         get_vhost_stats/1, get_vhost_stats_at/2, get_user_stats/2, get_user_messages_at/3,
++         get_dates/1,
++         get_users_settings/1, get_user_settings/2, set_user_settings/3,
++         drop_user/2]).
++
++% gen_server call timeout
++-define(CALL_TIMEOUT, 30000).
++-define(MYSQL_TIMEOUT, 60000).
++-define(INDEX_SIZE, integer_to_list(170)).
++-define(PROCNAME, mod_logdb_mysql).
++
++-import(mod_logdb, [list_to_bool/1, bool_to_list/1,
++                    list_to_string/1, string_to_list/1,
++                    convert_timestamp_brief/1]).
++
++-record(state, {dbref, vhost, server, port, db, user, password}).
++
++% replace "." with "_"
++escape_vhost(VHost) -> lists:map(fun(46) -> 95;
++                                    (A) -> A
++                                 end, VHost).
++prefix() ->
++   "`logdb_".
++
++suffix(VHost) ->
++   "_" ++ escape_vhost(VHost) ++ "`".
++
++messages_table(VHost, Date) ->
++   prefix() ++ "messages_" ++ Date ++ suffix(VHost).
++
++stats_table(VHost) ->
++   prefix() ++ "stats" ++ suffix(VHost).
++
++temp_table(VHost) ->
++   prefix() ++ "temp" ++ suffix(VHost).
++
++settings_table(VHost) ->
++   prefix() ++ "settings" ++ suffix(VHost).
++
++users_table(VHost) ->
++   prefix() ++ "users" ++ suffix(VHost).
++servers_table(VHost) ->
++   prefix() ++ "servers" ++ suffix(VHost).
++resources_table(VHost) ->
++   prefix() ++ "resources" ++ suffix(VHost).
++
++ets_users_table(VHost) -> list_to_atom("logdb_users_" ++ VHost).
++ets_servers_table(VHost) -> list_to_atom("logdb_servers_" ++ VHost).
++ets_resources_table(VHost) -> list_to_atom("logdb_resources_" ++ VHost).
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%
++% gen_mod callbacks
++%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++start(VHost, Opts) ->
++   Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
++   gen_server:start({local, Proc}, ?MODULE, [VHost, Opts], []).
++
++stop(VHost) ->
++   Proc = gen_mod:get_module_proc(VHost, ?PROCNAME),
++   gen_server:call(Proc, {stop}, ?CALL_TIMEOUT).
++
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++%
++% gen_server callbacks
++%
++%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
++init([VHost, Opts]) ->
++   crypto:start(),
++
++   Server = gen_mod:get_opt(server, Opts, "localhost"),
++   Port = gen_mod:get_opt(port, Opts, 3306),
++   DB = gen_mod:get_opt(db, Opts, "logdb"),
++   User = gen_mod:get_opt(user, Opts, "root"),
++   Password = gen_mod:get_opt(password, Opts, ""),
++
++   St = #state{vhost=VHost,
++               server=Server, port=Port, db=DB,
++               user=User, password=Password},
++
++   case open_mysql_connection(St) of
++       {ok, DBRef} ->
++           State = St#state{dbref=DBRef},
++           ok = create_stats_table(State),
++           ok = create_settings_table(State),
++           ok = create_users_table(State),
++           % clear ets cache every ...
++           timer:send_interval(timer:hours(12), clear_ets_tables),
++           ok = create_servers_table(State),
++           ok = create_resources_table(State),
++           erlang:monitor(process, DBRef),
++           {ok, State};
++       {error, Reason} ->
++           ?ERROR_MSG("MySQL connection failed: ~p~n", [Reason]),
++           {stop, db_connection_failed}
++   end.
++
++open_mysql_connection(#state{server=Server, port=Port, db=DB,
++                             user=DBUser, password=Password} = _State) ->
++   LogFun = fun(debug, _Format, _Argument) ->
++                 %?MYDEBUG(Format, Argument);
++                 ok;
++               (error, Format, Argument) ->
++                 ?ERROR_MSG(Format, Argument);
++               (Level, Format, Argument) ->
++                 ?MYDEBUG("MySQL (~p)~n", [Level]),
++                 ?MYDEBUG(Format, Argument)
++            end,
++   ?INFO_MSG("Opening mysql connection ~s@~s:~p/~s", [DBUser, Server, Port, DB]),
++   mysql_conn:start(Server, Port, DBUser, Password, DB, LogFun).
++
++close_mysql_connection(DBRef) ->
++   ?MYDEBUG("Closing ~p mysql connection", [DBRef]),
++   mysql_conn:stop(DBRef).
++
++handle_call({log_message, Msg}, _From, #state{dbref=DBRef, vhost=VHost}=State) ->
++    Date = convert_timestamp_brief(Msg#msg.timestamp),
++
++    Table = messages_table(VHost, Date),
++    Owner_id = get_user_id(DBRef, VHost, Msg#msg.owner_name),
++    Peer_name_id = get_user_id(DBRef, VHost, Msg#msg.peer_name),
++    Peer_server_id = get_server_id(DBRef, VHost, Msg#msg.peer_server),
++    Peer_resource_id = get_resource_id(DBRef, VHost, Msg#msg.peer_resource),
++
++    Query = ["INSERT INTO ",Table," ",
++               "(owner_id,",
++                "peer_name_id,",
++                "peer_server_id,",
++                "peer_resource_id,",
++                "direction,",
++                "type,",
++                "subject,",
++                "body,",
++                "timestamp) ",
++               "VALUES ",
++               "('", Owner_id, "',",
++                 "'", Peer_name_id, "',",
++                 "'", Peer_server_id, "',",
++                 "'", Peer_resource_id, "',",
++                 "'", atom_to_list(Msg#msg.direction), "',",
++                 "'", Msg#msg.type, "',",
++                 "'", ejabberd_odbc:escape(Msg#msg.subject), "',",
++                 "'", ejabberd_odbc:escape(Msg#msg.body), "',",
++                 "'", Msg#msg.timestamp, "');"],
++
++    Reply =
++       case sql_query_internal_silent(DBRef, Query) of
++            {updated, _} ->
++               ?MYDEBUG("Logged ok for ~p, peer: ~p", [Msg#msg.owner_name++"@"++VHost,
++                                                       Msg#msg.peer_name++"@"++Msg#msg.peer_server]),
++               increment_user_stats(DBRef, Msg#msg.owner_name, Owner_id, VHost, Peer_name_id, Peer_server_id, Date);
++            {error, Reason} ->
++               case ejabberd_regexp:run(Reason, "#42S02") of
++                    % Table doesn't exist
++                    match ->
++                       case create_msg_table(DBRef, VHost, Date) of
++                            error ->
++                               error;
++                            ok ->
++                               {updated, _} = sql_query_internal(DBRef, Query),
++                               increment_user_stats(DBRef, Msg#msg.owner_name, Owner_id, VHost, Peer_name_id, Peer_server_id, Date)
++                       end;
++                    _ ->
++                       ?ERROR_MSG("Failed to log message: ~p", [Reason]),
++                       error
++               end
++       end,
++    {reply, Reply, State};
++handle_call({rebuild_stats_at, Date}, _From, #state{dbref=DBRef, vhost=VHost}=State) ->
++    Reply = rebuild_stats_at_int(DBRef, VHost, Date),
++    {reply, Reply, State};
++handle_call({delete_messages_by_user_at, [], _Date}, _From, State) ->
++    {reply, error, State};
++handle_call({delete_messages_by_user_at, Msgs, Date}, _From, #state{dbref=DBRef, vhost=VHost}=State) ->
++    Temp = lists:flatmap(fun(#msg{timestamp=Timestamp} = _Msg) ->
++                             ["\"",Timestamp,"\"",","]
++                         end, Msgs),
++
++    Temp1 = lists:append([lists:sublist(Temp, length(Temp)-1), ");"]),
++
++    Query = ["DELETE FROM ",messages_table(VHost, Date)," ",
++                             "WHERE timestamp IN (", Temp1],
 +
 +    Reply =
 +      case sql_query_internal(DBRef, Query) of
 +    Query = ["SELECT username,dolog_default,dolog_list,donotlog_list ",
 +                "FROM ",settings_table(VHost)," ",
 +             "JOIN ",users_table(VHost)," ON user_id=owner_id;"],
-+    Reply = 
++    Reply =
 +      case sql_query_internal(DBRef, Query) of
 +           {data, Result} ->
 +              {ok, lists:map(fun([Owner, DoLogDef, DoLogL, DoNotLogL]) ->
 +                       ?MYDEBUG("New settings for ~s@~s", [User, VHost]),
 +                       ok;
 +                   {error, Reason} ->
-+                       case regexp:match(Reason, "#23000") of
++                       case ejabberd_regexp:run(Reason, "#23000") of
 +                            % Already exists
-+                            {match, _, _} ->
++                            match ->
 +                                ok;
 +                             _ ->
 +                                ?ERROR_MSG("Failed setup user ~p@~p: ~p", [User, VHost, Reason]),
 +         {data, Tables} ->
 +            lists:foldl(fun([Table], Dates) ->
 +                           Reg = lists:sublist(prefix(),2,length(prefix())) ++ ".*" ++ escape_vhost(VHost),
-+                           case regexp:match(Table, Reg) of
-+                                {match, 1, _} ->
++                           case re:run(Table, Reg) of
++                                {match, [{1, _}]} ->
 +                                   ?MYDEBUG("matched ~p against ~p", [Table, Reg]),
-+                                   case regexp:match(Table,"[0-9]+-[0-9]+-[0-9]+") of
-+                                        {match, S, E} ->
++                                   case re:run(Table,"[0-9]+-[0-9]+-[0-9]+") of
++                                        {match, [{S, E}]} ->
 +                                            lists:append(Dates, [lists:sublist(Table,S,E)]);
 +                                        nomatch ->
 +                                            Dates
 +                                   end;
-+                               
 +                                _ ->
 +                                   Dates
 +                           end
 +            rebuild_all_stats_int(State),
 +            ok;
 +         {error, Reason} ->
-+            case regexp:match(Reason, "#42S01") of
-+                 {match, _, _} ->
++            case ejabberd_regexp:run(Reason, "#42S01") of
++                 match ->
 +                   ?MYDEBUG("Stats table for ~p already exists", [VHost]),
 +                   CheckQuery = ["SHOW COLUMNS FROM ",SName," LIKE 'peer_%_id';"],
 +                   case sql_query_internal(DBRef, CheckQuery) of
 +                          NewId;
 +                      {error, Reason} ->
 +                          % this can be in clustered environment
-+                          {match, _, _} = regexp:match(Reason, "#23000"),
++                          match = ejabberd_regexp:run(Reason, "#23000"),
 +                          ?ERROR_MSG("Duplicate key name for ~p", [User]),
 +                          {ok, ClID} = get_user_id_from_db(DBRef, VHost, User),
 +                          ClID
 +                Id;
 +             {error, Reason} ->
 +                % this can be in clustered environment
-+                {match, _, _} = regexp:match(Reason, "#23000"),
++                match = ejabberd_regexp:run(Reason, "#23000"),
 +                ?ERROR_MSG("Duplicate key name for ~p", [Server]),
 +                update_servers_from_db(DBRef, VHost),
 +                [[Id1]] = ets:match(ets_servers_table(VHost), {Server, '$1'}),
 +                          NewId;
 +                      {error, Reason} ->
 +                          % this can be in clustered environment
-+                          {match, _, _} = regexp:match(Reason, "#23000"),
++                          match = ejabberd_regexp:run(Reason, "#23000"),
 +                          ?ERROR_MSG("Duplicate key name for ~p", [Resource]),
 +                          {ok, ClID} = get_resource_id_from_db(DBRef, VHost, Resource),
 +                          ClID
 +
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +%
-+% SQL internals 
++% SQL internals
 +%
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +sql_query_internal(DBRef, Query) ->
 +get_result({error, MySQLRes}) ->
 +    Reason = mysql:get_result_reason(MySQLRes),
 +    {error, Reason}.
---- mod_logdb_mysql5.erl.orig  2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb_mysql5.erl       2009-07-30 09:00:14.000000000 +0300
+diff --git src/mod_logdb_mysql5.erl src/mod_logdb_mysql5.erl
+new file mode 100644
+index 0000000..59efc77
+--- /dev/null
++++ src/mod_logdb_mysql5.erl
 @@ -0,0 +1,979 @@
 +%%%----------------------------------------------------------------------
 +%%% File    : mod_logdb_mysql5.erl
 +%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
 +%%% Purpose : MySQL 5 backend for mod_logdb
 +%%% Version : trunk
-+%%% Id      : $Id$
++%%% Id      : $Id: mod_logdb_mysql5.erl 1360 2009-07-30 06:00:14Z malik $
 +%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
 +%%%----------------------------------------------------------------------
 +
 +    Query = ["SELECT username,dolog_default,dolog_list,donotlog_list ",
 +                "FROM ",settings_table(VHost)," ",
 +             "JOIN ",users_table(VHost)," ON user_id=owner_id;"],
-+    Reply = 
++    Reply =
 +      case sql_query_internal(DBRef, Query) of
 +           {data, Result} ->
 +              {ok, lists:map(fun([Owner, DoLogDef, DoLogL, DoNotLogL]) ->
 +                       ?MYDEBUG("New settings for ~s@~s", [User, VHost]),
 +                       ok;
 +                   {error, Reason} ->
-+                       case regexp:match(Reason, "#23000") of
++                       case ejabberd_regexp:run(Reason, "#23000") of
 +                            % Already exists
-+                            {match, _, _} ->
++                            match ->
 +                                ok;
 +                             _ ->
 +                                ?ERROR_MSG("Failed setup user ~p@~p: ~p", [User, VHost, Reason]),
 +         {data, Tables} ->
 +            lists:foldl(fun([Table], Dates) ->
 +                           Reg = lists:sublist(prefix(),2,length(prefix())) ++ ".*" ++ escape_vhost(VHost),
-+                           case regexp:match(Table, Reg) of
-+                                {match, 1, _} ->
-+                                   case regexp:match(Table,"[0-9]+-[0-9]+-[0-9]+") of
-+                                        {match, S, E} ->
++                           case re:run(Table, Reg) of
++                                {match, [{1, _}]} ->
++                                   case re:run(Table,"[0-9]+-[0-9]+-[0-9]+") of
++                                        {match, [{S, E}]} ->
 +                                            lists:append(Dates, [lists:sublist(Table,S,E)]);
 +                                        nomatch ->
 +                                            Dates
 +            rebuild_all_stats_int(State),
 +            ok;
 +         {error, Reason} ->
-+            case regexp:match(Reason, "#42S01") of
-+                 {match, _, _} ->
++            case ejabberd_regexp:run(Reason, "#42S01") of
++                 match ->
 +                   ?MYDEBUG("Stats table for ~p already exists", [VHost]),
 +                   CheckQuery = ["SHOW COLUMNS FROM ",SName," LIKE 'peer_%_id';"],
 +                   case sql_query_internal(DBRef, CheckQuery) of
 +
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +%
-+% SQL internals 
++% SQL internals
 +%
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +sql_query_internal(DBRef, Query) ->
 +                   DBIdNew;
 +               {error, Reason} ->
 +                   % this can be in clustered environment
-+                   {match, _, _} = regexp:match(Reason, "#23000"),
++                   match = ejabberd_regexp:run(Reason, "#23000"),
 +                   ?ERROR_MSG("Duplicate key name for ~p", [User]),
 +                   {data, [[ClID]]} = sql_query_internal(DBRef, SQuery),
 +                   ClID
 +    io_lib:format("
 +CREATE PROCEDURE ~s(tablename TEXT, atdate TEXT, owner TEXT, peer_name TEXT, peer_server TEXT, peer_resource TEXT, mdirection VARCHAR(4), mtype VARCHAR(10), msubject TEXT, mbody TEXT, mtimestamp DOUBLE)
 +BEGIN
-+   DECLARE ownerID MEDIUMINT UNSIGNED; 
++   DECLARE ownerID MEDIUMINT UNSIGNED;
 +   DECLARE peer_nameID MEDIUMINT UNSIGNED;
 +   DECLARE peer_serverID MEDIUMINT UNSIGNED;
 +   DECLARE peer_resourceID MEDIUMINT UNSIGNED;
 +   SELECT user_id INTO @ownerID FROM ~s WHERE username=owner;
 +   IF @ownerID IS NULL THEN
 +      INSERT INTO ~s SET username=owner;
-+      SET @ownerID = LAST_INSERT_ID(); 
++      SET @ownerID = LAST_INSERT_ID();
 +   END IF;
 +
 +   SELECT user_id INTO @peer_nameID FROM ~s WHERE username=peer_name;
 +      END IF;
 +   END IF;
 +END;", [logmessage_name(VHost),UName,UName,UName,UName,SName,SName,RName,RName,UName,UName,SName,RName,StName,StName]).
---- mod_logdb_pgsql.erl.orig   2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb_pgsql.erl        2009-07-30 09:49:10.000000000 +0300
+diff --git src/mod_logdb_pgsql.erl src/mod_logdb_pgsql.erl
+new file mode 100644
+index 0000000..1227519
+--- /dev/null
++++ src/mod_logdb_pgsql.erl
 @@ -0,0 +1,1104 @@
 +%%%----------------------------------------------------------------------
 +%%% File    : mod_logdb_pgsql.erl
 +%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
 +%%% Purpose : Posgresql backend for mod_logdb
 +%%% Version : trunk
-+%%% Id      : $Id$
++%%% Id      : $Id: mod_logdb_pgsql.erl 1360 2009-07-30 06:00:14Z malik $
 +%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
 +%%%----------------------------------------------------------------------
 +
 +    case sql_query_internal(DBRef, Query) of
 +         {data, Recs} ->
 +            lists:foldl(fun({_Schema, Table, _Type, _Owner}, Dates) ->
-+                             case regexp:match(Table,"[0-9]+-[0-9]+-[0-9]+") of
-+                                  {match, S, E} ->
++                             case re:run(Table,"[0-9]+-[0-9]+-[0-9]+") of
++                                  {match, [{S, E}]} ->
 +                                      lists:append(Dates, [lists:sublist(Table,S,E)]);
 +                                  nomatch ->
 +                                      Dates
 +            ok;
 +         {atomic, exists} ->
 +            ?MYDEBUG("Stats table for ~p already exists", [VHost]),
-+            {match, F, L} = regexp:match(SName, "\".*\""),
++            {match, [{F, L}]} = re:run(SName, "\".*\""),
 +            QTable = lists:sublist(SName, F+1, L-2),
 +            OIDQuery = ["SELECT c.oid FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relname='",QTable,"' AND pg_catalog.pg_table_is_visible(c.oid);"],
 +            {data,[{OID}]} = sql_query_internal(DBRef, OIDQuery),
 +         {atomic, created} ->
 +             ?MYDEBUG("Created users table for ~p", [VHost]),
 +             ok;
-+         {atomic, exists} -> 
++         {atomic, exists} ->
 +             ?MYDEBUG("Users table for ~p already exists", [VHost]),
 +             ok;
 +         {aborted, _} -> error
 +
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +%
-+% SQL internals 
++% SQL internals
 +%
 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 +% like do_transaction/2 in mysql_conn.erl (changeset by Yariv Sadan <yarivvv@gmail.com>)
 +         {error, Error} ->
 +            ?ERROR_MSG("Failed: ~p while ~p", [Error, lists:append(Query)]),
 +            {error, Error};
-+         Rez -> Rez
-+    end.
-+
-+sql_query_internal_silent(DBRef, Query) ->
-+    ?MYDEBUG("DOING: \"~s\"", [lists:append(Query)]),
-+    % TODO: use pquery?
-+    get_result(pgsql:squery(DBRef, Query)).
-+
-+get_result({ok, ["CREATE TABLE"]}) ->
-+    {updated, 1};
-+get_result({ok, ["DROP TABLE"]}) ->
-+    {updated, 1};
-+get_result({ok, ["ALTER TABLE"]}) ->
-+    {updated, 1};
-+get_result({ok,["DROP VIEW"]}) ->
-+    {updated, 1};
-+get_result({ok,["DROP FUNCTION"]}) ->
-+    {updated, 1};
-+get_result({ok, ["CREATE INDEX"]}) ->
-+    {updated, 1};
-+get_result({ok, ["CREATE FUNCTION"]}) ->
-+    {updated, 1};
-+get_result({ok, [{"SELECT", _Rows, Recs}]}) ->
-+    Fun = fun(Rec) ->
-+              list_to_tuple(
-+                  lists:map(fun(Elem) when is_binary(Elem) ->
-+                                  binary_to_list(Elem);
-+                               (Elem) when is_list(Elem) ->
-+                                  Elem;
-+                               (Elem) when is_integer(Elem) ->
-+                                  integer_to_list(Elem);
-+                               (Elem) when is_float(Elem) ->
-+                                  float_to_list(Elem);
-+                               (Elem) when is_boolean(Elem) ->
-+                                  atom_to_list(Elem);
-+                               (Elem) ->
-+                                  ?ERROR_MSG("Unknown element type ~p", [Elem]),
-+                                  Elem
-+                            end, Rec))
-+          end,
-+    Res = lists:map(Fun, Recs),
-+    %{data, [list_to_tuple(Rec) || Rec <- Recs]};
-+    {data, Res};
-+get_result({ok, ["INSERT " ++ OIDN]}) ->
-+    [_OID, N] = string:tokens(OIDN, " "),
-+    {updated, list_to_integer(N)};
-+get_result({ok, ["DELETE " ++ N]}) ->
-+    {updated, list_to_integer(N)};
-+get_result({ok, ["UPDATE " ++ N]}) ->
-+    {updated, list_to_integer(N)};
-+get_result({ok, ["BEGIN"]}) ->
-+    {updated, 1};
-+get_result({ok, ["LOCK TABLE"]}) ->
-+    {updated, 1};
-+get_result({ok, ["ROLLBACK"]}) ->
-+    {updated, 1};
-+get_result({ok, ["COMMIT"]}) ->
-+    {updated, 1};
-+get_result({ok, ["SET"]}) ->
-+    {updated, 1};
-+get_result({ok, [{error, Error}]}) ->
-+    {error, Error};
-+get_result(Rez) ->
-+    {error, undefined, Rez}.
-+
---- mod_logdb_mnesia_old.erl.orig      2009-11-22 13:06:23.000000000 +0200
-+++ mod_logdb_mnesia_old.erl   2009-02-05 20:12:58.000000000 +0200
-@@ -0,0 +1,258 @@
-+%%%----------------------------------------------------------------------
-+%%% File    : mod_logdb_mnesia_old.erl
-+%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
-+%%% Purpose : mod_logmnesia backend for mod_logdb (should be used only for copy_tables functionality)
-+%%% Version : trunk
-+%%% Id      : $Id$
-+%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
-+%%%----------------------------------------------------------------------
-+
-+-module(mod_logdb_mnesia_old).
-+-author('o.palij@gmail.com').
-+
-+-include("ejabberd.hrl").
-+-include("jlib.hrl").
-+
-+-behaviour(gen_logdb).
-+
-+-export([start/2, stop/1,
-+         log_message/2,
-+         rebuild_stats/1,
-+         rebuild_stats_at/2,
-+         rebuild_stats_at1/2,
-+         delete_messages_by_user_at/3, delete_all_messages_by_user_at/3, delete_messages_at/2,
-+         get_vhost_stats/1, get_vhost_stats_at/2, get_user_stats/2, get_user_messages_at/3,
-+         get_dates/1,
-+         get_users_settings/1, get_user_settings/2, set_user_settings/3,
-+         drop_user/2]).
-+
-+-record(stats, {user, server, table, count}).
-+-record(msg,   {to_user, to_server, to_resource, from_user, from_server, from_resource, id, type, subject, body, timestamp}).
-+
-+tables_prefix() -> "messages_".
-+% stats_table should not start with tables_prefix(VHost) ! 
-+% i.e. lists:prefix(tables_prefix(VHost), atom_to_list(stats_table())) must be /= true
-+stats_table() -> list_to_atom("messages-stats").
-+% table name as atom from Date
-+-define(ATABLE(Date), list_to_atom(tables_prefix() ++ Date)).
-+-define(LTABLE(Date), tables_prefix() ++ Date).
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% gen_logdb callbacks
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+start(_Opts, _VHost) ->
-+   case mnesia:system_info(is_running) of
-+        yes ->
-+          ok = create_stats_table(),
-+          {ok, ok};
-+        no ->
-+          ?ERROR_MSG("Mnesia not running", []),
-+          error;
-+        Status ->
-+          ?ERROR_MSG("Mnesia status: ~p", [Status]),
-+          error
-+   end.
-+
-+stop(_VHost) ->
-+   ok.
-+
-+log_message(_VHost, _Msg) ->
-+   error.
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% gen_logdb callbacks (maintaince)
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+rebuild_stats(_VHost) ->
-+     ok.
-+
-+rebuild_stats_at(VHost, Date) ->
-+    Table = ?LTABLE(Date),
-+    {Time, Value}=timer:tc(?MODULE, rebuild_stats_at1, [VHost, Table]),
-+    ?INFO_MSG("rebuild_stats_at ~p elapsed ~p sec: ~p~n", [Date, Time/1000000, Value]),
-+    Value.
-+rebuild_stats_at1(VHost, Table) ->
-+    CFun = fun(Msg, Stats) ->
-+               To = Msg#msg.to_user ++ "@" ++ Msg#msg.to_server,
-+               Stats_to = if 
-+                            Msg#msg.to_server == VHost ->
-+                               case lists:keysearch(To, 1, Stats) of
-+                                    {value, {Who_to, Count_to}} ->
-+                                       lists:keyreplace(To, 1, Stats, {Who_to, Count_to + 1});
-+                                    false ->
-+                                        lists:append(Stats, [{To, 1}])
-+                               end;
-+                            true ->
-+                               Stats
-+                          end,
-+               From = Msg#msg.from_user ++ "@" ++ Msg#msg.from_server,
-+               Stats_from = if
-+                              Msg#msg.from_server == VHost  ->
-+                                 case lists:keysearch(From, 1, Stats_to) of
-+                                      {value, {Who_from, Count_from}} ->
-+                                         lists:keyreplace(From, 1, Stats_to, {Who_from, Count_from + 1});
-+                                      false ->
-+                                         lists:append(Stats_to, [{From, 1}])
-+                                 end;
-+                              true ->
-+                                 Stats_to
-+                            end,
-+               Stats_from
-+           end,
-+    DFun = fun(#stats{table=STable, server=Server} = Stat, _Acc)
-+                when STable == Table, Server == VHost ->
-+                 mnesia:delete_object(stats_table(), Stat, write);
-+              (_Stat, _Acc) -> ok
-+           end,
-+    case mnesia:transaction(fun() ->
-+                               mnesia:write_lock_table(list_to_atom(Table)),
-+                               mnesia:write_lock_table(stats_table()),
-+                               % Calc stats for VHost at Date
-+                               AStats = mnesia:foldl(CFun, [], list_to_atom(Table)),
-+                               % Delete all stats for VHost at Date
-+                               mnesia:foldl(DFun, [], stats_table()),
-+                               % Write new calc'ed stats
-+                               lists:foreach(fun({Who, Count}) ->
-+                                                 Jid = jlib:string_to_jid(Who),
-+                                                 JUser = Jid#jid.user,
-+                                                 WStat = #stats{user=JUser, server=VHost, table=Table, count=Count},
-+                                                 mnesia:write(stats_table(), WStat, write)
-+                                             end, AStats)
-+                            end) of
-+         {aborted, Reason} ->
-+              ?ERROR_MSG("Failed to rebuild_stats_at for ~p at ~p: ~p", [VHost, Table, Reason]),
-+              error;
-+         {atomic, _} ->
-+              ok
-+    end.
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% gen_logdb callbacks (delete)
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+delete_messages_by_user_at(_VHost, _Msgs, _Date) ->
-+    error.
-+
-+delete_all_messages_by_user_at(_User, _VHost, _Date) ->
-+    error.
-+
-+delete_messages_at(VHost, Date) ->
-+   Table = list_to_atom(tables_prefix() ++ Date),
-+
-+   DFun = fun(#msg{to_server=To_server, from_server=From_server}=Msg, _Acc)
-+                when To_server == VHost; From_server == VHost ->
-+                   mnesia:delete_object(Table, Msg, write);
-+             (_Msg, _Acc) -> ok
-+          end,
-+   
-+   case mnesia:transaction(fun() ->
-+                            mnesia:foldl(DFun, [], Table)
-+                           end) of
-+        {aborted, Reason} ->
-+            ?ERROR_MSG("Failed to delete_messages_at for ~p at ~p: ~p", [VHost, Date, Reason]),
-+            error;
-+        {atomic, _} ->
-+            ok
-+   end.
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% gen_logdb callbacks (get)
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+get_vhost_stats(_VHost) ->
-+    {error, "does not emplemented"}.
-+
-+get_vhost_stats_at(VHost, Date) ->
-+    Fun = fun() ->
-+             Pat = #stats{user='$1', server=VHost, table=tables_prefix()++Date, count = '$2'},
-+             mnesia:select(stats_table(), [{Pat, [], [['$1', '$2']]}])
-+          end,
-+    case mnesia:transaction(Fun) of
-+         {atomic, Result} ->
-+                   RFun = fun([User, Count]) ->
-+                             {User, Count}
-+                          end,
-+                   {ok, lists:reverse(lists:keysort(2, lists:map(RFun, Result)))};
-+         {aborted, Reason} -> {error, Reason}
-+    end.
-+
-+get_user_stats(_User, _VHost) ->
-+    {error, "does not emplemented"}.
-+
-+get_user_messages_at(User, VHost, Date) ->
-+    Table_name = tables_prefix() ++ Date,
-+    case mnesia:transaction(fun() ->
-+                               Pat_to = #msg{to_user=User, to_server=VHost, _='_'},
-+                               Pat_from = #msg{from_user=User, from_server=VHost,  _='_'},
-+                               mnesia:select(list_to_atom(Table_name),
-+                                             [{Pat_to, [], ['$_']},
-+                                              {Pat_from, [], ['$_']}])
-+                       end) of
-+          {atomic, Result} ->
-+                   Msgs = lists:map(fun(#msg{to_user=To_user, to_server=To_server, to_resource=To_res,
-+                                             from_user=From_user, from_server=From_server, from_resource=From_res,
-+                                             type=Type,
-+                                             subject=Subj,
-+                                             body=Body, timestamp=Timestamp} = _Msg) ->
-+                                        Subject = case Subj of
-+                                                       "None" -> "";
-+                                                       _ -> Subj
-+                                                  end,
-+                                        {msg, To_user, To_server, To_res, From_user, From_server, From_res, Type, Subject, Body, Timestamp}
-+                                    end, Result),
-+                   {ok, Msgs};
-+          {aborted, Reason} ->
-+                   {error, Reason}
-+    end.
-+
-+get_dates(_VHost) ->
-+    Tables = mnesia:system_info(tables),
-+    MessagesTables =
-+        lists:filter(fun(Table) ->
-+                         lists:prefix(tables_prefix(), atom_to_list(Table))
-+                     end,
-+                     Tables),
-+    lists:map(fun(Table) ->
-+                  lists:sublist(atom_to_list(Table),
-+                                length(tables_prefix())+1,
-+                                length(atom_to_list(Table)))
-+              end,
-+              MessagesTables).
-+
-+get_users_settings(_VHost) ->
-+    {ok, []}.
-+get_user_settings(_User, _VHost) ->
-+    {ok, []}.
-+set_user_settings(_User, _VHost, _Set) ->
-+    ok.
-+drop_user(_User, _VHost) ->
-+    ok.
-+
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+%
-+% internal 
-+%
-+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-+% called from db_logon/2
-+create_stats_table() ->
-+    SName = stats_table(),
-+    case mnesia:create_table(SName,
-+                             [{disc_only_copies, [node()]},
-+                              {type, bag},
-+                              {attributes, record_info(fields, stats)},
-+                              {record_name, stats}
-+                             ]) of
-+         {atomic, ok} ->
-+             ?INFO_MSG("Created stats table", []),
-+             ok;
-+         {aborted, {already_exists, _}} ->
-+             ok;
-+         {aborted, Reason} ->
-+             ?ERROR_MSG("Failed to create stats table: ~p", [Reason]),
-+             error
-+    end.
---- gen_logdb.erl.orig 2009-11-22 13:06:23.000000000 +0200
-+++ gen_logdb.erl      2009-07-22 16:43:26.000000000 +0300
-@@ -0,0 +1,164 @@
-+%%%----------------------------------------------------------------------
-+%%% File    : gen_logdb.erl
-+%%% Author  : Oleg Palij (mailto,xmpp:o.palij@gmail.com)
-+%%% Purpose : Describes generic behaviour for mod_logdb backends.
-+%%% Version : trunk
-+%%% Id      : $Id$
-+%%% Url     : http://www.dp.uz.gov.ua/o.palij/mod_logdb/
-+%%%----------------------------------------------------------------------
-+
-+-module(gen_logdb).
-+-author('o.palij@gmail.com').
-+
-+-export([behaviour_info/1]).
-+
-+behaviour_info(callbacks) ->
-+   [
-+    % called from handle_info(start, _)
-+    % it should logon database and return reference to started instance
-+    % start(VHost, Opts) -> {ok, SPid} | error
-+    %  Options - list of options to connect to db
-+    %    Types: Options = list() -> [] |
-+    %                              [{user, "logdb"},
-+    %                               {pass, "1234"},
-+    %                               {db, "logdb"}] | ...
-+    %          VHost = list() -> "jabber.example.org"
-+    {start, 2},
-+
-+    % called from cleanup/1
-+    % it should logoff database and do cleanup
-+    % stop(VHost)
-+    %    Types: VHost = list() -> "jabber.example.org"
-+    {stop, 1},
-+
-+    % called from handle_call({addlog, _}, _, _)
-+    % it should log messages to database
-+    % log_message(VHost, Msg) -> ok | error
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Msg = record() -> #msg
-+    {log_message, 2},
-+
-+    % called from ejabberdctl rebuild_stats
-+    % it should rebuild stats table (if used) for vhost
-+    % rebuild_stats(VHost)
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    {rebuild_stats, 1},
-+
-+    % it should rebuild stats table (if used) for vhost at Date
-+    % rebuild_stats_at(VHost, Date)
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Date = list() -> "2007-02-12"
-+    {rebuild_stats_at, 2},
-+
-+    % called from user_messages_at_parse_query/5
-+    % it should delete selected user messages at date
-+    % delete_messages_by_user_at(VHost, Msgs, Date) -> ok | error
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Msgs = list() -> [ #msg1, msg2, ... ]
-+    %          Date = list() -> "2007-02-12"
-+    {delete_messages_by_user_at, 3},
-+
-+    % called from user_messages_parse_query/4 | vhost_messages_at_parse_query/4
-+    % it should delete all user messages at date
-+    % delete_all_messages_by_user_at(User, VHost, Date) -> ok | error
-+    %    Types:
-+    %          User = list() -> "admin"
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Date = list() -> "2007-02-12"
-+    {delete_all_messages_by_user_at, 3},
-+
-+    % called from vhost_messages_parse_query/3
-+    % it should delete messages for vhost at date and update stats
-+    % delete_messages_at(VHost, Date) -> ok | error
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Date = list() -> "2007-02-12"
-+    {delete_messages_at, 2},
-+
-+    % called from ejabberd_web_admin:vhost_messages_stats/3
-+    % it should return sorted list of count of messages by dates for vhost
-+    % get_vhost_stats(VHost) -> {ok, [{Date1, Msgs_count1}, {Date2, Msgs_count2}, ... ]} |
-+    %                           {error, Reason}
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          DateN = list() -> "2007-02-12"
-+    %          Msgs_countN = number() -> 241
-+    {get_vhost_stats, 1},
-+
-+    % called from ejabberd_web_admin:vhost_messages_stats_at/4
-+    % it should return sorted list of count of messages by users at date for vhost
-+    % get_vhost_stats_at(VHost, Date) -> {ok, [{User1, Msgs_count1}, {User2, Msgs_count2}, ....]} |
-+    %                                    {error, Reason}
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Date = list() -> "2007-02-12"
-+    %          UserN = list() -> "admin"
-+    %          Msgs_countN = number() -> 241
-+    {get_vhost_stats_at, 2},
-+
-+    % called from ejabberd_web_admin:user_messages_stats/4
-+    % it should return sorted list of count of messages by date for user at vhost
-+    % get_user_stats(User, VHost) -> {ok, [{Date1, Msgs_count1}, {Date2, Msgs_count2}, ...]} |
-+    %                                {error, Reason}
-+    %    Types:
-+    %          User = list() -> "admin"
-+    %          VHost = list() -> "jabber.example.org"
-+    %          DateN = list() -> "2007-02-12"
-+    %          Msgs_countN = number() -> 241
-+    {get_user_stats, 2},
-+
-+    % called from ejabberd_web_admin:user_messages_stats_at/5
-+    % it should return all user messages at date
-+    % get_user_messages_at(User, VHost, Date) -> {ok, Msgs} | {error, Reason}
-+    %    Types:
-+    %          User = list() -> "admin"
-+    %          VHost = list() -> "jabber.example.org"
-+    %          Date = list() -> "2007-02-12"
-+    %          Msgs = list() -> [ #msg1, msg2, ... ]
-+    {get_user_messages_at, 3},
-+
-+    % called from many places
-+    % it should return list of dates for vhost
-+    % get_dates(VHost) -> [Date1, Date2, ... ]
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    %          DateN = list() -> "2007-02-12"
-+    {get_dates, 1},
-+
-+    % called from start
-+    % it should return list with users settings for VHost in db
-+    % get_users_settings(VHost) -> [#user_settings1, #user_settings2, ... ] | error
-+    %    Types:
-+    %          VHost = list() -> "jabber.example.org"
-+    {get_users_settings, 1},
-+
-+    % called from many places
-+    % it should return User settings at VHost from db
-+    % get_user_settings(User, VHost) -> error | {ok, #user_settings}
-+    %    Types:
-+    %          User = list() -> "admin"
-+    %          VHost = list() -> "jabber.example.org"
-+    {get_user_settings, 2},
-+
-+    % called from web admin
-+    % it should set User settings at VHost
-+    % set_user_settings(User, VHost, #user_settings) -> ok | error
-+    %    Types:
-+    %          User = list() -> "admin"
-+    %          VHost = list() -> "jabber.example.org"
-+    {set_user_settings, 3},
-+
-+    % called from remove_user (ejabberd hook)
-+    % it should remove user messages and settings at VHost
-+    % drop_user(User, VHost) -> ok | error
-+    %    Types:
-+    %          User = list() -> "admin"
-+    %          VHost = list() -> "jabber.example.org"
-+    {drop_user, 2}
-+   ];
-+behaviour_info(_) ->
-+   undefined.
---- mod_muc/mod_muc_room-2.1.0.erl     2009-11-22 12:30:40.000000000 +0200
-+++ mod_muc/mod_muc_room.erl   2009-11-22 12:33:43.000000000 +0200
-@@ -625,6 +625,12 @@
-     {reply, {ok, NSD#state.config}, StateName, NSD};
- handle_sync_event({change_state, NewStateData}, _From, StateName, _StateData) ->
-     {reply, {ok, NewStateData}, StateName, NewStateData};
-+handle_sync_event({get_jid_nick, Jid}, _From, StateName, StateData) ->
-+    R = case ?DICT:find(jlib:jid_tolower(Jid), StateData#state.users) of
-+             error -> [];
-+             {ok, {user, _, Nick, _, _}} -> Nick
-+        end,
-+    {reply, R, StateName, StateData};
- handle_sync_event(_Event, _From, StateName, StateData) ->
-     Reply = ok,
-     {reply, Reply, StateName, StateData}.
---- msgs/uk-2.1.0.msg  2009-11-22 12:30:40.000000000 +0200
-+++ msgs/uk.msg        2009-11-22 12:36:12.000000000 +0200
-@@ -369,3 +369,31 @@
- {"You need an x:data capable client to search","Для пошуку необхідний x:data-придатний клієнт"}.
- {"Your contact offline message queue is full. The message has been discarded.","Черга повідомлень, що не були доставлені, переповнена. Повідомлення не було збережено."}.
- {"Your messages to ~s are being blocked. To unblock them, visit ~s","Ваші повідомлення до ~s блокуються. Для розблокування відвідайте ~s"}.
-+% mod_logdb
-+{"Users Messages", "Повідомлення користувачів"}.
-+{"Date", "Дата"}.
-+{"Count", "Кількість"}.
-+{"Logged messages for ", "Збережені повідомлення для "}.
-+{" at ", " за "}.
-+{"No logged messages for ", "Відсутні повідомлення для "}.
-+{"Date, Time", "Дата, Час"}.
-+{"Direction: Jid", "Напрямок: Jid"}.
-+{"Subject", "Тема"}.
-+{"Body", "Текст"}.
-+{"Messages", "Повідомлення"}.
-+{"Filter Selected", "Відфільтрувати виділені"}.
-+{"Do Not Log Messages", "Не зберігати повідомлення"}.
-+{"Log Messages", "Зберігати повідомлення"}.
-+{"Messages logging engine", "Система збереження повідомлень"}.
-+{"Default", "За замовчуванням"}.
-+{"Set logging preferences", "Вкажіть налагоджування збереження повідомлень"}.
-+{"Messages logging engine users", "Користувачі системи збереження повідомлень"}.
-+{"Messages logging engine settings", "Налагоджування системи збереження повідомлень"}.
-+{"Set run-time settings", "Вкажіть поточні налагоджування"}.
-+{"Groupchat messages logging", "Збереження повідомлень типу groupchat"}.
-+{"Jids/Domains to ignore", "Ігнорувати наступні jids/домени"}.
-+{"Purge messages older than (days)", "Видаляти повідомлення старіші ніж (дні)"}.
-+{"Poll users settings (seconds)", "Оновлювати налагоджування користувачів кожні (секунд)"}.
-+{"Drop", "Видаляти"}.
-+{"Do not drop", "Не видаляти"}.
-+{"Drop messages on user removal", "Видаляти повідомлення під час видалення користувача"}.
---- msgs/ru-2.1.0.msg  2009-11-22 12:30:40.000000000 +0200
-+++ msgs/ru.msg        2009-11-22 12:35:52.000000000 +0200
-@@ -369,3 +369,31 @@
- {"You need an x:data capable client to search","Чтобы воспользоваться поиском, требуется x:data-совместимый клиент"}.
- {"Your contact offline message queue is full. The message has been discarded.","Очередь недоставленных сообщений Вашего адресата переполнена. Сообщение не было сохранено."}.
- {"Your messages to ~s are being blocked. To unblock them, visit ~s","Ваши сообщения к ~s блокируются. Для снятия блокировки перейдите по ссылке ~s"}.
-+% mod_logdb.erl
-+{"Users Messages", "Сообщения пользователей"}.
-+{"Date", "Дата"}.
-+{"Count", "Количество"}.
-+{"Logged messages for ", "Сохранённые cообщения для "}.
-+{" at ", " за "}.
-+{"No logged messages for ", "Отсутствуют сообщения для "}.
-+{"Date, Time", "Дата, Время"}.
-+{"Direction: Jid", "Направление: Jid"}.
-+{"Subject", "Тема"}.
-+{"Body", "Текст"}.
-+{"Messages", "Сообщения"}.
-+{"Filter Selected", "Отфильтровать выделенные"}.
-+{"Do Not Log Messages", "Не сохранять сообщения"}.
-+{"Log Messages", "Сохранять сообщения"}.
-+{"Messages logging engine", "Система логирования сообщений"}.
-+{"Default", "По умолчанию"}.
-+{"Set logging preferences", "Задайте настройки логирования"}.
-+{"Messages logging engine users", "Пользователи системы логирования сообщений"}.
-+{"Messages logging engine settings", "Настройки системы логирования сообщений"}.
-+{"Set run-time settings", "Задайте текущие настройки"}.
-+{"Groupchat messages logging", "Логирование сообщений типа groupchat"}.
-+{"Jids/Domains to ignore", "Игнорировать следующие jids/домены"}.
-+{"Purge messages older than (days)", "Удалять сообщения старее чем (дни)"}.
-+{"Poll users settings (seconds)", "Обновлять настройки пользователей через (секунд)"}.
-+{"Drop", "Удалять"}.
-+{"Do not drop", "Не удалять"}.
-+{"Drop messages on user removal", "Удалять сообщения при удалении пользователя"}.
---- msgs/pl-2.1.0.msg  2009-11-22 12:30:40.000000000 +0200
-+++ msgs/pl.msg        2009-11-22 12:35:07.000000000 +0200
-@@ -369,3 +369,27 @@
- {"You need an x:data capable client to search","Potrzebujesz klienta obsługującego x:data aby wyszukiwać"}.
- {"Your contact offline message queue is full. The message has been discarded.","Kolejka wiadomości offline adresata jest pełna. Wiadomość została odrzucona."}.
- {"Your messages to ~s are being blocked. To unblock them, visit ~s","Twoje wiadomości do ~s są blokowane. Aby je odblokować, odwiedź ~s"}.
-+% mod_logdb
-+{"Users Messages", "Wiadomości użytkownika"}.
-+{"Date", "Data"}.
-+{"Count", "Liczba"}.
-+{"Logged messages for ", "Zapisane wiadomości dla "}.
-+{" at ", " o "}.
-+{"No logged messages for ", "Brak zapisanych wiadomości dla "}.
-+{"Date, Time", "Data, Godzina"}.
-+{"Direction: Jid", "Kierunek: Jid"}.
-+{"Subject", "Temat"}.
-+{"Body", "Treść"}.
-+{"Messages","Wiadomości"}.
-+{"Filter Selected", "Odfiltruj zaznaczone"}.
-+{"Do Not Log Messages", "Nie zapisuj wiadomości"}.
-+{"Log Messages", "Zapisuj wiadomości"}.
-+{"Messages logging engine", "System zapisywania historii rozmów"}.
-+{"Default", "Domyślne"}.
-+{"Set logging preferences", "Ustaw preferencje zapisywania"}.
-+{"Messages logging engine settings", "Ustawienia systemu logowania"}.
-+{"Set run-time settings", "Zapisz ustawienia systemu logowania"}.
-+{"Groupchat messages logging", "Zapisywanie rozmów z konferencji"}.
-+{"Jids/Domains to ignore", "JID/Domena która ma być ignorowana"}.
-+{"Purge messages older than (days)", "Usuń wiadomości starsze niż (w dniach)"}.
-+{"Poll users settings (seconds)", "Czas aktualizacji preferencji użytkowników (sekundy)"}.
---- msgs/nl-2.1.0.msg  2009-11-22 12:30:40.000000000 +0200
-+++ msgs/nl.msg        2009-11-22 12:34:41.000000000 +0200
-@@ -369,3 +369,15 @@
- {"You need an x:data capable client to search","U hebt een client nodig die x:data ondersteunt om te zoeken"}.
- {"Your contact offline message queue is full. The message has been discarded.","Te veel offline berichten voor dit contactpersoon. Het bericht is niet opgeslagen."}.
- {"Your messages to ~s are being blocked. To unblock them, visit ~s","Uw berichten aan ~s worden geblokkeerd. Om ze te deblokkeren, ga naar ~s"}.
-+% mod_logdb
-+{"Users Messages", "Gebruikersberichten"}.
-+{"Date", "Datum"}.
-+{"Count", "Aantal"}.
-+{"Logged messages for ", "Gelogde berichten van "}.
-+{" at ", " op "}.
-+{"No logged messages for ", "Geen gelogde berichten van "}.
-+{"Date, Time", "Datum en tijd"}.
-+{"Direction: Jid", "Richting: Jabber ID"}.
-+{"Subject", "Onderwerp"}.
-+{"Body", "Berichtveld"}.
-+{"Messages", "Berichten"}.
---- ./mod_roster-2.1.0.erl     2009-11-22 12:30:40.000000000 +0200
-+++ mod_roster.erl     2009-11-22 12:40:40.000000000 +0200
-@@ -61,7 +61,7 @@
- -include("mod_roster.hrl").
- -include("web/ejabberd_http.hrl").
- -include("web/ejabberd_web_admin.hrl").
--
-+-include("mod_logdb.hrl").
- start(Host, Opts) ->
-     IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
-@@ -937,6 +937,14 @@
-     Res = user_roster_parse_query(User, Server, Items1, Query),
-     Items = mnesia:dirty_index_read(roster, US, #roster.us),
-     SItems = lists:sort(Items),
-+
-+    Settings = case gen_mod:is_loaded(Server, mod_logdb) of
-+         true ->
-+             mod_logdb:get_user_settings(User, Server);
-+         false ->
-+             []
-+    end,
++         Rez -> Rez
++    end.
 +
-     FItems =
-       case SItems of
-           [] ->
-@@ -984,7 +992,33 @@
-                                             [?INPUTT("submit",
-                                                      "remove" ++
-                                                      ejabberd_web_admin:term_to_id(R#roster.jid),
--                                                     "Remove")])])
-+                                                     "Remove")]),
-+                                         case gen_mod:is_loaded(Server, mod_logdb) of
-+                                              true ->
-+                                                 Peer = jlib:jid_to_string(R#roster.jid),
-+                                                 A = lists:member(Peer, Settings#user_settings.dolog_list),
-+                                                 B = lists:member(Peer, Settings#user_settings.donotlog_list),
-+                                                 {Name, Value} =
-+                                                   if
-+                                                     A ->
-+                                                       {"donotlog", "Do Not Log Messages"};
-+                                                     B ->
-+                                                       {"dolog", "Log Messages"};
-+                                                     Settings#user_settings.dolog_default == true ->
-+                                                       {"donotlog", "Do Not Log Messages"};
-+                                                     Settings#user_settings.dolog_default == false ->
-+                                                       {"dolog", "Log Messages"}
-+                                                   end,
++sql_query_internal_silent(DBRef, Query) ->
++    ?MYDEBUG("DOING: \"~s\"", [lists:append(Query)]),
++    % TODO: use pquery?
++    get_result(pgsql:squery(DBRef, Query)).
 +
-+                                                 ?XAE("td", [{"class", "valign"}],
-+                                                      [?INPUTT("submit",
-+                                                               Name ++
-+                                                               ejabberd_web_admin:term_to_id(R#roster.jid),
-+                                                               Value)]);
-+                                              false ->
-+                                                 ?X([])
-+                                         end
-+                                        ])
-                           end, SItems))])]
-       end,
-     [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++
-@@ -1084,11 +1118,42 @@
-                                                {"subscription", "remove"}],
-                                               []}]}}),
-                             throw(submitted);
--                        false ->
--                            ok
--                    end
--
--            end
-+                          false ->
-+                            case lists:keysearch(
-+                                   "donotlog" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of
-+                                {value, _} ->
-+                                     Peer = jlib:jid_to_string(JID),
-+                                     Settings = mod_logdb:get_user_settings(User, Server),
-+                                     DNLL = case lists:member(Peer, Settings#user_settings.donotlog_list) of
-+                                                 false -> lists:append(Settings#user_settings.donotlog_list, [Peer]);
-+                                                 true -> Settings#user_settings.donotlog_list
-+                                            end,
-+                                     DLL = lists:delete(jlib:jid_to_string(JID), Settings#user_settings.dolog_list),
-+                                     Sett = Settings#user_settings{donotlog_list=DNLL, dolog_list=DLL},
-+                                     % TODO: check returned value
-+                                     ok = mod_logdb:set_user_settings(User, Server, Sett),
-+                                     throw(nothing);
-+                                false ->
-+                                   case lists:keysearch(
-+                                          "dolog" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of
-+                                       {value, _} ->
-+                                          Peer = jlib:jid_to_string(JID),
-+                                          Settings = mod_logdb:get_user_settings(User, Server),
-+                                          DLL = case lists:member(Peer, Settings#user_settings.dolog_list) of
-+                                                     false -> lists:append(Settings#user_settings.dolog_list, [Peer]);
-+                                                     true -> Settings#user_settings.dolog_list
-+                                                end,
-+                                          DNLL = lists:delete(jlib:jid_to_string(JID), Settings#user_settings.donotlog_list),
-+                                          Sett = Settings#user_settings{donotlog_list=DNLL, dolog_list=DLL},
-+                                          % TODO: check returned value
-+                                          ok = mod_logdb:set_user_settings(User, Server, Sett),
-+                                          throw(nothing);
-+                                       false ->
-+                                           ok
-+                                   end % dolog
-+                            end % donotlog
-+                      end % remove
-+              end % validate
-       end, Items),
-     nothing.
---- ./mod_roster_odbc-2.1.0.erl        2009-11-22 12:30:40.000000000 +0200
-+++ mod_roster_odbc.erl        2009-11-22 12:42:38.000000000 +0200
-@@ -59,7 +59,7 @@
- -include("mod_roster.hrl").
++get_result({ok, ["CREATE TABLE"]}) ->
++    {updated, 1};
++get_result({ok, ["DROP TABLE"]}) ->
++    {updated, 1};
++get_result({ok, ["ALTER TABLE"]}) ->
++    {updated, 1};
++get_result({ok,["DROP VIEW"]}) ->
++    {updated, 1};
++get_result({ok,["DROP FUNCTION"]}) ->
++    {updated, 1};
++get_result({ok, ["CREATE INDEX"]}) ->
++    {updated, 1};
++get_result({ok, ["CREATE FUNCTION"]}) ->
++    {updated, 1};
++get_result({ok, [{"SELECT", _Rows, Recs}]}) ->
++    Fun = fun(Rec) ->
++              list_to_tuple(
++                  lists:map(fun(Elem) when is_binary(Elem) ->
++                                  binary_to_list(Elem);
++                               (Elem) when is_list(Elem) ->
++                                  Elem;
++                               (Elem) when is_integer(Elem) ->
++                                  integer_to_list(Elem);
++                               (Elem) when is_float(Elem) ->
++                                  float_to_list(Elem);
++                               (Elem) when is_boolean(Elem) ->
++                                  atom_to_list(Elem);
++                               (Elem) ->
++                                  ?ERROR_MSG("Unknown element type ~p", [Elem]),
++                                  Elem
++                            end, Rec))
++          end,
++    Res = lists:map(Fun, Recs),
++    %{data, [list_to_tuple(Rec) || Rec <- Recs]};
++    {data, Res};
++get_result({ok, ["INSERT " ++ OIDN]}) ->
++    [_OID, N] = string:tokens(OIDN, " "),
++    {updated, list_to_integer(N)};
++get_result({ok, ["DELETE " ++ N]}) ->
++    {updated, list_to_integer(N)};
++get_result({ok, ["UPDATE " ++ N]}) ->
++    {updated, list_to_integer(N)};
++get_result({ok, ["BEGIN"]}) ->
++    {updated, 1};
++get_result({ok, ["LOCK TABLE"]}) ->
++    {updated, 1};
++get_result({ok, ["ROLLBACK"]}) ->
++    {updated, 1};
++get_result({ok, ["COMMIT"]}) ->
++    {updated, 1};
++get_result({ok, ["SET"]}) ->
++    {updated, 1};
++get_result({ok, [{error, Error}]}) ->
++    {error, Error};
++get_result(Rez) ->
++    {error, undefined, Rez}.
++
+diff --git src/mod_muc/mod_muc_room.erl src/mod_muc/mod_muc_room.erl
+index 02c83ed..7693b66 100644
+--- src/mod_muc/mod_muc_room.erl
++++ src/mod_muc/mod_muc_room.erl
+@@ -726,6 +726,12 @@ handle_sync_event({change_config, Config}, _From, StateName, StateData) ->
+     {reply, {ok, NSD#state.config}, StateName, NSD};
+ handle_sync_event({change_state, NewStateData}, _From, StateName, _StateData) ->
+     {reply, {ok, NewStateData}, StateName, NewStateData};
++handle_sync_event({get_jid_nick, Jid}, _From, StateName, StateData) ->
++    R = case ?DICT:find(jlib:jid_tolower(Jid), StateData#state.users) of
++             error -> [];
++             {ok, {user, _, Nick, _, _}} -> Nick
++        end,
++    {reply, R, StateName, StateData};
+ handle_sync_event(_Event, _From, StateName, StateData) ->
+     Reply = ok,
+     {reply, Reply, StateName, StateData}.
+diff --git src/mod_roster.erl src/mod_roster.erl
+index b15497f..ace8ba7 100644
+--- src/mod_roster.erl
++++ src/mod_roster.erl
+@@ -62,6 +62,8 @@
  -include("web/ejabberd_http.hrl").
  -include("web/ejabberd_web_admin.hrl").
--
 +-include("mod_logdb.hrl").
++
  
  start(Host, Opts) ->
      IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
-@@ -1038,6 +1038,14 @@
+@@ -1334,6 +1336,14 @@ user_roster(User, Server, Query, Lang) ->
      Res = user_roster_parse_query(User, Server, Items1, Query),
      Items = get_roster(LUser, LServer),
      SItems = lists:sort(Items),
      FItems =
        case SItems of
            [] ->
-@@ -1085,7 +1093,33 @@
+@@ -1381,7 +1391,33 @@ user_roster(User, Server, Query, Lang) ->
                                              [?INPUTT("submit",
                                                       "remove" ++
                                                       ejabberd_web_admin:term_to_id(R#roster.jid),
 -                                                     "Remove")])])
-+                                                     "Remove")]),
++                                                      "Remove")]),
 +                                         case gen_mod:is_loaded(Server, mod_logdb) of
 +                                              true ->
 +                                                 Peer = jlib:jid_to_string(R#roster.jid),
                            end, SItems))])]
        end,
      [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++
-@@ -1185,11 +1219,42 @@
+@@ -1481,11 +1517,42 @@ user_roster_item_parse_query(User, Server, Items, Query) ->
                                                 {"subscription", "remove"}],
                                                []}]}}),
                              throw(submitted);
        end, Items),
      nothing.
  
+diff --git src/msgs/nl.msg src/msgs/nl.msg
+index 70e739f..019b7b4 100644
+--- src/msgs/nl.msg
++++ src/msgs/nl.msg
+@@ -419,3 +419,15 @@
+ {"Your Jabber account was successfully created.","Uw Jabber-account is succesvol gecreeerd."}.
+ {"Your Jabber account was successfully deleted.","Uw Jabber-account is succesvol verwijderd."}.
+ {"Your messages to ~s are being blocked. To unblock them, visit ~s","Uw berichten aan ~s worden geblokkeerd. Om ze te deblokkeren, ga naar ~s"}.
++% mod_logdb
++{"Users Messages", "Gebruikersberichten"}.
++{"Date", "Datum"}.
++{"Count", "Aantal"}.
++{"Logged messages for ", "Gelogde berichten van "}.
++{" at ", " op "}.
++{"No logged messages for ", "Geen gelogde berichten van "}.
++{"Date, Time", "Datum en tijd"}.
++{"Direction: Jid", "Richting: Jabber ID"}.
++{"Subject", "Onderwerp"}.
++{"Body", "Berichtveld"}.
++{"Messages", "Berichten"}.
+diff --git src/msgs/pl.msg src/msgs/pl.msg
+index 4bc2063..4395f3c 100644
+--- src/msgs/pl.msg
++++ src/msgs/pl.msg
+@@ -419,3 +419,27 @@
+ {"Your Jabber account was successfully created.","Twoje konto zostało stworzone."}.
+ {"Your Jabber account was successfully deleted.","Twoje konto zostało usunięte."}.
+ {"Your messages to ~s are being blocked. To unblock them, visit ~s","Twoje wiadomości do ~s są blokowane. Aby je odblokować, odwiedź ~s"}.
++% mod_logdb
++{"Users Messages", "Wiadomości użytkownika"}.
++{"Date", "Data"}.
++{"Count", "Liczba"}.
++{"Logged messages for ", "Zapisane wiadomości dla "}.
++{" at ", " o "}.
++{"No logged messages for ", "Brak zapisanych wiadomości dla "}.
++{"Date, Time", "Data, Godzina"}.
++{"Direction: Jid", "Kierunek: Jid"}.
++{"Subject", "Temat"}.
++{"Body", "Treść"}.
++{"Messages","Wiadomości"}.
++{"Filter Selected", "Odfiltruj zaznaczone"}.
++{"Do Not Log Messages", "Nie zapisuj wiadomości"}.
++{"Log Messages", "Zapisuj wiadomości"}.
++{"Messages logging engine", "System zapisywania historii rozmów"}.
++{"Default", "Domyślne"}.
++{"Set logging preferences", "Ustaw preferencje zapisywania"}.
++{"Messages logging engine settings", "Ustawienia systemu logowania"}.
++{"Set run-time settings", "Zapisz ustawienia systemu logowania"}.
++{"Groupchat messages logging", "Zapisywanie rozmów z konferencji"}.
++{"Jids/Domains to ignore", "JID/Domena która ma być ignorowana"}.
++{"Purge messages older than (days)", "Usuń wiadomości starsze niż (w dniach)"}.
++{"Poll users settings (seconds)", "Czas aktualizacji preferencji użytkowników (sekundy)"}.
+diff --git src/msgs/ru.msg src/msgs/ru.msg
+index ece7348..99879ec 100644
+--- src/msgs/ru.msg
++++ src/msgs/ru.msg
+@@ -419,3 +419,31 @@
+ {"Your Jabber account was successfully created.","Ваш Jabber-аккаунт был успешно создан."}.
+ {"Your Jabber account was successfully deleted.","Ваш Jabber-аккаунт был успешно удален."}.
+ {"Your messages to ~s are being blocked. To unblock them, visit ~s","Ваши сообщения к ~s блокируются. Для снятия блокировки перейдите по ссылке ~s"}.
++% mod_logdb.erl
++{"Users Messages", "Сообщения пользователей"}.
++{"Date", "Дата"}.
++{"Count", "Количество"}.
++{"Logged messages for ", "Сохранённые cообщения для "}.
++{" at ", " за "}.
++{"No logged messages for ", "Отсутствуют сообщения для "}.
++{"Date, Time", "Дата, Время"}.
++{"Direction: Jid", "Направление: Jid"}.
++{"Subject", "Тема"}.
++{"Body", "Текст"}.
++{"Messages", "Сообщения"}.
++{"Filter Selected", "Отфильтровать выделенные"}.
++{"Do Not Log Messages", "Не сохранять сообщения"}.
++{"Log Messages", "Сохранять сообщения"}.
++{"Messages logging engine", "Система логирования сообщений"}.
++{"Default", "По умолчанию"}.
++{"Set logging preferences", "Задайте настройки логирования"}.
++{"Messages logging engine users", "Пользователи системы логирования сообщений"}.
++{"Messages logging engine settings", "Настройки системы логирования сообщений"}.
++{"Set run-time settings", "Задайте текущие настройки"}.
++{"Groupchat messages logging", "Логирование сообщений типа groupchat"}.
++{"Jids/Domains to ignore", "Игнорировать следующие jids/домены"}.
++{"Purge messages older than (days)", "Удалять сообщения старее чем (дни)"}.
++{"Poll users settings (seconds)", "Обновлять настройки пользователей через (секунд)"}.
++{"Drop", "Удалять"}.
++{"Do not drop", "Не удалять"}.
++{"Drop messages on user removal", "Удалять сообщения при удалении пользователя"}.
+diff --git src/msgs/uk.msg src/msgs/uk.msg
+index 6e21c90..1cdd1ea 100644
+--- src/msgs/uk.msg
++++ src/msgs/uk.msg
+@@ -407,3 +407,31 @@
+ {"Your Jabber account was successfully created.","Ваш Jabber-акаунт було успішно створено."}.
+ {"Your Jabber account was successfully deleted.","Ваш Jabber-акаунт було успішно видалено."}.
+ {"Your messages to ~s are being blocked. To unblock them, visit ~s","Ваші повідомлення до ~s блокуються. Для розблокування відвідайте ~s"}.
++% mod_logdb
++{"Users Messages", "Повідомлення користувачів"}.
++{"Date", "Дата"}.
++{"Count", "Кількість"}.
++{"Logged messages for ", "Збережені повідомлення для "}.
++{" at ", " за "}.
++{"No logged messages for ", "Відсутні повідомлення для "}.
++{"Date, Time", "Дата, Час"}.
++{"Direction: Jid", "Напрямок: Jid"}.
++{"Subject", "Тема"}.
++{"Body", "Текст"}.
++{"Messages", "Повідомлення"}.
++{"Filter Selected", "Відфільтрувати виділені"}.
++{"Do Not Log Messages", "Не зберігати повідомлення"}.
++{"Log Messages", "Зберігати повідомлення"}.
++{"Messages logging engine", "Система збереження повідомлень"}.
++{"Default", "За замовчуванням"}.
++{"Set logging preferences", "Вкажіть налагоджування збереження повідомлень"}.
++{"Messages logging engine users", "Користувачі системи збереження повідомлень"}.
++{"Messages logging engine settings", "Налагоджування системи збереження повідомлень"}.
++{"Set run-time settings", "Вкажіть поточні налагоджування"}.
++{"Groupchat messages logging", "Збереження повідомлень типу groupchat"}.
++{"Jids/Domains to ignore", "Ігнорувати наступні jids/домени"}.
++{"Purge messages older than (days)", "Видаляти повідомлення старіші ніж (дні)"}.
++{"Poll users settings (seconds)", "Оновлювати налагоджування користувачів кожні (секунд)"}.
++{"Drop", "Видаляти"}.
++{"Do not drop", "Не видаляти"}.
++{"Drop messages on user removal", "Видаляти повідомлення під час видалення користувача"}.
index 02c510c56dd03bb472f910bc7e6ee72c020d100d..c1411784d09d9de63f93169143ee98c819e26120 100644 (file)
@@ -20,7 +20,19 @@ index 5de409d..ac3dba8 100644
  \titem{\{search, true|false\}}\ind{options!search}This option specifies whether the search
    functionality is enabled or not
    If disabled, the option \term{host} will be ignored and the
-@@ -4087,14 +4098,17 @@ Examples:
+@@ -4128,6 +4142,11 @@ consists of the following \modvcardldap{}-specific options:
+ \begin{description}
+ \hostitem{vjud}
+ \iqdiscitem{\ns{vcard-temp}}
++\titem{access\_get}\ind{options!accessget} Access rule that defines
++  who is allowed to see vCard of local users.
++  If a rule returns `deny' on the requester
++  user name, that user cannot see vCards of local users.
++  By default anybody can see the vCards of local users.
+ \titem{\{search, true|false\}}\ind{options!search}This option specifies whether the search
+   functionality is enabled (value: \term{true}) or disabled (value:
+   \term{false}). If disabled, the option \term{host} will be ignored and the
+@@ -4651,14 +4651,17 @@ Examples:
   ]}.
  \end{verbatim}
  \item The second situation differs in a way that search results are not limited,
@@ -40,18 +52,6 @@ index 5de409d..ac3dba8 100644
    ...
   ]}.
  \end{verbatim}
-@@ -4128,6 +4142,11 @@ consists of the following \modvcardldap{}-specific options:
- \begin{description}
- \hostitem{vjud}
- \iqdiscitem{\ns{vcard-temp}}
-+\titem{access\_get}\ind{options!accessget} Access rule that defines
-+  who is allowed to see vCard of local users.
-+  If a rule returns `deny' on the requester
-+  user name, that user cannot see vCards of local users.
-+  By default anybody can see the vCards of local users.
- \titem{\{search, true|false\}}\ind{options!search}This option specifies whether the search
-   functionality is enabled (value: \term{true}) or disabled (value:
-   \term{false}). If disabled, the option \term{host} will be ignored and the
 diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
 index 4384087..c54e8ea 100644
 --- a/src/mod_vcard.erl
index 3fa24470becf2fc5dbb5383e5e2989433448574d..04e25456abcdde5b89afeb8be44d97067c6ad570 100644 (file)
 Summary:       Fault-tolerant distributed Jabber/XMPP server
 Summary(pl.UTF-8):     Odporny na awarie rozproszony serwer Jabbera/XMPP
 Name:          %{realname}
-Version:       2.1.11
-Release:       2
+Version:       2.1.12
+Release:       0.1
 License:       GPL
 Group:         Applications/Communications
 Source0:       http://www.process-one.net/downloads/ejabberd/%{version}/%{realname}-%{version}.tgz
-# Source0-md5: a70b040c4e7602f47718c8afe8780d50
+# Source0-md5: 7d49242cf04282f3c4cebfafa2cc2f46
 Source1:       %{realname}.init
 Source2:       %{realname}.sysconfig
 Source3:       %{realname}.sh
@@ -28,7 +28,7 @@ Source6:      ejabberd-module-pgsql-%{pgsql_module_rev}.tar.bz2
 Patch0:                %{realname}-makefile.patch
 Patch1:                %{realname}-config.patch
 Patch2:                %{realname}-mod_muc.patch
-# http://www.dp.uz.gov.ua/o.palij/mod_logdb/patch-src-mod_logdb-2.1.0.diff
+# http://www.dp.uz.gov.ua/o.palij/mod_logdb/patch-mod_logdb-2.1.12.diff
 Patch3:                %{realname}-mod_logdb.patch
 Patch4:                %{realname}-vcard-access-get.patch
 URL:           http://www.ejabberd.im/
@@ -75,7 +75,6 @@ Server-side logging module.
 %patch2 -p1
 %patch4 -p1
 %if %{with logdb}
-cd src
 %patch3 -p0
 %endif
 
This page took 0.229219 seconds and 4 git commands to generate.