+From 9a2ed8d2b20ef052b71b065e686cc049d18999ac Mon Sep 17 00:00:00 2001
+From: Oleh Palii <o.palij@gmail.com>
+Date: Sat, 31 Aug 2019 11:04:57 +0300
+Subject: [PATCH 1/3] apply mod_logdb to 19.08
+
+---
+ priv/msgs/nl.msg | 14 +
+ priv/msgs/pl.msg | 26 +
+ priv/msgs/ru.msg | 30 +
+ priv/msgs/uk.msg | 30 +
+ rebar.config | 4 +-
+ src/gen_logdb.erl | 162 ++++
+ src/mod_logdb.erl | 1951 ++++++++++++++++++++++++++++++++++++++
+ src/mod_logdb.hrl | 33 +
+ src/mod_logdb_mnesia.erl | 553 +++++++++++
+ src/mod_logdb_mysql.erl | 1050 ++++++++++++++++++++
+ src/mod_logdb_mysql5.erl | 979 +++++++++++++++++++
+ src/mod_logdb_pgsql.erl | 1104 +++++++++++++++++++++
+ src/mod_roster.erl | 77 +-
+ 13 files changed, 6007 insertions(+), 6 deletions(-)
+ create mode 100644 src/gen_logdb.erl
+ create mode 100644 src/mod_logdb.erl
+ create mode 100644 src/mod_logdb.hrl
+ create mode 100644 src/mod_logdb_mnesia.erl
+ create mode 100644 src/mod_logdb_mysql.erl
+ create mode 100644 src/mod_logdb_mysql5.erl
+ create mode 100644 src/mod_logdb_pgsql.erl
+
+diff --git a/priv/msgs/nl.msg b/priv/msgs/nl.msg
+index 8009d529ff..fd3d3b0ebb 100644
+--- a/priv/msgs/nl.msg
++++ b/priv/msgs/nl.msg
+@@ -345,3 +345,17 @@
+ {"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 Jabber account was successfully created.","Uw Jabber-account is succesvol gecreeerd."}.
+ {"Your Jabber account was successfully deleted.","Uw Jabber-account is succesvol verwijderd."}.
++% mod_logdb
++{"Users Messages", "Gebruikersberichten"}.
++{"Date", "Datum"}.
++{"Count", "Aantal"}.
++{"Logged messages for ~s", "Gelogde berichten van ~s"}.
++{"Logged messages for ~s at ~s", "Gelogde berichten van ~s op ~s"}.
++{" at ", " op "}.
++{"No logged messages for ~s", "Geen gelogde berichten van ~s"}.
++{"No logged messages for ~s at ~s", "Geen gelogde berichten van ~s op ~s"}.
++{"Date, Time", "Datum en tijd"}.
++{"Direction: Jid", "Richting: Jabber ID"}.
++{"Subject", "Onderwerp"}.
++{"Body", "Berichtveld"}.
++{"Messages", "Berichten"}.
+diff --git a/priv/msgs/pl.msg b/priv/msgs/pl.msg
+index 2ca75b259c..fffae5742e 100644
+--- a/priv/msgs/pl.msg
++++ b/priv/msgs/pl.msg
+@@ -444,3 +444,29 @@
+ {"You're not allowed to create nodes","Nie masz uprawnień do tworzenia węzłów"}.
+ {"Your Jabber account was successfully created.","Twoje konto zostało stworzone."}.
+ {"Your Jabber account was successfully deleted.","Twoje konto zostało usunięte."}.
++% mod_logdb
++{"Users Messages", "Wiadomości użytkownika"}.
++{"Date", "Data"}.
++{"Count", "Liczba"}.
++{"Logged messages for ~s", "Zapisane wiadomości dla ~s"}.
++{"Logged messages for ~s at", "Zapisane wiadomości dla ~s o ~s"}.
++{" at ", " o "}.
++{"No logged messages for ~s", "Brak zapisanych wiadomości dla ~s"}.
++{"No logged messages for ~s at ~s", "Brak zapisanych wiadomości dla ~s o ~s"}.
++{"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 a/priv/msgs/ru.msg b/priv/msgs/ru.msg
+index f7dff97ea1..42be5d4f15 100644
+--- a/priv/msgs/ru.msg
++++ b/priv/msgs/ru.msg
+@@ -507,3 +507,33 @@
+ {"Your Jabber account was successfully created.","Ваш Jabber-аккаунт был успешно создан."}.
+ {"Your Jabber account was successfully deleted.","Ваш Jabber-аккаунт был успешно удален."}.
+ {"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","Ваши запросы на добавление в контакт-лист, а также сообщения к ~s блокируются. Для снятия блокировки перейдите по ссылке ~s"}.
++% mod_logdb.erl
++{"Users Messages", "Сообщения пользователей"}.
++{"Date", "Дата"}.
++{"Count", "Количество"}.
++{"Logged messages for ~s", "Сохранённые cообщения для ~s"}.
++{"Logged messages for ~s at ~s", "Сохранённые cообщения для ~s за ~s"}.
++{" at ", " за "}.
++{"No logged messages for ~s", "Отсутствуют сообщения для ~s"}.
++{"No logged messages for ~s at ~s", "Отсутствуют сообщения для ~s за ~s"}.
++{"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/priv/msgs/uk.msg b/priv/msgs/uk.msg
+index 0fbc336d51..c0b90047fa 100644
+--- a/priv/msgs/uk.msg
++++ b/priv/msgs/uk.msg
+@@ -349,3 +349,33 @@
+ {"Your contact offline message queue is full. The message has been discarded.","Черга повідомлень, що не були доставлені, переповнена. Повідомлення не було збережено."}.
+ {"Your Jabber account was successfully created.","Ваш Jabber-акаунт було успішно створено."}.
+ {"Your Jabber account was successfully deleted.","Ваш Jabber-акаунт було успішно видалено."}.
++% mod_logdb
++{"Users Messages", "Повідомлення користувачів"}.
++{"Date", "Дата"}.
++{"Count", "Кількість"}.
++{"Logged messages for ~s", "Збережені повідомлення для ~s"}.
++{"Logged messages for ~s at ~s", "Збережені повідомлення для ~s за ~s"}.
++{" at ", " за "}.
++{"No logged messages for ~s", "Відсутні повідомлення для ~s"}.
++{"No logged messages for ~s at ~s", "Відсутні повідомлення для ~s за ~s"}.
++{"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/rebar.config b/rebar.config
+index e05fe84e6e..c3b87afd28 100644
+--- a/rebar.config
++++ b/rebar.config
+@@ -35,8 +35,8 @@
+ {mqtree, ".*", {git, "https://github.com/processone/mqtree", {tag, "1.0.4"}}},
+ {if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.29"}}}},
+ {if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.30"}}}},
+- {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
+- {tag, "1.0.11"}}}},
++ {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/paleg/p1_mysql",
++ {tag, "1.0.11_multi"}}}},
+ {if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
+ {tag, "1.1.8"}}}},
+ {if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
+diff --git a/src/gen_logdb.erl b/src/gen_logdb.erl
+new file mode 100644
+index 0000000000..8bad112969
+--- /dev/null
++++ b/src/gen_logdb.erl
+@@ -0,0 +1,162 @@
++%%%----------------------------------------------------------------------
++%%% File : gen_logdb.erl
++%%% Author : Oleg Palij (mailto:o.palij@gmail.com)
++%%% Purpose : Describes generic behaviour for mod_logdb backends.
++%%% Url : https://paleg.github.io/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 a/src/mod_logdb.erl b/src/mod_logdb.erl
+new file mode 100644
+index 0000000000..bf0240d139
+--- /dev/null
++++ b/src/mod_logdb.erl
+@@ -0,0 +1,1951 @@