linphone-desktop/linphone-app/src/components/sip-addresses/SipAddressesModel.cpp
Julien Wadel 39f72680ea Fix hidden timelines.
Do timeline deletion on SDK callabacks to avoid using deleted objects.
From secure chats rooms, forward messages on the secure chat rooms if selected from contacts.
Update SDK.
2022-10-27 13:55:07 +02:00

673 lines
26 KiB
C++

/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#include <QDateTime>
#include <QElapsedTimer>
#include <QUrl>
#include <QtDebug>
#include "components/call/CallModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/history/HistoryModel.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "utils/Utils.hpp"
#include "SipAddressesModel.hpp"
// =============================================================================
using namespace std;
// -----------------------------------------------------------------------------
static inline QVariantMap buildVariantMap (const SipAddressesModel::SipAddressEntry &sipAddressEntry) {
return QVariantMap{
{ "sipAddress", sipAddressEntry.sipAddress },
{ "contactModel", QVariant::fromValue(sipAddressEntry.contact.get()) },
{ "presenceStatus", sipAddressEntry.presenceStatus },
{ "__localToConferenceEntry", QVariant::fromValue(&sipAddressEntry.localAddressToConferenceEntry) }
};
}
SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(parent) {
initSipAddresses();
CoreManager *coreManager = CoreManager::getInstance();
mCoreHandlers = coreManager->getHandlers();
QObject::connect(coreManager, &CoreManager::chatRoomModelCreated, this, &SipAddressesModel::handleChatRoomModelCreated);
QObject::connect(coreManager, &CoreManager::historyModelCreated, this, &SipAddressesModel::handleHistoryModelCreated);
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
QObject::connect(contacts, &ContactsListModel::contactAdded, this, &SipAddressesModel::handleContactAdded);
QObject::connect(contacts, &ContactsListModel::contactRemoved, this, &SipAddressesModel::handleContactRemoved);
QObject::connect(contacts, &ContactsListModel::sipAddressAdded, this, &SipAddressesModel::handleSipAddressAdded);
QObject::connect(contacts, &ContactsListModel::sipAddressRemoved, this, &SipAddressesModel::handleSipAddressRemoved);
CoreHandlers *coreHandlers = mCoreHandlers.get();
QObject::connect(coreHandlers, &CoreHandlers::messagesReceived, this, &SipAddressesModel::handleMessagesReceived);
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &SipAddressesModel::handleCallStateChanged);
QObject::connect(coreHandlers, &CoreHandlers::presenceReceived, this, &SipAddressesModel::handlePresenceReceived);
QObject::connect(coreHandlers, &CoreHandlers::isComposingChanged, this, &SipAddressesModel::handleIsComposingChanged);
}
// -----------------------------------------------------------------------------
void SipAddressesModel::reset(){
mPeerAddressToSipAddressEntry.clear();
mRefs.clear();
resetInternalData();
initSipAddresses();
emit sipAddressReset();
}
int SipAddressesModel::rowCount (const QModelIndex &) const {
return mRefs.count();
}
QHash<int, QByteArray> SipAddressesModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$modelData";
return roles;
}
QVariant SipAddressesModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mRefs.count())
return QVariant();
if (role == Qt::DisplayRole)
return buildVariantMap(*mRefs[row]);
return QVariant();
}
// -----------------------------------------------------------------------------
QVariantMap SipAddressesModel::find (const QString &sipAddress) const {
QString cleanedAddress = Utils::cleanSipAddress(sipAddress);
auto it = mPeerAddressToSipAddressEntry.find(cleanedAddress);
if (it == mPeerAddressToSipAddressEntry.end())
return QVariantMap();
return buildVariantMap(*it);
}
// -----------------------------------------------------------------------------
ContactModel *SipAddressesModel::mapSipAddressToContact (const QString &sipAddress) const {
QString cleanedAddress = Utils::cleanSipAddress(sipAddress);
auto it = mPeerAddressToSipAddressEntry.find(cleanedAddress);
return it == mPeerAddressToSipAddressEntry.end() ? nullptr : it->contact.get();
}
// -----------------------------------------------------------------------------
SipAddressObserver *SipAddressesModel::getSipAddressObserver (const QString &peerAddress, const QString &localAddress) {
SipAddressObserver *model = new SipAddressObserver(peerAddress, localAddress);
const QString cleanedPeerAddress = Utils::cleanSipAddress(peerAddress);
const QString cleanedLocalAddress = Utils::cleanSipAddress(localAddress);
auto it = mPeerAddressToSipAddressEntry.find(cleanedPeerAddress);
if (it != mPeerAddressToSipAddressEntry.end()) {
model->setContact(it->contact);
model->setPresenceStatus(it->presenceStatus);
auto it2 = it->localAddressToConferenceEntry.find(cleanedLocalAddress);
if (it2 != it->localAddressToConferenceEntry.end())
model->setUnreadMessageCount(it2->unreadMessageCount+it2->missedCallCount);
}
mObservers.insert(cleanedPeerAddress, model);
QObject::connect(model, &SipAddressObserver::destroyed, this, [this, model, cleanedPeerAddress, cleanedLocalAddress]() {
// Do not use `model` methods. `model` is partially destroyed here!
if (mObservers.remove(cleanedPeerAddress, model) == 0)
qWarning() << QStringLiteral("Unable to remove (%1, %2) from observers.")
.arg(cleanedPeerAddress).arg(cleanedLocalAddress);
});
return model;
}
// -----------------------------------------------------------------------------
QString SipAddressesModel::getTransportFromSipAddress (const QString &sipAddress) {
if( sipAddress.toUpper().contains("TRANSPORT="))
{// Transport has been specified : check for it
const shared_ptr<const linphone::Address> address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(sipAddress));
if (!address)
return QString("TLS"); // Return TLS by default
switch (address->getTransport()) {
case linphone::TransportType::Udp:
return QStringLiteral("UDP");
case linphone::TransportType::Tcp:
return QStringLiteral("TCP");
case linphone::TransportType::Tls:
return QStringLiteral("TLS");
case linphone::TransportType::Dtls:
return QStringLiteral("DTLS");
}
}
return QString("TLS");
}
QString SipAddressesModel::addTransportToSipAddress (const QString &sipAddress, const QString &transport) {
shared_ptr<linphone::Address> address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(sipAddress));
if (!address)
return QString("");
LinphoneEnums::TransportType transportType;
LinphoneEnums::fromString(transport, &transportType);
address->setTransport(LinphoneEnums::toLinphone(transportType));
return Utils::coreStringToAppString(address->asString());
}
// -----------------------------------------------------------------------------
QString SipAddressesModel::interpretSipAddress (const QString &sipAddress, bool checkUsername) {
shared_ptr<linphone::Address> lAddress = CoreManager::getInstance()->getCore()->interpretUrl(
Utils::appStringToCoreString(sipAddress)
);
if (lAddress && (!checkUsername || !lAddress->getUsername().empty()))
return Utils::coreStringToAppString(lAddress->asStringUriOnly());
return QString("");
}
QString SipAddressesModel::interpretSipAddress (const QString &sipAddress, const QString &domain) {
auto core = CoreManager::getInstance()->getCore();
if(!core){
qWarning() << "No core to interpret address";
}else{
auto accountParams = CoreManager::getInstance()->getCore()->createAccountParams();
shared_ptr<linphone::Address> lAddressTemp = core->createPrimaryContactParsed();// Create an address
if( lAddressTemp ){
lAddressTemp->setDomain(Utils::appStringToCoreString(domain)); // Set the domain and use the address into account
accountParams->setIdentityAddress(lAddressTemp);
auto account = CoreManager::getInstance()->getCore()->createAccount(accountParams);
if( account){
shared_ptr<linphone::Address> lAddress = account->normalizeSipUri(Utils::appStringToCoreString(sipAddress));
if (lAddress) {
return Utils::coreStringToAppString(lAddress->asStringUriOnly());
} else {
qWarning() << "Cannot normalize Sip Uri : " << sipAddress << " / " << domain;
return QString("");
}
}else{
qWarning() << "Cannot create an account to interpret parse address : " << sipAddress;
}
}else{
qWarning() << "Cannot create a Primary Contact Parsed";
}
}
return QString("");
}
QString SipAddressesModel::interpretSipAddress (const QUrl &sipAddress) {
return sipAddress.toString();
}
bool SipAddressesModel::addressIsValid (const QString &address) {
return !!linphone::Factory::get()->createAddress(Utils::appStringToCoreString(address));
}
bool SipAddressesModel::sipAddressIsValid (const QString &sipAddress) {
shared_ptr<linphone::Address> address = linphone::Factory::get()->createAddress(Utils::appStringToCoreString(sipAddress));
return address && !address->getUsername().empty();
}
// Return at most : sip:username@domain
QString SipAddressesModel::cleanSipAddress (const QString &sipAddress) {
return Utils::cleanSipAddress(sipAddress);
}
// -----------------------------------------------------------------------------
bool SipAddressesModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
}
bool SipAddressesModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mRefs.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mPeerAddressToSipAddressEntry.remove(mRefs.takeAt(row)->sipAddress);
endRemoveRows();
return true;
}
// -----------------------------------------------------------------------------
void SipAddressesModel::handleChatRoomModelCreated (const QSharedPointer<ChatRoomModel> &chatRoomModel) {
ChatRoomModel *ptr = chatRoomModel.get();
QObject::connect(ptr, &ChatRoomModel::allEntriesRemoved, this, [this, ptr] {
handleAllEntriesRemoved(ptr);
});
QObject::connect(ptr, &ChatRoomModel::lastEntryRemoved, this, [this, ptr] {
handleLastEntryRemoved(ptr);
});
QObject::connect(ptr, &ChatRoomModel::messageCountReset, this, [this, ptr] {
handleMessageCountReset(ptr);
});
QObject::connect(ptr, &ChatRoomModel::messageSent, this, &SipAddressesModel::handleMessageSent);
}
void SipAddressesModel::handleHistoryModelCreated (HistoryModel *historyModel) {
QObject::connect(historyModel, &HistoryModel::callCountReset, this, [this] {
handleAllCallCountReset();
});
}
void SipAddressesModel::handleContactAdded (QSharedPointer<ContactModel> contact) {
for (const auto &sipAddress : contact->getVcardModel()->getSipAddresses()) {
addOrUpdateSipAddress(sipAddress.toString(), contact);
}
}
void SipAddressesModel::handleContactRemoved (QSharedPointer<ContactModel> contact) {
for (const auto &sipAddress : contact->getVcardModel()->getSipAddresses())
removeContactOfSipAddress(sipAddress.toString());
}
void SipAddressesModel::handleSipAddressAdded (QSharedPointer<ContactModel> contact, const QString &sipAddress) {
ContactModel *mappedContact = mapSipAddressToContact(sipAddress);
if (mappedContact) {
qWarning() << "Unable to map sip address" << sipAddress << "to" << contact.get() << "- already used by" << mappedContact;
return;
}
addOrUpdateSipAddress(sipAddress, contact);
}
void SipAddressesModel::handleSipAddressRemoved (QSharedPointer<ContactModel> contact, const QString &sipAddress) {
ContactModel *mappedContact = mapSipAddressToContact(sipAddress);
if (contact.get() != mappedContact) {
qWarning() << "Unable to remove sip address" << sipAddress << "of" << contact.get() << "- already used by" << mappedContact;
return;
}
removeContactOfSipAddress(sipAddress);
}
void SipAddressesModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &message) {
const QString peerAddress(Utils::coreStringToAppString(message->getChatRoom()->getPeerAddress()->asStringUriOnly()));
addOrUpdateSipAddress(peerAddress, message);
}
void SipAddressesModel::handleMessagesReceived (const std::list<shared_ptr<linphone::ChatMessage>> &messages) {
for(auto message: messages){
const QString peerAddress(Utils::coreStringToAppString(message->getChatRoom()->getPeerAddress()->asStringUriOnly()));
addOrUpdateSipAddress(peerAddress, message);
}
}
void SipAddressesModel::handleCallStateChanged (
const shared_ptr<linphone::Call> &call,
linphone::Call::State state
) {
if (state == linphone::Call::State::End || state == linphone::Call::State::Error)
addOrUpdateSipAddress(
Utils::coreStringToAppString(call->getRemoteAddress()->asStringUriOnly()), call
);
}
void SipAddressesModel::handlePresenceReceived (
const QString &sipAddress,
const shared_ptr<const linphone::PresenceModel> &presenceModel
) {
Presence::PresenceStatus status;
switch (presenceModel->getConsolidatedPresence()) {
case linphone::ConsolidatedPresence::Online:
status = Presence::PresenceStatus::Online;
break;
case linphone::ConsolidatedPresence::Busy:
status = Presence::PresenceStatus::Busy;
break;
case linphone::ConsolidatedPresence::DoNotDisturb:
status = Presence::PresenceStatus::DoNotDisturb;
break;
case linphone::ConsolidatedPresence::Offline:
status = Presence::PresenceStatus::Offline;
break;
}
auto it = mPeerAddressToSipAddressEntry.find(sipAddress);
if (it != mPeerAddressToSipAddressEntry.end()) {
qInfo() << QStringLiteral("Update presence of `%1`: %2.").arg(sipAddress).arg(status);
it->presenceStatus = status;
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
}
updateObservers(sipAddress, status);
}
void SipAddressesModel::handleAllEntriesRemoved (ChatRoomModel *chatRoomModel) {
auto it = mPeerAddressToSipAddressEntry.find(chatRoomModel->getPeerAddress());
if (it == mPeerAddressToSipAddressEntry.end())
return;
auto it2 = it->localAddressToConferenceEntry.find(Utils::cleanSipAddress(chatRoomModel->getLocalAddress()));
if (it2 == it->localAddressToConferenceEntry.end())
return;
it->localAddressToConferenceEntry.erase(it2);
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
// No history, no contact => Remove sip address from list.
if (!it->contact && it->localAddressToConferenceEntry.empty()) {
removeRow(row);
return;
}
emit dataChanged(index(row, 0), index(row, 0));
}
void SipAddressesModel::handleLastEntryRemoved (ChatRoomModel *chatRoomModel) {
auto it = mPeerAddressToSipAddressEntry.find(chatRoomModel->getPeerAddress());
if (it == mPeerAddressToSipAddressEntry.end())
return;
auto it2 = it->localAddressToConferenceEntry.find(Utils::cleanSipAddress(chatRoomModel->getLocalAddress()));
if (it2 == it->localAddressToConferenceEntry.end())
return;
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
Q_ASSERT(chatRoomModel->rowCount() > 0);
const QVariantMap map = chatRoomModel->data(
chatRoomModel->index(chatRoomModel->rowCount() - 1, 0),
ChatRoomModel::ChatEntry
).toMap();
// Update the timestamp with the new last chat message timestamp.
it2->timestamp = map["timestamp"].toDateTime();
emit dataChanged(index(row, 0), index(row, 0));
}
void SipAddressesModel::handleAllCallCountReset () {
for( auto peer = mPeerAddressToSipAddressEntry.begin() ; peer != mPeerAddressToSipAddressEntry.end() ; ++peer){
for( auto local = peer->localAddressToConferenceEntry.begin() ; local != peer->localAddressToConferenceEntry.end() ; ++local){
local->missedCallCount = 0;
updateObservers(peer.key(), local.key(), local->unreadMessageCount, local->missedCallCount);
}
int row = mRefs.indexOf(&(*peer));
emit dataChanged(index(row, 0), index(row, 0));
}
}
void SipAddressesModel::handleMessageCountReset (ChatRoomModel *chatRoomModel) {
const QString &peerAddress = Utils::cleanSipAddress(chatRoomModel->getPeerAddress());
auto it = mPeerAddressToSipAddressEntry.find(peerAddress);
if (it == mPeerAddressToSipAddressEntry.end())
return;
const QString &localAddress = Utils::cleanSipAddress(chatRoomModel->getLocalAddress());
auto it2 = it->localAddressToConferenceEntry.find(localAddress);
if (it2 == it->localAddressToConferenceEntry.end())
return;
it2->unreadMessageCount = 0;
it2->missedCallCount = 0;
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
updateObservers(peerAddress, localAddress, 0, 0);
}
void SipAddressesModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &message) {
if(message->getChatRoom() && message->getChatRoom()->getPeerAddress()){
const QString peerAddress(Utils::coreStringToAppString(message->getChatRoom()->getPeerAddress()->asStringUriOnly()));
addOrUpdateSipAddress(peerAddress, message);
}
}
void SipAddressesModel::handleIsComposingChanged (const shared_ptr<linphone::ChatRoom> &chatRoom) {
auto it = mPeerAddressToSipAddressEntry.find(Utils::cleanSipAddress(Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly())));
if (it == mPeerAddressToSipAddressEntry.end())
return;
auto it2 = it->localAddressToConferenceEntry.find(
Utils::cleanSipAddress(Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly()))
);
if (it2 == it->localAddressToConferenceEntry.end())
return;
it2->isComposing = chatRoom->isRemoteComposing();
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
}
// -----------------------------------------------------------------------------
void SipAddressesModel::addOrUpdateSipAddress (SipAddressEntry &sipAddressEntry, QSharedPointer<ContactModel> contact) {
const QString &sipAddress = sipAddressEntry.sipAddress;
sipAddressEntry.contact = contact;
if (!sipAddressEntry.contact)
qWarning() << QStringLiteral("`contact` field is empty on sip address: `%1`.").arg(sipAddress);
updateObservers(sipAddress, contact);
}
void SipAddressesModel::addOrUpdateSipAddress (SipAddressEntry &sipAddressEntry, const shared_ptr<linphone::Call> &call) {
const shared_ptr<linphone::CallLog> callLog = call->getCallLog();
QString localAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(callLog->getLocalAddress()->asStringUriOnly())));
QString peerAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(callLog->getRemoteAddress()->asStringUriOnly())));
ConferenceEntry &conferenceEntry = sipAddressEntry.localAddressToConferenceEntry[
localAddress
];
qInfo() << QStringLiteral("Update (`%1`, `%2`) from chat call.").arg(sipAddressEntry.sipAddress, localAddress);
conferenceEntry.timestamp = callLog->getStatus() == linphone::Call::Status::Success
? QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000)
: QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
conferenceEntry.missedCallCount = CoreManager::getInstance()->getMissedCallCount(peerAddress, localAddress);
updateObservers(sipAddressEntry.sipAddress, localAddress, conferenceEntry.unreadMessageCount,conferenceEntry.missedCallCount);
}
void SipAddressesModel::addOrUpdateSipAddress (SipAddressEntry &sipAddressEntry, const shared_ptr<linphone::ChatMessage> &message) {
shared_ptr<linphone::ChatRoom> chatRoom(message->getChatRoom());
int count = chatRoom->getUnreadMessagesCount();
QString localAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly())));
QString peerAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly())));
qInfo() << QStringLiteral("Update (`%1`, `%2`) from chat message.").arg(sipAddressEntry.sipAddress, localAddress);
ConferenceEntry &conferenceEntry = sipAddressEntry.localAddressToConferenceEntry[localAddress];
conferenceEntry.timestamp = QDateTime::fromMSecsSinceEpoch(message->getTime() * 1000);
conferenceEntry.unreadMessageCount = count ;
conferenceEntry.missedCallCount = CoreManager::getInstance()->getMissedCallCount(peerAddress, localAddress);
updateObservers(sipAddressEntry.sipAddress, localAddress, count,conferenceEntry.missedCallCount);
}
template<typename T>
void SipAddressesModel::addOrUpdateSipAddress (const QString &sipAddress, T data) {
auto it = mPeerAddressToSipAddressEntry.find(sipAddress);
if (it != mPeerAddressToSipAddressEntry.end()) {
addOrUpdateSipAddress(*it, data);
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
return;
}
SipAddressEntry sipAddressEntry{ sipAddress, nullptr, Presence::Offline, {} };
addOrUpdateSipAddress(sipAddressEntry, data);
int row = mRefs.count();
beginInsertRows(QModelIndex(), row, row);
mPeerAddressToSipAddressEntry[sipAddress] = move(sipAddressEntry);
mRefs << &mPeerAddressToSipAddressEntry[sipAddress];
endInsertRows();
emit layoutChanged();
}
// -----------------------------------------------------------------------------
void SipAddressesModel::removeContactOfSipAddress (const QString &sipAddress) {
auto it = mPeerAddressToSipAddressEntry.find(sipAddress);
if (it == mPeerAddressToSipAddressEntry.end()) {
qWarning() << QStringLiteral("Unable to remove unavailable sip address: `%1`.").arg(sipAddress);
return;
}
// Try to map other contact on this sip address.
auto contactModel = CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(sipAddress);
updateObservers(sipAddress, contactModel);
qInfo() << QStringLiteral("Map new contact on sip address: `%1`.").arg(sipAddress) << contactModel.get();
addOrUpdateSipAddress(*it, contactModel);
int row = mRefs.indexOf(&(*it));
Q_ASSERT(row != -1);
// History or contact exists, signal changes.
if (!it->localAddressToConferenceEntry.empty() || contactModel) {
emit dataChanged(index(row, 0), index(row, 0));
return;
}
// Remove sip address if no history.
removeRow(row);
}
// -----------------------------------------------------------------------------
void SipAddressesModel::initSipAddresses () {
QElapsedTimer timer, stepsTimer;
timer.start();
stepsTimer.start();
initSipAddressesFromChat();
qInfo() << "Sip addresses model from Chats :" << stepsTimer.restart() << "ms.";
initSipAddressesFromCalls();
qInfo() << "Sip addresses model from Calls :" << stepsTimer.restart() << "ms.";
initRefs();
qInfo() << "Sip addresses model from Refs :" << stepsTimer.restart() << "ms.";
initSipAddressesFromContacts();
qInfo() << "Sip addresses model from Contacts :" << stepsTimer.restart() << "ms.";
qInfo() << "Sip addresses model initialized in:" << timer.elapsed() << "ms.";
}
void SipAddressesModel::initSipAddressesFromChat () {
for (const auto &chatRoom : CoreManager::getInstance()->getCore()->getChatRooms()) {
auto lastMessage = chatRoom->getLastMessageInHistory();
if( !lastMessage)
continue;
QString peerAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly())));
QString localAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly())));
getSipAddressEntry(peerAddress)->localAddressToConferenceEntry[localAddress] = {
chatRoom->getUnreadMessagesCount(),
CoreManager::getInstance()->getMissedCallCount(peerAddress, localAddress),
false,
QDateTime::fromMSecsSinceEpoch(lastMessage->getTime() * 1000)
};
}
}
void SipAddressesModel::initSipAddressesFromCalls () {
using ConferenceId = QPair<QString, QString>;
QSet<ConferenceId> conferenceDone;
for (const auto &callLog : CoreManager::getInstance()->getCore()->getCallLogs()) {
const QString peerAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(callLog->getRemoteAddress()->asStringUriOnly())));
const QString localAddress(Utils::cleanSipAddress(Utils::coreStringToAppString(callLog->getLocalAddress()->asStringUriOnly())));
ConferenceId conferenceId{ peerAddress, localAddress };
if (conferenceDone.contains(conferenceId))
continue; // Already used.
conferenceDone << conferenceId;
// The duration can be wrong if status is not success.
QDateTime timestamp(callLog->getStatus() == linphone::Call::Status::Success
? QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000)
: QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000));
auto &localToConferenceEntry = getSipAddressEntry(peerAddress)->localAddressToConferenceEntry;
auto it = localToConferenceEntry.find(localAddress);
if (it == localToConferenceEntry.end())
localToConferenceEntry[localAddress] = { 0,0, false, move(timestamp) };
else if (it->timestamp.isNull() || timestamp > it->timestamp)
it->timestamp = move(timestamp);
}
}
void SipAddressesModel::initSipAddressesFromContacts () {
for (auto &contact : CoreManager::getInstance()->getContactsListModel()->mList)
handleContactAdded(contact.objectCast<ContactModel>());
}
void SipAddressesModel::initRefs () {
for (const auto &sipAddressEntry : mPeerAddressToSipAddressEntry)
mRefs << &sipAddressEntry;
}
// -----------------------------------------------------------------------------
void SipAddressesModel::updateObservers (const QString &sipAddress, QSharedPointer<ContactModel> contact) {
for (auto &observer : mObservers.values(sipAddress))
observer->setContact(contact);
}
void SipAddressesModel::updateObservers (const QString &sipAddress, const Presence::PresenceStatus &presenceStatus) {
for (auto &observer : mObservers.values(sipAddress))
observer->setPresenceStatus(presenceStatus);
}
void SipAddressesModel::updateObservers (const QString &peerAddress, const QString &localAddress, int messageCount, int missedCallCount) {
for (auto &observer : mObservers.values(peerAddress)) {
if (observer->getLocalAddress() == localAddress) {
observer->setUnreadMessageCount(messageCount+missedCallCount);
return;
}
}
}