main-db.cpp 180.38 KiB
/*
 * 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