-
Mickaël Turnel authored79d7c508
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of Liblinphone.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if (__GNUC__ == 9 && __GNUC_MINOR__ >= 1)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
#include <ctime>
#include "linphone/utils/algorithm.h"
#include "linphone/utils/static-string.h"
#include "c-wrapper/internal/c-tools.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-room/chat-room-p.h"
#ifdef HAVE_ADVANCED_IM
#include "chat/chat-room/client-group-chat-room.h"
#include "chat/chat-room/client-group-chat-room-p.h"
#include "chat/chat-room/server-group-chat-room.h"
#endif
#include "conference/participant-device.h"
#include "conference/participant.h"
#include "core/core-p.h"
#include "event-log/event-log-p.h"
#include "event-log/events.h"
#include "main-db-key-p.h"
#include "main-db-p.h"
#ifdef HAVE_DB_STORAGE
#include "internal/db-transaction.h"
#endif
#include "internal/statements.h"
#include "c-wrapper/c-wrapper.h"
// =============================================================================
// See: http://soci.sourceforge.net/doc/3.2/exchange.html
// Part: Object lifetime and immutability
// -----------------------------------------------------------------------------
using namespace std;
LINPHONE_BEGIN_NAMESPACE
#ifdef HAVE_DB_STORAGE
namespace {
constexpr unsigned int ModuleVersionEvents = makeVersion(1, 0, 16);
constexpr unsigned int ModuleVersionFriends = makeVersion(1, 0, 0);
constexpr unsigned int ModuleVersionLegacyFriendsImport = makeVersion(1, 0, 0);
constexpr unsigned int ModuleVersionLegacyHistoryImport = makeVersion(1, 0, 0);
constexpr unsigned int ModuleVersionLegacyCallLogsImport = makeVersion(1, 0, 0);
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
constexpr int LegacyFriendListColId = 0;
constexpr int LegacyFriendListColName = 1;
constexpr int LegacyFriendListColRlsUri = 2;
constexpr int LegacyFriendListColSyncUri = 3;
constexpr int LegacyFriendListColRevision = 4;
constexpr int LegacyFriendColFriendListId = 1;
constexpr int LegacyFriendColSipAddress = 2;
constexpr int LegacyFriendColSubscribePolicy = 3;
constexpr int LegacyFriendColSendSubscribe = 4;
constexpr int LegacyFriendColRefKey = 5;
constexpr int LegacyFriendColVCard = 6;
constexpr int LegacyFriendColVCardEtag = 7;
constexpr int LegacyFriendColVCardSyncUri = 8;
constexpr int LegacyFriendColPresenceReceived = 9;
constexpr int LegacyMessageColLocalAddress = 1;
constexpr int LegacyMessageColRemoteAddress = 2;
constexpr int LegacyMessageColDirection = 3;
constexpr int LegacyMessageColText = 4;
constexpr int LegacyMessageColState = 7;
constexpr int LegacyMessageColUrl = 8;
constexpr int LegacyMessageColDate = 9;
constexpr int LegacyMessageColAppData = 10;
constexpr int LegacyMessageColContentId = 11;
constexpr int LegacyMessageColContentType = 13;
constexpr int LegacyMessageColIsSecured = 14;
constexpr int LegacyCallLogColFrom = 1;
constexpr int LegacyCallLogColTo = 2;
constexpr int LegacyCallLogColDirection = 3;
constexpr int LegacyCallLogColDuration = 4;
constexpr int LegacyCallLogColStartTime = 5;
constexpr int LegacyCallLogColConnectedTime = 6;
constexpr int LegacyCallLogColStatus = 7;
constexpr int LegacyCallLogColVideoEnabled = 8;
constexpr int LegacyCallLogColQuality = 9;
constexpr int LegacyCallLogColCallId = 10;
constexpr int LegacyCallLogColRefKey = 11;
}
#endif
// -----------------------------------------------------------------------------
// soci helpers.
// -----------------------------------------------------------------------------
#ifdef HAVE_DB_STORAGE
static inline vector<char> blobToVector (soci::blob &in) {
size_t len = in.get_len();
if (!len)
return vector<char>();
vector<char> out(len);
in.read(0, &out[0], len);
return out;
}
static inline string blobToString (soci::blob &in) {
vector<char> out = blobToVector(in);
return string(out.begin(), out.end());
}
static constexpr string &blobToString (string &in) {
return in;
}
template<typename T>
static T getValueFromRow (const soci::row &row, int index, bool &isNull) {
isNull = false;
if (row.get_indicator(size_t(index)) == soci::i_null) {
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
isNull = true;
return T();
}
return row.get<T>(size_t(index));
}
#endif
// -----------------------------------------------------------------------------
// Event filter tools.
// -----------------------------------------------------------------------------
#ifdef HAVE_DB_STORAGE
// Some tools to build filters at compile time.
template<typename T>
struct EnumToSql {
T first;
const char *second;
};
template<typename T>
static constexpr const char *mapEnumToSql (const EnumToSql<T> enumToSql[], size_t n, T key) {
return n == 0 ? "" : (
enumToSql[n - 1].first == key ? enumToSql[n - 1].second : mapEnumToSql(enumToSql, n - 1, key)
);
}
template<EventLog::Type ...Type>
struct SqlEventFilterBuilder {};
template<EventLog::Type Type, EventLog::Type... List>
struct SqlEventFilterBuilder<Type, List...> {
static constexpr auto get () L_AUTO_RETURN(
StaticIntString<int(Type)>() + "," + SqlEventFilterBuilder<List...>::get()
);
};
template<EventLog::Type Type>
struct SqlEventFilterBuilder<Type> {
static constexpr auto get () L_AUTO_RETURN(StaticIntString<int(Type)>());
};
#endif
// -----------------------------------------------------------------------------
// Event filters.
// -----------------------------------------------------------------------------
#ifdef HAVE_DB_STORAGE
namespace {
#ifdef _WIN32
// TODO: Find a workaround to deal with StaticString concatenation!!!
constexpr char ConferenceCallFilter[] = "3,21,4";
constexpr char ConferenceChatMessageFilter[] = "5";
constexpr char ConferenceInfoNoDeviceFilter[] = "1,2,6,7,8,9,12,13,14,15,16";
constexpr char ConferenceInfoFilter[] = "1,2,6,7,8,9,10,11,12,13,14,15,16";
constexpr char ConferenceChatMessageSecurityFilter[] = "5,13,14,15,16";
#else
constexpr auto ConferenceCallFilter = SqlEventFilterBuilder<
EventLog::Type::ConferenceCallStarted,
EventLog::Type::ConferenceCallConnected,
EventLog::Type::ConferenceCallEnded
>::get();
constexpr auto ConferenceChatMessageFilter = SqlEventFilterBuilder<EventLog::Type::ConferenceChatMessage>::get();
constexpr auto ConferenceInfoNoDeviceFilter = SqlEventFilterBuilder<
EventLog::Type::ConferenceCreated,
EventLog::Type::ConferenceTerminated,
EventLog::Type::ConferenceParticipantAdded,
EventLog::Type::ConferenceParticipantRemoved,
EventLog::Type::ConferenceParticipantSetAdmin,
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
EventLog::Type::ConferenceParticipantUnsetAdmin,
EventLog::Type::ConferenceSubjectChanged,
EventLog::Type::ConferenceSecurityEvent,
EventLog::Type::ConferenceEphemeralMessageLifetimeChanged,
EventLog::Type::ConferenceEphemeralMessageManagedByAdmin,
EventLog::Type::ConferenceEphemeralMessageManagedByParticipants,
EventLog::Type::ConferenceEphemeralMessageEnabled,
EventLog::Type::ConferenceEphemeralMessageDisabled
>::get();
constexpr auto ConferenceInfoFilter = ConferenceInfoNoDeviceFilter + "," + SqlEventFilterBuilder<
EventLog::Type::ConferenceParticipantDeviceAdded,
EventLog::Type::ConferenceParticipantDeviceRemoved,
EventLog::Type::ConferenceParticipantDeviceStatusChanged,
EventLog::Type::ConferenceParticipantDeviceMediaChanged
>::get();
constexpr auto ConferenceChatMessageSecurityFilter = ConferenceChatMessageFilter + "," + SqlEventFilterBuilder<
EventLog::Type::ConferenceSecurityEvent,
EventLog::Type::ConferenceEphemeralMessageLifetimeChanged,
EventLog::Type::ConferenceEphemeralMessageEnabled,
EventLog::Type::ConferenceEphemeralMessageDisabled,
EventLog::Type::ConferenceEphemeralMessageManagedByAdmin,
EventLog::Type::ConferenceEphemeralMessageManagedByParticipants
>::get();
#endif // ifdef _WIN32
constexpr EnumToSql<MainDb::Filter> EventFilterToSql[] = {
{ MainDb::ConferenceCallFilter, ConferenceCallFilter },
{ MainDb::ConferenceChatMessageFilter, ConferenceChatMessageFilter },
{ MainDb::ConferenceInfoNoDeviceFilter, ConferenceInfoNoDeviceFilter },
{ MainDb::ConferenceInfoFilter, ConferenceInfoFilter },
{ MainDb::ConferenceChatMessageSecurityFilter, ConferenceChatMessageSecurityFilter }
};
}
static const char *mapEventFilterToSql (MainDb::Filter filter) {
return mapEnumToSql(
EventFilterToSql, sizeof EventFilterToSql / sizeof EventFilterToSql[0], filter
);
}
// -----------------------------------------------------------------------------
static string buildSqlEventFilter (
const list<MainDb::Filter> &filters,
MainDb::FilterMask mask,
const string &condKeyWord = "WHERE"
) {
L_ASSERT(findIf(filters, [](const MainDb::Filter &filter) { return filter == MainDb::NoFilter; }) == filters.cend());
if (mask == MainDb::NoFilter)
return "";
bool isStart = true;
string sql;
for (const auto &filter : filters) {
if (!mask.isSet(filter))
continue;
if (isStart) {
isStart = false;
sql += " " + condKeyWord + " type IN (";
} else
sql += ", ";
sql += mapEventFilterToSql(filter);
}
if (!isStart)
sql += ") ";
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
return sql;
}
#endif
// -----------------------------------------------------------------------------
// Misc helpers.
// -----------------------------------------------------------------------------
shared_ptr<AbstractChatRoom> MainDbPrivate::findChatRoom (const ConferenceId &conferenceId) const {
L_Q();
shared_ptr<AbstractChatRoom> chatRoom = q->getCore()->findChatRoom(conferenceId);
if (!chatRoom)
lError() << "Unable to find chat room: " << conferenceId << ".";
return chatRoom;
}
shared_ptr<MediaConference::Conference> MainDbPrivate::findAudioVideoConference (const ConferenceId &conferenceId) const {
L_Q();
shared_ptr<MediaConference::Conference> conference = q->getCore()->findAudioVideoConference(conferenceId);
if (!conference)
lError() << "Unable to find chat room: " << conferenceId << ".";
return conference;
}
// -----------------------------------------------------------------------------
// Low level API.
// -----------------------------------------------------------------------------
long long MainDbPrivate::insertSipAddress (const string &sipAddress) {
#ifdef HAVE_DB_STORAGE
long long sipAddressId = selectSipAddressId(sipAddress);
if (sipAddressId >= 0)
return sipAddressId;
lInfo() << "Insert new sip address in database: `" << sipAddress << "`.";
*dbSession.getBackendSession() << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress);
return dbSession.getLastInsertId();
#else
return -1;
#endif
}
void MainDbPrivate::insertContent (long long chatMessageId, const Content &content) {
#ifdef HAVE_DB_STORAGE
soci::session *session = dbSession.getBackendSession();
const long long &contentTypeId = insertContentType(content.getContentType().getMediaType());
const string &body = content.getBodyAsUtf8String();
*session << "INSERT INTO chat_message_content (event_id, content_type_id, body, body_encoding_type) VALUES"
" (:chatMessageId, :contentTypeId, :body, 1)",
soci::use(chatMessageId), soci::use(contentTypeId), soci::use(body);
const long long &chatMessageContentId = dbSession.getLastInsertId();
if (content.isFile()) {
const FileContent &fileContent = static_cast<const FileContent &>(content);
const string &name = fileContent.getFileName();
const size_t &size = fileContent.getFileSize();
const string &path = fileContent.getFilePath();
int duration = fileContent.getFileDuration();
*session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path, duration) VALUES"
" (:chatMessageContentId, :name, :size, :path, :duration)",
soci::use(chatMessageContentId), soci::use(name), soci::use(size), soci::use(path), soci::use(duration);
}
for (const auto &appData : content.getAppDataMap())
*session << "INSERT INTO chat_message_content_app_data (chat_message_content_id, name, data) VALUES"
" (:chatMessageContentId, :name, :data)",
soci::use(chatMessageContentId), soci::use(appData.first), soci::use(appData.second);
#endif
}
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
long long MainDbPrivate::insertContentType (const string &contentType) {
#ifdef HAVE_DB_STORAGE
soci::session *session = dbSession.getBackendSession();
long long contentTypeId;
*session << "SELECT id FROM content_type WHERE value = :contentType", soci::use(contentType), soci::into(contentTypeId);
if (session->got_data())
return contentTypeId;
lInfo() << "Insert new content type in database: `" << contentType << "`.";
*session << "INSERT INTO content_type (value) VALUES (:contentType)", soci::use(contentType);
return dbSession.getLastInsertId();
#else
return -1;
#endif
}
long long MainDbPrivate::insertOrUpdateImportedBasicChatRoom (
long long peerSipAddressId,
long long localSipAddressId,
const tm &creationTime
) {
#ifdef HAVE_DB_STORAGE
soci::session *session = dbSession.getBackendSession();
long long chatRoomId = selectChatRoomId(peerSipAddressId, localSipAddressId);
if (chatRoomId >= 0) {
*session << "UPDATE chat_room SET last_update_time = :lastUpdateTime WHERE id = :chatRoomId",
soci::use(creationTime), soci::use(chatRoomId);
return chatRoomId;
}
const int capabilities = ChatRoom::CapabilitiesMask(
{ ChatRoom::Capabilities::Basic, ChatRoom::Capabilities::Migratable }
);
lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId <<
", local=" << localSipAddressId << ", capabilities=" << capabilities << ").";
*session << "INSERT INTO chat_room ("
" peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities"
") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities)",
soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(creationTime),
soci::use(capabilities);
return dbSession.getLastInsertId();
#else
return -1;
#endif
}
long long MainDbPrivate::insertChatRoom (const shared_ptr<AbstractChatRoom> &chatRoom, unsigned int notifyId) {
#ifdef HAVE_DB_STORAGE
const ConferenceId &conferenceId = chatRoom->getConferenceId();
const long long &peerSipAddressId = insertSipAddress(conferenceId.getPeerAddress().asString());
const long long &localSipAddressId = insertSipAddress(conferenceId.getLocalAddress().asString());
long long chatRoomId = selectChatRoomId(peerSipAddressId, localSipAddressId);
if (chatRoomId >= 0) {
// The chat room is already stored in DB, but still update the notify id that might have changed
lInfo() << "Update chat room in database: " << conferenceId << ".";
*dbSession.getBackendSession() << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE id = :chatRoomId",
soci::use(notifyId), soci::use(chatRoomId);
} else {
lInfo() << "Insert new chat room in database: " << conferenceId << ".";
const tm &creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime());
const tm &lastUpdateTime = Utils::getTimeTAsTm(chatRoom->getLastUpdateTime());
// Remove capabilities like `Proxy`.
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
const int &capabilities = chatRoom->getCapabilities() & ~ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Proxy);
const string &subject = chatRoom->getSubject();
const int &flags = chatRoom->hasBeenLeft();
int ephemeralEnabled = chatRoom->ephemeralEnabled() ? 1 : 0;
long ephemeralLifeTime = chatRoom->getEphemeralLifetime();
*dbSession.getBackendSession() << "INSERT INTO chat_room ("
" peer_sip_address_id, local_sip_address_id, creation_time,"
" last_update_time, capabilities, subject, flags, last_notify_id, ephemeral_enabled, ephemeral_messages_lifetime"
") VALUES ("
" :peerSipAddressId, :localSipAddressId, :creationTime,"
" :lastUpdateTime, :capabilities, :subject, :flags, :lastNotifyId, :ephemeralEnabled, :ephemeralLifeTime"
")",
soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime),
soci::use(lastUpdateTime), soci::use(capabilities), soci::use(subject), soci::use(flags),
soci::use(notifyId), soci::use(ephemeralEnabled), soci::use(ephemeralLifeTime);
chatRoomId = dbSession.getLastInsertId();
}
// Do not add 'me' when creating a server-group-chat-room.
if (conferenceId.getLocalAddress() != conferenceId.getPeerAddress()) {
shared_ptr<Participant> me = chatRoom->getMe();
long long meId = insertChatRoomParticipant(
chatRoomId,
insertSipAddress(me->getAddress().asString()),
me->isAdmin()
);
for (const auto &device : me->getDevices())
insertChatRoomParticipantDevice(meId, insertSipAddress(device->getAddress().asString()), device->getName());
}
for (const auto &participant : chatRoom->getParticipants()) {
long long participantId = insertChatRoomParticipant(
chatRoomId,
insertSipAddress(participant->getAddress().asString()),
participant->isAdmin()
);
for (const auto &device : participant->getDevices())
insertChatRoomParticipantDevice(participantId, insertSipAddress(device->getAddress().asString()), device->getName());
}
return chatRoomId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertChatRoomParticipant (
long long chatRoomId,
long long participantSipAddressId,
bool isAdmin
) {
#ifdef HAVE_DB_STORAGE
soci::session *session = dbSession.getBackendSession();
long long chatRoomParticipantId = selectChatRoomParticipantId(chatRoomId, participantSipAddressId);
auto isAdminInt = static_cast<int>(isAdmin);
if (chatRoomParticipantId >= 0) {
// See: https://stackoverflow.com/a/15299655 (cast to reference)
*session << "UPDATE chat_room_participant SET is_admin = :isAdmin WHERE id = :chatRoomParticipantId",
soci::use(isAdminInt), soci::use(chatRoomParticipantId);
return chatRoomParticipantId;
}
*session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)"
" VALUES (:chatRoomId, :participantSipAddressId, :isAdmin)",
soci::use(chatRoomId), soci::use(participantSipAddressId), soci::use(isAdminInt);
return dbSession.getLastInsertId();
#else
return -1;
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
#endif
}
void MainDbPrivate::insertChatRoomParticipantDevice (
long long participantId,
long long participantDeviceSipAddressId,
const string &deviceName
) {
#ifdef HAVE_DB_STORAGE
soci::session *session = dbSession.getBackendSession();
long long count;
*session << "SELECT COUNT(*) FROM chat_room_participant_device"
" WHERE chat_room_participant_id = :participantId"
" AND participant_device_sip_address_id = :participantDeviceSipAddressId",
soci::into(count), soci::use(participantId), soci::use(participantDeviceSipAddressId);
if (count)
return;
*session << "INSERT INTO chat_room_participant_device (chat_room_participant_id, participant_device_sip_address_id, name)"
" VALUES (:participantId, :participantDeviceSipAddressId, :participantDeviceName)",
soci::use(participantId), soci::use(participantDeviceSipAddressId), soci::use(deviceName);
#endif
}
void MainDbPrivate::insertChatMessageParticipant (long long chatMessageId, long long sipAddressId, int state, time_t stateChangeTime) {
#ifdef HAVE_DB_STORAGE
const tm &stateChangeTm = Utils::getTimeTAsTm(stateChangeTime);
*dbSession.getBackendSession() <<
"INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state, state_change_time)"
" VALUES (:chatMessageId, :sipAddressId, :state, :stateChangeTm)",
soci::use(chatMessageId), soci::use(sipAddressId), soci::use(state), soci::use(stateChangeTm);
#endif
}
long long MainDbPrivate::insertConferenceInfo (const std::shared_ptr<ConferenceInfo> &conferenceInfo) {
#ifdef HAVE_DB_STORAGE
if (!conferenceInfo->getOrganizer().isValid() || !conferenceInfo->getUri().isValid()) {
lError() << "Trying to insert a Conference Info without organizer or URI!";
return -1;
}
const long long &organizerSipAddressId = insertSipAddress(conferenceInfo->getOrganizer().asString());
const long long &uriSipAddressid = insertSipAddress(conferenceInfo->getUri().asString());
const tm &startTime = Utils::getTimeTAsTm(conferenceInfo->getDateTime());
int duration = conferenceInfo->getDuration();
const string &subject = conferenceInfo->getSubject();
const string &description = conferenceInfo->getDescription();
long long conferenceInfoId = selectConferenceInfoId(uriSipAddressid);
if (conferenceInfoId >= 0) {
// The conference info is already stored in DB, but still update it some information might have changed
lInfo() << "Update conferenceInfo in database: " << conferenceInfoId << ".";
*dbSession.getBackendSession() << "UPDATE conference_info SET"
" organizer_sip_address_id = :organizerSipAddressId,"
" start_time = :startTime,"
" duration = :duration,"
" subject = :subject,"
" description = :description"
" WHERE id = :conferenceInfoId",
soci::use(organizerSipAddressId), soci::use(startTime), soci::use(duration),
soci::use(subject), soci::use(description), soci::use(conferenceInfoId);
} else {
lInfo() << "Insert new conference info in database.";
*dbSession.getBackendSession() << "INSERT INTO conference_info ("
" organizer_sip_address_id, uri_sip_address_id, start_time, duration, subject, description"
") VALUES ("
" :organizerSipAddressId, :uriSipAddressid, :startTime, :duration, :subject, :description"
")",
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
soci::use(organizerSipAddressId), soci::use(uriSipAddressid), soci::use(startTime),
soci::use(duration), soci::use(subject), soci::use(description);
conferenceInfoId = dbSession.getLastInsertId();
}
for (const auto & participantAddress : conferenceInfo->getParticipants()) {
insertConferenceInfoParticipant(
conferenceInfoId,
insertSipAddress(participantAddress.asString())
);
}
cache(conferenceInfo, conferenceInfoId);
return conferenceInfoId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceInfoParticipant (long long conferenceInfoId, long long participantSipAddressId) {
#ifdef HAVE_DB_STORAGE
long long conferenceInfoParticipantId = selectConferenceInfoParticipantId(conferenceInfoId, participantSipAddressId);
if (conferenceInfoParticipantId >= 0) {
return conferenceInfoParticipantId;
}
*dbSession.getBackendSession() << "INSERT INTO conference_info_participant (conference_info_id, participant_sip_address_id)"
" VALUES (:conferenceInfoId, :participantSipAddressId)",
soci::use(conferenceInfoId), soci::use(participantSipAddressId);
return dbSession.getLastInsertId();
#else
return -1;
#endif
}
long long MainDbPrivate::insertOrUpdateConferenceCall (const std::shared_ptr<CallLog> &callLog, const std::shared_ptr<ConferenceInfo> &conferenceInfo) {
#ifdef HAVE_DB_STORAGE
long long conferenceInfoId = -1;
if (conferenceInfo != nullptr) {
const long long &uriSipAddressid = insertSipAddress(conferenceInfo->getUri().asString());
conferenceInfoId = selectConferenceInfoId(uriSipAddressid);
if (conferenceInfoId < 0) {
conferenceInfoId = insertConferenceInfo(conferenceInfo);
}
callLog->setConferenceInfoId(conferenceInfoId);
}
int duration = callLog->getDuration();
const tm &connectedTime = Utils::getTimeTAsTm(callLog->getConnectedTime());
int status = callLog->getStatus();
int videoEnabled = callLog->isVideoEnabled() ? 1 : 0;
double quality = static_cast<double>(callLog->getQuality());
const string &callId = callLog->getCallId();
const string &refKey = callLog->getRefKey();
soci::indicator confInfoInd = conferenceInfoId > -1 ? soci::i_ok : soci::i_null;
long long conferenceCallId = selectConferenceCallId(callLog->getCallId());
if (conferenceCallId < 0) {
lInfo() << "Insert new conference call in database: " << callLog->getCallId();
const long long fromSipAddressId = insertSipAddress(ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(callLog->getFromAddress())).asString());
const long long toSipAddressId = insertSipAddress(ConferenceAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(callLog->getToAddress())).asString());
int direction = static_cast<int>(callLog->getDirection());
const tm &startTime = Utils::getTimeTAsTm(callLog->getStartTime());
*dbSession.getBackendSession() << "INSERT INTO conference_call ("
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
" from_sip_address_id, to_sip_address_id, direction, duration, start_time, connected_time, status, video_enabled,"
" quality, call_id, refkey, conference_info_id"
") VALUES ("
" :fromSipAddressId, :toSipAddressId, :direction, :duration, :startTime, :connectedTime, :status, :videoEnabled,"
" :quality, :callId, :refKey, :conferenceInfoId"
")",
soci::use(fromSipAddressId), soci::use(toSipAddressId), soci::use(direction), soci::use(duration), soci::use(startTime),
soci::use(connectedTime), soci::use(status), soci::use(videoEnabled), soci::use(quality), soci::use(callId),
soci::use(refKey), soci::use(conferenceInfoId, confInfoInd);
conferenceCallId = dbSession.getLastInsertId();
} else {
lInfo() << "Update conference call in database: " << callLog->getCallId();
*dbSession.getBackendSession() << "UPDATE conference_call SET"
" duration = :duration, connected_time = :connectedTime, status = :status, video_enabled = :videoEnabled,"
" quality = :quality, call_id = :callId, refkey = :refKey, conference_info_id = :conferenceInfoId"
" WHERE id = :conferenceCallId",
soci::use(duration), soci::use(connectedTime), soci::use(status), soci::use(videoEnabled), soci::use(quality),
soci::use(callId), soci::use(refKey), soci::use(conferenceInfoId, confInfoInd),
soci::use(conferenceCallId);
}
cache(callLog, conferenceCallId);
return conferenceCallId;
#else
return -1;
#endif
}
// -----------------------------------------------------------------------------
long long MainDbPrivate::selectSipAddressId (const string &sipAddress) const {
#ifdef HAVE_DB_STORAGE
long long sipAddressId;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectSipAddressId),
soci::use(sipAddress), soci::into(sipAddressId);
return session->got_data() ? sipAddressId : -1;
#else
return -1;
#endif
}
long long MainDbPrivate::selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const {
#ifdef HAVE_DB_STORAGE
long long chatRoomId;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectChatRoomId),
soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::into(chatRoomId);
return session->got_data() ? chatRoomId : -1;
#else
return -1;
#endif
}
long long MainDbPrivate::selectChatRoomId (const ConferenceId &conferenceId) const {
#ifdef HAVE_DB_STORAGE
long long peerSipAddressId = selectSipAddressId(conferenceId.getPeerAddress().asString());
if (peerSipAddressId < 0)
return -1;
long long localSipAddressId = selectSipAddressId(conferenceId.getLocalAddress().asString());
if (localSipAddressId < 0)
return -1;
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
long long id = selectChatRoomId(peerSipAddressId, localSipAddressId);
if (id != -1) {
cache(conferenceId, id);
}
return id;
#else
return -1;
#endif
}
ConferenceId MainDbPrivate::selectConferenceId (const long long chatRoomId) const {
#ifdef HAVE_DB_STORAGE
string peerSipAddress;
string localSipAddress;
string query = "SELECT peer_sip_address_id, local_sip_address_id FROM chat_room WHERE id = :1";
soci::session *session = dbSession.getBackendSession();
*session << query, soci::use(chatRoomId), soci::into(peerSipAddress), soci::into(localSipAddress);
ConferenceId conferenceId = ConferenceId(
IdentityAddress(peerSipAddress),
IdentityAddress(localSipAddress)
);
if (conferenceId.isValid()) {
cache(conferenceId, chatRoomId);
}
return conferenceId;
#else
return ConferenceId();
#endif
}
long long MainDbPrivate::selectChatRoomParticipantId (long long chatRoomId, long long participantSipAddressId) const {
#ifdef HAVE_DB_STORAGE
long long chatRoomParticipantId;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectChatRoomParticipantId),
soci::use(chatRoomId), soci::use(participantSipAddressId), soci::into(chatRoomParticipantId);
return session->got_data() ? chatRoomParticipantId : -1;
#else
return -1;
#endif
}
long long MainDbPrivate::selectOneToOneChatRoomId (long long sipAddressIdA, long long sipAddressIdB, bool encrypted) const {
#ifdef HAVE_DB_STORAGE
long long chatRoomId;
const int encryptedCapability = int(ChatRoom::Capabilities::Encrypted);
const int expectedCapabilities = encrypted ? encryptedCapability : 0;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectOneToOneChatRoomId),
soci::use(sipAddressIdA, "1"), soci::use(sipAddressIdB, "2"),
soci::use(encryptedCapability, "3"), soci::use(expectedCapabilities, "4"),
soci::into(chatRoomId);
return session->got_data() ? chatRoomId : -1;
#else
return -1;
#endif
}
long long MainDbPrivate::selectConferenceInfoId (long long uriSipAddressId) {
#ifdef HAVE_DB_STORAGE
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
long long conferenceInfoId;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectConferenceInfoId),
soci::use(uriSipAddressId), soci::into(conferenceInfoId);
return session->got_data() ? conferenceInfoId : -1;
#else
return -1;
#endif
}
long long MainDbPrivate::selectConferenceInfoParticipantId (long long conferenceInfoId, long long participantSipAddressId) const {
#ifdef HAVE_DB_STORAGE
long long conferenceInfoParticipantId;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectConferenceInfoParticipantId),
soci::use(conferenceInfoId), soci::use(participantSipAddressId), soci::into(conferenceInfoParticipantId);
return session->got_data() ? conferenceInfoParticipantId : -1;
#else
return -1;
#endif
}
long long MainDbPrivate::selectConferenceCallId (const std::string &callId) {
#ifdef HAVE_DB_STORAGE
long long conferenceCallId;
soci::session *session = dbSession.getBackendSession();
*session << Statements::get(Statements::SelectConferenceCall),
soci::use(callId), soci::into(conferenceCallId);
return session->got_data() ? conferenceCallId : -1;
#else
return -1;
#endif
}
// -----------------------------------------------------------------------------
void MainDbPrivate::deleteContents (long long chatMessageId) {
#ifdef HAVE_DB_STORAGE
*dbSession.getBackendSession() << "DELETE FROM chat_message_content WHERE event_id = :chatMessageId",
soci::use(chatMessageId);
#endif
}
void MainDbPrivate::deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId) {
#ifdef HAVE_DB_STORAGE
*dbSession.getBackendSession() << "DELETE FROM chat_room_participant"
" WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :participantSipAddressId",
soci::use(chatRoomId), soci::use(participantSipAddressId);
#endif
}
void MainDbPrivate::deleteChatRoomParticipantDevice (
long long participantId,
long long participantDeviceSipAddressId
) {
#ifdef HAVE_DB_STORAGE
*dbSession.getBackendSession() << "DELETE FROM chat_room_participant_device"
" WHERE chat_room_participant_id = :participantId"
" AND participant_device_sip_address_id = :participantDeviceSipAddressId",
soci::use(participantId), soci::use(participantDeviceSipAddressId);
#endif
}
// -----------------------------------------------------------------------------
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
// Events API.
// -----------------------------------------------------------------------------
#ifdef HAVE_DB_STORAGE
shared_ptr<EventLog> MainDbPrivate::selectGenericConferenceEvent (
const shared_ptr<AbstractChatRoom> &chatRoom,
const soci::row &row
) const {
L_ASSERT(chatRoom);
EventLog::Type type = EventLog::Type(row.get<int>(1));
if (type == EventLog::Type::ConferenceChatMessage) {
long long eventId = getConferenceEventIdFromRow(row);
shared_ptr<EventLog> eventLog = getEventFromCache(eventId);
if (!eventLog) {
eventLog = selectConferenceChatMessageEvent(chatRoom, type, row);
if (eventLog)
cache(eventLog, eventId);
}
return eventLog;
}
return selectConferenceInfoEvent(chatRoom->getConferenceId(), row);
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceInfoEvent (
const ConferenceId &conferenceId,
const soci::row &row
) const {
long long eventId = getConferenceEventIdFromRow(row);
shared_ptr<EventLog> eventLog = getEventFromCache(eventId);
if (eventLog)
return eventLog;
EventLog::Type type = EventLog::Type(row.get<int>(1));
switch (type) {
case EventLog::Type::None:
case EventLog::Type::ConferenceChatMessage:
case EventLog::Type::ConferenceCallStarted:
case EventLog::Type::ConferenceCallConnected:
case EventLog::Type::ConferenceCallEnded:
return nullptr;
case EventLog::Type::ConferenceCreated:
case EventLog::Type::ConferenceTerminated:
eventLog = selectConferenceEvent(conferenceId, type, row);
break;
case EventLog::Type::ConferenceParticipantAdded:
case EventLog::Type::ConferenceParticipantRemoved:
case EventLog::Type::ConferenceParticipantSetAdmin:
case EventLog::Type::ConferenceParticipantUnsetAdmin:
eventLog = selectConferenceParticipantEvent(conferenceId, type, row);
break;
case EventLog::Type::ConferenceParticipantDeviceAdded:
case EventLog::Type::ConferenceParticipantDeviceRemoved:
case EventLog::Type::ConferenceParticipantDeviceMediaChanged:
case EventLog::Type::ConferenceParticipantDeviceStatusChanged:
eventLog = selectConferenceParticipantDeviceEvent(conferenceId, type, row);
break;
case EventLog::Type::ConferenceAvailableMediaChanged:
eventLog = selectConferenceAvailableMediaEvent(conferenceId, type, row);
break;
case EventLog::Type::ConferenceSubjectChanged:
eventLog = selectConferenceSubjectEvent(conferenceId, type, row);
break;
case EventLog::Type::ConferenceSecurityEvent:
eventLog = selectConferenceSecurityEvent(conferenceId, type, row);
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
break;
case EventLog::Type::ConferenceEphemeralMessageLifetimeChanged:
case EventLog::Type::ConferenceEphemeralMessageManagedByAdmin:
case EventLog::Type::ConferenceEphemeralMessageManagedByParticipants:
case EventLog::Type::ConferenceEphemeralMessageEnabled:
case EventLog::Type::ConferenceEphemeralMessageDisabled:
eventLog = selectConferenceEphemeralMessageEvent(conferenceId, type, row);
}
if (eventLog)
cache(eventLog, eventId);
return eventLog;
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
) const {
return make_shared<ConferenceEvent>(
type,
getConferenceEventCreationTimeFromRow(row),
conferenceId
);
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceCallEvent (
const soci::row &row
) const {
L_Q();
long long eventId = dbSession.resolveId(row, 0);
shared_ptr<EventLog> eventLog = getEventFromCache(eventId);
if (eventLog)
return eventLog;
EventLog::Type type = EventLog::Type(row.get<int>(1));
long long conferenceCallId = dbSession.resolveId(row, 3);
auto callLog = getCallLogFromCache(conferenceCallId);
if (callLog == nullptr) {
callLog = CallLog::create(q->getCore(), static_cast<LinphoneCallDir>(row.get<int>(6)), linphone_address_new(row.get<string>(4).c_str()), linphone_address_new(row.get<string>(5).c_str()));
callLog->setDuration(row.get<int>(7));
callLog->setStartTime(dbSession.getTime(row, 8));
callLog->setConnectedTime(dbSession.getTime(row, 9));
callLog->setStatus(static_cast<LinphoneCallStatus>(row.get<int>(10)));
callLog->setVideoEnabled(!!row.get<int>(11));
callLog->setQuality((float) row.get<double>(12));
soci::indicator ind = row.get_indicator(13);
if (ind == soci::i_ok) callLog->setCallId(row.get<string>(13));
ind = row.get_indicator(14);
if (ind == soci::i_ok) callLog->setRefKey(row.get<string>(14));
cache(callLog, conferenceCallId);
}
std::shared_ptr<ConferenceInfo> conferenceInfo = nullptr;
if (row.get_indicator(15) != soci::i_null) {
long long conferenceInfoId = dbSession.resolveId(row, 15);
callLog->setConferenceInfoId(conferenceInfoId);
auto conferenceInfo = getConferenceInfoFromCache(conferenceInfoId);
if (conferenceInfo == nullptr) {
conferenceInfo = ConferenceInfo::create();
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
IdentityAddress organizer = IdentityAddress(row.get<string>(16));
conferenceInfo->setOrganizer(organizer);
ConferenceAddress uri = ConferenceAddress(row.get<string>(17));
conferenceInfo->setUri(uri);
conferenceInfo->setDateTime(dbSession.getTime(row, 18));
conferenceInfo->setDuration(row.get<int>(19));
conferenceInfo->setSubject(row.get<string>(20));
conferenceInfo->setDescription(row.get<string>(21));
static const string query = "SELECT sip_address.value"
" FROM sip_address, conference_info, conference_info_participant"
" WHERE conference_info.id = :conferenceInfoId"
" AND sip_address.id = conference_info_participant.participant_sip_address_id"
" AND conference_info_participant.conference_info_id = conference_info.id";
soci::session *session = dbSession.getBackendSession();
soci::rowset<soci::row> participantRows = (session->prepare << query, soci::use(conferenceInfoId));
for (const auto &participantRow : participantRows) {
IdentityAddress participant(participantRow.get<string>(0));
conferenceInfo->addParticipant(participant);
}
cache(conferenceInfo, conferenceInfoId);
}
}
eventLog = make_shared<ConferenceCallEvent>(
type,
dbSession.getTime(row, 2),
callLog,
conferenceInfo
);
cache(eventLog, eventId);
return eventLog;
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
const shared_ptr<AbstractChatRoom> &chatRoom,
EventLog::Type type,
const soci::row &row
) const {
long long eventId = getConferenceEventIdFromRow(row);
shared_ptr<ChatMessage> chatMessage = getChatMessageFromCache(eventId);
if (!chatMessage) {
chatMessage = shared_ptr<ChatMessage>(new ChatMessage(
chatRoom,
ChatMessage::Direction(row.get<int>(8))
));
chatMessage->setIsSecured(!!row.get<int>(9));
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
ChatMessage::State messageState = ChatMessage::State(row.get<int>(7));
// This is necessary if linphone has crashed while sending a message. It will set the correct state so the user can resend it.
if (messageState == ChatMessage::State::Idle
|| messageState == ChatMessage::State::InProgress
|| messageState == ChatMessage::State::FileTransferInProgress) {
messageState = ChatMessage::State::NotDelivered;
}
dChatMessage->forceState(messageState);
dChatMessage->forceFromAddress(IdentityAddress(row.get<string>(3)));
dChatMessage->forceToAddress(ConferenceAddress(row.get<string>(4)));
dChatMessage->setTime(dbSession.getTime(row, 5));
dChatMessage->setImdnMessageId(row.get<string>(6));
dChatMessage->setPositiveDeliveryNotificationRequired(!!row.get<int>(14));
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
dChatMessage->setDisplayNotificationRequired(!!row.get<int>(15));
dChatMessage->markContentsAsNotLoaded();
dChatMessage->setIsReadOnly(true);
if (!!row.get<int>(18)) {
dChatMessage->markAsRead();
}
dChatMessage->setForwardInfo(row.get<string>(19));
if (row.get_indicator(20) != soci::i_null) {
dChatMessage->enableEphemeralWithTime((long)row.get<double>(20));
dChatMessage->setEphemeralExpireTime(dbSession.getTime(row, 21));
}
if (row.get_indicator(24) != soci::i_null) {
dChatMessage->setReplyToMessageIdAndSenderAddress(row.get<string>(23), IdentityAddress(row.get<string>(24)));
}
cache(chatMessage, eventId);
}
return make_shared<ConferenceChatMessageEvent>(
getConferenceEventCreationTimeFromRow(row),
chatMessage
);
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceParticipantEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
) const {
shared_ptr<AbstractChatRoom> chatRoom = findChatRoom(conferenceId);
IdentityAddress participantAddress(IdentityAddress(row.get<string>(12)));
std::shared_ptr<ConferenceParticipantEvent> event = make_shared<ConferenceParticipantEvent>(
type,
getConferenceEventCreationTimeFromRow(row),
conferenceId,
participantAddress
);
event->setNotifyId(getConferenceEventNotifyIdFromRow(row));
return event;
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceParticipantDeviceEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
) const {
shared_ptr<AbstractChatRoom> chatRoom = findChatRoom(conferenceId);
IdentityAddress participantAddress(IdentityAddress(row.get<string>(12)));
IdentityAddress deviceAddress(IdentityAddress(row.get<string>(11)));
shared_ptr<ConferenceParticipantDeviceEvent> event = make_shared<ConferenceParticipantDeviceEvent>(
type,
getConferenceEventCreationTimeFromRow(row),
conferenceId,
participantAddress,
deviceAddress
);
event->setNotifyId(getConferenceEventNotifyIdFromRow(row));
return event;
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceSecurityEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
) const {
return make_shared<ConferenceSecurityEvent>(
getConferenceEventCreationTimeFromRow(row),
conferenceId,
static_cast<ConferenceSecurityEvent::SecurityEventType>(row.get<int>(16)),
IdentityAddress(row.get<string>(17))
);
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceEphemeralMessageEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
) const {
return make_shared<ConferenceEphemeralMessageEvent>(
type,
getConferenceEventCreationTimeFromRow(row),
conferenceId,
(long)row.get<double>(22)
);
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceAvailableMediaEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
) const {
std::map<ConferenceMediaCapabilities, bool> mediaCapabilities;
// TODO: choose rows
mediaCapabilities[ConferenceMediaCapabilities::Audio] = false;
mediaCapabilities[ConferenceMediaCapabilities::Video] = false;
mediaCapabilities[ConferenceMediaCapabilities::Text] = false;
shared_ptr<ConferenceAvailableMediaEvent> event = make_shared<ConferenceAvailableMediaEvent>(
getConferenceEventCreationTimeFromRow(row),
conferenceId,
mediaCapabilities
);
event->setNotifyId(getConferenceEventNotifyIdFromRow(row));
return event;
}
shared_ptr<EventLog> MainDbPrivate::selectConferenceSubjectEvent (
const ConferenceId &conferenceId,
EventLog::Type type,
const soci::row &row
) const {
shared_ptr<ConferenceSubjectEvent> event = make_shared<ConferenceSubjectEvent>(
getConferenceEventCreationTimeFromRow(row),
conferenceId,
row.get<string>(13)
);
event->setNotifyId(getConferenceEventNotifyIdFromRow(row));
return event;
}
#endif
// -----------------------------------------------------------------------------
long long MainDbPrivate::insertEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
const int &type = int(eventLog->getType());
const tm &creationTime = Utils::getTimeTAsTm(eventLog->getCreationTime());
*dbSession.getBackendSession() << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)",
soci::use(type), soci::use(creationTime);
return dbSession.getLastInsertId();
#else
return -1;
#endif
1191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
}
long long MainDbPrivate::insertConferenceEvent (const shared_ptr<EventLog> &eventLog, long long *chatRoomId) {
#ifdef HAVE_DB_STORAGE
shared_ptr<ConferenceEvent> conferenceEvent = static_pointer_cast<ConferenceEvent>(eventLog);
long long eventId = -1;
const ConferenceId &conferenceId = conferenceEvent->getConferenceId();
const long long &curChatRoomId = selectChatRoomId(conferenceId);
if (curChatRoomId < 0) {
// A conference event can be inserted in database only if chat room exists.
// Otherwise it's an error.
lError() << "Unable to find chat room storage id of: " << conferenceId << ".";
} else {
eventId = insertEvent(eventLog);
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO conference_event (event_id, chat_room_id)"
" VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(curChatRoomId);
const tm &lastUpdateTime = Utils::getTimeTAsTm(eventLog->getCreationTime());
*session << "UPDATE chat_room SET last_update_time = :lastUpdateTime"
" WHERE id = :chatRoomId", soci::use(lastUpdateTime),
soci::use(curChatRoomId);
if (eventLog->getType() == EventLog::Type::ConferenceTerminated)
*session << "UPDATE chat_room SET flags = 1, last_notify_id = 0 WHERE id = :chatRoomId", soci::use(curChatRoomId);
else if (eventLog->getType() == EventLog::Type::ConferenceCreated)
*session << "UPDATE chat_room SET flags = 0 WHERE id = :chatRoomId", soci::use(curChatRoomId);
}
if (chatRoomId)
*chatRoomId = curChatRoomId;
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceCallEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
shared_ptr<ConferenceCallEvent> conferenceCallEvent = static_pointer_cast<ConferenceCallEvent>(eventLog);
long long eventId = -1;
auto callLog = conferenceCallEvent->getCallLog();
auto conferenceInfo = conferenceCallEvent->getConferenceInfo();
long long conferenceCallId = selectConferenceCallId(callLog->getCallId());
//EventLog::Type type = conferenceCallEvent->getType();
// switch(type) {
// case EventLog::Type::ConferenceCallStarted:
// if (conferenceCallId >= 0) {
// lWarning() << "Conference call is already stored in db for call-id: " << callLog->getCallId();
// return -1;
// }
// break;
// case EventLog::Type::ConferenceCallConnected:
// if (conferenceCallId < 0) {
// lWarning() << "Cannot add ConferenceCallConnected event as conference call is not present in db for call-id: " << callLog->getCallId();
// return -1;
// }
// break;
// case EventLog::Type::ConferenceCallEnded:
// if (conferenceCallId < 0) {
// lWarning() << "Cannot add ConferenceCallEnded event as conference call is not present in db for call-id: " << callLog->getCallId();
// return -1;
// }
// break;
// default:
1261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
// lError() << "Trying to insert a conference call without the correct event type!";
// return -1;
// }
conferenceCallId = insertOrUpdateConferenceCall(callLog, conferenceInfo);
eventId = insertEvent(eventLog);
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO conference_call_event (event_id, conference_call_id)"
" VALUES (:eventId, :conferenceCallId)", soci::use(eventId), soci::use(conferenceCallId);
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
const long long &eventId = insertConferenceEvent(eventLog);
if (eventId < 0)
return -1;
shared_ptr<ChatMessage> chatMessage = static_pointer_cast<ConferenceChatMessageEvent>(eventLog)->getChatMessage();
const long long &fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString());
const long long &toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString());
const string &forwardInfo = chatMessage->getForwardInfo();
const tm &messageTime = Utils::getTimeTAsTm(chatMessage->getTime());
const int &state = int(chatMessage->getState());
const int &direction = int(chatMessage->getDirection());
const string &imdnMessageId = chatMessage->getImdnMessageId();
const int &isSecured = chatMessage->isSecured() ? 1 : 0;
const int &deliveryNotificationRequired = chatMessage->getPrivate()->getPositiveDeliveryNotificationRequired();
const int &displayNotificationRequired = chatMessage->getPrivate()->getDisplayNotificationRequired();
const int &markedAsRead = chatMessage->getPrivate()->isMarkedAsRead() ? 1 : 0;
const bool &isEphemeral = chatMessage->isEphemeral();
const string &callId = chatMessage->getPrivate()->getCallId();
const string &replyMessageId = chatMessage->getReplyToMessageId();
long long sipAddressId = 0;
if (!replyMessageId.empty()) {
sipAddressId = insertSipAddress(chatMessage->getReplyToSenderAddress().asString());
}
const long long &replyToSipAddressId = sipAddressId;
*dbSession.getBackendSession() << "INSERT INTO conference_chat_message_event ("
" event_id, from_sip_address_id, to_sip_address_id,"
" time, state, direction, imdn_message_id, is_secured,"
" delivery_notification_required, display_notification_required,"
" marked_as_read, forward_info, call_id, reply_message_id, reply_sender_address_id"
") VALUES ("
" :eventId, :localSipaddressId, :remoteSipaddressId,"
" :time, :state, :direction, :imdnMessageId, :isSecured,"
" :deliveryNotificationRequired, :displayNotificationRequired,"
" :markedAsRead, :forwardInfo, :callId, :replyMessageId, :replyToSipAddressId"
")", soci::use(eventId), soci::use(fromSipAddressId), soci::use(toSipAddressId),
soci::use(messageTime), soci::use(state), soci::use(direction),
soci::use(imdnMessageId), soci::use(isSecured),
soci::use(deliveryNotificationRequired), soci::use(displayNotificationRequired),
soci::use(markedAsRead), soci::use(forwardInfo), soci::use(callId),
soci::use(replyMessageId), soci::use(replyToSipAddressId);
if (isEphemeral) {
long ephemeralLifetime = chatMessage->getEphemeralLifetime();
const tm &expireTime = Utils::getTimeTAsTm(chatMessage->getEphemeralExpireTime());
*dbSession.getBackendSession() << "INSERT INTO chat_message_ephemeral_event ("
" event_id, ephemeral_lifetime, expired_time"
") VALUES ("
" :eventId, :ephemeralLifetime, :expireTime"
1331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
")", soci::use(eventId), soci::use(ephemeralLifetime), soci::use(expireTime);
}
for (const Content *content : chatMessage->getContents())
insertContent(eventId, *content);
shared_ptr<AbstractChatRoom> chatRoom(chatMessage->getChatRoom());
for (const auto &participant : chatRoom->getParticipants()) {
const long long &participantSipAddressId = selectSipAddressId(participant->getAddress().asString());
insertChatMessageParticipant(eventId, participantSipAddressId, state, chatMessage->getTime());
}
const long long &dbChatRoomId = selectChatRoomId(chatRoom->getConferenceId());
*dbSession.getBackendSession() << "UPDATE chat_room SET last_message_id = :1 WHERE id = :2", soci::use(eventId), soci::use(dbChatRoomId);
if (direction == int(ChatMessage::Direction::Incoming) && !markedAsRead) {
int *count = unreadChatMessageCountCache[chatRoom->getConferenceId()];
if (count)
++*count;
}
return eventId;
#else
return -1;
#endif
}
void MainDbPrivate::updateConferenceChatMessageEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
shared_ptr<ChatMessage> chatMessage = static_pointer_cast<ConferenceChatMessageEvent>(eventLog)->getChatMessage();
const EventLogPrivate *dEventLog = eventLog->getPrivate();
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
const long long &eventId = dEventKey->storageId;
// 1. Get current chat message state and database state.
const ChatMessage::State state = chatMessage->getState();
ChatMessage::State dbState;
bool dbMarkedAsRead;
{
int intState;
int intMarkedAsRead;
*dbSession.getBackendSession() << "SELECT state, marked_as_read FROM conference_chat_message_event WHERE event_id = :eventId",
soci::into(intState), soci::into(intMarkedAsRead), soci::use(eventId);
dbState = ChatMessage::State(intState);
dbMarkedAsRead = intMarkedAsRead == 1;
}
const bool markedAsRead = chatMessage->getPrivate()->isMarkedAsRead();
// 2. Update unread chat message count if necessary.
const bool isOutgoing = chatMessage->getDirection() == ChatMessage::Direction::Outgoing;
shared_ptr<AbstractChatRoom> chatRoom(chatMessage->getChatRoom());
if (!isOutgoing && markedAsRead) {
int *count = unreadChatMessageCountCache[chatRoom->getConferenceId()];
if (count && !dbMarkedAsRead) {
L_ASSERT(*count > 0);
--*count;
}
}
// 3. Update chat message event.
{
const string &imdnMessageId = chatMessage->getImdnMessageId();
// Do not store transfer state.
const int stateInt = int(
state == ChatMessage::State::InProgress ||
state == ChatMessage::State::FileTransferDone ||
state == ChatMessage::State::FileTransferInProgress ||
state == ChatMessage::State::FileTransferError
? dbState
1401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
: state
);
const int markedAsReadInt = markedAsRead ? 1 : 0;
*dbSession.getBackendSession() << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId, marked_as_read = :markedAsRead"
" WHERE event_id = :eventId",
soci::use(stateInt), soci::use(imdnMessageId), soci::use(markedAsReadInt), soci::use(eventId);
}
// 4. Update contents.
deleteContents(eventId);
for (const auto &content : chatMessage->getContents())
insertContent(eventId, *content);
// 5. Update participants.
if (isOutgoing && (state == ChatMessage::State::Delivered || state == ChatMessage::State::NotDelivered))
for (const auto &participant : chatRoom->getParticipants())
setChatMessageParticipantState(eventLog, participant->getAddress(), state, std::time(nullptr));
#endif
}
long long MainDbPrivate::insertConferenceNotifiedEvent (const shared_ptr<EventLog> &eventLog, long long *chatRoomId) {
#ifdef HAVE_DB_STORAGE
long long curChatRoomId;
const long long &eventId = insertConferenceEvent(eventLog, &curChatRoomId);
if (eventId < 0)
return -1;
const unsigned int &lastNotifyId = static_pointer_cast<ConferenceNotifiedEvent>(eventLog)->getNotifyId();
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO conference_notified_event (event_id, notify_id)"
" VALUES (:eventId, :notifyId)", soci::use(eventId), soci::use(lastNotifyId);
*session << "UPDATE chat_room SET last_notify_id = :lastNotifyId WHERE id = :chatRoomId",
soci::use(lastNotifyId), soci::use(curChatRoomId);
if (chatRoomId)
*chatRoomId = curChatRoomId;
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceParticipantEvent (
const shared_ptr<EventLog> &eventLog,
long long *chatRoomId,
bool executeAction
) {
#ifdef HAVE_DB_STORAGE
long long curChatRoomId;
const long long &eventId = insertConferenceNotifiedEvent(eventLog, &curChatRoomId);
if (eventId < 0)
return -1;
shared_ptr<ConferenceParticipantEvent> participantEvent =
static_pointer_cast<ConferenceParticipantEvent>(eventLog);
const long long &participantAddressId = insertSipAddress(
participantEvent->getParticipantAddress().asString()
);
*dbSession.getBackendSession() << "INSERT INTO conference_participant_event (event_id, participant_sip_address_id)"
" VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId);
if (executeAction) {
bool isAdmin = eventLog->getType() == EventLog::Type::ConferenceParticipantSetAdmin;
switch (eventLog->getType()) {
case EventLog::Type::ConferenceParticipantAdded:
1471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
case EventLog::Type::ConferenceParticipantSetAdmin:
case EventLog::Type::ConferenceParticipantUnsetAdmin:
insertChatRoomParticipant(curChatRoomId, participantAddressId, isAdmin);
break;
case EventLog::Type::ConferenceParticipantRemoved:
deleteChatRoomParticipant(curChatRoomId, participantAddressId);
break;
default:
break;
}
}
if (chatRoomId)
*chatRoomId = curChatRoomId;
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
long long chatRoomId;
const long long &eventId = insertConferenceParticipantEvent(eventLog, &chatRoomId);
if (eventId < 0)
return -1;
shared_ptr<ConferenceParticipantDeviceEvent> participantDeviceEvent =
static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
const string participantAddress = participantDeviceEvent->getParticipantAddress().asString();
const long long &participantAddressId = selectSipAddressId(participantAddress);
if (participantAddressId < 0) {
lError() << "Unable to find sip address id of: `" << participantAddress << "`.";
return -1;
}
const long long &participantId = selectChatRoomParticipantId(chatRoomId, participantAddressId);
if (participantId < 0) {
lError() << "Unable to find valid participant id in database with chat room id = " << chatRoomId <<
" and participant address id = " << participantAddressId;
return -1;
}
const long long &deviceAddressId = insertSipAddress(
participantDeviceEvent->getDeviceAddress().asString()
);
*dbSession.getBackendSession() << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)"
" VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId);
switch (eventLog->getType()) {
case EventLog::Type::ConferenceParticipantDeviceAdded:
insertChatRoomParticipantDevice(participantId, deviceAddressId, participantDeviceEvent->getDeviceName());
break;
case EventLog::Type::ConferenceParticipantDeviceRemoved:
deleteChatRoomParticipantDevice(participantId, deviceAddressId);
break;
default:
break;
}
return eventId;
#else
return -1;
#endif
}
1541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
long long MainDbPrivate::insertConferenceSecurityEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
long long chatRoomId;
const long long &eventId = insertConferenceEvent(eventLog, &chatRoomId);
if (eventId < 0)
return -1;
const int &securityEventType = int(static_pointer_cast<ConferenceSecurityEvent>(eventLog)->getSecurityEventType());
const string &faultyDevice = static_pointer_cast<ConferenceSecurityEvent>(eventLog)->getFaultyDeviceAddress().asString();
// insert security event into new table "conference_security_event"
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO conference_security_event (event_id, security_alert, faulty_device)"
" VALUES (:eventId, :securityEventType, :faultyDevice)", soci::use(eventId), soci::use(securityEventType), soci::use(faultyDevice);
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceAvailableMediaEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
long long chatRoomId;
const long long &eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId);
if (eventId < 0)
return -1;
const int audio = static_pointer_cast<ConferenceAvailableMediaEvent>(eventLog)->audioEnabled() ? 1 : 0;
const int video = static_pointer_cast<ConferenceAvailableMediaEvent>(eventLog)->videoEnabled() ? 1 : 0;
const int chat = static_pointer_cast<ConferenceAvailableMediaEvent>(eventLog)->chatEnabled() ? 1 : 0;
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO conference_available_media_event (event_id, audio, video, chat)"
" VALUES (:eventId, :audio, :video, :chat)", soci::use(eventId), soci::use(audio), soci::use(video), soci::use(chat);
*session << "UPDATE chat_room SET audio = :audio, video = :video, chat = :chat"
" WHERE id = :chatRoomId", soci::use(audio), soci::use(video), soci::use(chat), soci::use(chatRoomId);
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceSubjectEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE
long long chatRoomId;
const long long &eventId = insertConferenceNotifiedEvent(eventLog, &chatRoomId);
if (eventId < 0)
return -1;
const string &subject = static_pointer_cast<ConferenceSubjectEvent>(eventLog)->getSubject();
soci::session *session = dbSession.getBackendSession();
*session << "INSERT INTO conference_subject_event (event_id, subject)"
" VALUES (:eventId, :subject)", soci::use(eventId), soci::use(subject);
*session << "UPDATE chat_room SET subject = :subject"
" WHERE id = :chatRoomId", soci::use(subject), soci::use(chatRoomId);
return eventId;
#else
return -1;
#endif
}
long long MainDbPrivate::insertConferenceEphemeralMessageEvent (const shared_ptr<EventLog> &eventLog) {
#ifdef HAVE_DB_STORAGE