Commit f181b6d6 authored by Ronan Abhamon's avatar Ronan Abhamon

feat(app):

  - supports linphone cbs
  - handle received messages
  - `SipAddressesModel` refactoring
parent 555bf660
linphone @ fb3c9841
Subproject commit 7650064a1cb5b914b157c788e4ff8fa22d971f78
Subproject commit fb3c9841ee5142d1826e2674591797343bd728ff
......@@ -48,6 +48,7 @@ endforeach ()
list(APPEND LIBS "${CMAKE_SOURCE_DIR}/../OUTPUT/desktop/lib64/liblinphone++.so")
list(APPEND LIBS "${CMAKE_SOURCE_DIR}/../OUTPUT/desktop/lib64/libbelcard.so")
list(APPEND LIBS "${CMAKE_SOURCE_DIR}/../OUTPUT/desktop/lib64/libbellesip.so")
set(SOURCES
src/app/App.cpp
......@@ -63,6 +64,7 @@ set(SOURCES
src/components/contact/VcardModel.cpp
src/components/contacts/ContactsListModel.cpp
src/components/contacts/ContactsListProxyModel.cpp
src/components/core/CoreHandlers.cpp
src/components/core/CoreManager.cpp
src/components/notifier/Notifier.cpp
src/components/settings/AccountSettingsModel.cpp
......@@ -87,6 +89,7 @@ set(HEADERS
src/components/contact/VcardModel.hpp
src/components/contacts/ContactsListModel.hpp
src/components/contacts/ContactsListProxyModel.hpp
src/components/core/CoreHandlers.hpp
src/components/core/CoreManager.hpp
src/components/notifier/Notifier.hpp
src/components/presence/Presence.hpp
......
......@@ -70,6 +70,8 @@ void App::initContentApp () {
registerTypes();
addContextProperties();
CoreManager::getInstance()->enableHandlers();
// Load main view.
qInfo() << "Loading main view...";
m_engine.load(QUrl(QML_VIEW_MAIN_WINDOW));
......
......@@ -6,12 +6,20 @@
#include "Database.hpp"
// =============================================================================
#ifdef _WIN32
#define DATABASES_PATH \
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
#define DATABASE_PATH_CONFIG "linphonerc"
#else
#define DATABASES_PATH \
QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
#define DATABASE_PATH_CONFIG ".linphonerc"
#endif // ifdef _WIN32
#define DATABASE_PATH_AVATARS ".linphone/avatars/"
......@@ -56,6 +64,10 @@ string Database::getCallHistoryPath () {
return getDatabaseFilePath(DATABASE_PATH_CALL_HISTORY_LIST);
}
string Database::getConfigPath () {
return getDatabaseFilePath(DATABASE_PATH_CONFIG);
}
string Database::getFriendsListPath () {
return getDatabaseFilePath(DATABASE_PATH_FRIENDS_LIST);
}
......
......@@ -12,6 +12,7 @@ namespace Database {
std::string getAvatarsPath ();
std::string getCallHistoryPath ();
std::string getConfigPath ();
std::string getFriendsListPath ();
std::string getMessageHistoryPath ();
}
......
#include <QtDebug>
#include "CoreManager.hpp"
#include "CoreHandlers.hpp"
using namespace std;
// =============================================================================
void CoreHandlers::onAuthenticationRequested (
const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::AuthInfo> &auth_info,
linphone::AuthMethod method
) {
qDebug() << "Auth request";
}
void CoreHandlers::onCallStateChanged (
const shared_ptr<linphone::Core> &lc,
const shared_ptr<linphone::Call> &call,
linphone::CallState cstate,
const string &message
) {
qDebug() << "call";
}
void CoreHandlers::onMessageReceived (
const shared_ptr<linphone::Core> &lc,
const shared_ptr<linphone::ChatRoom> &room,
const shared_ptr<linphone::ChatMessage> &message
) {
CoreManager::getInstance()->getSipAddressesModel()->handleReceivedMessage(room, message);
}
#ifndef CORE_HANDLERS_H_
#define CORE_HANDLERS_H_
#include <linphone++/linphone.hh>
// =============================================================================
class CoreHandlers : public linphone::CoreListener {
public:
void onAuthenticationRequested (
const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::AuthInfo> &auth_info,
linphone::AuthMethod method
) override;
void onCallStateChanged (
const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call,
linphone::CallState cstate,
const std::string &message
) override;
void onMessageReceived (
const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message
) override;
};
#endif // CORE_HANDLERS_H_
#include <QTimer>
#include "../../app/Database.hpp"
#include "CoreHandlers.hpp"
#include "CoreManager.hpp"
......@@ -8,17 +11,37 @@ using namespace std;
CoreManager *CoreManager::m_instance = nullptr;
CoreManager::CoreManager (QObject *parent) : QObject(parent),
m_core(linphone::Factory::get()->createCore(nullptr, "", "", nullptr)) {
CoreManager::CoreManager (QObject *parent) : QObject(parent), m_handlers(make_shared<CoreHandlers>()) {
string config_path = Database::getConfigPath();
if (config_path.length() == 0)
qFatal("Unable to get config path.");
m_core = linphone::Factory::get()->createCore(m_handlers, config_path, "");
setDatabasesPaths();
}
CoreManager::~CoreManager () {
delete m_cbs_timer;
}
void CoreManager::enableHandlers () {
m_cbs_timer->start();
}
void CoreManager::init () {
if (!m_instance) {
m_instance = new CoreManager();
m_instance->m_contacts_list_model = new ContactsListModel(m_instance);
m_instance->m_sip_addresses_model = new SipAddressesModel(m_instance);
QTimer *timer = m_instance->m_cbs_timer = new QTimer(m_instance);
timer->setInterval(20);
QObject::connect(
timer, &QTimer::timeout, m_instance, []() {
m_instance->m_core->iterate();
}
);
}
}
......
......@@ -6,11 +6,13 @@
// =============================================================================
class QTimer;
class CoreManager : public QObject {
Q_OBJECT;
public:
~CoreManager () = default;
~CoreManager ();
std::shared_ptr<linphone::Core> getCore () {
return m_core;
......@@ -28,6 +30,8 @@ public:
return m_sip_addresses_model;
}
void enableHandlers ();
static void init ();
static CoreManager *getInstance () {
......@@ -44,9 +48,13 @@ private:
void setDatabasesPaths ();
std::shared_ptr<linphone::Core> m_core;
std::shared_ptr<linphone::CoreListener> m_handlers;
ContactsListModel *m_contacts_list_model;
SipAddressesModel *m_sip_addresses_model;
QTimer *m_cbs_timer;
static CoreManager *m_instance;
};
......
......@@ -3,8 +3,7 @@
// ===================================================================
AccountSettingsModel::AccountSettingsModel (QObject *parent) :
QObject(parent) {
}
QObject(parent) {}
QString AccountSettingsModel::getUsername () const {
return "Edward Miller ";
......@@ -12,7 +11,7 @@ QString AccountSettingsModel::getUsername () const {
void AccountSettingsModel::setUsername (const QString &username) {
// NOTHING TODO.
(void)username;
(void) username;
}
Presence::PresenceLevel AccountSettingsModel::getPresenceLevel () const {
......@@ -30,3 +29,16 @@ QString AccountSettingsModel::getSipAddress () const {
bool AccountSettingsModel::getAutoAnswerStatus () const {
return true;
}
// TODO: TMP
/*
shared_ptr<linphone::ProxyConfig> cfg = m_core->getDefaultProxyConfig();
shared_ptr<linphone::Address> address = cfg->getIdentityAddress();
shared_ptr<linphone::AuthInfo> auth_info = m_core->findAuthInfo("", address->getUsername(), cfg->getDomain());
if (auth_info)
qDebug() << "OK";
else
qDebug() << "FAIL";
*/
......@@ -8,20 +8,16 @@
#include "SipAddressesModel.hpp"
using namespace std;
// =============================================================================
SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(parent) {
fetchSipAddresses();
initSipAddresses();
ContactsListModel *contacts = CoreManager::getInstance()->getContactsListModel();
QObject::connect(contacts, &ContactsListModel::contactAdded, this, &SipAddressesModel::updateFromNewContact);
QObject::connect(
contacts, &ContactsListModel::contactRemoved, this, [this](const ContactModel *contact) {
for (const auto &sip_address : contact->getVcardModel()->getSipAddresses())
tryToRemoveSipAddress(sip_address.toString());
}
);
QObject::connect(contacts, &ContactsListModel::contactAdded, this, &SipAddressesModel::handleContactAdded);
QObject::connect(contacts, &ContactsListModel::contactRemoved, this, &SipAddressesModel::handleContactRemoved);
QObject::connect(
contacts, &ContactsListModel::sipAddressAdded, this, [this](ContactModel *contact, const QString &sip_address) {
......@@ -32,7 +28,7 @@ SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(pare
return;
}
updateFromNewContactSipAddress(contact, sip_address);
addOrUpdateSipAddress(sip_address, contact);
}
);
......@@ -44,7 +40,7 @@ SipAddressesModel::SipAddressesModel (QObject *parent) : QAbstractListModel(pare
return;
}
tryToRemoveSipAddress(sip_address);
removeContactOfSipAddress(sip_address);
}
);
}
......@@ -133,6 +129,14 @@ void SipAddressesModel::handleAllHistoryEntriesRemoved () {
emit dataChanged(index(row, 0), index(row, 0));
}
void SipAddressesModel::handleReceivedMessage (
const shared_ptr<linphone::ChatRoom> &room,
const shared_ptr<linphone::ChatMessage> &message
) {
const QString &sip_address = ::Utils::linphoneStringToQString(message->getFromAddress()->asString());
addOrUpdateSipAddress(sip_address, nullptr, static_cast<qint64>(message->getTime()));
}
// -----------------------------------------------------------------------------
bool SipAddressesModel::removeRow (int row, const QModelIndex &parent) {
......@@ -160,49 +164,60 @@ bool SipAddressesModel::removeRows (int row, int count, const QModelIndex &paren
return true;
}
void SipAddressesModel::updateFromNewContact (ContactModel *contact) {
void SipAddressesModel::handleContactAdded (ContactModel *contact) {
for (const auto &sip_address : contact->getVcardModel()->getSipAddresses())
updateFromNewContactSipAddress(contact, sip_address.toString());
addOrUpdateSipAddress(sip_address.toString(), contact);
}
void SipAddressesModel::updateFromNewContactSipAddress (ContactModel *contact, const QString &sip_address) {
void SipAddressesModel::handleContactRemoved (const ContactModel *contact) {
for (const auto &sip_address : contact->getVcardModel()->getSipAddresses())
removeContactOfSipAddress(sip_address.toString());
}
void SipAddressesModel::addOrUpdateSipAddress (const QString &sip_address, ContactModel *contact, qint64 timestamp) {
auto it = m_sip_addresses.find(sip_address);
if (it != m_sip_addresses.end()) {
if (contact) {
(*it)["contact"] = QVariant::fromValue(contact);
updateObservers(sip_address, contact);
}
// New sip address.
if (it == m_sip_addresses.end()) {
QVariantMap map;
map["sipAddress"] = sip_address;
map["contact"] = QVariant::fromValue(contact);
if (timestamp)
(*it)["timestamp"] = QDateTime::fromMSecsSinceEpoch(timestamp * 1000);
updateObservers(sip_address, contact);
int row = m_refs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
int row = m_refs.count();
return;
}
beginInsertRows(QModelIndex(), row, row);
QVariantMap map;
map["sipAddress"] = sip_address;
qInfo() << QStringLiteral("Add sip address: `%1`.").arg(sip_address);
if (contact) {
map["contact"] = QVariant::fromValue(contact);
updateObservers(sip_address, contact);
}
m_sip_addresses[sip_address] = map;
m_refs << &m_sip_addresses[sip_address];
if (timestamp)
map["timestamp"] = QDateTime::fromMSecsSinceEpoch(timestamp * 1000);
endInsertRows();
int row = m_refs.count();
emit dataChanged(index(row, 0), index(row, 0));
beginInsertRows(QModelIndex(), row, row);
return;
}
qInfo() << QStringLiteral("Add sip address: `%1`.").arg(sip_address);
// Sip address exists, update contact.
(*it)["contact"] = QVariant::fromValue(contact);
m_sip_addresses[sip_address] = map;
m_refs << &m_sip_addresses[sip_address];
updateObservers(sip_address, contact);
endInsertRows();
int row = m_refs.indexOf(&(*it));
Q_ASSERT(row != -1);
emit dataChanged(index(row, 0), index(row, 0));
}
void SipAddressesModel::tryToRemoveSipAddress (const QString &sip_address) {
void SipAddressesModel::removeContactOfSipAddress (const QString &sip_address) {
auto it = m_sip_addresses.find(sip_address);
if (it == m_sip_addresses.end()) {
qWarning() << QStringLiteral("Unable to remove unavailable sip address: `%1`.").arg(sip_address);
......@@ -227,7 +242,7 @@ void SipAddressesModel::tryToRemoveSipAddress (const QString &sip_address) {
removeRow(row);
}
void SipAddressesModel::fetchSipAddresses () {
void SipAddressesModel::initSipAddresses () {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
// Get sip addresses from chatrooms.
......@@ -275,7 +290,7 @@ void SipAddressesModel::fetchSipAddresses () {
// Get sip addresses from contacts.
for (auto &contact : CoreManager::getInstance()->getContactsListModel()->m_list)
updateFromNewContact(contact);
handleContactAdded(contact);
}
void SipAddressesModel::updateObservers (const QString &sip_address, ContactModel *contact) {
......
......@@ -25,15 +25,22 @@ public:
Q_INVOKABLE void handleAllHistoryEntriesRemoved ();
void handleReceivedMessage (
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message
);
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
void updateFromNewContact (ContactModel *contact);
void updateFromNewContactSipAddress (ContactModel *contact, const QString &sip_address);
void tryToRemoveSipAddress (const QString &sip_address);
void handleContactAdded (ContactModel *contact);
void handleContactRemoved (const ContactModel *contact);
void addOrUpdateSipAddress (const QString &sip_address, ContactModel *contact = nullptr, qint64 timestamp = 0);
void removeContactOfSipAddress (const QString &sip_address);
void fetchSipAddresses ();
void initSipAddresses ();
void updateObservers (const QString &sip_address, ContactModel *contact);
......
#include <QDateTime>
#include "../core/CoreManager.hpp"
#include "TimelineModel.hpp"
......@@ -23,5 +25,6 @@ bool TimelineModel::filterAcceptsRow (int source_row, const QModelIndex &source_
}
bool TimelineModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
return sourceModel()->data(left).toMap()["timestamp"] > sourceModel()->data(right).toMap()["timestamp"];
return sourceModel()->data(left).toMap()["timestamp"].toDateTime().toMSecsSinceEpoch() >
sourceModel()->data(right).toMap()["timestamp"].toDateTime().toMSecsSinceEpoch();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment