From 0d78319d3cfeeb336f0cb54423a02484d2f99357 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= Date: Fri, 17 May 2013 08:43:04 +0200 Subject: [PATCH] - up to 2.1.12; vcard-access-get.patch needs update --- ejabberd-mod_logdb.patch | 1900 +++++++++++++++---------------- ejabberd-vcard-access-get.patch | 26 +- ejabberd.spec | 9 +- 3 files changed, 926 insertions(+), 1009 deletions(-) diff --git a/ejabberd-mod_logdb.patch b/ejabberd-mod_logdb.patch index 30ea02a..db65297 100644 --- a/ejabberd-mod_logdb.patch +++ b/ejabberd-mod_logdb.patch @@ -1,12 +1,185 @@ ---- 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/ +%%%---------------------------------------------------------------------- + @@ -23,9 +196,9 @@ +% 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 @@ -138,7 +311,6 @@ + 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), @@ -359,7 +531,7 @@ + {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}]), @@ -372,7 +544,6 @@ + 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), @@ -469,12 +640,7 @@ + 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}). @@ -536,7 +702,7 @@ + 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), @@ -601,7 +767,7 @@ + _ -> 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), @@ -616,12 +782,12 @@ + 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). @@ -630,7 +796,7 @@ +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}, ... ] @@ -827,7 +993,7 @@ + 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), + @@ -868,7 +1034,7 @@ + +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), @@ -1042,8 +1208,7 @@ +string_to_list([]) -> + []; +string_to_list(String) -> -+ {ok, List} = regexp:split(String, "\n"), -+ List. ++ ejabberd_regexp:split(String, "\n"). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% @@ -1135,7 +1300,7 @@ + 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), @@ -1544,7 +1709,7 @@ + +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) @@ -2096,15 +2261,18 @@ + ] + )] + 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/ +%%%---------------------------------------------------------------------- + @@ -2134,15 +2302,18 @@ + {"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/ +%%%---------------------------------------------------------------------- + @@ -2155,7 +2326,7 @@ + +-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 @@ -2169,10 +2340,10 @@ + 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}). @@ -2235,7 +2406,7 @@ + {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() -> @@ -2497,10 +2668,10 @@ + 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 @@ -2683,220 +2854,487 @@ + {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 @@ -3022,7 +3460,7 @@ + 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]) -> @@ -3076,9 +3514,9 @@ + ?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]), @@ -3235,16 +3673,15 @@ + {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 @@ -3451,8 +3888,8 @@ + 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 @@ -3640,7 +4077,7 @@ + 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 @@ -3665,7 +4102,7 @@ + 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'}), @@ -3702,7 +4139,7 @@ + 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 @@ -3715,7 +4152,7 @@ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% -+% SQL internals ++% SQL internals +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +sql_query_internal(DBRef, Query) -> @@ -3739,15 +4176,18 @@ +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/ +%%%---------------------------------------------------------------------- + @@ -4020,7 +4460,7 @@ + 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]) -> @@ -4073,9 +4513,9 @@ + ?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]), @@ -4229,10 +4669,10 @@ + {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 @@ -4446,8 +4886,8 @@ + 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 @@ -4547,7 +4987,7 @@ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% -+% SQL internals ++% SQL internals +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +sql_query_internal(DBRef, Query) -> @@ -4585,7 +5025,7 @@ + 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 @@ -4602,7 +5042,7 @@ + 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; @@ -4632,7 +5072,7 @@ + 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; @@ -4721,15 +5161,18 @@ + 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/ +%%%---------------------------------------------------------------------- + @@ -5219,8 +5662,8 @@ + 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 @@ -5448,7 +5891,7 @@ + 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), @@ -5522,7 +5965,7 @@ + {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 @@ -5722,7 +6165,7 @@ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% -+% SQL internals ++% SQL internals +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% like do_transaction/2 in mysql_conn.erl (changeset by Yariv Sadan ) @@ -5763,751 +6206,102 @@ + {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), @@ -6522,12 +6316,12 @@ 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), @@ -6557,7 +6351,7 @@ 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); @@ -6605,3 +6399,127 @@ 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", "Видаляти повідомлення під час видалення користувача"}. diff --git a/ejabberd-vcard-access-get.patch b/ejabberd-vcard-access-get.patch index 02c510c..c141178 100644 --- a/ejabberd-vcard-access-get.patch +++ b/ejabberd-vcard-access-get.patch @@ -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 diff --git a/ejabberd.spec b/ejabberd.spec index 3fa2447..04e2545 100644 --- a/ejabberd.spec +++ b/ejabberd.spec @@ -11,12 +11,12 @@ 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 -- 2.44.0